Update Cryville.Common.
This commit is contained in:
@@ -1,12 +1,30 @@
|
||||
using System;
|
||||
|
||||
namespace Cryville.Common {
|
||||
/// <summary>
|
||||
/// Represents a cancellable asynchronized task.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class AsyncDelivery<T> {
|
||||
/// <summary>
|
||||
/// The delegate to cancel the task.
|
||||
/// </summary>
|
||||
public Action CancelSource { private get; set; }
|
||||
/// <summary>
|
||||
/// The delegate to call on task completion.
|
||||
/// </summary>
|
||||
public Action<bool, T> Destination { private get; set; }
|
||||
/// <summary>
|
||||
/// Delivers the result to the destination.
|
||||
/// </summary>
|
||||
/// <param name="succeeded">Whether the task has succeeded.</param>
|
||||
/// <param name="result">The result.</param>
|
||||
public void Deliver(bool succeeded, T result) {
|
||||
if (Destination != null) Destination(succeeded, result);
|
||||
}
|
||||
/// <summary>
|
||||
/// Cancels the task.
|
||||
/// </summary>
|
||||
public void Cancel() {
|
||||
if (CancelSource != null) CancelSource();
|
||||
}
|
||||
|
@@ -1,22 +1,42 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Cryville.Common {
|
||||
/// <summary>
|
||||
/// Provides a set of <see langword="static" /> methods related to file system and IO.
|
||||
/// </summary>
|
||||
public static class IOExtensions {
|
||||
/// <summary>
|
||||
/// Gets a subdirectory of a directory. The subdirectory is created if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="dir">The parent directory.</param>
|
||||
/// <param name="name">The name of the subdirectory.</param>
|
||||
/// <returns></returns>
|
||||
public static DirectoryInfo GetSubdirectory(this DirectoryInfo dir, string name) {
|
||||
var l1 = dir.GetDirectories(name);
|
||||
if (l1.Length == 0) return dir.CreateSubdirectory(name);
|
||||
else return l1[0];
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads a string length-prefixed with a <see cref="System.UInt16" />.
|
||||
/// </summary>
|
||||
/// <param name="reader">The binary reader.</param>
|
||||
/// <param name="encoding">The encoding of the string.</param>
|
||||
/// <returns>The string read from the reader.</returns>
|
||||
public static string ReadUInt16String(this BinaryReader reader, Encoding encoding = null) {
|
||||
if (encoding == null) encoding = Encoding.UTF8;
|
||||
var len = reader.ReadUInt16();
|
||||
byte[] buffer = reader.ReadBytes(len);
|
||||
return encoding.GetString(buffer);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string length-prefixed with a <see cref="System.UInt16" />.
|
||||
/// </summary>
|
||||
/// <param name="writer">The binary writer.</param>
|
||||
/// <param name="value">The string to write by the writer.</param>
|
||||
/// <param name="encoding">The encoding of the string.</param>
|
||||
public static void WriteUInt16String(this BinaryWriter writer, string value, Encoding encoding = null) {
|
||||
if (encoding == null) encoding = Encoding.UTF8;
|
||||
byte[] buffer = encoding.GetBytes(value);
|
||||
|
@@ -1,23 +1,42 @@
|
||||
using Ionic.Zip;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Cryville.Common {
|
||||
/// <summary>
|
||||
/// A logger.
|
||||
/// </summary>
|
||||
public abstract class Logger {
|
||||
static readonly Dictionary<string, Logger> Instances = new Dictionary<string, Logger>();
|
||||
static readonly Dictionary<string, StreamWriter> Files = new Dictionary<string, StreamWriter>();
|
||||
static string logPath = null;
|
||||
/// <summary>
|
||||
/// Sets the path where the log files shall be stored.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
public static void SetLogPath(string path) {
|
||||
logPath = path;
|
||||
var dir = new DirectoryInfo(path);
|
||||
if (!dir.Exists) Directory.CreateDirectory(dir.FullName);
|
||||
}
|
||||
/// <summary>
|
||||
/// Logs to the specified logger.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the logger.</param>
|
||||
/// <param name="level">The severity level.</param>
|
||||
/// <param name="module">The module that is logging.</param>
|
||||
/// <param name="format">The format string.</param>
|
||||
/// <param name="args">The arguments for formatting.</param>
|
||||
public static void Log(string key, int level, string module, string format, params object[] args) {
|
||||
if (!Instances.ContainsKey(key)) return;
|
||||
Instances[key].Log(level, module, string.Format(format, args));
|
||||
if (Files.ContainsKey(key)) Files[key].WriteLine("[{0:O}] [{1}] <{2}> {3}", DateTime.UtcNow, level, module, string.Format(format, args));
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds a created logger to the shared logger manager.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the logger.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
public static void Create(string key, Logger logger) {
|
||||
Instances[key] = logger;
|
||||
if (logPath != null) {
|
||||
@@ -26,37 +45,65 @@ namespace Cryville.Common {
|
||||
};
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Closes all loggers and related file streams.
|
||||
/// </summary>
|
||||
public static void Close() {
|
||||
Instances.Clear();
|
||||
foreach (var f in Files) f.Value.Dispose();
|
||||
Files.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs to the logger.
|
||||
/// </summary>
|
||||
/// <param name="level">The severity level.</param>
|
||||
/// <param name="module">The module that is logging.</param>
|
||||
/// <param name="msg">The message.</param>
|
||||
public virtual void Log(int level, string module, string msg) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="Logger" /> that calls a callback function on log.
|
||||
/// </summary>
|
||||
public class InstantLogger : Logger {
|
||||
readonly Action<int, string, string> callback;
|
||||
/// <summary>
|
||||
/// Creates an instance of the <see cref="InstantLogger" /> class.
|
||||
/// </summary>
|
||||
/// <param name="callback">The callback function.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="callback" /> is <see langword="null" />.</exception>
|
||||
public InstantLogger(Action<int, string, string> callback) {
|
||||
if (callback == null)
|
||||
throw new ArgumentNullException("callback");
|
||||
this.callback = callback;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override void Log(int level, string module, string msg) {
|
||||
base.Log(level, module, msg);
|
||||
callback(level, module, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="Logger" /> that buffers the logs for enumeration.
|
||||
/// </summary>
|
||||
public class BufferedLogger : Logger {
|
||||
readonly List<LogEntry> buffer = new List<LogEntry>();
|
||||
/// <summary>
|
||||
/// Creates an instance of the <see cref="BufferedLogger" /> class.
|
||||
/// </summary>
|
||||
public BufferedLogger() { }
|
||||
/// <inheritdoc />
|
||||
public override void Log(int level, string module, string msg) {
|
||||
base.Log(level, module, msg);
|
||||
lock (buffer) {
|
||||
buffer.Add(new LogEntry(level, module, msg));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerates the buffered logs.
|
||||
/// </summary>
|
||||
/// <param name="callback">The callback function to receive the logs.</param>
|
||||
public void Enumerate(Action<int, string, string> callback) {
|
||||
lock (buffer) {
|
||||
foreach (var i in buffer) {
|
||||
@@ -67,7 +114,7 @@ namespace Cryville.Common {
|
||||
}
|
||||
}
|
||||
|
||||
public struct LogEntry {
|
||||
struct LogEntry {
|
||||
public int level;
|
||||
public string module;
|
||||
public string msg;
|
||||
|
@@ -1,18 +1,38 @@
|
||||
namespace Cryville.Common.Math {
|
||||
/// <summary>
|
||||
/// Represents a column vector of vector type <typeparamref name="T" />.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The vector type of the elements.</typeparam>
|
||||
public class ColumnVector<T> {
|
||||
readonly T[] content;
|
||||
/// <summary>
|
||||
/// The size of the vector.
|
||||
/// </summary>
|
||||
public int Size {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a column vector with specified size.
|
||||
/// </summary>
|
||||
/// <param name="size">The size of the vector.</param>
|
||||
public ColumnVector(int size) {
|
||||
content = new T[size];
|
||||
Size = size;
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a column vector from an array.
|
||||
/// </summary>
|
||||
/// <param name="c">The array.</param>
|
||||
public ColumnVector(T[] c) {
|
||||
Size = c.Length;
|
||||
content = c;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the element at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="i">The zero-based index of the element to get or set.</param>
|
||||
/// <returns>The element at the specified index.</returns>
|
||||
public T this[int i] {
|
||||
get {
|
||||
return content[i];
|
||||
@@ -21,12 +41,24 @@ namespace Cryville.Common.Math {
|
||||
content[i] = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Performs dot operation with a <see cref="System.Single" /> column vector.
|
||||
/// </summary>
|
||||
/// <param name="lhs">The lefthand column vector.</param>
|
||||
/// <param name="o">The vector operator.</param>
|
||||
/// <returns>The result of the dot operation.</returns>
|
||||
public T Dot(ColumnVector<float> lhs, IVectorOperator<T> o) {
|
||||
T res = default(T);
|
||||
for (var i = 0; i < Size; i++)
|
||||
res = o.Add(res, o.ScalarMultiply(lhs[i], content[i]));
|
||||
return res;
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a <see cref="System.Single" /> column vector and fills it with polynomial coefficients.
|
||||
/// </summary>
|
||||
/// <param name="size">The size of the column vector.</param>
|
||||
/// <param name="num">The base number.</param>
|
||||
/// <returns>A <see cref="System.Single" /> column vector filled with polynomial coefficients.</returns>
|
||||
public static ColumnVector<float> WithPolynomialCoefficients(int size, float num) {
|
||||
var m = new ColumnVector<float>(size);
|
||||
for (var i = 0; i < size; i++)
|
||||
|
@@ -1,6 +1,22 @@
|
||||
namespace Cryville.Common.Math {
|
||||
/// <summary>
|
||||
/// Provides a set of operators for vector type <typeparamref name="T" />.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The vector type.</typeparam>
|
||||
public interface IVectorOperator<T> {
|
||||
/// <summary>
|
||||
/// Adds two vectors.
|
||||
/// </summary>
|
||||
/// <param name="lhs">Lefthand vector.</param>
|
||||
/// <param name="rhs">Righthand vector.</param>
|
||||
/// <returns>The sum of the two vectors.</returns>
|
||||
T Add(T lhs, T rhs);
|
||||
/// <summary>
|
||||
/// Multiplies a vector with a number.
|
||||
/// </summary>
|
||||
/// <param name="lhs">The number.</param>
|
||||
/// <param name="rhs">The vector.</param>
|
||||
/// <returns>The product of the number and the vector.</returns>
|
||||
T ScalarMultiply(float lhs, T rhs);
|
||||
}
|
||||
}
|
||||
|
@@ -1,18 +1,41 @@
|
||||
namespace Cryville.Common.Math {
|
||||
/// <summary>
|
||||
/// Represents a square matrix.
|
||||
/// </summary>
|
||||
public class SquareMatrix {
|
||||
readonly float[,] content;
|
||||
/// <summary>
|
||||
/// The size of the matrix.
|
||||
/// </summary>
|
||||
public int Size {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a square matrix with the specified size.
|
||||
/// </summary>
|
||||
/// <param name="size">The size of the matrix.</param>
|
||||
public SquareMatrix(int size) {
|
||||
content = new float[size, size];
|
||||
Size = size;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the element at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="r">The zero-based row index.</param>
|
||||
/// <param name="c">The zero-based column index.</param>
|
||||
/// <returns>The element at the specified index.</returns>
|
||||
public float this[int r, int c] {
|
||||
get { return content[r, c]; }
|
||||
set { content[r, c] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Eliminates the square matrix against a column vector.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The vector type.</typeparam>
|
||||
/// <param name="v">The column vector.</param>
|
||||
/// <param name="o">The column operator.</param>
|
||||
/// <returns>The column vector eliminated.</returns>
|
||||
public ColumnVector<T> Eliminate<T>(ColumnVector<T> v, IVectorOperator<T> o) {
|
||||
int s = Size;
|
||||
float[,] d = (float[,])content.Clone();
|
||||
@@ -48,6 +71,11 @@
|
||||
}
|
||||
return new ColumnVector<T>(res);
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a square matrix and fills it with polynomial coefficients.
|
||||
/// </summary>
|
||||
/// <param name="size">The size of the square matrix.</param>
|
||||
/// <returns>A square matrix filled with polynomial coefficients.</returns>
|
||||
public static SquareMatrix WithPolynomialCoefficients(int size) {
|
||||
var m = new SquareMatrix(size);
|
||||
for (var r = 0; r < size; r++) {
|
||||
|
@@ -4,16 +4,36 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Cryville.Common {
|
||||
/// <summary>
|
||||
/// Provides a set of <see langword="static" /> methods for refletion.
|
||||
/// </summary>
|
||||
public static class ReflectionHelper {
|
||||
static readonly Type[] emptyTypeArray = {};
|
||||
/// <summary>
|
||||
/// Gets the parameterless constructor of a type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <returns>The parameterless constructor of the type.</returns>
|
||||
public static ConstructorInfo GetEmptyConstructor(Type type) {
|
||||
return type.GetConstructor(emptyTypeArray);
|
||||
}
|
||||
static readonly object[] emptyObjectArray = {};
|
||||
/// <summary>
|
||||
/// Invokes the parameterless constructor of a type and returns the result.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <returns>The created instance.</returns>
|
||||
public static object InvokeEmptyConstructor(Type type) {
|
||||
return GetEmptyConstructor(type).Invoke(emptyObjectArray);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find a member with the specified attribute type in a type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The attribute type.</typeparam>
|
||||
/// <param name="t">The type containing the member with the specified attribute type.</param>
|
||||
/// <param name="mi">The member.</param>
|
||||
/// <returns>Whether the member is found.</returns>
|
||||
public static bool TryFindMemberWithAttribute<T>(Type t, out MemberInfo mi) where T : Attribute {
|
||||
try {
|
||||
mi = FindMemberWithAttribute<T>(t);
|
||||
@@ -24,6 +44,13 @@ namespace Cryville.Common {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Finds a member with the specified attribute type in a type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The attribute type.</typeparam>
|
||||
/// <param name="type">The type containing the member with the specified attribute type.</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="MissingMemberException">The member is not found or multiple members are found.</exception>
|
||||
public static MemberInfo FindMemberWithAttribute<T>(Type type) where T : Attribute {
|
||||
var mil = type.FindMembers(
|
||||
MemberTypes.Field | MemberTypes.Property,
|
||||
@@ -36,10 +63,22 @@ namespace Cryville.Common {
|
||||
return mil[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether a type is a <see cref="Dictionary{TKey, TValue}" />.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <returns>Whether the type is a <see cref="Dictionary{TKey, TValue}" />.</returns>
|
||||
public static bool IsGenericDictionary(Type type) {
|
||||
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the member from a type with the specified name.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="name">The name of the member.</param>
|
||||
/// <returns>The member.</returns>
|
||||
/// <exception cref="MissingMemberException">The member is not found or multiple members are found.</exception>
|
||||
public static MemberInfo GetMember(Type type, string name) {
|
||||
var mil = type.GetMember(
|
||||
name,
|
||||
@@ -50,16 +89,29 @@ namespace Cryville.Common {
|
||||
throw new MissingMemberException(type.Name, name);
|
||||
return mil[0];
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of a member.
|
||||
/// </summary>
|
||||
/// <param name="mi">The member.</param>
|
||||
/// <returns>The type of the member.</returns>
|
||||
/// <exception cref="ArgumentException"><paramref name="mi" /> is not a field or a property.</exception>
|
||||
public static Type GetMemberType(MemberInfo mi) {
|
||||
if (mi is FieldInfo)
|
||||
return ((FieldInfo)mi).FieldType;
|
||||
if (mi is PropertyInfo)
|
||||
return ((PropertyInfo)mi).PropertyType;
|
||||
else
|
||||
throw new ArgumentException();
|
||||
throw new ArgumentException("Member is not field or property.");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a member of an object.
|
||||
/// </summary>
|
||||
/// <param name="mi">The member.</param>
|
||||
/// <param name="obj">The object.</param>
|
||||
/// <returns>The value.</returns>
|
||||
/// <exception cref="ArgumentException"><paramref name="mi" /> is not a field or a property.</exception>
|
||||
public static object GetValue(MemberInfo mi, object obj) {
|
||||
if (mi is FieldInfo)
|
||||
return ((FieldInfo)mi).GetValue(obj);
|
||||
@@ -68,7 +120,15 @@ namespace Cryville.Common {
|
||||
else
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of a member of an object.
|
||||
/// </summary>
|
||||
/// <param name="mi">The member.</param>
|
||||
/// <param name="obj">The object.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="binder">An optional binder to convert the value.</param>
|
||||
/// <exception cref="ArgumentException"><paramref name="mi" /> is not a field or a property.</exception>
|
||||
public static void SetValue(MemberInfo mi, object obj, object value, Binder binder = null) {
|
||||
if (mi is FieldInfo)
|
||||
((FieldInfo)mi).SetValue(obj, value, BindingFlags.Default, binder, null);
|
||||
@@ -78,6 +138,11 @@ namespace Cryville.Common {
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the subclasses of a type in the current app domain.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type.</typeparam>
|
||||
/// <returns>An array containing all the subclasses of the type in the current app domain.</returns>
|
||||
public static Type[] GetSubclassesOf<T>() where T : class {
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
IEnumerable<Type> r = new List<Type>();
|
||||
@@ -90,6 +155,11 @@ namespace Cryville.Common {
|
||||
return r.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a simple name of a type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <returns>A simple name of the class.</returns>
|
||||
public static string GetSimpleName(Type type) {
|
||||
string result = type.Name;
|
||||
var typeargs = type.GetGenericArguments();
|
||||
|
@@ -2,10 +2,24 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Cryville.Common {
|
||||
/// <summary>
|
||||
/// Provides a set of <see langword="static" /> methods related to string operations.
|
||||
/// </summary>
|
||||
public static class StringUtils {
|
||||
/// <summary>
|
||||
/// Removes the extension in a file name or file path.
|
||||
/// </summary>
|
||||
/// <param name="s">The file name or file path.</param>
|
||||
/// <returns>The file name or file path with the extension removed.</returns>
|
||||
public static string TrimExt(string s) {
|
||||
return s.Substring(0, s.LastIndexOf("."));
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the value of a <see cref="TimeSpan" /> to a human-readable string.
|
||||
/// </summary>
|
||||
/// <param name="timeSpan">The time span.</param>
|
||||
/// <param name="digits">The digit count for seconds.</param>
|
||||
/// <returns>A human-readable string representing the time span.</returns>
|
||||
public static string ToString(this TimeSpan timeSpan, int digits) {
|
||||
var b = new StringBuilder();
|
||||
bool flag = false;
|
||||
|
@@ -7,32 +7,52 @@ using UnityEngine.Rendering;
|
||||
#endif
|
||||
|
||||
namespace Cryville.Common.Unity {
|
||||
/// <summary>
|
||||
/// A worker that performs network tasks in the background.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It is required to call <see cref="TickBackgroundTasks" /> every tick to keep the worker working.
|
||||
/// </remarks>
|
||||
public class NetworkTaskWorker {
|
||||
bool suspended;
|
||||
NetworkTask currentNetworkTask;
|
||||
readonly Queue<NetworkTask> networkTasks = new Queue<NetworkTask>();
|
||||
|
||||
/// <summary>
|
||||
/// Current queued task count.
|
||||
/// </summary>
|
||||
public int TaskCount { get { return networkTasks.Count; } }
|
||||
|
||||
/// <summary>
|
||||
/// Submits a new network task.
|
||||
/// </summary>
|
||||
/// <param name="task">The task.</param>
|
||||
public void SubmitNetworkTask(NetworkTask task) {
|
||||
networkTasks.Enqueue(task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ticks the worker.
|
||||
/// </summary>
|
||||
/// <returns>The status of the worker.</returns>
|
||||
public WorkerStatus TickBackgroundTasks() {
|
||||
if (suspended) return WorkerStatus.Suspended;
|
||||
if (currentNetworkTask != null) {
|
||||
if (currentNetworkTask.Canceled) currentNetworkTask = null;
|
||||
if (currentNetworkTask.Cancelled) currentNetworkTask = null;
|
||||
else if (currentNetworkTask.Done()) currentNetworkTask = null;
|
||||
}
|
||||
while (networkTasks.Count > 0 && currentNetworkTask == null) {
|
||||
var task = networkTasks.Dequeue();
|
||||
if (task.Canceled) continue;
|
||||
if (task.Cancelled) continue;
|
||||
currentNetworkTask = task;
|
||||
currentNetworkTask.Start();
|
||||
}
|
||||
return currentNetworkTask == null ? WorkerStatus.Idle : WorkerStatus.Working;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the current working task (if present) and suspends all background tasks.
|
||||
/// </summary>
|
||||
public void SuspendBackgroundTasks() {
|
||||
suspended = true;
|
||||
if (currentNetworkTask != null) {
|
||||
@@ -41,63 +61,123 @@ namespace Cryville.Common.Unity {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resumes background tasks.
|
||||
/// </summary>
|
||||
public void ResumeBackgroundTasks() {
|
||||
suspended = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Status of a <see cref="NetworkTaskWorker" />.
|
||||
/// </summary>
|
||||
public enum WorkerStatus {
|
||||
Idle, Working, Suspended,
|
||||
/// <summary>
|
||||
/// The worker is not working nor suspended.
|
||||
/// </summary>
|
||||
Idle,
|
||||
/// <summary>
|
||||
/// The worker is working on a task.
|
||||
/// </summary>
|
||||
Working,
|
||||
/// <summary>
|
||||
/// The worker is suspended.
|
||||
/// </summary>
|
||||
Suspended,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A network task.
|
||||
/// </summary>
|
||||
public abstract class NetworkTask {
|
||||
protected NetworkTask(string uri) {
|
||||
Uri = uri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The URI of the resource.
|
||||
/// </summary>
|
||||
public string Uri { get; private set; }
|
||||
|
||||
public bool Canceled { get; private set; }
|
||||
/// <summary>
|
||||
/// Whether the task is cancelled.
|
||||
/// </summary>
|
||||
public bool Cancelled { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the task.
|
||||
/// </summary>
|
||||
public virtual void Cancel() {
|
||||
Canceled = true;
|
||||
Cancelled = true;
|
||||
}
|
||||
|
||||
#if UNITY_5_4_OR_NEWER
|
||||
protected UnityWebRequest www;
|
||||
|
||||
/// <summary>
|
||||
/// Starts the task.
|
||||
/// </summary>
|
||||
public virtual void Start() {
|
||||
www = new UnityWebRequest(Uri);
|
||||
www.SendWebRequest();
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets whether the task is done.
|
||||
/// </summary>
|
||||
/// <returns>Whether the task is done.</returns>
|
||||
public virtual bool Done() {
|
||||
if (!www.isDone) return false;
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
protected WWW www;
|
||||
public virtual WWW Start() {
|
||||
return new WWW(Uri);
|
||||
/// <summary>
|
||||
/// Starts the task.
|
||||
/// </summary>
|
||||
public virtual void Start() {
|
||||
www = new WWW(Uri);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets whether the task is done.
|
||||
/// </summary>
|
||||
/// <returns>Whether the task is done.</returns>
|
||||
public virtual bool Done() {
|
||||
if (!www.isDone) return false;
|
||||
return true;
|
||||
}
|
||||
public abstract void Done();
|
||||
#endif
|
||||
}
|
||||
/// <summary>
|
||||
/// A <see cref="NetworkTask" /> that loads a texture.
|
||||
/// </summary>
|
||||
public class LoadTextureTask : NetworkTask {
|
||||
/// <summary>
|
||||
/// Creates an instance of the <see cref="LoadTextureTask" /> class.
|
||||
/// </summary>
|
||||
/// <param name="uri">The URI of the resource.</param>
|
||||
/// <param name="callback">The callback function upon load complete.</param>
|
||||
public LoadTextureTask(string uri, Action<bool, Texture2D> callback) : base(uri) {
|
||||
Callback = callback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The callback function upon load complete.
|
||||
/// </summary>
|
||||
public Action<bool, Texture2D> Callback { get; private set; }
|
||||
|
||||
#if UNITY_5_4_OR_NEWER
|
||||
DownloadHandlerTexture handler;
|
||||
/// <inheritdoc />
|
||||
public override void Start() {
|
||||
handler = new DownloadHandlerTexture();
|
||||
www = new UnityWebRequest(Uri, "GET", handler, null);
|
||||
www.SendWebRequest();
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override bool Done() {
|
||||
if (!handler.isDone) return false;
|
||||
if (handler.texture != null) {
|
||||
if (!www.isDone) return false;
|
||||
if (handler.isDone && handler.texture != null) {
|
||||
var buffer = handler.texture;
|
||||
/*var result = new Texture2D(buffer.width, buffer.height, buffer.format, true);
|
||||
if (SystemInfo.copyTextureSupport.HasFlag(CopyTextureSupport.Basic)) {
|
||||
@@ -119,17 +199,21 @@ namespace Cryville.Common.Unity {
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
public override void PostProcess(WWW www) {
|
||||
/// <inheritdoc />
|
||||
public override bool Done() {
|
||||
if (!www.isDone) return false;
|
||||
bool succeeded = string.IsNullOrEmpty(www.error);
|
||||
if (succeeded) {
|
||||
var buffer = www.texture;
|
||||
var result = new Texture2D(buffer.width, buffer.height, buffer.format, true);
|
||||
/*var result = new Texture2D(buffer.width, buffer.height, buffer.format, true);
|
||||
result.SetPixels(buffer.GetPixels());
|
||||
result.Apply(true, true);
|
||||
Texture2D.Destroy(buffer);
|
||||
Callback(true, result);
|
||||
Callback(true, result);*/
|
||||
Callback(true, buffer);
|
||||
}
|
||||
else Callback(false, null);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@@ -3,16 +3,27 @@ using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
/// <summary>
|
||||
/// A <see cref="ILayoutElement" /> that takes the length of one axis to compute the preferred length of the other axis with respect to a aspect ratio.
|
||||
/// </summary>
|
||||
public class AspectRatioLayoutElement : UIBehaviour, ILayoutElement {
|
||||
[SerializeField]
|
||||
[Tooltip("The aspect ratio. Width divided by height.")]
|
||||
private float m_aspectRatio = 1;
|
||||
/// <summary>
|
||||
/// The aspect ratio. Width divided by height.
|
||||
/// </summary>
|
||||
public float AspectRatio {
|
||||
get { return m_aspectRatio; }
|
||||
set { SetProperty(ref m_aspectRatio, value); }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Whether to compute the length of the y axis.")]
|
||||
private bool m_isVertical = false;
|
||||
/// <summary>
|
||||
/// Whether to compute the length of the y axis.
|
||||
/// </summary>
|
||||
public bool IsVertical {
|
||||
get { return m_isVertical; }
|
||||
set { SetProperty(ref m_isVertical, value); }
|
||||
@@ -29,26 +40,35 @@ namespace Cryville.Common.Unity.UI {
|
||||
LayoutRebuilder.MarkLayoutForRebuild(transform as RectTransform);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public float minWidth {
|
||||
get {
|
||||
return m_isVertical ? 0 : (transform as RectTransform).rect.height * m_aspectRatio;
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public float preferredWidth { get { return minWidth; } }
|
||||
/// <inheritdoc />
|
||||
public float flexibleWidth { get { return 0; } }
|
||||
|
||||
/// <inheritdoc />
|
||||
public float minHeight {
|
||||
get {
|
||||
return m_isVertical ? (transform as RectTransform).rect.width / m_aspectRatio : 0;
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public float preferredHeight { get { return minHeight; } }
|
||||
/// <inheritdoc />
|
||||
public float flexibleHeight { get { return 0; } }
|
||||
|
||||
/// <inheritdoc />
|
||||
public int layoutPriority { get { return 1; } }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CalculateLayoutInputHorizontal() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CalculateLayoutInputVertical() { }
|
||||
|
||||
protected override void OnDidApplyAnimationProperties() {
|
||||
|
@@ -1,9 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
/// <summary>
|
||||
/// A <see cref="DockLayoutGroup" /> that sets the aspect ratio of the docking element.
|
||||
/// </summary>
|
||||
public sealed class DockAspectRatioLayoutGroup : DockLayoutGroup {
|
||||
[SerializeField]
|
||||
[Tooltip("The aspect ratio of the docking element.")]
|
||||
private float m_dockAspectRatio = 1;
|
||||
/// <summary>
|
||||
/// The aspect ratio of the docking element.
|
||||
/// </summary>
|
||||
public float DockAspectRatio {
|
||||
get { return m_dockAspectRatio; }
|
||||
set { base.SetProperty(ref m_dockAspectRatio, value); }
|
||||
|
@@ -2,30 +2,60 @@
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
/// <summary>
|
||||
/// A <see cref="LayoutGroup" /> that docks its first child element to one side.
|
||||
/// </summary>
|
||||
public abstract class DockLayoutGroup : LayoutGroup {
|
||||
/// <summary>
|
||||
/// The dock side.
|
||||
/// </summary>
|
||||
public enum Side {
|
||||
/// <summary>
|
||||
/// Top.
|
||||
/// </summary>
|
||||
Top = 0,
|
||||
/// <summary>
|
||||
/// Right.
|
||||
/// </summary>
|
||||
Right = 1,
|
||||
/// <summary>
|
||||
/// Bottom.
|
||||
/// </summary>
|
||||
Bottom = 2,
|
||||
/// <summary>
|
||||
/// Left.
|
||||
/// </summary>
|
||||
Left = 3,
|
||||
}
|
||||
[SerializeField]
|
||||
[Tooltip("The docking side of the first child element.")]
|
||||
private Side m_side;
|
||||
/// <summary>
|
||||
/// The docking side of the first child element.
|
||||
/// </summary>
|
||||
public Side DockSide {
|
||||
get { return m_side; }
|
||||
set { base.SetProperty(ref m_side, value); }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The slide index. The children slide along the cross axis.")]
|
||||
private float m_slideIndex;
|
||||
/// <summary>
|
||||
/// The slide index. The children slide along the axis.
|
||||
/// </summary>
|
||||
public float SlideIndex {
|
||||
get { return m_slideIndex; }
|
||||
set { base.SetProperty(ref m_slideIndex, value); }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public sealed override void CalculateLayoutInputHorizontal() { base.CalculateLayoutInputHorizontal(); }
|
||||
/// <inheritdoc />
|
||||
public sealed override void CalculateLayoutInputVertical() { }
|
||||
/// <inheritdoc />
|
||||
public sealed override void SetLayoutHorizontal() { SetChildrenAlongAxis(0); }
|
||||
/// <inheritdoc />
|
||||
public sealed override void SetLayoutVertical() { SetChildrenAlongAxis(1); }
|
||||
|
||||
private float GetSlidePosition(float groupHeight, float dockHeight) {
|
||||
@@ -68,6 +98,11 @@ namespace Cryville.Common.Unity.UI {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the first child element along the axis.
|
||||
/// </summary>
|
||||
/// <param name="groupSize">The size of the layout group.</param>
|
||||
/// <returns></returns>
|
||||
protected abstract float GetDockElementSize(Vector2 groupSize);
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
/// <summary>
|
||||
/// A <see cref="DockLayoutGroup" /> that sets the occupied ratio of the docking element.
|
||||
/// </summary>
|
||||
public sealed class DockOccupiedRatioLayoutGroup : DockLayoutGroup {
|
||||
[SerializeField]
|
||||
[Tooltip("The occupied ratio of the docking element.")]
|
||||
private float m_dockOccupiedRatio = 1;
|
||||
/// <summary>
|
||||
/// The occupied ratio of the docking element.
|
||||
/// </summary>
|
||||
public float DockOccupiedRatio {
|
||||
get { return m_dockOccupiedRatio; }
|
||||
set { base.SetProperty(ref m_dockOccupiedRatio, value); }
|
||||
|
@@ -2,11 +2,17 @@
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
/// <summary>
|
||||
/// Fits the size of a <see cref="GridLayoutGroup" /> with its cells.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(GridLayoutGroup))]
|
||||
public class GridLayoutSizeFitter : MonoBehaviour {
|
||||
RectTransform rectTransform;
|
||||
GridLayoutGroup gridLayoutGroup;
|
||||
Canvas canvas;
|
||||
/// <summary>
|
||||
/// The item count per line.
|
||||
/// </summary>
|
||||
public int GroupItemCount = 3;
|
||||
|
||||
#pragma warning disable IDE0051
|
||||
|
@@ -10,6 +10,7 @@ namespace Cryville.Common.Unity.UI {
|
||||
[ExecuteInEditMode]
|
||||
public class ImageSliced3 : MaskableGraphic {
|
||||
[SerializeField]
|
||||
[Tooltip("The sliced sprite.")]
|
||||
private Sprite m_sprite;
|
||||
/// <summary>
|
||||
/// The sliced sprite.
|
||||
@@ -45,6 +46,7 @@ namespace Cryville.Common.Unity.UI {
|
||||
DiagonalRight = 5,
|
||||
}
|
||||
[SerializeField]
|
||||
[Tooltip("The mode how a sliced image is generated when it is too compact.")]
|
||||
private CompactMode m_compact;
|
||||
/// <summary>
|
||||
/// The mode how a sliced image is generated when it is too compact.
|
||||
|
@@ -2,9 +2,16 @@
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
/// <summary>
|
||||
/// Fits the length of an axis of an element with respect to the children count and the shared aspect ratio.
|
||||
/// </summary>
|
||||
public class LayoutAspectRatioFitter : MonoBehaviour {
|
||||
[SerializeField]
|
||||
[Tooltip("The aspect ratio per element.")]
|
||||
private float m_aspectRatioPerElement = 1;
|
||||
/// <summary>
|
||||
/// The aspect ratio per element.
|
||||
/// </summary>
|
||||
public float AspectRatioPerElement {
|
||||
get { return m_aspectRatioPerElement; }
|
||||
set { m_aspectRatioPerElement = value; }
|
||||
|
@@ -2,16 +2,27 @@
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
/// <summary>
|
||||
/// A non-interactive <see cref="Slider" /> that has an internal tweening behaviour.
|
||||
/// </summary>
|
||||
public class ProgressBar : Slider {
|
||||
[SerializeField][Range(0f, 1f)]
|
||||
[Tooltip("The tweening parameter.")]
|
||||
float m_smooth = 0;
|
||||
/// <summary>
|
||||
/// The tweening parameter.
|
||||
/// </summary>
|
||||
public float Smooth {
|
||||
get { return m_smooth; }
|
||||
set { m_smooth = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The target value.")]
|
||||
float m_targetValue;
|
||||
/// <summary>
|
||||
/// Gets the current displayed value or sets the target value.
|
||||
/// </summary>
|
||||
public override float value {
|
||||
get { return base.value; }
|
||||
set { m_targetValue = value; }
|
||||
|
@@ -3,61 +3,84 @@ using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Cryville.Common.Unity.UI {
|
||||
/// <summary>
|
||||
/// A handler for loading an item.
|
||||
/// </summary>
|
||||
/// <param name="index">The zero-based index of the item.</param>
|
||||
/// <param name="gameObject">The game object for the item instantiated from the item template.</param>
|
||||
/// <returns></returns>
|
||||
public delegate bool LoadItemHandler(int index, GameObject gameObject);
|
||||
/// <summary>
|
||||
/// A scrollable grid that dynamically loads its items.
|
||||
/// </summary>
|
||||
public sealed class ScrollableItemGrid : MonoBehaviour {
|
||||
[SerializeField]
|
||||
[Tooltip("The item template.")]
|
||||
private GameObject m_itemTemplate;
|
||||
/// <summary>
|
||||
/// The item template.
|
||||
/// </summary>
|
||||
public GameObject ItemTemplate {
|
||||
get { return m_itemTemplate; }
|
||||
set { m_itemTemplate = value; OnTemplateUpdate(); }
|
||||
}
|
||||
public Func<int, GameObject, bool> LoadItem { private get; set; }
|
||||
|
||||
public enum Corner {
|
||||
UpperLeft = 0,
|
||||
UpperRight = 1,
|
||||
LowerLeft = 2,
|
||||
LowerRight = 3,
|
||||
}
|
||||
[SerializeField]
|
||||
private Corner m_startCorner; // TODO
|
||||
public Corner StartCorner {
|
||||
get { return m_startCorner; }
|
||||
set { m_startCorner = value; OnFrameUpdate(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The handler for loading an item.
|
||||
/// </summary>
|
||||
public LoadItemHandler LoadItem { private get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Axis.
|
||||
/// </summary>
|
||||
public enum Axis {
|
||||
Horizontal = 0, Vertical = 1,
|
||||
/// <summary>
|
||||
/// Horizontal (x) axis.
|
||||
/// </summary>
|
||||
Horizontal = 0,
|
||||
/// <summary>
|
||||
/// Vertical (y) axis.
|
||||
/// </summary>
|
||||
Vertical = 1,
|
||||
}
|
||||
[SerializeField]
|
||||
[Tooltip("The main axis.")]
|
||||
private Axis m_startAxis;
|
||||
/// <summary>
|
||||
/// The main axis.
|
||||
/// </summary>
|
||||
public Axis StartAxis {
|
||||
get { return m_startAxis; }
|
||||
set { m_startAxis = value; OnFrameUpdate(); }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private Vector2 m_spacing; // TODO
|
||||
public Vector2 Spacing {
|
||||
get { return m_spacing; }
|
||||
set { m_spacing = value; OnFrameUpdate(); }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The item count.")]
|
||||
private int m_itemCount = 3;
|
||||
/// <summary>
|
||||
/// The item count.
|
||||
/// </summary>
|
||||
public int ItemCount {
|
||||
get { return m_itemCount; }
|
||||
set { m_itemCount = value; OnRefresh(); }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The item count per line.")]
|
||||
private int m_lineItemCount = 3;
|
||||
/// <summary>
|
||||
/// The item count per line.
|
||||
/// </summary>
|
||||
public int LineItemCount {
|
||||
get { return m_lineItemCount; }
|
||||
set { m_lineItemCount = value; OnFrameUpdate(); }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The length of the cross axis per line.")]
|
||||
private float m_lineHeight = 100;
|
||||
/// <summary>
|
||||
/// The length of the cross axis per line.
|
||||
/// </summary>
|
||||
public float LineHeight {
|
||||
get { return m_lineHeight; }
|
||||
set { m_lineHeight = value; OnFrameUpdate(); }
|
||||
@@ -78,6 +101,9 @@ namespace Cryville.Common.Unity.UI {
|
||||
);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The maximum count of visible lines.
|
||||
/// </summary>
|
||||
public int VisibleLines {
|
||||
get {
|
||||
return Mathf.CeilToInt(VisibleSize.y / m_lineHeight) + 1;
|
||||
|
Reference in New Issue
Block a user