diff --git a/Assets/TEngine/Runtime/Utility/Log.cs b/Assets/TEngine/Runtime/Log/Log.cs similarity index 100% rename from Assets/TEngine/Runtime/Utility/Log.cs rename to Assets/TEngine/Runtime/Log/Log.cs diff --git a/Assets/TEngine/Runtime/Utility/Log.cs.meta b/Assets/TEngine/Runtime/Log/Log.cs.meta similarity index 100% rename from Assets/TEngine/Runtime/Utility/Log.cs.meta rename to Assets/TEngine/Runtime/Log/Log.cs.meta diff --git a/Assets/TEngine/Runtime/Utility/Utility.Assembly.cs b/Assets/TEngine/Runtime/Utility/Utility.Assembly.cs new file mode 100644 index 00000000..e9f51a68 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Assembly.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// 程序集相关的实用函数。 + /// + public static class Assembly + { + private static readonly System.Reflection.Assembly[] s_Assemblies = null; + private static readonly Dictionary s_CachedTypes = new Dictionary(StringComparer.Ordinal); + + static Assembly() + { + s_Assemblies = AppDomain.CurrentDomain.GetAssemblies(); + } + + /// + /// 获取已加载的程序集。 + /// + /// 已加载的程序集。 + public static System.Reflection.Assembly[] GetAssemblies() + { + return s_Assemblies; + } + + /// + /// 获取已加载的程序集中的所有类型。 + /// + /// 已加载的程序集中的所有类型。 + public static Type[] GetTypes() + { + List results = new List(); + foreach (System.Reflection.Assembly assembly in s_Assemblies) + { + results.AddRange(assembly.GetTypes()); + } + + return results.ToArray(); + } + + /// + /// 获取已加载的程序集中的所有类型。 + /// + /// 已加载的程序集中的所有类型。 + public static void GetTypes(List results) + { + if (results == null) + { + throw new GameFrameworkException("Results is invalid."); + } + + results.Clear(); + foreach (System.Reflection.Assembly assembly in s_Assemblies) + { + results.AddRange(assembly.GetTypes()); + } + } + + /// + /// 获取已加载的程序集中的指定类型。 + /// + /// 要获取的类型名。 + /// 已加载的程序集中的指定类型。 + public static Type GetType(string typeName) + { + if (string.IsNullOrEmpty(typeName)) + { + throw new GameFrameworkException("Type name is invalid."); + } + + Type type = null; + if (s_CachedTypes.TryGetValue(typeName, out type)) + { + return type; + } + + type = Type.GetType(typeName); + if (type != null) + { + s_CachedTypes.Add(typeName, type); + return type; + } + + foreach (System.Reflection.Assembly assembly in s_Assemblies) + { + type = Type.GetType(Text.Format("{0}, {1}", typeName, assembly.FullName)); + if (type != null) + { + s_CachedTypes.Add(typeName, type); + return type; + } + } + + return null; + } + } + } +} diff --git a/Assets/TEngine/Runtime/Utility/Utility.Assembly.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Assembly.cs.meta new file mode 100644 index 00000000..db7cdf79 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Assembly.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7609018db739fe545ba5be5d32f7eb3c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.Compression.ICompressionHelper.cs b/Assets/TEngine/Runtime/Utility/Utility.Compression.ICompressionHelper.cs new file mode 100644 index 00000000..56b15eaa --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Compression.ICompressionHelper.cs @@ -0,0 +1,52 @@ +using System.IO; + +namespace TEngine +{ + public static partial class Utility + { + public static partial class Compression + { + /// + /// 压缩解压缩辅助器接口。 + /// + public interface ICompressionHelper + { + /// + /// 压缩数据。 + /// + /// 要压缩的数据的二进制流。 + /// 要压缩的数据的二进制流的偏移。 + /// 要压缩的数据的二进制流的长度。 + /// 压缩后的数据的二进制流。 + /// 是否压缩数据成功。 + bool Compress(byte[] bytes, int offset, int length, Stream compressedStream); + + /// + /// 压缩数据。 + /// + /// 要压缩的数据的二进制流。 + /// 压缩后的数据的二进制流。 + /// 是否压缩数据成功。 + bool Compress(Stream stream, Stream compressedStream); + + /// + /// 解压缩数据。 + /// + /// 要解压缩的数据的二进制流。 + /// 要解压缩的数据的二进制流的偏移。 + /// 要解压缩的数据的二进制流的长度。 + /// 解压缩后的数据的二进制流。 + /// 是否解压缩数据成功。 + bool Decompress(byte[] bytes, int offset, int length, Stream decompressedStream); + + /// + /// 解压缩数据。 + /// + /// 要解压缩的数据的二进制流。 + /// 解压缩后的数据的二进制流。 + /// 是否解压缩数据成功。 + bool Decompress(Stream stream, Stream decompressedStream); + } + } + } +} diff --git a/Assets/TEngine/Runtime/Utility/Utility.Compression.ICompressionHelper.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Compression.ICompressionHelper.cs.meta new file mode 100644 index 00000000..0a96ad30 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Compression.ICompressionHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3d82356f5e654704daa0769074b9e5a7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.Compression.cs b/Assets/TEngine/Runtime/Utility/Utility.Compression.cs new file mode 100644 index 00000000..ab15faf3 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Compression.cs @@ -0,0 +1,337 @@ +using System; +using System.IO; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// 压缩解压缩相关的实用函数。 + /// + public static partial class Compression + { + private static ICompressionHelper s_CompressionHelper = null; + + /// + /// 设置压缩解压缩辅助器。 + /// + /// 要设置的压缩解压缩辅助器。 + public static void SetCompressionHelper(ICompressionHelper compressionHelper) + { + s_CompressionHelper = compressionHelper; + } + + /// + /// 压缩数据。 + /// + /// 要压缩的数据的二进制流。 + /// 压缩后的数据的二进制流。 + public static byte[] Compress(byte[] bytes) + { + if (bytes == null) + { + throw new GameFrameworkException("Bytes is invalid."); + } + + return Compress(bytes, 0, bytes.Length); + } + + /// + /// 压缩数据。 + /// + /// 要压缩的数据的二进制流。 + /// 压缩后的数据的二进制流。 + /// 是否压缩数据成功。 + public static bool Compress(byte[] bytes, Stream compressedStream) + { + if (bytes == null) + { + throw new GameFrameworkException("Bytes is invalid."); + } + + return Compress(bytes, 0, bytes.Length, compressedStream); + } + + /// + /// 压缩数据。 + /// + /// 要压缩的数据的二进制流。 + /// 要压缩的数据的二进制流的偏移。 + /// 要压缩的数据的二进制流的长度。 + /// 压缩后的数据的二进制流。 + public static byte[] Compress(byte[] bytes, int offset, int length) + { + using (MemoryStream compressedStream = new MemoryStream()) + { + if (Compress(bytes, offset, length, compressedStream)) + { + return compressedStream.ToArray(); + } + else + { + return null; + } + } + } + + /// + /// 压缩数据。 + /// + /// 要压缩的数据的二进制流。 + /// 要压缩的数据的二进制流的偏移。 + /// 要压缩的数据的二进制流的长度。 + /// 压缩后的数据的二进制流。 + /// 是否压缩数据成功。 + public static bool Compress(byte[] bytes, int offset, int length, Stream compressedStream) + { + if (s_CompressionHelper == null) + { + throw new GameFrameworkException("Compressed helper is invalid."); + } + + if (bytes == null) + { + throw new GameFrameworkException("Bytes is invalid."); + } + + if (offset < 0 || length < 0 || offset + length > bytes.Length) + { + throw new GameFrameworkException("Offset or length is invalid."); + } + + if (compressedStream == null) + { + throw new GameFrameworkException("Compressed stream is invalid."); + } + + try + { + return s_CompressionHelper.Compress(bytes, offset, length, compressedStream); + } + catch (Exception exception) + { + if (exception is GameFrameworkException) + { + throw; + } + + throw new GameFrameworkException(Text.Format("Can not compress with exception '{0}'.", exception), exception); + } + } + + /// + /// 压缩数据。 + /// + /// 要压缩的数据的二进制流。 + /// 压缩后的数据的二进制流。 + public static byte[] Compress(Stream stream) + { + using (MemoryStream compressedStream = new MemoryStream()) + { + if (Compress(stream, compressedStream)) + { + return compressedStream.ToArray(); + } + else + { + return null; + } + } + } + + /// + /// 压缩数据。 + /// + /// 要压缩的数据的二进制流。 + /// 压缩后的数据的二进制流。 + /// 是否压缩数据成功。 + public static bool Compress(Stream stream, Stream compressedStream) + { + if (s_CompressionHelper == null) + { + throw new GameFrameworkException("Compressed helper is invalid."); + } + + if (stream == null) + { + throw new GameFrameworkException("Stream is invalid."); + } + + if (compressedStream == null) + { + throw new GameFrameworkException("Compressed stream is invalid."); + } + + try + { + return s_CompressionHelper.Compress(stream, compressedStream); + } + catch (Exception exception) + { + if (exception is GameFrameworkException) + { + throw; + } + + throw new GameFrameworkException(Text.Format("Can not compress with exception '{0}'.", exception), exception); + } + } + + /// + /// 解压缩数据。 + /// + /// 要解压缩的数据的二进制流。 + /// 解压缩后的数据的二进制流。 + public static byte[] Decompress(byte[] bytes) + { + if (bytes == null) + { + throw new GameFrameworkException("Bytes is invalid."); + } + + return Decompress(bytes, 0, bytes.Length); + } + + /// + /// 解压缩数据。 + /// + /// 要解压缩的数据的二进制流。 + /// 解压缩后的数据的二进制流。 + /// 是否解压缩数据成功。 + public static bool Decompress(byte[] bytes, Stream decompressedStream) + { + if (bytes == null) + { + throw new GameFrameworkException("Bytes is invalid."); + } + + return Decompress(bytes, 0, bytes.Length, decompressedStream); + } + + /// + /// 解压缩数据。 + /// + /// 要解压缩的数据的二进制流。 + /// 要解压缩的数据的二进制流的偏移。 + /// 要解压缩的数据的二进制流的长度。 + /// 解压缩后的数据的二进制流。 + public static byte[] Decompress(byte[] bytes, int offset, int length) + { + using (MemoryStream decompressedStream = new MemoryStream()) + { + if (Decompress(bytes, offset, length, decompressedStream)) + { + return decompressedStream.ToArray(); + } + else + { + return null; + } + } + } + + /// + /// 解压缩数据。 + /// + /// 要解压缩的数据的二进制流。 + /// 要解压缩的数据的二进制流的偏移。 + /// 要解压缩的数据的二进制流的长度。 + /// 解压缩后的数据的二进制流。 + /// 是否解压缩数据成功。 + public static bool Decompress(byte[] bytes, int offset, int length, Stream decompressedStream) + { + if (s_CompressionHelper == null) + { + throw new GameFrameworkException("Compressed helper is invalid."); + } + + if (bytes == null) + { + throw new GameFrameworkException("Bytes is invalid."); + } + + if (offset < 0 || length < 0 || offset + length > bytes.Length) + { + throw new GameFrameworkException("Offset or length is invalid."); + } + + if (decompressedStream == null) + { + throw new GameFrameworkException("Decompressed stream is invalid."); + } + + try + { + return s_CompressionHelper.Decompress(bytes, offset, length, decompressedStream); + } + catch (Exception exception) + { + if (exception is GameFrameworkException) + { + throw; + } + + throw new GameFrameworkException(Text.Format("Can not decompress with exception '{0}'.", exception), exception); + } + } + + /// + /// 解压缩数据。 + /// + /// 要解压缩的数据的二进制流。 + /// 是否解压缩数据成功。 + public static byte[] Decompress(Stream stream) + { + using (MemoryStream decompressedStream = new MemoryStream()) + { + if (Decompress(stream, decompressedStream)) + { + return decompressedStream.ToArray(); + } + else + { + return null; + } + } + } + + /// + /// 解压缩数据。 + /// + /// 要解压缩的数据的二进制流。 + /// 解压缩后的数据的二进制流。 + /// 是否解压缩数据成功。 + public static bool Decompress(Stream stream, Stream decompressedStream) + { + if (s_CompressionHelper == null) + { + throw new GameFrameworkException("Compressed helper is invalid."); + } + + if (stream == null) + { + throw new GameFrameworkException("Stream is invalid."); + } + + if (decompressedStream == null) + { + throw new GameFrameworkException("Decompressed stream is invalid."); + } + + try + { + return s_CompressionHelper.Decompress(stream, decompressedStream); + } + catch (Exception exception) + { + if (exception is GameFrameworkException) + { + throw; + } + + throw new GameFrameworkException(Text.Format("Can not decompress with exception '{0}'.", exception), exception); + } + } + } + } +} diff --git a/Assets/TEngine/Runtime/Utility/Utility.Compression.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Compression.cs.meta new file mode 100644 index 00000000..d07061b3 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Compression.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f1ec2480f190a1e419297e6efd755541 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.Converter.cs b/Assets/TEngine/Runtime/Utility/Utility.Converter.cs new file mode 100644 index 00000000..f0d8502c --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Converter.cs @@ -0,0 +1,841 @@ +using System; +using System.Text; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// 类型转换相关的实用函数。 + /// + public static class Converter + { + private const float InchesToCentimeters = 2.54f; // 1 inch = 2.54 cm + private const float CentimetersToInches = 1f / InchesToCentimeters; // 1 cm = 0.3937 inches + + /// + /// 获取数据在此计算机结构中存储时的字节顺序。 + /// + public static bool IsLittleEndian + { + get + { + return BitConverter.IsLittleEndian; + } + } + + /// + /// 获取或设置屏幕每英寸点数。 + /// + public static float ScreenDpi + { + get; + set; + } + + /// + /// 将像素转换为厘米。 + /// + /// 像素。 + /// 厘米。 + public static float GetCentimetersFromPixels(float pixels) + { + if (ScreenDpi <= 0) + { + throw new GameFrameworkException("You must set screen DPI first."); + } + + return InchesToCentimeters * pixels / ScreenDpi; + } + + /// + /// 将厘米转换为像素。 + /// + /// 厘米。 + /// 像素。 + public static float GetPixelsFromCentimeters(float centimeters) + { + if (ScreenDpi <= 0) + { + throw new GameFrameworkException("You must set screen DPI first."); + } + + return CentimetersToInches * centimeters * ScreenDpi; + } + + /// + /// 将像素转换为英寸。 + /// + /// 像素。 + /// 英寸。 + public static float GetInchesFromPixels(float pixels) + { + if (ScreenDpi <= 0) + { + throw new GameFrameworkException("You must set screen DPI first."); + } + + return pixels / ScreenDpi; + } + + /// + /// 将英寸转换为像素。 + /// + /// 英寸。 + /// 像素。 + public static float GetPixelsFromInches(float inches) + { + if (ScreenDpi <= 0) + { + throw new GameFrameworkException("You must set screen DPI first."); + } + + return inches * ScreenDpi; + } + + /// + /// 以字节数组的形式获取指定的布尔值。 + /// + /// 要转换的布尔值。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(bool value) + { + byte[] buffer = new byte[1]; + GetBytes(value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的布尔值。 + /// + /// 要转换的布尔值。 + /// 用于存放结果的字节数组。 + public static void GetBytes(bool value, byte[] buffer) + { + GetBytes(value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的布尔值。 + /// + /// 要转换的布尔值。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static void GetBytes(bool value, byte[] buffer, int startIndex) + { + if (buffer == null) + { + throw new GameFrameworkException("Buffer is invalid."); + } + + if (startIndex < 0 || startIndex + 1 > buffer.Length) + { + throw new GameFrameworkException("Start index is invalid."); + } + + buffer[startIndex] = value ? (byte)1 : (byte)0; + } + + /// + /// 返回由字节数组中首字节转换来的布尔值。 + /// + /// 字节数组。 + /// 如果 value 中的首字节非零,则为 true,否则为 false。 + public static bool GetBoolean(byte[] value) + { + return BitConverter.ToBoolean(value, 0); + } + + /// + /// 返回由字节数组中指定位置的一个字节转换来的布尔值。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 如果 value 中指定位置的字节非零,则为 true,否则为 false。 + public static bool GetBoolean(byte[] value, int startIndex) + { + return BitConverter.ToBoolean(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 Unicode 字符值。 + /// + /// 要转换的字符。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(char value) + { + byte[] buffer = new byte[2]; + GetBytes((short)value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 Unicode 字符值。 + /// + /// 要转换的字符。 + /// 用于存放结果的字节数组。 + public static void GetBytes(char value, byte[] buffer) + { + GetBytes((short)value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 Unicode 字符值。 + /// + /// 要转换的字符。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static void GetBytes(char value, byte[] buffer, int startIndex) + { + GetBytes((short)value, buffer, startIndex); + } + + /// + /// 返回由字节数组中前两个字节转换来的 Unicode 字符。 + /// + /// 字节数组。 + /// 由两个字节构成的字符。 + public static char GetChar(byte[] value) + { + return BitConverter.ToChar(value, 0); + } + + /// + /// 返回由字节数组中指定位置的两个字节转换来的 Unicode 字符。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由两个字节构成的字符。 + public static char GetChar(byte[] value, int startIndex) + { + return BitConverter.ToChar(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 16 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(short value) + { + byte[] buffer = new byte[2]; + GetBytes(value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 16 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static void GetBytes(short value, byte[] buffer) + { + GetBytes(value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 16 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static unsafe void GetBytes(short value, byte[] buffer, int startIndex) + { + if (buffer == null) + { + throw new GameFrameworkException("Buffer is invalid."); + } + + if (startIndex < 0 || startIndex + 2 > buffer.Length) + { + throw new GameFrameworkException("Start index is invalid."); + } + + fixed (byte* valueRef = buffer) + { + *(short*)(valueRef + startIndex) = value; + } + } + + /// + /// 返回由字节数组中前两个字节转换来的 16 位有符号整数。 + /// + /// 字节数组。 + /// 由两个字节构成的 16 位有符号整数。 + public static short GetInt16(byte[] value) + { + return BitConverter.ToInt16(value, 0); + } + + /// + /// 返回由字节数组中指定位置的两个字节转换来的 16 位有符号整数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由两个字节构成的 16 位有符号整数。 + public static short GetInt16(byte[] value, int startIndex) + { + return BitConverter.ToInt16(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 16 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(ushort value) + { + byte[] buffer = new byte[2]; + GetBytes((short)value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 16 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static void GetBytes(ushort value, byte[] buffer) + { + GetBytes((short)value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 16 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static void GetBytes(ushort value, byte[] buffer, int startIndex) + { + GetBytes((short)value, buffer, startIndex); + } + + /// + /// 返回由字节数组中前两个字节转换来的 16 位无符号整数。 + /// + /// 字节数组。 + /// 由两个字节构成的 16 位无符号整数。 + public static ushort GetUInt16(byte[] value) + { + return BitConverter.ToUInt16(value, 0); + } + + /// + /// 返回由字节数组中指定位置的两个字节转换来的 16 位无符号整数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由两个字节构成的 16 位无符号整数。 + public static ushort GetUInt16(byte[] value, int startIndex) + { + return BitConverter.ToUInt16(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 32 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(int value) + { + byte[] buffer = new byte[4]; + GetBytes(value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 32 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static void GetBytes(int value, byte[] buffer) + { + GetBytes(value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 32 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static unsafe void GetBytes(int value, byte[] buffer, int startIndex) + { + if (buffer == null) + { + throw new GameFrameworkException("Buffer is invalid."); + } + + if (startIndex < 0 || startIndex + 4 > buffer.Length) + { + throw new GameFrameworkException("Start index is invalid."); + } + + fixed (byte* valueRef = buffer) + { + *(int*)(valueRef + startIndex) = value; + } + } + + /// + /// 返回由字节数组中前四个字节转换来的 32 位有符号整数。 + /// + /// 字节数组。 + /// 由四个字节构成的 32 位有符号整数。 + public static int GetInt32(byte[] value) + { + return BitConverter.ToInt32(value, 0); + } + + /// + /// 返回由字节数组中指定位置的四个字节转换来的 32 位有符号整数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由四个字节构成的 32 位有符号整数。 + public static int GetInt32(byte[] value, int startIndex) + { + return BitConverter.ToInt32(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 32 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(uint value) + { + byte[] buffer = new byte[4]; + GetBytes((int)value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 32 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static void GetBytes(uint value, byte[] buffer) + { + GetBytes((int)value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 32 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static void GetBytes(uint value, byte[] buffer, int startIndex) + { + GetBytes((int)value, buffer, startIndex); + } + + /// + /// 返回由字节数组中前四个字节转换来的 32 位无符号整数。 + /// + /// 字节数组。 + /// 由四个字节构成的 32 位无符号整数。 + public static uint GetUInt32(byte[] value) + { + return BitConverter.ToUInt32(value, 0); + } + + /// + /// 返回由字节数组中指定位置的四个字节转换来的 32 位无符号整数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由四个字节构成的 32 位无符号整数。 + public static uint GetUInt32(byte[] value, int startIndex) + { + return BitConverter.ToUInt32(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 64 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(long value) + { + byte[] buffer = new byte[8]; + GetBytes(value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 64 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static void GetBytes(long value, byte[] buffer) + { + GetBytes(value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 64 位有符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static unsafe void GetBytes(long value, byte[] buffer, int startIndex) + { + if (buffer == null) + { + throw new GameFrameworkException("Buffer is invalid."); + } + + if (startIndex < 0 || startIndex + 8 > buffer.Length) + { + throw new GameFrameworkException("Start index is invalid."); + } + + fixed (byte* valueRef = buffer) + { + *(long*)(valueRef + startIndex) = value; + } + } + + /// + /// 返回由字节数组中前八个字节转换来的 64 位有符号整数。 + /// + /// 字节数组。 + /// 由八个字节构成的 64 位有符号整数。 + public static long GetInt64(byte[] value) + { + return BitConverter.ToInt64(value, 0); + } + + /// + /// 返回由字节数组中指定位置的八个字节转换来的 64 位有符号整数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由八个字节构成的 64 位有符号整数。 + public static long GetInt64(byte[] value, int startIndex) + { + return BitConverter.ToInt64(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的 64 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(ulong value) + { + byte[] buffer = new byte[8]; + GetBytes((long)value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的 64 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static void GetBytes(ulong value, byte[] buffer) + { + GetBytes((long)value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的 64 位无符号整数值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static void GetBytes(ulong value, byte[] buffer, int startIndex) + { + GetBytes((long)value, buffer, startIndex); + } + + /// + /// 返回由字节数组中前八个字节转换来的 64 位无符号整数。 + /// + /// 字节数组。 + /// 由八个字节构成的 64 位无符号整数。 + public static ulong GetUInt64(byte[] value) + { + return BitConverter.ToUInt64(value, 0); + } + + /// + /// 返回由字节数组中指定位置的八个字节转换来的 64 位无符号整数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由八个字节构成的 64 位无符号整数。 + public static ulong GetUInt64(byte[] value, int startIndex) + { + return BitConverter.ToUInt64(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的单精度浮点值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static unsafe byte[] GetBytes(float value) + { + byte[] buffer = new byte[4]; + GetBytes(*(int*)&value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的单精度浮点值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static unsafe void GetBytes(float value, byte[] buffer) + { + GetBytes(*(int*)&value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的单精度浮点值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static unsafe void GetBytes(float value, byte[] buffer, int startIndex) + { + GetBytes(*(int*)&value, buffer, startIndex); + } + + /// + /// 返回由字节数组中前四个字节转换来的单精度浮点数。 + /// + /// 字节数组。 + /// 由四个字节构成的单精度浮点数。 + public static float GetSingle(byte[] value) + { + return BitConverter.ToSingle(value, 0); + } + + /// + /// 返回由字节数组中指定位置的四个字节转换来的单精度浮点数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由四个字节构成的单精度浮点数。 + public static float GetSingle(byte[] value, int startIndex) + { + return BitConverter.ToSingle(value, startIndex); + } + + /// + /// 以字节数组的形式获取指定的双精度浮点值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static unsafe byte[] GetBytes(double value) + { + byte[] buffer = new byte[8]; + GetBytes(*(long*)&value, buffer, 0); + return buffer; + } + + /// + /// 以字节数组的形式获取指定的双精度浮点值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + public static unsafe void GetBytes(double value, byte[] buffer) + { + GetBytes(*(long*)&value, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定的双精度浮点值。 + /// + /// 要转换的数字。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + public static unsafe void GetBytes(double value, byte[] buffer, int startIndex) + { + GetBytes(*(long*)&value, buffer, startIndex); + } + + /// + /// 返回由字节数组中前八个字节转换来的双精度浮点数。 + /// + /// 字节数组。 + /// 由八个字节构成的双精度浮点数。 + public static double GetDouble(byte[] value) + { + return BitConverter.ToDouble(value, 0); + } + + /// + /// 返回由字节数组中指定位置的八个字节转换来的双精度浮点数。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 由八个字节构成的双精度浮点数。 + public static double GetDouble(byte[] value, int startIndex) + { + return BitConverter.ToDouble(value, startIndex); + } + + /// + /// 以字节数组的形式获取 UTF-8 编码的字符串。 + /// + /// 要转换的字符串。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(string value) + { + return GetBytes(value, Encoding.UTF8); + } + + /// + /// 以字节数组的形式获取 UTF-8 编码的字符串。 + /// + /// 要转换的字符串。 + /// 用于存放结果的字节数组。 + /// buffer 内实际填充了多少字节。 + public static int GetBytes(string value, byte[] buffer) + { + return GetBytes(value, Encoding.UTF8, buffer, 0); + } + + /// + /// 以字节数组的形式获取 UTF-8 编码的字符串。 + /// + /// 要转换的字符串。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + /// buffer 内实际填充了多少字节。 + public static int GetBytes(string value, byte[] buffer, int startIndex) + { + return GetBytes(value, Encoding.UTF8, buffer, startIndex); + } + + /// + /// 以字节数组的形式获取指定编码的字符串。 + /// + /// 要转换的字符串。 + /// 要使用的编码。 + /// 用于存放结果的字节数组。 + public static byte[] GetBytes(string value, Encoding encoding) + { + if (value == null) + { + throw new GameFrameworkException("Value is invalid."); + } + + if (encoding == null) + { + throw new GameFrameworkException("Encoding is invalid."); + } + + return encoding.GetBytes(value); + } + + /// + /// 以字节数组的形式获取指定编码的字符串。 + /// + /// 要转换的字符串。 + /// 要使用的编码。 + /// 用于存放结果的字节数组。 + /// buffer 内实际填充了多少字节。 + public static int GetBytes(string value, Encoding encoding, byte[] buffer) + { + return GetBytes(value, encoding, buffer, 0); + } + + /// + /// 以字节数组的形式获取指定编码的字符串。 + /// + /// 要转换的字符串。 + /// 要使用的编码。 + /// 用于存放结果的字节数组。 + /// buffer 内的起始位置。 + /// buffer 内实际填充了多少字节。 + public static int GetBytes(string value, Encoding encoding, byte[] buffer, int startIndex) + { + if (value == null) + { + throw new GameFrameworkException("Value is invalid."); + } + + if (encoding == null) + { + throw new GameFrameworkException("Encoding is invalid."); + } + + return encoding.GetBytes(value, 0, value.Length, buffer, startIndex); + } + + /// + /// 返回由字节数组使用 UTF-8 编码转换成的字符串。 + /// + /// 字节数组。 + /// 转换后的字符串。 + public static string GetString(byte[] value) + { + return GetString(value, Encoding.UTF8); + } + + /// + /// 返回由字节数组使用指定编码转换成的字符串。 + /// + /// 字节数组。 + /// 要使用的编码。 + /// 转换后的字符串。 + public static string GetString(byte[] value, Encoding encoding) + { + if (value == null) + { + throw new GameFrameworkException("Value is invalid."); + } + + if (encoding == null) + { + throw new GameFrameworkException("Encoding is invalid."); + } + + return encoding.GetString(value); + } + + /// + /// 返回由字节数组使用 UTF-8 编码转换成的字符串。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 长度。 + /// 转换后的字符串。 + public static string GetString(byte[] value, int startIndex, int length) + { + return GetString(value, startIndex, length, Encoding.UTF8); + } + + /// + /// 返回由字节数组使用指定编码转换成的字符串。 + /// + /// 字节数组。 + /// value 内的起始位置。 + /// 长度。 + /// 要使用的编码。 + /// 转换后的字符串。 + public static string GetString(byte[] value, int startIndex, int length, Encoding encoding) + { + if (value == null) + { + throw new GameFrameworkException("Value is invalid."); + } + + if (encoding == null) + { + throw new GameFrameworkException("Encoding is invalid."); + } + + return encoding.GetString(value, startIndex, length); + } + } + } +} diff --git a/Assets/TEngine/Runtime/Utility/Utility.Converter.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Converter.cs.meta new file mode 100644 index 00000000..474171d6 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Converter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7362a66e3741e8440bcc831815b4426c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.Encryption.cs b/Assets/TEngine/Runtime/Utility/Utility.Encryption.cs new file mode 100644 index 00000000..5063057c --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Encryption.cs @@ -0,0 +1,127 @@ +using System; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// 加密解密相关的实用函数。 + /// + public static class Encryption + { + internal const int QuickEncryptLength = 220; + + /// + /// 将 bytes 使用 code 做异或运算的快速版本。 + /// + /// 原始二进制流。 + /// 异或二进制流。 + /// 异或后的二进制流。 + public static byte[] GetQuickXorBytes(byte[] bytes, byte[] code) + { + return GetXorBytes(bytes, 0, QuickEncryptLength, code); + } + + /// + /// 将 bytes 使用 code 做异或运算的快速版本。此方法将复用并改写传入的 bytes 作为返回值,而不额外分配内存空间。 + /// + /// 原始及异或后的二进制流。 + /// 异或二进制流。 + public static void GetQuickSelfXorBytes(byte[] bytes, byte[] code) + { + GetSelfXorBytes(bytes, 0, QuickEncryptLength, code); + } + + /// + /// 将 bytes 使用 code 做异或运算。 + /// + /// 原始二进制流。 + /// 异或二进制流。 + /// 异或后的二进制流。 + public static byte[] GetXorBytes(byte[] bytes, byte[] code) + { + if (bytes == null) + { + return null; + } + + return GetXorBytes(bytes, 0, bytes.Length, code); + } + + /// + /// 将 bytes 使用 code 做异或运算。此方法将复用并改写传入的 bytes 作为返回值,而不额外分配内存空间。 + /// + /// 原始及异或后的二进制流。 + /// 异或二进制流。 + public static void GetSelfXorBytes(byte[] bytes, byte[] code) + { + if (bytes == null) + { + return; + } + + GetSelfXorBytes(bytes, 0, bytes.Length, code); + } + + /// + /// 将 bytes 使用 code 做异或运算。 + /// + /// 原始二进制流。 + /// 异或计算的开始位置。 + /// 异或计算长度,若小于 0,则计算整个二进制流。 + /// 异或二进制流。 + /// 异或后的二进制流。 + public static byte[] GetXorBytes(byte[] bytes, int startIndex, int length, byte[] code) + { + if (bytes == null) + { + return null; + } + + int bytesLength = bytes.Length; + byte[] results = new byte[bytesLength]; + Array.Copy(bytes, 0, results, 0, bytesLength); + GetSelfXorBytes(results, startIndex, length, code); + return results; + } + + /// + /// 将 bytes 使用 code 做异或运算。此方法将复用并改写传入的 bytes 作为返回值,而不额外分配内存空间。 + /// + /// 原始及异或后的二进制流。 + /// 异或计算的开始位置。 + /// 异或计算长度。 + /// 异或二进制流。 + public static void GetSelfXorBytes(byte[] bytes, int startIndex, int length, byte[] code) + { + if (bytes == null) + { + return; + } + + if (code == null) + { + throw new GameFrameworkException("Code is invalid."); + } + + int codeLength = code.Length; + if (codeLength <= 0) + { + throw new GameFrameworkException("Code length is invalid."); + } + + if (startIndex < 0 || length < 0 || startIndex + length > bytes.Length) + { + throw new GameFrameworkException("Start index or length is invalid."); + } + + int codeIndex = startIndex % codeLength; + for (int i = startIndex; i < length; i++) + { + bytes[i] ^= code[codeIndex++]; + codeIndex %= codeLength; + } + } + } + } +} diff --git a/Assets/TEngine/Runtime/Utility/Utility.Encryption.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Encryption.cs.meta new file mode 100644 index 00000000..09a69ef3 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Encryption.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a279fdc81b03f4847a1b1a209af2a68e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.File.cs b/Assets/TEngine/Runtime/Utility/Utility.File.cs new file mode 100644 index 00000000..8eba4910 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.File.cs @@ -0,0 +1,232 @@ +using System; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEngine; + +namespace TEngine +{ + /// + /// Unity平台路径类型。 + /// + public enum UnityPlatformPathType : int + { + dataPath = 0, + streamingAssetsPath, + persistentDataPath, + temporaryCachePath, + } + + public static partial class Utility + { + /// + /// 文件相关的实用函数。 + /// + public static class File + { + public static bool CreateFile(string filePath, bool isCreateDir = true) + { + if (!System.IO.File.Exists(filePath)) + { + string dir = System.IO.Path.GetDirectoryName(filePath); + if (!Directory.Exists(dir)) + { + if (isCreateDir) + { + Directory.CreateDirectory(dir); + } + else + { + Log.Error("文件夹不存在 Path=" + dir); + return false; + } + } + + System.IO.File.Create(filePath); + } + + return true; + } + + public static bool CreateFile(string filePath, string info, bool isCreateDir = true) + { + StreamWriter sw; + FileInfo t = new FileInfo(filePath); + if (!t.Exists) + { + string dir = System.IO.Path.GetDirectoryName(filePath); + if (!Directory.Exists(dir)) + { + if (isCreateDir) + { + Directory.CreateDirectory(dir); + } + else + { +#if UNITY_EDITOR + EditorUtility.DisplayDialog("Tips", "文件夹不存在", "CANCEL"); +#endif + Log.Error("文件夹不存在 Path=" + dir); + return false; + } + } + + sw = t.CreateText(); + } + else + { + sw = t.AppendText(); + } + + sw.WriteLine(info); + sw.Close(); + sw.Dispose(); + return true; + } + + public static string GetPersistentDataPlatformPath(string filePath) + { + filePath = +#if UNITY_ANDROID && !UNITY_EDITOR + Application.dataPath + "!assets" + "/" + filePath; +#else + Application.streamingAssetsPath + "/" + filePath; +#endif + return filePath; + } + + public static string GetPath(string path) + { + return path.Replace("\\", "/"); + } + + public static string Md5ByPathName(string pathName) + { + try + { + FileStream file = new FileStream(pathName, FileMode.Open); + System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); + byte[] retVal = md5.ComputeHash(file); + file.Close(); + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < retVal.Length; i++) + { + sb.Append(retVal[i].ToString("x2")); + } + + return sb.ToString(); + } + catch (Exception ex) + { + Log.Error("to md5 fail,error:" + ex.Message); + return "Error"; + } + } + + public static string GetLengthString(long length) + { + if (length < 1024) + { + return $"{length.ToString()} Bytes"; + } + + if (length < 1024 * 1024) + { + return $"{(length / 1024f):F2} KB"; + } + + return length < 1024 * 1024 * 1024 ? $"{(length / 1024f / 1024f):F2} MB" : $"{(length / 1024f / 1024f / 1024f):F2} GB"; + } + + public static string GetByteLengthString(long byteLength) + { + if (byteLength < 1024L) // 2 ^ 10 + { + return Utility.Text.Format("{0} Bytes", byteLength.ToString()); + } + + if (byteLength < 1048576L) // 2 ^ 20 + { + return Utility.Text.Format("{0} KB", (byteLength / 1024f).ToString("F2")); + } + + if (byteLength < 1073741824L) // 2 ^ 30 + { + return Utility.Text.Format("{0} MB", (byteLength / 1048576f).ToString("F2")); + } + + if (byteLength < 1099511627776L) // 2 ^ 40 + { + return Utility.Text.Format("{0} GB", (byteLength / 1073741824f).ToString("F2")); + } + + if (byteLength < 1125899906842624L) // 2 ^ 50 + { + return Utility.Text.Format("{0} TB", (byteLength / 1099511627776f).ToString("F2")); + } + + if (byteLength < 1152921504606846976L) // 2 ^ 60 + { + return Utility.Text.Format("{0} PB", (byteLength / 1125899906842624f).ToString("F2")); + } + + return Utility.Text.Format("{0} EB", (byteLength / 1152921504606846976f).ToString("F2")); + } + + public static string BinToUtf8(byte[] total) + { + byte[] result = total; + if (total[0] == 0xef && total[1] == 0xbb && total[2] == 0xbf) + { + // utf8文件的前三个字节为特殊占位符,要跳过 + result = new byte[total.Length - 3]; + System.Array.Copy(total, 3, result, 0, total.Length - 3); + } + + string utf8string = System.Text.Encoding.UTF8.GetString(result); + return utf8string; + } + + /// + /// 数据格式转换 + /// + /// 数据 + /// + public static string FormatData(long data) + { + string result = ""; + if (data < 0) + data = 0; + + if (data > 1024 * 1024) + { + result = ((int)(data / (1024 * 1024))).ToString() + "MB"; + } + else if (data > 1024) + { + result = ((int)(data / 1024)).ToString() + "KB"; + } + else + { + result = data + "B"; + } + + return result; + } + + /// + /// 获取文件大小 + /// + /// 文件路径 + /// + public static long GetFileSize(string path) + { + using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + return file.Length; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/TEngine/Runtime/Utility/Utility.File.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.File.cs.meta new file mode 100644 index 00000000..41e1974a --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.File.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6d1483cbdd562774a95cb697ed574e43 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.Folder.cs b/Assets/TEngine/Runtime/Utility/Utility.Folder.cs new file mode 100644 index 00000000..b8e3169f --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Folder.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// Folder 相关的实用函数。 + /// + public static partial class Folder + { + /// + /// 清理文件夹。 + /// + /// 文件夹路径。 + /// 操作成功。 + public static bool ClearFolder(string path) + { + try + { + var di = new DirectoryInfo(path); + if (!di.Exists) + { + return false; + } + + foreach (var file in di.GetFiles()) + { + file.Delete(); + } + + foreach (var dir in di.GetDirectories()) + { + dir.Delete(true); + } + + return true; + } + catch (Exception e) + { + throw new GameFrameworkException($"ClearFolder invalid:{e.Message}"); + } + } + + /// + /// 拷贝文件到根目录。 + /// + /// 源文件目录。 + /// 目标文件目录。 + /// 查找选项。 + /// 操作成功。 + public static bool CopyFilesToRootPath(string sourceRootPath, string destRootPath, SearchOption searchOption = SearchOption.AllDirectories) + { + string[] fileNames = Directory.GetFiles(sourceRootPath, "*", searchOption); + foreach (string fileName in fileNames) + { + string destFileName = System.IO.Path.Combine(destRootPath, fileName.Substring(sourceRootPath.Length)); + FileInfo destFileInfo = new FileInfo(destFileName); + if (destFileInfo.Directory != null && !destFileInfo.Directory.Exists) + { + destFileInfo.Directory.Create(); + } + + System.IO.File.Copy(fileName, destFileName, true); + } + + return true; + } + + /// + /// 拷贝文件夹。 + /// + /// 需要被拷贝的文件夹路径。 + /// 拷贝目标路径。 + public static bool CopyFolder(string srcPath, string tarPath) + { + if (!Directory.Exists(srcPath)) + { + return false; + } + + if (!Directory.Exists(tarPath)) + { + Directory.CreateDirectory(tarPath); + } + + //获得源文件下所有文件 + List files = new List(Directory.GetFiles(srcPath)); + files.ForEach(f => + { + string destFile = System.IO.Path.Combine(tarPath, System.IO.Path.GetFileName(f)); + System.IO.File.Copy(f, destFile, true); //覆盖模式 + }); + + //获得源文件下所有目录文件 + List folders = new List(Directory.GetDirectories(srcPath)); + folders.ForEach(f => + { + string destDir = System.IO.Path.Combine(tarPath, System.IO.Path.GetFileName(f)); + CopyFolder(f, destDir); //递归实现子文件夹拷贝 + }); + return true; + } + + /// + /// 拷贝文件。 + /// + /// 源文件目录。 + /// 目标文件目录。 + /// 搜索选项。 + /// 操作成功。 + public static bool CopyFiles(string sourceRootPath, string destRootPath, SearchOption searchOption = SearchOption.AllDirectories) + { + string[] fileNames = Directory.GetFiles(sourceRootPath, "*", searchOption); + foreach (string fileName in fileNames) + { + FileInfo sourceFileInfo = new FileInfo(fileName); + string destFileName = System.IO.Path.Combine(destRootPath, sourceFileInfo.Name); + FileInfo destFileInfo = new FileInfo(destFileName); + if (destFileInfo.Directory != null && !destFileInfo.Directory.Exists) + { + destFileInfo.Directory.Create(); + } + + System.IO.File.Copy(fileName, destFileName, true); + } + + return true; + } + } + } +} \ No newline at end of file diff --git a/Assets/TEngine/Runtime/Utility/Utility.Folder.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Folder.cs.meta new file mode 100644 index 00000000..504065f3 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Folder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 30d9951d450df9647a77c814ea8f68f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.Json.IJsonHelper.cs b/Assets/TEngine/Runtime/Utility/Utility.Json.IJsonHelper.cs new file mode 100644 index 00000000..06c2bfd7 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Json.IJsonHelper.cs @@ -0,0 +1,39 @@ +using System; + +namespace TEngine +{ + public static partial class Utility + { + public static partial class Json + { + /// + /// JSON 辅助器接口。 + /// + public interface IJsonHelper + { + /// + /// 将对象序列化为 JSON 字符串。 + /// + /// 要序列化的对象。 + /// 序列化后的 JSON 字符串。 + string ToJson(object obj); + + /// + /// 将 JSON 字符串反序列化为对象。 + /// + /// 对象类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + T ToObject(string json); + + /// + /// 将 JSON 字符串反序列化为对象。 + /// + /// 对象类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + object ToObject(Type objectType, string json); + } + } + } +} diff --git a/Assets/TEngine/Runtime/Utility/Utility.Json.IJsonHelper.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Json.IJsonHelper.cs.meta new file mode 100644 index 00000000..70e988d8 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Json.IJsonHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 54fba14fdfb53ab4f9edcd7eb3a9bc4c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.Json.cs b/Assets/TEngine/Runtime/Utility/Utility.Json.cs new file mode 100644 index 00000000..34d14604 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Json.cs @@ -0,0 +1,112 @@ +using System; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// JSON 相关的实用函数。 + /// + public static partial class Json + { + private static IJsonHelper s_JsonHelper = null; + + /// + /// 设置 JSON 辅助器。 + /// + /// 要设置的 JSON 辅助器。 + public static void SetJsonHelper(IJsonHelper jsonHelper) + { + s_JsonHelper = jsonHelper; + } + + /// + /// 将对象序列化为 JSON 字符串。 + /// + /// 要序列化的对象。 + /// 序列化后的 JSON 字符串。 + public static string ToJson(object obj) + { + if (s_JsonHelper == null) + { + throw new GameFrameworkException("JSON helper is invalid."); + } + + try + { + return s_JsonHelper.ToJson(obj); + } + catch (Exception exception) + { + if (exception is GameFrameworkException) + { + throw; + } + + throw new GameFrameworkException(Text.Format("Can not convert to JSON with exception '{0}'.", exception), exception); + } + } + + /// + /// 将 JSON 字符串反序列化为对象。 + /// + /// 对象类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + public static T ToObject(string json) + { + if (s_JsonHelper == null) + { + throw new GameFrameworkException("JSON helper is invalid."); + } + + try + { + return s_JsonHelper.ToObject(json); + } + catch (Exception exception) + { + if (exception is GameFrameworkException) + { + throw; + } + + throw new GameFrameworkException(Text.Format("Can not convert to object with exception '{0}'.", exception), exception); + } + } + + /// + /// 将 JSON 字符串反序列化为对象。 + /// + /// 对象类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + public static object ToObject(Type objectType, string json) + { + if (s_JsonHelper == null) + { + throw new GameFrameworkException("JSON helper is invalid."); + } + + if (objectType == null) + { + throw new GameFrameworkException("Object type is invalid."); + } + + try + { + return s_JsonHelper.ToObject(objectType, json); + } + catch (Exception exception) + { + if (exception is GameFrameworkException) + { + throw; + } + + throw new GameFrameworkException(Text.Format("Can not convert to object with exception '{0}'.", exception), exception); + } + } + } + } +} diff --git a/Assets/TEngine/Runtime/Utility/Utility.Json.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Json.cs.meta new file mode 100644 index 00000000..ba6d03e1 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Json.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4ee7fcac5a1ebab449eba2456434d3e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.Marshal.cs b/Assets/TEngine/Runtime/Utility/Utility.Marshal.cs new file mode 100644 index 00000000..61b9c83d --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Marshal.cs @@ -0,0 +1,233 @@ +using System; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// Marshal 相关的实用函数。 + /// + public static class Marshal + { + private const int BlockSize = 1024 * 4; + private static IntPtr s_CachedHGlobalPtr = IntPtr.Zero; + private static int s_CachedHGlobalSize = 0; + + /// + /// 获取缓存的从进程的非托管内存中分配的内存的大小。 + /// + public static int CachedHGlobalSize + { + get + { + return s_CachedHGlobalSize; + } + } + + /// + /// 确保从进程的非托管内存中分配足够大小的内存并缓存。 + /// + /// 要确保从进程的非托管内存中分配内存的大小。 + public static void EnsureCachedHGlobalSize(int ensureSize) + { + if (ensureSize < 0) + { + throw new GameFrameworkException("Ensure size is invalid."); + } + + if (s_CachedHGlobalPtr == IntPtr.Zero || s_CachedHGlobalSize < ensureSize) + { + FreeCachedHGlobal(); + int size = (ensureSize - 1 + BlockSize) / BlockSize * BlockSize; + s_CachedHGlobalPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(size); + s_CachedHGlobalSize = size; + } + } + + /// + /// 释放缓存的从进程的非托管内存中分配的内存。 + /// + public static void FreeCachedHGlobal() + { + if (s_CachedHGlobalPtr != IntPtr.Zero) + { + System.Runtime.InteropServices.Marshal.FreeHGlobal(s_CachedHGlobalPtr); + s_CachedHGlobalPtr = IntPtr.Zero; + s_CachedHGlobalSize = 0; + } + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 存储转换结果的二进制流。 + public static byte[] StructureToBytes(T structure) + { + return StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T))); + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 要转换的对象的大小。 + /// 存储转换结果的二进制流。 + internal static byte[] StructureToBytes(T structure, int structureSize) + { + if (structureSize < 0) + { + throw new GameFrameworkException("Structure size is invalid."); + } + + EnsureCachedHGlobalSize(structureSize); + System.Runtime.InteropServices.Marshal.StructureToPtr(structure, s_CachedHGlobalPtr, true); + byte[] result = new byte[structureSize]; + System.Runtime.InteropServices.Marshal.Copy(s_CachedHGlobalPtr, result, 0, structureSize); + return result; + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 存储转换结果的二进制流。 + public static void StructureToBytes(T structure, byte[] result) + { + StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), result, 0); + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 要转换的对象的大小。 + /// 存储转换结果的二进制流。 + internal static void StructureToBytes(T structure, int structureSize, byte[] result) + { + StructureToBytes(structure, structureSize, result, 0); + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 存储转换结果的二进制流。 + /// 写入存储转换结果的二进制流的起始位置。 + public static void StructureToBytes(T structure, byte[] result, int startIndex) + { + StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), result, startIndex); + } + + /// + /// 将数据从对象转换为二进制流。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象。 + /// 要转换的对象的大小。 + /// 存储转换结果的二进制流。 + /// 写入存储转换结果的二进制流的起始位置。 + internal static void StructureToBytes(T structure, int structureSize, byte[] result, int startIndex) + { + if (structureSize < 0) + { + throw new GameFrameworkException("Structure size is invalid."); + } + + if (result == null) + { + throw new GameFrameworkException("Result is invalid."); + } + + if (startIndex < 0) + { + throw new GameFrameworkException("Start index is invalid."); + } + + if (startIndex + structureSize > result.Length) + { + throw new GameFrameworkException("Result length is not enough."); + } + + EnsureCachedHGlobalSize(structureSize); + System.Runtime.InteropServices.Marshal.StructureToPtr(structure, s_CachedHGlobalPtr, true); + System.Runtime.InteropServices.Marshal.Copy(s_CachedHGlobalPtr, result, startIndex, structureSize); + } + + /// + /// 将数据从二进制流转换为对象。 + /// + /// 要转换的对象的类型。 + /// 要转换的二进制流。 + /// 存储转换结果的对象。 + public static T BytesToStructure(byte[] buffer) + { + return BytesToStructure(System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), buffer, 0); + } + + /// + /// 将数据从二进制流转换为对象。 + /// + /// 要转换的对象的类型。 + /// 要转换的二进制流。 + /// 读取要转换的二进制流的起始位置。 + /// 存储转换结果的对象。 + public static T BytesToStructure(byte[] buffer, int startIndex) + { + return BytesToStructure(System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), buffer, startIndex); + } + + /// + /// 将数据从二进制流转换为对象。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象的大小。 + /// 要转换的二进制流。 + /// 存储转换结果的对象。 + internal static T BytesToStructure(int structureSize, byte[] buffer) + { + return BytesToStructure(structureSize, buffer, 0); + } + + /// + /// 将数据从二进制流转换为对象。 + /// + /// 要转换的对象的类型。 + /// 要转换的对象的大小。 + /// 要转换的二进制流。 + /// 读取要转换的二进制流的起始位置。 + /// 存储转换结果的对象。 + internal static T BytesToStructure(int structureSize, byte[] buffer, int startIndex) + { + if (structureSize < 0) + { + throw new GameFrameworkException("Structure size is invalid."); + } + + if (buffer == null) + { + throw new GameFrameworkException("Buffer is invalid."); + } + + if (startIndex < 0) + { + throw new GameFrameworkException("Start index is invalid."); + } + + if (startIndex + structureSize > buffer.Length) + { + throw new GameFrameworkException("Buffer length is not enough."); + } + + EnsureCachedHGlobalSize(structureSize); + System.Runtime.InteropServices.Marshal.Copy(buffer, startIndex, s_CachedHGlobalPtr, structureSize); + return (T)System.Runtime.InteropServices.Marshal.PtrToStructure(s_CachedHGlobalPtr, typeof(T)); + } + } + } +} diff --git a/Assets/TEngine/Runtime/Utility/Utility.Marshal.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Marshal.cs.meta new file mode 100644 index 00000000..bff1a979 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Marshal.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e4eaf023a908b6847bc7c1b16e025fcd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.Path.cs b/Assets/TEngine/Runtime/Utility/Utility.Path.cs new file mode 100644 index 00000000..f14e2094 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Path.cs @@ -0,0 +1,93 @@ +using System.IO; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// 路径相关的实用函数。 + /// + public static class Path + { + /// + /// 获取规范的路径。 + /// + /// 要规范的路径。 + /// 规范的路径。 + public static string GetRegularPath(string path) + { + if (path == null) + { + return null; + } + + return path.Replace('\\', '/'); + } + + /// + /// 获取远程格式的路径(带有file:// 或 http:// 前缀)。 + /// + /// 原始路径。 + /// 远程格式路径。 + public static string GetRemotePath(string path) + { + string regularPath = GetRegularPath(path); + if (regularPath == null) + { + return null; + } + + return regularPath.Contains("://") ? regularPath : ("file:///" + regularPath).Replace("file:////", "file:///"); + } + + /// + /// 移除空文件夹。 + /// + /// 要处理的文件夹名称。 + /// 是否移除空文件夹成功。 + public static bool RemoveEmptyDirectory(string directoryName) + { + if (string.IsNullOrEmpty(directoryName)) + { + throw new GameFrameworkException("Directory name is invalid."); + } + + try + { + if (!Directory.Exists(directoryName)) + { + return false; + } + + // 不使用 SearchOption.AllDirectories,以便于在可能产生异常的环境下删除尽可能多的目录 + string[] subDirectoryNames = Directory.GetDirectories(directoryName, "*"); + int subDirectoryCount = subDirectoryNames.Length; + foreach (string subDirectoryName in subDirectoryNames) + { + if (RemoveEmptyDirectory(subDirectoryName)) + { + subDirectoryCount--; + } + } + + if (subDirectoryCount > 0) + { + return false; + } + + if (Directory.GetFiles(directoryName, "*").Length > 0) + { + return false; + } + + Directory.Delete(directoryName); + return true; + } + catch + { + return false; + } + } + } + } +} diff --git a/Assets/TEngine/Runtime/Utility/Utility.Path.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Path.cs.meta new file mode 100644 index 00000000..77bcd4dd --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Path.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ffffdb31a0e4d6e49a95d47aa1976e94 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.Random.cs b/Assets/TEngine/Runtime/Utility/Utility.Random.cs new file mode 100644 index 00000000..f11a3646 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Random.cs @@ -0,0 +1,72 @@ +using System; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// 随机相关的实用函数。 + /// + public static class Random + { + private static System.Random s_Random = new System.Random((int)DateTime.UtcNow.Ticks); + + /// + /// 设置随机数种子。 + /// + /// 随机数种子。 + public static void SetSeed(int seed) + { + s_Random = new System.Random(seed); + } + + /// + /// 返回非负随机数。 + /// + /// 大于等于零且小于 System.Int32.MaxValue 的 32 位带符号整数。 + public static int GetRandom() + { + return s_Random.Next(); + } + + /// + /// 返回一个小于所指定最大值的非负随机数。 + /// + /// 要生成的随机数的上界(随机数不能取该上界值)。maxValue 必须大于等于零。 + /// 大于等于零且小于 maxValue 的 32 位带符号整数,即:返回值的范围通常包括零但不包括 maxValue。不过,如果 maxValue 等于零,则返回 maxValue。 + public static int GetRandom(int maxValue) + { + return s_Random.Next(maxValue); + } + + /// + /// 返回一个指定范围内的随机数。 + /// + /// 返回的随机数的下界(随机数可取该下界值)。 + /// 返回的随机数的上界(随机数不能取该上界值)。maxValue 必须大于等于 minValue。 + /// 一个大于等于 minValue 且小于 maxValue 的 32 位带符号整数,即:返回的值范围包括 minValue 但不包括 maxValue。如果 minValue 等于 maxValue,则返回 minValue。 + public static int GetRandom(int minValue, int maxValue) + { + return s_Random.Next(minValue, maxValue); + } + + /// + /// 返回一个介于 0.0 和 1.0 之间的随机数。 + /// + /// 大于等于 0.0 并且小于 1.0 的双精度浮点数。 + public static double GetRandomDouble() + { + return s_Random.NextDouble(); + } + + /// + /// 用随机数填充指定字节数组的元素。 + /// + /// 包含随机数的字节数组。 + public static void GetRandomBytes(byte[] buffer) + { + s_Random.NextBytes(buffer); + } + } + } +} diff --git a/Assets/TEngine/Runtime/Utility/Utility.Random.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Random.cs.meta new file mode 100644 index 00000000..0da5fa3b --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Random.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d141c00a7ebf38141b1661ed1acb48f1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.Unity.cs b/Assets/TEngine/Runtime/Utility/Utility.Unity.cs new file mode 100644 index 00000000..76e25b5d --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Unity.cs @@ -0,0 +1,391 @@ +using System; +using System.Collections; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Internal; +using Object = UnityEngine.Object; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// Unity相关的实用函数。 + /// + public static partial class Unity + { + private static GameObject _entity; + private static MainBehaviour _behaviour; + + #region 控制协程Coroutine + + public static Coroutine StartCoroutine(string methodName) + { + if (string.IsNullOrEmpty(methodName)) + { + return null; + } + + _MakeEntity(); + return _behaviour.StartCoroutine(methodName); + } + + public static Coroutine StartCoroutine(IEnumerator routine) + { + if (routine == null) + { + return null; + } + + _MakeEntity(); + return _behaviour.StartCoroutine(routine); + } + + public static Coroutine StartCoroutine(string methodName, [DefaultValue("null")] object value) + { + if (string.IsNullOrEmpty(methodName)) + { + return null; + } + + _MakeEntity(); + return _behaviour.StartCoroutine(methodName, value); + } + + public static void StopCoroutine(string methodName) + { + if (string.IsNullOrEmpty(methodName)) + { + return; + } + + if (_entity != null) + { + _behaviour.StopCoroutine(methodName); + } + } + + public static void StopCoroutine(IEnumerator routine) + { + if (routine == null) + { + return; + } + + if (_entity != null) + { + _behaviour.StopCoroutine(routine); + } + } + + public static void StopCoroutine(Coroutine routine) + { + if (routine == null) + return; + + if (_entity != null) + { + _behaviour.StopCoroutine(routine); + routine = null; + } + } + + public static void StopAllCoroutines() + { + if (_entity != null) + { + _behaviour.StopAllCoroutines(); + } + } + + #endregion + + #region 注入UnityUpdate/FixedUpdate/LateUpdate + + /// + /// 为给外部提供的 添加帧更新事件。 + /// + /// + public static void AddUpdateListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.AddUpdateListener(fun); + } + + /// + /// 为给外部提供的 添加物理帧更新事件。 + /// + /// + public static void AddFixedUpdateListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.AddFixedUpdateListener(fun); + } + + /// + /// 为给外部提供的 添加Late帧更新事件。 + /// + /// + public static void AddLateUpdateListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.AddLateUpdateListener(fun); + } + + /// + /// 移除帧更新事件。 + /// + /// + public static void RemoveUpdateListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.RemoveUpdateListener(fun); + } + + /// + /// 移除物理帧更新事件。 + /// + /// + public static void RemoveFixedUpdateListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.RemoveFixedUpdateListener(fun); + } + + /// + /// 移除Late帧更新事件。 + /// + /// + public static void RemoveLateUpdateListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.RemoveLateUpdateListener(fun); + } + + #endregion + + #region Unity Events 注入 + /// + /// 为给外部提供的Destroy注册事件。 + /// + /// + public static void AddDestroyListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.AddDestroyListener(fun); + } + + /// + /// 为给外部提供的Destroy反注册事件。 + /// + /// + public static void RemoveDestroyListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.RemoveDestroyListener(fun); + } + + /// + /// 为给外部提供的OnDrawGizmos注册事件。 + /// + /// + public static void AddOnDrawGizmosListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.RemoveDestroyListener(fun); + } + + /// + /// 为给外部提供的OnDrawGizmos反注册事件。 + /// + /// + public static void RemoveOnDrawGizmosListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.RemoveDestroyListener(fun); + } + + /// + /// 为给外部提供的OnApplicationPause注册事件。 + /// + /// + public static void AddOnApplicationPauseListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.AddOnApplicationPauseListener(fun); + } + + /// + /// 为给外部提供的OnApplicationPause反注册事件。 + /// + /// + public static void RemoveOnApplicationPauseListener(UnityAction fun) + { + _MakeEntity(); + _behaviour.AddOnApplicationPauseListener(fun); + } + #endregion + + /// + /// 释放Behaviour生命周期。 + /// + public static void Release() + { + _MakeEntity(); + _behaviour.Release(); + } + + private static void _MakeEntity() + { + if (_entity != null) + { + return; + } + + _entity = new GameObject("__MonoUtility__") + { + hideFlags = HideFlags.HideAndDontSave + }; + _entity.SetActive(true); + +#if UNITY_EDITOR + if (Application.isPlaying) +#endif + { + Object.DontDestroyOnLoad(_entity); + } + + UnityEngine.Assertions.Assert.IsFalse(_behaviour); + _behaviour = _entity.AddComponent(); + } + + private class MainBehaviour : MonoBehaviour + { + private event UnityAction updateEvent; + private event UnityAction fixedUpdateEvent; + private event UnityAction lateUpdateEvent; + private event UnityAction destroyEvent; + private event UnityAction onDrawGizmosEvent; + private event UnityAction onApplicationPause; + + void Update() + { + if (updateEvent != null) + { + updateEvent(); + } + } + + void FixedUpdate() + { + if (fixedUpdateEvent != null) + { + fixedUpdateEvent(); + } + } + + void LateUpdate() + { + if (lateUpdateEvent != null) + { + lateUpdateEvent(); + } + } + + private void OnDestroy() + { + if (destroyEvent != null) + { + destroyEvent(); + } + } + + private void OnDrawGizmos() + { + if (onDrawGizmosEvent != null) + { + onDrawGizmosEvent(); + } + } + + private void OnApplicationPause(bool pauseStatus) + { + if (onApplicationPause != null) + { + onApplicationPause(pauseStatus); + } + } + + public void AddLateUpdateListener(UnityAction fun) + { + lateUpdateEvent += fun; + } + + public void RemoveLateUpdateListener(UnityAction fun) + { + lateUpdateEvent -= fun; + } + + public void AddFixedUpdateListener(UnityAction fun) + { + fixedUpdateEvent += fun; + } + + public void RemoveFixedUpdateListener(UnityAction fun) + { + fixedUpdateEvent -= fun; + } + + public void AddUpdateListener(UnityAction fun) + { + updateEvent += fun; + } + + public void RemoveUpdateListener(UnityAction fun) + { + updateEvent -= fun; + } + + public void AddDestroyListener(UnityAction fun) + { + destroyEvent += fun; + } + + public void RemoveDestroyListener(UnityAction fun) + { + destroyEvent -= fun; + } + + public void AddOnDrawGizmosListener(UnityAction fun) + { + onDrawGizmosEvent += fun; + } + + public void RemoveOnDrawGizmosListener(UnityAction fun) + { + onDrawGizmosEvent -= fun; + } + + public void AddOnApplicationPauseListener(UnityAction fun) + { + onApplicationPause += fun; + } + + public void RemoveOnApplicationPauseListener(UnityAction fun) + { + onApplicationPause -= fun; + } + + public void Release() + { + updateEvent = null; + fixedUpdateEvent = null; + lateUpdateEvent = null; + onDrawGizmosEvent = null; + destroyEvent = null; + onApplicationPause = null; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/TEngine/Runtime/Utility/Utility.Unity.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Unity.cs.meta new file mode 100644 index 00000000..5f785dea --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Unity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1b5e063f21f5cba4d85471c343c33271 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.Verifier.Crc32.cs b/Assets/TEngine/Runtime/Utility/Utility.Verifier.Crc32.cs new file mode 100644 index 00000000..7c44a9a7 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Verifier.Crc32.cs @@ -0,0 +1,87 @@ +namespace TEngine +{ + public static partial class Utility + { + public static partial class Verifier + { + /// + /// CRC32 算法。 + /// + private sealed class Crc32 + { + private const int TableLength = 256; + private const uint DefaultPolynomial = 0xedb88320; + private const uint DefaultSeed = 0xffffffff; + + private readonly uint m_Seed; + private readonly uint[] m_Table; + private uint m_Hash; + + public Crc32() + : this(DefaultPolynomial, DefaultSeed) + { + } + + public Crc32(uint polynomial, uint seed) + { + m_Seed = seed; + m_Table = InitializeTable(polynomial); + m_Hash = seed; + } + + public void Initialize() + { + m_Hash = m_Seed; + } + + public void HashCore(byte[] bytes, int offset, int length) + { + m_Hash = CalculateHash(m_Table, m_Hash, bytes, offset, length); + } + + public uint HashFinal() + { + return ~m_Hash; + } + + private static uint CalculateHash(uint[] table, uint value, byte[] bytes, int offset, int length) + { + int last = offset + length; + for (int i = offset; i < last; i++) + { + unchecked + { + value = (value >> 8) ^ table[bytes[i] ^ value & 0xff]; + } + } + + return value; + } + + private static uint[] InitializeTable(uint polynomial) + { + uint[] table = new uint[TableLength]; + for (int i = 0; i < TableLength; i++) + { + uint entry = (uint)i; + for (int j = 0; j < 8; j++) + { + if ((entry & 1) == 1) + { + entry = (entry >> 1) ^ polynomial; + } + else + { + entry >>= 1; + } + } + + table[i] = entry; + } + + return table; + } + } + } + } +} diff --git a/Assets/TEngine/Runtime/Utility/Utility.Verifier.Crc32.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Verifier.Crc32.cs.meta new file mode 100644 index 00000000..b683582b --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Verifier.Crc32.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9a7d0ce566dde9749b214b5ae065ac3d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TEngine/Runtime/Utility/Utility.Verifier.cs b/Assets/TEngine/Runtime/Utility/Utility.Verifier.cs new file mode 100644 index 00000000..5fd036c6 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Verifier.cs @@ -0,0 +1,188 @@ +using System; +using System.IO; + +namespace TEngine +{ + public static partial class Utility + { + /// + /// 校验相关的实用函数。 + /// + public static partial class Verifier + { + private const int CachedBytesLength = 0x1000; + private static readonly byte[] s_CachedBytes = new byte[CachedBytesLength]; + private static readonly Crc32 s_Algorithm = new Crc32(); + + /// + /// 计算二进制流的 CRC32。 + /// + /// 指定的二进制流。 + /// 计算后的 CRC32。 + public static int GetCrc32(byte[] bytes) + { + if (bytes == null) + { + throw new GameFrameworkException("Bytes is invalid."); + } + + return GetCrc32(bytes, 0, bytes.Length); + } + + /// + /// 计算二进制流的 CRC32。 + /// + /// 指定的二进制流。 + /// 二进制流的偏移。 + /// 二进制流的长度。 + /// 计算后的 CRC32。 + public static int GetCrc32(byte[] bytes, int offset, int length) + { + if (bytes == null) + { + throw new GameFrameworkException("Bytes is invalid."); + } + + if (offset < 0 || length < 0 || offset + length > bytes.Length) + { + throw new GameFrameworkException("Offset or length is invalid."); + } + + s_Algorithm.HashCore(bytes, offset, length); + int result = (int)s_Algorithm.HashFinal(); + s_Algorithm.Initialize(); + return result; + } + + /// + /// 计算二进制流的 CRC32。 + /// + /// 指定的二进制流。 + /// 计算后的 CRC32。 + public static int GetCrc32(Stream stream) + { + if (stream == null) + { + throw new GameFrameworkException("Stream is invalid."); + } + + while (true) + { + int bytesRead = stream.Read(s_CachedBytes, 0, CachedBytesLength); + if (bytesRead > 0) + { + s_Algorithm.HashCore(s_CachedBytes, 0, bytesRead); + } + else + { + break; + } + } + + int result = (int)s_Algorithm.HashFinal(); + s_Algorithm.Initialize(); + Array.Clear(s_CachedBytes, 0, CachedBytesLength); + return result; + } + + /// + /// 获取 CRC32 数值的二进制数组。 + /// + /// CRC32 数值。 + /// CRC32 数值的二进制数组。 + public static byte[] GetCrc32Bytes(int crc32) + { + return new byte[] { (byte)((crc32 >> 24) & 0xff), (byte)((crc32 >> 16) & 0xff), (byte)((crc32 >> 8) & 0xff), (byte)(crc32 & 0xff) }; + } + + /// + /// 获取 CRC32 数值的二进制数组。 + /// + /// CRC32 数值。 + /// 要存放结果的数组。 + public static void GetCrc32Bytes(int crc32, byte[] bytes) + { + GetCrc32Bytes(crc32, bytes, 0); + } + + /// + /// 获取 CRC32 数值的二进制数组。 + /// + /// CRC32 数值。 + /// 要存放结果的数组。 + /// CRC32 数值的二进制数组在结果数组内的起始位置。 + public static void GetCrc32Bytes(int crc32, byte[] bytes, int offset) + { + if (bytes == null) + { + throw new GameFrameworkException("Result is invalid."); + } + + if (offset < 0 || offset + 4 > bytes.Length) + { + throw new GameFrameworkException("Offset or length is invalid."); + } + + bytes[offset] = (byte)((crc32 >> 24) & 0xff); + bytes[offset + 1] = (byte)((crc32 >> 16) & 0xff); + bytes[offset + 2] = (byte)((crc32 >> 8) & 0xff); + bytes[offset + 3] = (byte)(crc32 & 0xff); + } + + internal static int GetCrc32(Stream stream, byte[] code, int length) + { + if (stream == null) + { + throw new GameFrameworkException("Stream is invalid."); + } + + if (code == null) + { + throw new GameFrameworkException("Code is invalid."); + } + + int codeLength = code.Length; + if (codeLength <= 0) + { + throw new GameFrameworkException("Code length is invalid."); + } + + int bytesLength = (int)stream.Length; + if (length < 0 || length > bytesLength) + { + length = bytesLength; + } + + int codeIndex = 0; + while (true) + { + int bytesRead = stream.Read(s_CachedBytes, 0, CachedBytesLength); + if (bytesRead > 0) + { + if (length > 0) + { + for (int i = 0; i < bytesRead && i < length; i++) + { + s_CachedBytes[i] ^= code[codeIndex++]; + codeIndex %= codeLength; + } + + length -= bytesRead; + } + + s_Algorithm.HashCore(s_CachedBytes, 0, bytesRead); + } + else + { + break; + } + } + + int result = (int)s_Algorithm.HashFinal(); + s_Algorithm.Initialize(); + Array.Clear(s_CachedBytes, 0, CachedBytesLength); + return result; + } + } + } +} diff --git a/Assets/TEngine/Runtime/Utility/Utility.Verifier.cs.meta b/Assets/TEngine/Runtime/Utility/Utility.Verifier.cs.meta new file mode 100644 index 00000000..be93c9a2 --- /dev/null +++ b/Assets/TEngine/Runtime/Utility/Utility.Verifier.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 968c23f2e5a22ec4f884c9932c8fa90b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: