diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..13d2135 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +[*.cs] + +# IDE0008: Use explicit type +dotnet_diagnostic.IDE0008.severity = none +csharp_style_var_when_type_is_apparent=false:suggestion +csharp_style_var_for_built_in_types=false:suggestion +csharp_style_var_elsewhere=false:suggestion diff --git a/.gitignore b/.gitignore index 8af868e..dcbcebe 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,12 @@ sysinfo.txt # Crashlytics generated file crashlytics-build.properties +# +/Docs +/Issues +/Obsolete +/Snapshots +/UI +/UserSettings +/*.zip +*.lnk diff --git a/.vsconfig b/.vsconfig new file mode 100644 index 0000000..d70cd98 --- /dev/null +++ b/.vsconfig @@ -0,0 +1,6 @@ +{ + "version": "1.0", + "components": [ + "Microsoft.VisualStudio.Workload.ManagedGame" + ] +} diff --git a/Assets/Animations.meta b/Assets/Animations.meta new file mode 100644 index 0000000..1376c51 --- /dev/null +++ b/Assets/Animations.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ff84d017aa87efe40a398305f6c66f4d +folderAsset: yes +timeCreated: 1611481582 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Animations/Canvas.controller b/Assets/Animations/Canvas.controller new file mode 100644 index 0000000..c28bc8f Binary files /dev/null and b/Assets/Animations/Canvas.controller differ diff --git a/Assets/Animations/Canvas.controller.meta b/Assets/Animations/Canvas.controller.meta new file mode 100644 index 0000000..b0822ff --- /dev/null +++ b/Assets/Animations/Canvas.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c96c5f91fd684d14d9d4c09a5f34ee5d +timeCreated: 1637144068 +licenseType: Free +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Animations/IMain.anim b/Assets/Animations/IMain.anim new file mode 100644 index 0000000..5de880d Binary files /dev/null and b/Assets/Animations/IMain.anim differ diff --git a/Assets/Animations/IMain.anim.meta b/Assets/Animations/IMain.anim.meta new file mode 100644 index 0000000..98525fc --- /dev/null +++ b/Assets/Animations/IMain.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2162866fb7549724a85cb3c854a136ad +timeCreated: 1637144548 +licenseType: Free +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Animations/IQuit.anim b/Assets/Animations/IQuit.anim new file mode 100644 index 0000000..9a39e8c Binary files /dev/null and b/Assets/Animations/IQuit.anim differ diff --git a/Assets/Animations/IQuit.anim.meta b/Assets/Animations/IQuit.anim.meta new file mode 100644 index 0000000..99af74a --- /dev/null +++ b/Assets/Animations/IQuit.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6e50faab4238b5548bb05a7d421f5405 +timeCreated: 1637145598 +licenseType: Free +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Animations/ISettings.anim b/Assets/Animations/ISettings.anim new file mode 100644 index 0000000..627a1fe Binary files /dev/null and b/Assets/Animations/ISettings.anim differ diff --git a/Assets/Animations/ISettings.anim.meta b/Assets/Animations/ISettings.anim.meta new file mode 100644 index 0000000..3ce9fdf --- /dev/null +++ b/Assets/Animations/ISettings.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8b9f1682ee8026b468ad15885e1ff6a5 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Animations/IStartup.anim b/Assets/Animations/IStartup.anim new file mode 100644 index 0000000..71a808d Binary files /dev/null and b/Assets/Animations/IStartup.anim differ diff --git a/Assets/Animations/IStartup.anim.meta b/Assets/Animations/IStartup.anim.meta new file mode 100644 index 0000000..df47c85 --- /dev/null +++ b/Assets/Animations/IStartup.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9d0c0a0c88a0e7a43b77b0065bb64721 +timeCreated: 1637144134 +licenseType: Free +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Animations/TMain_Settings.anim b/Assets/Animations/TMain_Settings.anim new file mode 100644 index 0000000..1b471ef Binary files /dev/null and b/Assets/Animations/TMain_Settings.anim differ diff --git a/Assets/Animations/TMain_Settings.anim.meta b/Assets/Animations/TMain_Settings.anim.meta new file mode 100644 index 0000000..a953c70 --- /dev/null +++ b/Assets/Animations/TMain_Settings.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 961473ba26b4b1942806c224266f8db7 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Animations/TQuit_.anim b/Assets/Animations/TQuit_.anim new file mode 100644 index 0000000..03fe8cb Binary files /dev/null and b/Assets/Animations/TQuit_.anim differ diff --git a/Assets/Animations/TQuit_.anim.meta b/Assets/Animations/TQuit_.anim.meta new file mode 100644 index 0000000..3ac4e62 --- /dev/null +++ b/Assets/Animations/TQuit_.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0cc97e0bf50ad9c4e834c28e6eddf416 +timeCreated: 1637145877 +licenseType: Free +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Animations/TSettings_Main.anim b/Assets/Animations/TSettings_Main.anim new file mode 100644 index 0000000..d2fe72f Binary files /dev/null and b/Assets/Animations/TSettings_Main.anim differ diff --git a/Assets/Animations/TSettings_Main.anim.meta b/Assets/Animations/TSettings_Main.anim.meta new file mode 100644 index 0000000..fee22ac --- /dev/null +++ b/Assets/Animations/TSettings_Main.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9f6fb5723dba03d42b9e8a3c3e9091a5 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Animations/TStartup_Main.anim b/Assets/Animations/TStartup_Main.anim new file mode 100644 index 0000000..2ccfb7d Binary files /dev/null and b/Assets/Animations/TStartup_Main.anim differ diff --git a/Assets/Animations/TStartup_Main.anim.meta b/Assets/Animations/TStartup_Main.anim.meta new file mode 100644 index 0000000..9eee4e3 --- /dev/null +++ b/Assets/Animations/TStartup_Main.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 63a0e2075f5ba8d489d8cd318c14720b +timeCreated: 1637144068 +licenseType: Free +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Animations/T_Quit.anim b/Assets/Animations/T_Quit.anim new file mode 100644 index 0000000..d1b896b Binary files /dev/null and b/Assets/Animations/T_Quit.anim differ diff --git a/Assets/Animations/T_Quit.anim.meta b/Assets/Animations/T_Quit.anim.meta new file mode 100644 index 0000000..0424cdf --- /dev/null +++ b/Assets/Animations/T_Quit.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cc249d3462d795b46aff263bc04baee2 +timeCreated: 1637144561 +licenseType: Free +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Config.unity b/Assets/Config.unity new file mode 100644 index 0000000..2f4d2c6 Binary files /dev/null and b/Assets/Config.unity differ diff --git a/Assets/Config.unity.meta b/Assets/Config.unity.meta new file mode 100644 index 0000000..688f8a1 --- /dev/null +++ b/Assets/Config.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 215ebdd4cb9187741a2e24f5e7d8511d +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Console.unity b/Assets/Console.unity new file mode 100644 index 0000000..021f929 Binary files /dev/null and b/Assets/Console.unity differ diff --git a/Assets/Console.unity.meta b/Assets/Console.unity.meta new file mode 100644 index 0000000..71a8172 --- /dev/null +++ b/Assets/Console.unity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8a36c371ab6077d43ac28fe09b0fe675 +timeCreated: 1620725915 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville.meta b/Assets/Cryville.meta new file mode 100644 index 0000000..21f8df3 --- /dev/null +++ b/Assets/Cryville.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: bdfbc84283159e8429c29a3d47e35bad +folderAsset: yes +timeCreated: 1605323574 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common.meta b/Assets/Cryville/Common.meta new file mode 100644 index 0000000..91beb28 --- /dev/null +++ b/Assets/Cryville/Common.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d213440bfd40d0d49a2950e04f3008ab +folderAsset: yes +timeCreated: 1594270605 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/AsyncDelivery.cs b/Assets/Cryville/Common/AsyncDelivery.cs new file mode 100644 index 0000000..5c5b996 --- /dev/null +++ b/Assets/Cryville/Common/AsyncDelivery.cs @@ -0,0 +1,14 @@ +using System; + +namespace Cryville.Common { + public class AsyncDelivery { + public Action CancelSource { private get; set; } + public Action Destination { private get; set; } + public void Deliver(bool succeeded, T result) { + if (Destination != null) Destination(succeeded, result); + } + public void Cancel() { + if (CancelSource != null) CancelSource(); + } + } +} diff --git a/Assets/Cryville/Common/AsyncDelivery.cs.meta b/Assets/Cryville/Common/AsyncDelivery.cs.meta new file mode 100644 index 0000000..792cd08 --- /dev/null +++ b/Assets/Cryville/Common/AsyncDelivery.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 857c1f0e990462a47bd0ed83448f923b +timeCreated: 1637755775 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/BinderAttribute.cs b/Assets/Cryville/Common/BinderAttribute.cs new file mode 100644 index 0000000..1a0ab02 --- /dev/null +++ b/Assets/Cryville/Common/BinderAttribute.cs @@ -0,0 +1,59 @@ +using System; +using System.Globalization; +using System.Reflection; + +namespace Cryville.Common { + public class BinderAttribute : Attribute { + public BinderAttribute(Type type) { + BinderType = type; + } + + public Type BinderType; + + public static Binder CreateBinderOfType(Type type) { + var l = type.GetCustomAttributes(typeof(BinderAttribute), true); + if (l.Length > 0) { + return (Binder)ReflectionHelper.InvokeEmptyConstructor( + ((BinderAttribute)l[0]).BinderType + ); + } + return new EmptyBinder(); + } + } + + public class EmptyBinder : Binder { + /*static readonly Type[] emptyTypeArray = {}; + static readonly object[] emptyObjectArray = {};*/ + + public override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture) { + throw new NotImplementedException(); + } + + public override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state) { + throw new NotImplementedException(); + } + + public override object ChangeType(object value, Type type, CultureInfo culture) { + if (value == null) + return null; + else if (type == value.GetType()) + return value; + else if (type.IsEnum && value is string) { + return Enum.Parse(type, (string)value); + } + throw new InvalidCastException(); + } + + public override void ReorderArgumentArray(ref object[] args, object state) { + throw new NotImplementedException(); + } + + public override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers) { + throw new NotImplementedException(); + } + + public override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers) { + throw new NotImplementedException(); + } + } +} diff --git a/Assets/Cryville/Common/BinderAttribute.cs.meta b/Assets/Cryville/Common/BinderAttribute.cs.meta new file mode 100644 index 0000000..47d4d8f --- /dev/null +++ b/Assets/Cryville/Common/BinderAttribute.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 146a308dba289ad4f91c07c69bb4688b +timeCreated: 1608801352 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Buffers.meta b/Assets/Cryville/Common/Buffers.meta new file mode 100644 index 0000000..49a92fe --- /dev/null +++ b/Assets/Cryville/Common/Buffers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 53f4e3167a1eee2478b0abc6302aee8f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Buffers/ArrayPool.cs b/Assets/Cryville/Common/Buffers/ArrayPool.cs new file mode 100644 index 0000000..20bef71 --- /dev/null +++ b/Assets/Cryville/Common/Buffers/ArrayPool.cs @@ -0,0 +1,65 @@ +namespace Cryville.Common.Buffers { + /// + /// A resource pool that allows reusing instances of arrays of type . + /// + /// The item type of the arrays in the pool. + public class ArrayPool { + private class Bucket : ObjectPool { + readonly int _size; + public Bucket(int size, int capacity) : base(capacity) { + _size = size; + } + protected override T[] Construct() { + return new T[_size]; + } + } + Bucket[] _buckets; + /// + /// Creates an instance of the class with the default maximum list size and bucket capacity. + /// + public ArrayPool() : this(0x40000000, 256) { } + /// + /// Creates an instance of the class. + /// + /// The maximum size of the arrays in the pool. + /// The capacity of each bucket. The pool groups arrays of similar sizes into buckets for faster access. + public ArrayPool(int maxSize, int capacityPerBucket) { + if (maxSize < 16) maxSize = 16; + int num = GetID(maxSize) + 1; + _buckets = new Bucket[num]; + for (int i = 0; i < num; i++) { + _buckets[i] = new Bucket(GetSize(i), capacityPerBucket); + } + } + /// + /// Rents an array that is at least the specified size from the pool. + /// + /// The minimum size of the array. + /// An array of type that is at least the specified size. + public T[] Rent(int size) { + int len2 = size; + if (len2 < 16) len2 = 16; + var arr = _buckets[GetID(len2)].Rent(); + return arr; + } + /// + /// Returns a rented array to the pool. + /// + /// The array to return. + public void Return(T[] arr) { + int len2 = arr.Length; + if (len2 < 16) len2 = 16; + _buckets[GetID(len2)].Return(arr); + } + static int GetID(int size) { + size -= 1; + size >>= 4; + int num = 0; + for (; size != 0; size >>= 1) num++; + return num; + } + static int GetSize(int id) { + return 0x10 << id; + } + } +} diff --git a/Assets/Cryville/Common/Buffers/ArrayPool.cs.meta b/Assets/Cryville/Common/Buffers/ArrayPool.cs.meta new file mode 100644 index 0000000..36246c1 --- /dev/null +++ b/Assets/Cryville/Common/Buffers/ArrayPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: df66519fa93e1b94ea5bb1702cc91b3f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Buffers/ListPool.cs b/Assets/Cryville/Common/Buffers/ListPool.cs new file mode 100644 index 0000000..90b9e9e --- /dev/null +++ b/Assets/Cryville/Common/Buffers/ListPool.cs @@ -0,0 +1,71 @@ +using System.Collections.Generic; + +namespace Cryville.Common.Buffers { + /// + /// A resource pool that allows reusing instances of lists of type . + /// + /// The item type of the lists in the pool. + public class ListPool { + private class Bucket : ObjectPool> { + readonly int _size; + public Bucket(int size, int capacity) : base(capacity) { + _size = size; + } + protected override List Construct() { + return new List(_size); + } + } + Bucket[] _buckets; + /// + /// Creates an instance of the class with the default maximum list size and bucket capacity. + /// + public ListPool() : this(0x40000000, 256) { } + /// + /// Creates an instance of the class. + /// + /// The maximum size of the lists in the pool. + /// The capacity of each bucket. The pool groups lists of similar sizes into buckets for faster access. + public ListPool(int maxSize, int capacityPerBucket) { + if (maxSize < 16) maxSize = 16; + int num = GetID(maxSize) + 1; + _buckets = new Bucket[num]; + for (int i = 0; i < num; i++) { + _buckets[i] = new Bucket(GetSize(i), capacityPerBucket); + } + } + /// + /// Rents a list of the specified size from the pool. The size of the list must not be changed when it is rented. + /// + /// The size of the list. + /// A of the specified size. + public List Rent(int size) { + int len2 = size; + if (len2 < 16) len2 = 16; + var list = _buckets[GetID(len2)].Rent(); + if (list.Count < size) + for (int i = list.Count; i < size; i++) list.Add(default(T)); + else if (list.Count > size) + list.RemoveRange(size, list.Count - size); + return list; + } + /// + /// Returns a rented list to the pool. + /// + /// The list to return. + public void Return(List list) { + int len2 = list.Capacity; + if (len2 < 16) len2 = 16; + _buckets[GetID(len2)].Return(list); + } + static int GetID(int size) { + size -= 1; + size >>= 4; + int num = 0; + for (; size != 0; size >>= 1) num++; + return num; + } + static int GetSize(int id) { + return 0x10 << id; + } + } +} diff --git a/Assets/Cryville/Common/Buffers/ListPool.cs.meta b/Assets/Cryville/Common/Buffers/ListPool.cs.meta new file mode 100644 index 0000000..68933cc --- /dev/null +++ b/Assets/Cryville/Common/Buffers/ListPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2b7b45ff20c33ac47b476371673b037c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Buffers/ObjectPool.cs b/Assets/Cryville/Common/Buffers/ObjectPool.cs new file mode 100644 index 0000000..3019b50 --- /dev/null +++ b/Assets/Cryville/Common/Buffers/ObjectPool.cs @@ -0,0 +1,42 @@ +namespace Cryville.Common.Buffers { + /// + /// A resource pool that allows reusing instances of type . + /// + /// The type of the objects in the pool. + public abstract class ObjectPool where T : class { + int _index; + readonly T[] _objs; + /// + /// Creates an instance of the class. + /// + /// The capacity of the pool. + public ObjectPool(int capacity) { + _objs = new T[capacity]; + } + /// + /// Rents a object from the pool. + /// + /// The rented object. + public T Rent() { + T obj = null; + if (_index < _objs.Length) { + obj = _objs[_index]; + _objs[_index++] = null; + } + if (obj == null) obj = Construct(); + return obj; + } + /// + /// Returns a rented object to the pool. + /// + /// The object to return. + public void Return(T obj) { + if (_index > 0) _objs[--_index] = obj; + } + /// + /// Constructs a new instance of type . + /// + /// The new instance. + protected abstract T Construct(); + } +} diff --git a/Assets/Cryville/Common/Buffers/ObjectPool.cs.meta b/Assets/Cryville/Common/Buffers/ObjectPool.cs.meta new file mode 100644 index 0000000..d178c09 --- /dev/null +++ b/Assets/Cryville/Common/Buffers/ObjectPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2745c44c3cc32be4ab3a43888c14b9a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Buffers/SimpleObjectPool.cs b/Assets/Cryville/Common/Buffers/SimpleObjectPool.cs new file mode 100644 index 0000000..fec023b --- /dev/null +++ b/Assets/Cryville/Common/Buffers/SimpleObjectPool.cs @@ -0,0 +1,16 @@ +namespace Cryville.Common.Buffers { + /// + /// A resource pool that allows reusing instances of type , which has a parameterless constructor. + /// + /// The type of the objects in the pool. + public class SimpleObjectPool : ObjectPool where T : class, new() { + /// + /// Creates an instance of the class. + /// + /// The capacity of the pool. + public SimpleObjectPool(int capacity) : base(capacity) { } + protected override T Construct() { + return new T(); + } + } +} diff --git a/Assets/Cryville/Common/Buffers/SimpleObjectPool.cs.meta b/Assets/Cryville/Common/Buffers/SimpleObjectPool.cs.meta new file mode 100644 index 0000000..b1bd779 --- /dev/null +++ b/Assets/Cryville/Common/Buffers/SimpleObjectPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b8cd439340f088d4eb83711a5bc6384d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Buffers/WStringPool.cs b/Assets/Cryville/Common/Buffers/WStringPool.cs new file mode 100644 index 0000000..6218b72 --- /dev/null +++ b/Assets/Cryville/Common/Buffers/WStringPool.cs @@ -0,0 +1,10 @@ +using System; +using System.Runtime.InteropServices; + +namespace Cryville.Common.Buffers { + public class WStringPool { + public WStringPool() { + + } + } +} diff --git a/Assets/Cryville/Common/Buffers/WStringPool.cs.meta b/Assets/Cryville/Common/Buffers/WStringPool.cs.meta new file mode 100644 index 0000000..0e9d82f --- /dev/null +++ b/Assets/Cryville/Common/Buffers/WStringPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 704270b37917aa1458db9d14bab07073 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/ComponentModel.meta b/Assets/Cryville/Common/ComponentModel.meta new file mode 100644 index 0000000..49fe228 --- /dev/null +++ b/Assets/Cryville/Common/ComponentModel.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3c27afc8f4f76d04dac0f0914798ccc0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/ComponentModel/LogarithmicScaleAttribute.cs b/Assets/Cryville/Common/ComponentModel/LogarithmicScaleAttribute.cs new file mode 100644 index 0000000..8c81727 --- /dev/null +++ b/Assets/Cryville/Common/ComponentModel/LogarithmicScaleAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace Cryville.Common.ComponentModel { + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] + public class LogarithmicScaleAttribute : Attribute { + public LogarithmicScaleAttribute() { } + } +} diff --git a/Assets/Cryville/Common/ComponentModel/LogarithmicScaleAttribute.cs.meta b/Assets/Cryville/Common/ComponentModel/LogarithmicScaleAttribute.cs.meta new file mode 100644 index 0000000..d2e69d4 --- /dev/null +++ b/Assets/Cryville/Common/ComponentModel/LogarithmicScaleAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c1e8a5b839ed6a64dbb9fc6b0bcf7cc2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/ComponentModel/PrecisionAttribute.cs b/Assets/Cryville/Common/ComponentModel/PrecisionAttribute.cs new file mode 100644 index 0000000..8c6c406 --- /dev/null +++ b/Assets/Cryville/Common/ComponentModel/PrecisionAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Cryville.Common.ComponentModel { + [AttributeUsage(AttributeTargets.Property, Inherited = false)] + public class PrecisionAttribute : Attribute { + public PrecisionAttribute(double precision) { + Precision = precision; + } + + public double Precision { get; set; } + } +} diff --git a/Assets/Cryville/Common/ComponentModel/PrecisionAttribute.cs.meta b/Assets/Cryville/Common/ComponentModel/PrecisionAttribute.cs.meta new file mode 100644 index 0000000..0f45163 --- /dev/null +++ b/Assets/Cryville/Common/ComponentModel/PrecisionAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ea83b8e303a1b8b43a2f2ff74a7a9a7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/ComponentModel/RangeAttribute.cs b/Assets/Cryville/Common/ComponentModel/RangeAttribute.cs new file mode 100644 index 0000000..ef535fc --- /dev/null +++ b/Assets/Cryville/Common/ComponentModel/RangeAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace Cryville.Common.ComponentModel { + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] + public class RangeAttribute : Attribute { + public RangeAttribute(float min, float max) { + Min = min; + Max = max; + } + + public float Min { get; set; } + public float Max { get; set; } + } +} diff --git a/Assets/Cryville/Common/ComponentModel/RangeAttribute.cs.meta b/Assets/Cryville/Common/ComponentModel/RangeAttribute.cs.meta new file mode 100644 index 0000000..ef066cb --- /dev/null +++ b/Assets/Cryville/Common/ComponentModel/RangeAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 569e766a56b73244dbade8de4c525faa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/ComponentModel/StepAttribute.cs b/Assets/Cryville/Common/ComponentModel/StepAttribute.cs new file mode 100644 index 0000000..f2d174a --- /dev/null +++ b/Assets/Cryville/Common/ComponentModel/StepAttribute.cs @@ -0,0 +1,11 @@ +using System; + +namespace Cryville.Common.ComponentModel { + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] + public class StepAttribute : Attribute { + public StepAttribute(float step) { + Step = step; + } + public float Step { get; set; } + } +} diff --git a/Assets/Cryville/Common/ComponentModel/StepAttribute.cs.meta b/Assets/Cryville/Common/ComponentModel/StepAttribute.cs.meta new file mode 100644 index 0000000..51bc31d --- /dev/null +++ b/Assets/Cryville/Common/ComponentModel/StepAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 94340a38155591146ada89db63bc4aeb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/FileStringAttribute.cs b/Assets/Cryville/Common/FileStringAttribute.cs new file mode 100644 index 0000000..dcaa297 --- /dev/null +++ b/Assets/Cryville/Common/FileStringAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace Cryville.Common { + public class FileStringAttribute : Attribute { + private readonly string filter; + + public string[] Filter { + get { + return filter.Split('|'); + } + } + + public FileStringAttribute(string ext) { + filter = ext; + } + } +} diff --git a/Assets/Cryville/Common/FileStringAttribute.cs.meta b/Assets/Cryville/Common/FileStringAttribute.cs.meta new file mode 100644 index 0000000..3694490 --- /dev/null +++ b/Assets/Cryville/Common/FileStringAttribute.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c3041eaac507d7548ae3460b33230271 +timeCreated: 1608801352 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Font.meta b/Assets/Cryville/Common/Font.meta new file mode 100644 index 0000000..711e504 --- /dev/null +++ b/Assets/Cryville/Common/Font.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7ad09f227a3c83141b6d9a0f55b4cb38 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Font/FontUtil.cs b/Assets/Cryville/Common/Font/FontUtil.cs new file mode 100644 index 0000000..ea43d4f --- /dev/null +++ b/Assets/Cryville/Common/Font/FontUtil.cs @@ -0,0 +1,9 @@ +using System.Globalization; + +namespace Cryville.Common.Font { + public static class FontUtil { + /*public static string MatchFontNameWithLang(string lang) { + + }*/ + } +} diff --git a/Assets/Cryville/Common/Font/FontUtil.cs.meta b/Assets/Cryville/Common/Font/FontUtil.cs.meta new file mode 100644 index 0000000..86f59b8 --- /dev/null +++ b/Assets/Cryville/Common/Font/FontUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f3cd70779125d96409f5a299a8034f5f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/IOExtensions.cs b/Assets/Cryville/Common/IOExtensions.cs new file mode 100644 index 0000000..a0e8ed6 --- /dev/null +++ b/Assets/Cryville/Common/IOExtensions.cs @@ -0,0 +1,27 @@ +using System; +using System.IO; +using System.Text; + +namespace Cryville.Common { + public static class IOExtensions { + 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]; + } + + 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); + } + + public static void WriteUInt16String(this BinaryWriter writer, string value, Encoding encoding = null) { + if (encoding == null) encoding = Encoding.UTF8; + byte[] buffer = encoding.GetBytes(value); + writer.Write((ushort)buffer.Length); + writer.Write(buffer); + } + } +} diff --git a/Assets/Cryville/Common/IOExtensions.cs.meta b/Assets/Cryville/Common/IOExtensions.cs.meta new file mode 100644 index 0000000..a2a7f6e --- /dev/null +++ b/Assets/Cryville/Common/IOExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 49f85de87c5e683429e4790c0dc3fd2c +timeCreated: 1620706538 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Logger.cs b/Assets/Cryville/Common/Logger.cs new file mode 100644 index 0000000..8686222 --- /dev/null +++ b/Assets/Cryville/Common/Logger.cs @@ -0,0 +1,79 @@ +using Ionic.Zip; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Cryville.Common { + public abstract class Logger { + static readonly Dictionary Instances = new Dictionary(); + static readonly Dictionary Files = new Dictionary(); + static string logPath = null; + public static void SetLogPath(string path) { + logPath = path; + var dir = new DirectoryInfo(path); + if (!dir.Exists) Directory.CreateDirectory(dir.FullName); + } + 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)); + } + public static void Create(string key, Logger logger) { + Instances[key] = logger; + if (logPath != null) { + Files[key] = new StreamWriter(logPath + "/" + ((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds).ToString() + "-" + key + ".log"); + Files[key].AutoFlush = true; + } + } + public static void Close() { + Instances.Clear(); + foreach (var f in Files) f.Value.Dispose(); + Files.Clear(); + } + + public virtual void Log(int level, string module, string msg) { } + } + + public class InstantLogger : Logger { + readonly Action callback; + public InstantLogger(Action callback) { + if (callback == null) + throw new ArgumentNullException("callback"); + this.callback = callback; + } + public override void Log(int level, string module, string msg) { + base.Log(level, module, msg); + callback(level, module, msg); + } + } + + public class BufferedLogger : Logger { + readonly List buffer = new List(); + public BufferedLogger() { } + public override void Log(int level, string module, string msg) { + base.Log(level, module, msg); + lock (buffer) { + buffer.Add(new LogEntry(level, module, msg)); + } + } + public void Enumerate(Action callback) { + lock (buffer) { + foreach (var i in buffer) { + callback(i.level, i.module, i.msg); + } + } + buffer.Clear(); + } + } + + public struct LogEntry { + public int level; + public string module; + public string msg; + public LogEntry(int level, string module, string msg) { + this.level = level; + this.module = module; + this.msg = msg; + } + } +} diff --git a/Assets/Cryville/Common/Logger.cs.meta b/Assets/Cryville/Common/Logger.cs.meta new file mode 100644 index 0000000..622df97 --- /dev/null +++ b/Assets/Cryville/Common/Logger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1c1729cfde78f1c479c9f7eb166e0107 +timeCreated: 1611126212 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Math.meta b/Assets/Cryville/Common/Math.meta new file mode 100644 index 0000000..ac60a74 --- /dev/null +++ b/Assets/Cryville/Common/Math.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c7912778bf022c34592b3ebf16782635 +folderAsset: yes +timeCreated: 1616377089 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Math/ColumnVector.cs b/Assets/Cryville/Common/Math/ColumnVector.cs new file mode 100644 index 0000000..6e16ed1 --- /dev/null +++ b/Assets/Cryville/Common/Math/ColumnVector.cs @@ -0,0 +1,37 @@ +namespace Cryville.Common.Math { + public class ColumnVector { + readonly T[] content; + public int Size { + get; + private set; + } + public ColumnVector(int size) { + content = new T[size]; + Size = size; + } + public ColumnVector(T[] c) { + Size = c.Length; + content = c; + } + public T this[int i] { + get { + return content[i]; + } + set { + content[i] = value; + } + } + public T Dot(ColumnVector lhs, IVectorOperator o) { + T res = default(T); + for (var i = 0; i < Size; i++) + res = o.Add(res, o.ScalarMultiply(lhs[i], content[i])); + return res; + } + public static ColumnVector WithPolynomialCoefficients(int size, float num) { + var m = new ColumnVector(size); + for (var i = 0; i < size; i++) + m[i] = (float)System.Math.Pow(num, i); + return m; + } + } +} diff --git a/Assets/Cryville/Common/Math/ColumnVector.cs.meta b/Assets/Cryville/Common/Math/ColumnVector.cs.meta new file mode 100644 index 0000000..717b70d --- /dev/null +++ b/Assets/Cryville/Common/Math/ColumnVector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b99c66d83f1330841a0c5a23e87bf873 +timeCreated: 1616406828 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Math/IVectorOperator.cs b/Assets/Cryville/Common/Math/IVectorOperator.cs new file mode 100644 index 0000000..0da9fd2 --- /dev/null +++ b/Assets/Cryville/Common/Math/IVectorOperator.cs @@ -0,0 +1,6 @@ +namespace Cryville.Common.Math { + public interface IVectorOperator { + T Add(T lhs, T rhs); + T ScalarMultiply(float lhs, T rhs); + } +} diff --git a/Assets/Cryville/Common/Math/IVectorOperator.cs.meta b/Assets/Cryville/Common/Math/IVectorOperator.cs.meta new file mode 100644 index 0000000..ff34251 --- /dev/null +++ b/Assets/Cryville/Common/Math/IVectorOperator.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6bd0295c670699c49b6f0944832387a9 +timeCreated: 1616379780 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Math/SquareMatrix.cs b/Assets/Cryville/Common/Math/SquareMatrix.cs new file mode 100644 index 0000000..c19fa6d --- /dev/null +++ b/Assets/Cryville/Common/Math/SquareMatrix.cs @@ -0,0 +1,63 @@ +namespace Cryville.Common.Math { + public class SquareMatrix { + readonly float[,] content; + public int Size { + get; + private set; + } + public SquareMatrix(int size) { + content = new float[size, size]; + Size = size; + } + public float this[int r, int c] { + get { return content[r, c]; } + set { content[r, c] = value; } + } + public ColumnVector Eliminate(ColumnVector v, IVectorOperator o) { + int s = Size; + float[,] d = (float[,])content.Clone(); + int[] refl = new int[s]; + for (int i = 0; i < s; i++) + refl[i] = i; + for (int r = 0; r < s; r++) { + for (int r0 = r; r0 < s; r0++) + if (d[refl[r0], r] != 0) { + refl[r] = r0; + refl[r0] = r; + break; + } + int or = refl[r]; + float sf0 = d[or, r]; + for (int c0 = r; c0 < s; c0++) + d[or, c0] /= sf0; + v[or] = o.ScalarMultiply(1 / sf0, v[or]); + for (int r1 = r + 1; r1 < s; r1++) { + int or1 = refl[r1]; + float sf1 = d[or1, r]; + for (int c1 = r; c1 < s; c1++) + d[or1, c1] -= d[or, c1] * sf1; + v[or1] = o.Add(v[or1], o.ScalarMultiply(-sf1, v[or])); + } + } + T[] res = new T[s]; + for (int r2 = s - 1; r2 >= 0; r2--) { + var v2 = v[refl[r2]]; + for (int c2 = r2 + 1; c2 < s; c2++) + v2 = o.Add(v2, o.ScalarMultiply(-d[refl[r2], c2], res[refl[c2]])); + res[refl[r2]] = v2; + } + return new ColumnVector(res); + } + public static SquareMatrix WithPolynomialCoefficients(int size) { + var m = new SquareMatrix(size); + for (var r = 0; r < size; r++) { + int d = 1; + for (var c = 0; c < size; c++) { + m[r, c] = d; + d *= r; + } + } + return m; + } + } +} diff --git a/Assets/Cryville/Common/Math/SquareMatrix.cs.meta b/Assets/Cryville/Common/Math/SquareMatrix.cs.meta new file mode 100644 index 0000000..f3a01bc --- /dev/null +++ b/Assets/Cryville/Common/Math/SquareMatrix.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bceea65ebaa5052409eb85086645232e +timeCreated: 1616377102 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Network.meta b/Assets/Cryville/Common/Network.meta new file mode 100644 index 0000000..f33e300 --- /dev/null +++ b/Assets/Cryville/Common/Network.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f8303a3eeefeacf4ca0c02b5d32e0cff +folderAsset: yes +timeCreated: 1621071543 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Network/HttpClient.cs b/Assets/Cryville/Common/Network/HttpClient.cs new file mode 100644 index 0000000..9955097 --- /dev/null +++ b/Assets/Cryville/Common/Network/HttpClient.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Sockets; +using System.Text; +using Microsoft.Win32; + +namespace Cryville.Common.Network { + public class HttpClient { + private readonly string _directHost; + protected string DirectHost { get { return _directHost; } } + + private readonly int _directPort; + protected int DirectPort { get { return _directPort; } } + + readonly Uri _baseUri; + readonly int origPort; + + protected string Version = "HTTP/1.1"; + protected TcpClient TcpClient; + protected virtual Stream Stream { + get { + return TcpClient.GetStream(); + } + } + + private readonly bool _proxied = false; + + public Dictionary Headers { get; set; } + + public HttpClient(Uri baseUri, int port = 80) { + _directHost = baseUri.Host; + _directPort = port; + _baseUri = baseUri; + origPort = _baseUri.Port; + Headers = new Dictionary(); + _proxied = GetProxy(ref _directHost, ref _directPort); + Logger.Log("main", 0, "Network", "Connecting to {0}:{1}", DirectHost, DirectPort); + TcpClient = new TcpClient(DirectHost, DirectPort); + } + + public virtual void Connect() { + if (_proxied) { + Request("CONNECT", _baseUri.Host + ":" + origPort.ToString()); + } + } + + public virtual void Close() { + TcpClient.Close(); + } + + public HttpResponse Request(string method, Uri uri, string body = null, Encoding encoding = null) { + string struri = GetUri(uri).PathAndQuery; + // if (_proxied) struri = GetUri(uri).AbsoluteUri; + return Request(method, struri, body, encoding); + } + + public HttpResponse Request(string method, string uri, string body = null, Encoding encoding = null) { + var headers = new Dictionary(); + // if (Stream.CanTimeout) Stream.ReadTimeout = Stream.WriteTimeout = 5000; + foreach (var h in Headers) + headers.Add(h.Key, h.Value); + // headers["Accept"] = "text/plain, */*"; + // headers["Connection"] = "close"; + headers["Host"] = _baseUri.Host; + byte[] payload = new byte[0]; + if (body != null) { + if (encoding == null) + encoding = Encoding.UTF8; + payload = encoding.GetBytes(body); + headers.Add("Content-Encoding", encoding.EncodingName); + headers.Add("Content-Length", payload.Length.ToString()); + } + string request_line = string.Format( + "{0} {1} {2}\r\n", method, uri, Version + ); + string header_fields = string.Concat(( + from h in headers select h.Key + ":" + h.Value + "\r\n" + ).ToArray()); + byte[] buffer0 = Encoding.ASCII.GetBytes(string.Format( + "{0}{1}\r\n", request_line, header_fields + )); + byte[] buffer1 = new byte[buffer0.Length + payload.Length]; + Array.Copy(buffer0, buffer1, buffer0.Length); + Array.Copy(payload, 0, buffer1, buffer0.Length, payload.Length); + Logger.Log("main", 0, "Network", Encoding.UTF8.GetString(buffer1)); + Stream.Write(buffer1, 0, buffer1.Length); + Stream.Flush(); + var response = new HttpResponse(Stream); + Logger.Log("main", 0, "Network", "{0}", response); + return response; + } + + protected virtual bool GetProxy(ref string host, ref int port) { + if (Environment.OSVersion.Platform == PlatformID.Win32NT) { + var reg = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings"); + var proxyEnable = (int)reg.GetValue("ProxyEnable"); + if (proxyEnable == 0) return false; + var proxyStr = (string)reg.GetValue("ProxyServer"); + if (!string.IsNullOrEmpty(proxyStr)) { + string[] proxies = proxyStr.Split(';'); + foreach (var p in proxies) { + if (p.StartsWith("http=")) { + string[] s = p.Split('=', ':'); + host = s[1]; + port = int.Parse(s[2]); + return true; + } + } + } + } + return false; + } + + protected Uri GetUri(string path) { + Uri address; + if (_baseUri != null) { + if (!Uri.TryCreate(_baseUri, path, out address)) { + return new Uri(Path.GetFullPath(path)); + } + } + else { + if (!Uri.TryCreate(path, UriKind.Absolute, out address)) { + return new Uri(Path.GetFullPath(path)); + } + } + return GetUri(address); + } + + protected Uri GetUri(Uri address) { + if (address == null) { + throw new ArgumentNullException("address"); + } + Uri uri = address; + if (!address.IsAbsoluteUri && _baseUri != null && !Uri.TryCreate(_baseUri, address, out uri)) { + return address; + } + return uri; + } + } +} diff --git a/Assets/Cryville/Common/Network/HttpClient.cs.meta b/Assets/Cryville/Common/Network/HttpClient.cs.meta new file mode 100644 index 0000000..0b11648 --- /dev/null +++ b/Assets/Cryville/Common/Network/HttpClient.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5ea931bf5488011468f3d1243a038874 +timeCreated: 1622589817 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Network/HttpResponse.cs b/Assets/Cryville/Common/Network/HttpResponse.cs new file mode 100644 index 0000000..9d3e4db --- /dev/null +++ b/Assets/Cryville/Common/Network/HttpResponse.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Cryville.Common.Network { + public class HttpResponse { + static readonly char[] spchar = new char[]{ ' ' }; + public string HttpVersion { get; private set; } + public string StatusCode { get; private set; } + public string ReasonPhase { get; private set; } + public Dictionary Headers { get; private set; } + public HttpResponseStream MessageBody { get; private set; } + internal HttpResponse(Stream stream) { + var reader = new BinaryReader(stream, Encoding.ASCII); + var statu_line = ReadLine(reader).Split(spchar, 3); + HttpVersion = statu_line[0]; + StatusCode = statu_line[1]; + ReasonPhase = statu_line[2]; + Logger.Log("main", 0, "Network", "Receive Response: {0} {1} {2}", HttpVersion, StatusCode, ReasonPhase); + Headers = new Dictionary(); + while (ParseHeader(reader, Headers)) ; + if (Headers.ContainsKey("content-length")) { + int length = int.Parse(Headers["content-length"]); + MessageBody = new HttpResponseBlockStream(reader, length); + } + else if (Headers.ContainsKey("transfer-encoding") && Headers["transfer-encoding"] == "chunked") { + MessageBody = new HttpResponseChunkedStream(reader); + } + } + + public override string ToString() { + return string.Format("<{0} {1} {2}>", HttpVersion, StatusCode, ReasonPhase); + } + + internal static bool ParseHeader(BinaryReader reader, Dictionary headers) { + // TODO Multiline header + var header = ReadLine(reader); + if (header == "") return false; + var s = header.Split(':'); + string field_name = s[0].Trim().ToLower(); + string field_value = s[1].Trim(); + if (headers.ContainsKey(field_name)) headers[field_name] += "," + field_value; + else headers.Add(field_name, field_value); + Logger.Log("main", 0, "Network", "Receive Header {0}: {1}", field_name, field_value); + return true; + } + + internal static string ReadLine(BinaryReader reader) { + StringBuilder result = new StringBuilder(); + char c; + while (true) { + c = reader.ReadChar(); + if (c == '\r') break; + result.Append(c); + } + // TODO Unseekable + reader.ReadByte(); + return result.ToString(); + } + } +} diff --git a/Assets/Cryville/Common/Network/HttpResponse.cs.meta b/Assets/Cryville/Common/Network/HttpResponse.cs.meta new file mode 100644 index 0000000..672fcee --- /dev/null +++ b/Assets/Cryville/Common/Network/HttpResponse.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 07e8215a93e3eb1418685009f0c58dcd +timeCreated: 1622596274 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Network/HttpResponseStream.cs b/Assets/Cryville/Common/Network/HttpResponseStream.cs new file mode 100644 index 0000000..767e944 --- /dev/null +++ b/Assets/Cryville/Common/Network/HttpResponseStream.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; + +namespace Cryville.Common.Network { + public abstract class HttpResponseStream : Stream { + public override bool CanRead { get { return true; } } + + public override bool CanSeek { get { return false; } } + + public override bool CanWrite { get { return false; } } + + public override long Length { get { throw new NotSupportedException(); } } + + public override long Position { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override void Flush() { + // Do nothing + } + + public abstract byte[] ReadToEnd(); + + public override long Seek(long offset, SeekOrigin origin) { + throw new NotSupportedException(); + } + + public override void SetLength(long value) { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) { + throw new NotSupportedException(); + } + } + + internal sealed class HttpResponseBlockStream : HttpResponseStream { + readonly BinaryReader _reader; + readonly int _length; + int _pos = 0; + internal HttpResponseBlockStream(BinaryReader reader, int length) { + _reader = reader; + _length = length; + } + public override int Read(byte[] buffer, int offset, int count) { + int recv = 0; + int recv_len = System.Math.Min(count, _length - _pos); + if (recv_len == 0) return 0; + while (recv < recv_len) { + recv += _reader.Read(buffer, offset + recv, count - recv); + Logger.Log("main", 0, "Network", "Message body received: {0}/{1}/{2}", recv, recv_len, _length); + } + _pos += recv_len; + return recv_len; + } + public override byte[] ReadToEnd() { + byte[] buffer = new byte[_length - _pos]; + Read(buffer, 0, buffer.Length); + return buffer; + } + } + + internal sealed class HttpResponseChunkedStream : HttpResponseStream { + readonly BinaryReader _reader; + byte[] _chunk = null; + int _pos = 0; + internal HttpResponseChunkedStream(BinaryReader reader) { + _reader = reader; + ReadChunk(); + } + public void ReadChunk() { + if (_chunk != null && _chunk.Length == 0) return; + string[] chunkHeader = HttpResponse.ReadLine(_reader).Split(';'); + // int chunkSize = Array.IndexOf(LEN, chunkHeader[0].ToLower()[0]); + int chunkSize = int.Parse(chunkHeader[0], NumberStyles.HexNumber); + if (chunkSize == -1) + throw new IOException("Corrupted chunk received"); + if (chunkSize == 0) { + _chunk = new byte[0]; + // TODO TE Header, now just discard + var headers = new Dictionary(); + while (HttpResponse.ParseHeader(_reader, headers)) ; + return; + } + _chunk = new byte[chunkSize]; + int recv = 0; + while (recv < chunkSize) { + recv += _reader.Read(_chunk, recv, chunkSize - recv); + Logger.Log("main", 0, "Network", "Message chunk received: {0}/{1}", recv, chunkSize); + } + _pos = 0; + if (HttpResponse.ReadLine(_reader) != "") + throw new IOException("Corrupted chunk received"); + } + public override int Read(byte[] buffer, int offset, int count) { + if (_chunk.Length == 0) return 0; + int recv = 0; + while (true) { + if (count - recv <= _chunk.Length - _pos) break; + Array.Copy(_chunk, _pos, buffer, recv, _chunk.Length - _pos); + recv += _chunk.Length - _pos; + ReadChunk(); + if (_chunk.Length == 0) return recv; + } + Array.Copy(_chunk, _pos, buffer, recv, count - recv); + return count; + } + public override byte[] ReadToEnd() { + if (_chunk.Length == 0) return new byte[0]; + List segs = new List(); + while (true) { + if (_pos != 0) { + var buffer = new byte[_chunk.Length - _pos]; + Array.Copy(_chunk, _pos, buffer, 0, buffer.Length); + segs.Add(buffer); + } + else segs.Add(_chunk); + ReadChunk(); + if (_chunk.Length == 0) { + var result = new byte[segs.Sum(i => i.Length)]; + int p = 0; + foreach (var i in segs) { + Array.Copy(i, 0, result, p, i.Length); + p += i.Length; + } + return result; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/Cryville/Common/Network/HttpResponseStream.cs.meta b/Assets/Cryville/Common/Network/HttpResponseStream.cs.meta new file mode 100644 index 0000000..ee4deb4 --- /dev/null +++ b/Assets/Cryville/Common/Network/HttpResponseStream.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f191de447a708da4f9d230e6545ce0a6 +timeCreated: 1635470462 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Network/HttpsClient.cs b/Assets/Cryville/Common/Network/HttpsClient.cs new file mode 100644 index 0000000..ed991ae --- /dev/null +++ b/Assets/Cryville/Common/Network/HttpsClient.cs @@ -0,0 +1,51 @@ +using Microsoft.Win32; +using System; +using System.IO; +using System.Net.Sockets; + +namespace Cryville.Common.Network { + public class HttpsClient : HttpClient { + readonly TlsTcpClient _tlsTcpClient; + + protected override Stream Stream { + get { + return _tlsTcpClient.Stream; + } + } + + public HttpsClient(Uri baseUri) : base(baseUri, 443) { + _tlsTcpClient = new TlsTcpClient(DirectHost, DirectPort); + } + + public override void Connect() { + _tlsTcpClient.Connect(); + base.Connect(); + } + + public override void Close() { + base.Close(); + _tlsTcpClient.Close(); + } + + protected override bool GetProxy(ref string host, ref int port) { + if (Environment.OSVersion.Platform == PlatformID.Win32NT) { + var reg = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings"); + var proxyEnable = (int)reg.GetValue("ProxyEnable"); + if (proxyEnable == 0) return false; + var proxyStr = (string)reg.GetValue("ProxyServer"); + if (!string.IsNullOrEmpty(proxyStr)) { + string[] proxies = proxyStr.Split(';'); + foreach (var p in proxies) { + if (p.StartsWith("https=")) { + string[] s = p.Split('=', ':'); + host = s[1]; + port = int.Parse(s[2]); + return true; + } + } + } + } + return false; + } + } +} diff --git a/Assets/Cryville/Common/Network/HttpsClient.cs.meta b/Assets/Cryville/Common/Network/HttpsClient.cs.meta new file mode 100644 index 0000000..37b119e --- /dev/null +++ b/Assets/Cryville/Common/Network/HttpsClient.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9b35290e0e147a342acc29a20c8fceaf +timeCreated: 1622503538 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Network/TlsTcpClient.cs b/Assets/Cryville/Common/Network/TlsTcpClient.cs new file mode 100644 index 0000000..53d967b --- /dev/null +++ b/Assets/Cryville/Common/Network/TlsTcpClient.cs @@ -0,0 +1,94 @@ +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Tls; +using Org.BouncyCastle.Tls.Crypto; +using Org.BouncyCastle.Tls.Crypto.Impl.BC; +using System.Collections; +using System.IO; +using System.Linq; +using System.Net.Sockets; + +namespace Cryville.Common.Network { + public class TlsTcpClient { + readonly TcpClient _tcpClient; + readonly TlsClientProtocol _protocol; + readonly TlsClient _tlsClient; + public Stream Stream { get; private set; } + public TlsTcpClient(string hostname, int port) { + _tcpClient = new TcpClient(hostname, port); + _protocol = new TlsClientProtocol(_tcpClient.GetStream()); + _tlsClient = new InternalTlsClient(new BcTlsCrypto(new SecureRandom())); + } + + public void Connect() { + _protocol.Connect(_tlsClient); + Stream = _protocol.Stream; + } + + public void Close() { + _protocol.Close(); + } + + private class InternalTlsClient : DefaultTlsClient { + public InternalTlsClient(TlsCrypto crypto) : base(crypto) { } + + protected override ProtocolVersion[] GetSupportedVersions() { + return ProtocolVersion.TLSv13.DownTo(ProtocolVersion.TLSv12); + } + + protected override IList GetProtocolNames() { + IList list = new ArrayList { + ProtocolName.Http_1_1, + ProtocolName.Http_2_Tls + }; + return list; + } + + private static readonly int[] supportedCipherSuites = { + CipherSuite.TLS_AES_128_GCM_SHA256, + CipherSuite.TLS_AES_256_GCM_SHA384, + CipherSuite.TLS_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_AES_128_CCM_SHA256, + CipherSuite.TLS_AES_128_CCM_8_SHA256, + }; + protected override int[] GetSupportedCipherSuites() { + return base.GetSupportedCipherSuites().Union(supportedCipherSuites).ToArray(); + } + + protected override IList GetSupportedSignatureAlgorithms() { + var result = base.GetSupportedSignatureAlgorithms(); + result.Add(SignatureAndHashAlgorithm.ecdsa_brainpoolP256r1tls13_sha256); + result.Add(SignatureAndHashAlgorithm.ecdsa_brainpoolP384r1tls13_sha384); + result.Add(SignatureAndHashAlgorithm.ecdsa_brainpoolP512r1tls13_sha512); + return result; + } + + public override TlsAuthentication GetAuthentication() { + return new NullTlsAuthentication(); + } + + public override void NotifyAlertReceived(short alertLevel, short alertDescription) { + Logger.Log("main", 0, "Network/TLS", "TLS Alert {0} {1}", alertLevel, alertDescription); + } + + public override void NotifyServerVersion(ProtocolVersion serverVersion) { + base.NotifyServerVersion(serverVersion); + Logger.Log("main", 0, "Network/TLS", "NotifyServerVersion {0}", serverVersion); + } + + public override void NotifySelectedCipherSuite(int selectedCipherSuite) { + base.NotifySelectedCipherSuite(selectedCipherSuite); + Logger.Log("main", 0, "Network/TLS", "NotifySelectedCipherSuite {0}", selectedCipherSuite); + } + } + + private class NullTlsAuthentication : TlsAuthentication { + public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest) { + return null; + } + + public void NotifyServerCertificate(TlsServerCertificate serverCertificate) { + // Do nothing + } + } + } +} diff --git a/Assets/Cryville/Common/Network/TlsTcpClient.cs.meta b/Assets/Cryville/Common/Network/TlsTcpClient.cs.meta new file mode 100644 index 0000000..e27e046 --- /dev/null +++ b/Assets/Cryville/Common/Network/TlsTcpClient.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c9c242bb90fc1cc479a8df1407f21940 +timeCreated: 1622021660 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Pdt.meta b/Assets/Cryville/Common/Pdt.meta new file mode 100644 index 0000000..0d9978e --- /dev/null +++ b/Assets/Cryville/Common/Pdt.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: faaabaf75aa95c94c9671f2e89a01687 +folderAsset: yes +timeCreated: 1605519813 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs b/Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs new file mode 100644 index 0000000..2af293a --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs @@ -0,0 +1,155 @@ +using System; + +namespace Cryville.Common.Pdt { + /// + /// Base of evaluator for PDT expressions. + /// + public abstract class PdtEvaluatorBase { + private struct StackFrame { + public int Offset; + public int Length; + public int Type; + } + int _framecount = 0; + int _goffset = 0; + readonly StackFrame[] _stack = new StackFrame[256]; + readonly byte[] _mem = new byte[0x100000]; + bool _revokepttconst; + /// + /// Evaluates an expression and passes the result to a target operator. + /// + /// The target operator. + /// The expression to evaluate. + public void Evaluate(PdtOperator target, PdtExpression exp) { + _framecount = 0; + _goffset = 0; + _revokepttconst = false; + for (var ins = exp.Instructions.First; ins != null; ins = ins.Next) + ins.Value.Execute(this); + Operate(target, _framecount, true); + if (exp.IsPotentialConstant) { + exp.IsConstant = exp.IsPotentialConstant = !_revokepttconst; + } + } + /// + /// Optimizes an expression by merging its instructions. + /// + /// The expression to optimize. + public void Optimize(PdtExpression exp) { + _framecount = 0; + _goffset = 0; + var il = exp.Instructions; + for (var ins = il.First; ins != null; ins = ins.Next) { + var i = ins.Value; + if (i is PdtInstruction.Operate) { + int fc0 = _framecount; + int fc1 = ((PdtInstruction.Operate)i).ParamCount; + try { i.Execute(this); } catch (Exception) { } + if (fc0 - _framecount == fc1) { + unsafe { + fixed (StackFrame* frame = &_stack[_framecount++]) { + frame->Type = PdtInternalType.Error; + frame->Offset = -1; + frame->Length = 0; + } + } + } + else { + var frame = _stack[_framecount - 1]; + il.AddAfter(ins, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length)); + ins = ins.Next; + for (var j = 0; j <= fc1; j++) il.Remove(ins.Previous); + } + } + else if (i is PdtInstruction.PushVariable) { + i.Execute(this); + var frame = _stack[_framecount - 1]; + if (frame.Type != PdtInternalType.Undefined) { + il.AddAfter(ins, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length)); + ins = ins.Next; + il.Remove(ins.Previous); + } + } + else i.Execute(this); + } + exp.IsConstant = true; + exp.IsPotentialConstant = true; + for (var ins = il.First; ins != null; ins = ins.Next) { + if (!(ins.Value is PdtInstruction.PushConstant)) { + exp.IsConstant = false; + } + else if (!(ins.Value is PdtInstruction.PushVariable)) { + exp.IsPotentialConstant = false; + return; + } + } + } + /// + /// Revokes the potential constant mark of the current expression. + /// + protected void RevokePotentialConstant() { + _revokepttconst = true; + } + internal unsafe void PushConstant(int type, byte[] value) { + fixed (StackFrame* frame = &_stack[_framecount++]) { + frame->Type = type; + frame->Offset = _goffset; + frame->Length = value.Length; + Array.Copy(value, 0, _mem, _goffset, value.Length); + _goffset += value.Length; + } + } + internal unsafe void PushVariable(ref string name) { + fixed (StackFrame* frame = &_stack[_framecount++]) { + byte[] value; + GetVariable(name, out frame->Type, out value); + frame->Offset = _goffset; + frame->Length = value.Length; + Array.Copy(value, 0, _mem, _goffset, value.Length); + _goffset += value.Length; + } + } + /// + /// Gets a variable of the specified name. + /// + /// The name of the variable. + /// The type of the variable. + /// The value of the variable. + protected abstract void GetVariable(string name, out int type, out byte[] value); + internal void Operate(ref string name, int pc) { + Operate(GetOperator(name, pc), pc); + } + /// + /// Gets an operator of the specified name and the suggested parameter count. + /// + /// The name of the operator. + /// Suggested parameter count. + /// An operator of the specific name. + /// The parameter count of the returned operator does not necessarily equal to . + protected abstract PdtOperator GetOperator(string name, int pc); + bool _failure; + unsafe void Operate(PdtOperator op, int pc, bool noset = false) { + fixed (byte* pmem = _mem) { + op.Begin(this); + for (int i = 0; i < pc; i++) { + var frame = _stack[--_framecount]; + op.LoadOperand(new PdtVariableMemory(frame.Type, pmem + frame.Offset, frame.Length)); + _goffset -= frame.Length; + } + op.Call(pmem + _goffset, noset); + } + } + internal unsafe PdtVariableMemory StackAlloc(int type, byte* ptr, int len) { + fixed (StackFrame* frame = &_stack[_framecount++]) { + frame->Type = type; + frame->Offset = _goffset; + frame->Length = len; + _goffset += len; + return new PdtVariableMemory(type, ptr, len); + } + } + internal void DiscardStack() { + _goffset -= _stack[--_framecount].Length; + } + } +} diff --git a/Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs.meta b/Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs.meta new file mode 100644 index 0000000..2ddb185 --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e91dc9e4fd28a584c8f2fce4f9e9b648 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Pdt/PdtExpression.cs b/Assets/Cryville/Common/Pdt/PdtExpression.cs new file mode 100644 index 0000000..769cedc --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtExpression.cs @@ -0,0 +1,247 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Cryville.Common.Pdt { + /// + /// PDT expression. + /// + public class PdtExpression { + internal LinkedList Instructions; + /// + /// Whether the value of this expression is constant. + /// + /// The value of this property is false until it is optimized. + public bool IsConstant { get; internal set; } + internal bool IsPotentialConstant; + internal PdtExpression(LinkedList ins) { + Instructions = ins; + } + public override string ToString() { + string r = ""; + bool flag = false; + foreach (PdtInstruction ins in Instructions) { + if (flag) r += "; "; + r += ins.ToString(); + flag = true; + } + return r; + } + } + internal abstract class PdtInstruction { + internal abstract void Execute(PdtEvaluatorBase etor); + public class PushConstant : PdtInstruction { + public int Type { get; private set; } + public byte[] Value { get; private set; } + public PushConstant(int type, byte[] value) { + Type = type; + Value = value; + } + public PushConstant(int type, byte[] buffer, int offset, int len) { + Type = type; + Value = new byte[len]; + Array.Copy(buffer, offset, Value, 0, len); + } + internal override void Execute(PdtEvaluatorBase etor) { + etor.PushConstant(Type, Value); + } + public override string ToString() { + return string.Format("pushc ({0:x8}){1}", Type, BitConverter.ToString(Value)); + } + } + public class PushVariable : PdtInstruction { + private string m_name; + public string Name { get { return m_name; } } + public PushVariable(string name) { + m_name = name; + } + internal override void Execute(PdtEvaluatorBase etor) { + etor.PushVariable(ref m_name); + } + public override string ToString() { + return string.Format("pushv {0}", Name); + } + } + public class Operate : PdtInstruction { + private string m_name; + public string Name { get { return m_name; } } + public int ParamCount { get; private set; } + public Operate(string name, int paramCount) { + m_name = name; + ParamCount = paramCount; + } + internal override void Execute(PdtEvaluatorBase etor) { + etor.Operate(ref m_name, ParamCount); + } + public override string ToString() { + return string.Format("op {0}({1})", Name, ParamCount); + } + } + } + public partial class PdtInterpreter { + readonly static Dictionary pri = new Dictionary { + { '*', 5 }, { '/', 5 }, { '%', 5 }, + { '+', 4 }, { '-', 4 }, + { '=', 3 }, { '<', 3 }, { '>', 3 }, + { '&', 2 }, + { '|', 1 }, { '!', 1 }, + { ',', 0 }, + }; + + readonly static PdtExpression _emptyexp; + static PdtInterpreter() { + var ins = new LinkedList(); + ins.AddLast(new PdtInstruction.PushConstant( + PdtInternalType.Number, BitConverter.GetBytes(1f) + )); + _emptyexp = new PdtExpression(ins); + } + + PdtExpToken GetToken() { + ws(); + var result = new PdtExpToken { + Type = ct & 0x0fe0 + }; + switch (result.Type) { + case 0x0020: result.Value = GetIdentifier(); break; + case 0x0040: result.Value = GetNumber(); break; + case 0x0100: result.Value = GetString(); break; + default: result.Value = cc.ToString(); Position++; break; + } + return result; + } + private struct PdtExpToken { + public int Type { get; set; } + public string Value { get; set; } + public override string ToString() { + return string.Format("0x{0:x4}: {1}", Type, Value); + } + public readonly static PdtExpToken EmptyOperator = new PdtExpToken { + Type = 0x0080, + Value = "", + }; + } + + /// + /// Interprets an expression from the current position and loads it onto an instruction set. + /// + /// The instruction set. + /// + /// The enclosing scope type of the (sub)expression. May be one of the following: + /// + /// -2The expression is in a root scope which ends at a semicolon. + /// -1The expression is in a bracketed scope which ends at a closing parenthesis. + /// Any non-negative valuesThe expression is in an auxiliary scope which ends before a closing parenthesis or an operator whose priority is lower (less) than the value of this parameter. + /// + /// + /// The parameter count in this (sub)expression. + /// The token already parsed but required for the interpretation of the subexpression. + /// The expression token following this (sub)expression. + PdtExpToken InterpretExp(LinkedList ins, int enc, out int pc, PdtExpToken? token = null) { + PdtExpToken t1, t2; + int insc0 = ins.Count; + pc = 1; + if (token == null) t1 = PdtExpToken.EmptyOperator; + else t1 = token.Value; + while (true) { + t2 = InterpretExpBlock(ins); + panic: + switch (t2.Type) { + case 0x0080: + if (t1.Value != "") { + int p1 = pri[t1.Value[0]]; + int p2 = pri[t2.Value[0]]; + if (p2 <= enc) goto exit; + if (p2 > p1) { + int _; + t2 = InterpretExp(ins, p1, out _, t2); + goto panic; + } + if (t1.Value != ",") ins.AddLast(new PdtInstruction.Operate(t1.Value, 2)); + else pc++; + } + t1 = t2; + break; + case 0x0400: + if (enc == -2) throw new FormatException("Expression not enclosed correctly: Too many closing brackets"); + if (ins.Count == insc0) pc = 0; + goto exit; + case 0x0800: + goto exit; + } + } + exit: + if (t1.Value != "," && t1.Value != "") ins.AddLast(new PdtInstruction.Operate(t1.Value, 2)); + else if (t1.Value == ",") pc++; + return t2; + } + + /// + /// Interprets an expression block which consists of several adjacent constants and subexpressions, optionally with a unary operator. + /// + /// The instruction set. + /// The expression token following this expression block. + PdtExpToken InterpretExpBlock(LinkedList ins) { + var t = GetToken(); + if (t.Type == 0x0080) { + var r = InterpretExpBlock(ins); + ins.AddLast(new PdtInstruction.Operate(t.Value, 1)); + return r; + } + bool flag = false; + PdtExpToken? buf = null; + while (true) { + if (buf != null && t.Type != 0x0200) { + PdtExpression def; + if (defs.TryGetValue(buf.Value.Value, out def)) { + foreach (var i in def.Instructions) ins.AddLast(i); + } + else ins.AddLast(new PdtInstruction.PushVariable(buf.Value.Value)); + buf = null; + TryPushAdjMul(ins, ref flag); + } + switch (t.Type) { + case 0x0020: + buf = t; + break; + case 0x0040: + float num = float.Parse(t.Value); + ins.AddLast(new PdtInstruction.PushConstant(PdtInternalType.Number, BitConverter.GetBytes(num))); + break; + case 0x0100: + int strlen = t.Value.Length; + unsafe { + var strbuf = new byte[strlen * sizeof(char) + sizeof(int)]; + fixed (byte* psuffix = strbuf) { + *(int*)psuffix = strlen; + } + Encoding.Unicode.GetBytes(t.Value, 0, strlen, strbuf, sizeof(int)); + ins.AddLast(new PdtInstruction.PushConstant(PdtInternalType.String, strbuf)); + } + break; + case 0x0200: + int pc; + InterpretExp(ins, -1, out pc); + if (buf != null) { + ins.AddLast(new PdtInstruction.Operate(buf.Value.Value, pc)); + buf = null; + } + else if (pc > 1) { + ins.AddLast(new PdtInstruction.Operate(",", pc)); + } + else if (pc == 0) + throw new FormatException("Empty subexpression"); + break; + default: + return t; + } + if (buf == null) TryPushAdjMul(ins, ref flag); + t = GetToken(); + } + } + void TryPushAdjMul(LinkedList ins, ref bool flag) { + if (flag) ins.AddLast(new PdtInstruction.Operate("*", 2)); + else flag = true; + } + } +} diff --git a/Assets/Cryville/Common/Pdt/PdtExpression.cs.meta b/Assets/Cryville/Common/Pdt/PdtExpression.cs.meta new file mode 100644 index 0000000..ed0cfd4 --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtExpression.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a551104b532c8d0469917e3e0e8c2cba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Pdt/PdtInternalType.cs b/Assets/Cryville/Common/Pdt/PdtInternalType.cs new file mode 100644 index 0000000..a1fcc4a --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtInternalType.cs @@ -0,0 +1,28 @@ +namespace Cryville.Common.Pdt { + /// + /// The identifiers of the internal types of PDT. + /// + public static class PdtInternalType { + internal readonly static int Error = "error".GetHashCode(); + /// + /// Array of a same variable-length type, with a suffix indicating the element count and the element type. + /// + public readonly static int Array = "array".GetHashCode(); + /// + /// IEEE 754 32-bit floating-point number. + /// + public readonly static int Number = "number".GetHashCode(); + /// + /// A sequence of UTF-16 code units, with a prefix indicating the number of the code units. + /// + public readonly static int String = "string".GetHashCode(); + /// + /// A sequence of UTF-16 code units representing the name of an undefined variable. + /// + public readonly static int Undefined = "undefined".GetHashCode(); + /// + /// Vector of a same constant-length type, with a suffix indicating the element type. + /// + public readonly static int Vector = "vector".GetHashCode(); + } +} diff --git a/Assets/Cryville/Common/Pdt/PdtInternalType.cs.meta b/Assets/Cryville/Common/Pdt/PdtInternalType.cs.meta new file mode 100644 index 0000000..bf554f6 --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtInternalType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 36eb4aecae64aff4891c4ddd2d1ff68c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Pdt/PdtInterpreter.cs b/Assets/Cryville/Common/Pdt/PdtInterpreter.cs new file mode 100644 index 0000000..669922e --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtInterpreter.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Text.RegularExpressions; + +namespace Cryville.Common.Pdt { + /// + /// Interpreter for Property Definition Tree (PDT) file format. + /// + /// The object type represented by the PDT. + public partial class PdtInterpreter { + /// + /// The character category map. + /// + /// + /// + /// 0x0001White Space + /// 0x0010Identifier + /// 0x0020Identifier Begin + /// 0x0040Digit + /// 0x0080Operator + /// 0x0100String + /// 0x0200Opening Bracket + /// 0x0400Closing Bracket + /// 0x0800End of Expression + /// 0x1000End of Key + /// + /// + readonly static int[] cm = new int[] { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0080, 0x0100, 0x0000, 0x0030, 0x0080, 0x0080, 0x0000, 0x0200, 0x0400, 0x0080, 0x0080, 0x0080, 0x0080, 0x0040, 0x0080, + 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x1000, 0x1800, 0x0080, 0x0080, 0x0080, 0x0000, + 0x0080, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0030, + 0x0000, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x1000, 0x0080, 0x1000, 0x0000, 0x0000, + }; + + /// + /// Interprets a source string to an object of type . + /// + /// The source string. + /// The interpreted object. + public static T Interpret(string src) { + return Interpret(src, BinderAttribute.CreateBinderOfType(typeof(T))); + } + /// + /// Interprets a source string to an object of type with a binder. + /// + /// The source string. + /// The binder. + /// The interpreted object. + public static T Interpret(string src, Binder binder) { + return new PdtInterpreter(src, binder).Interpret(); + } + + readonly string _src; + readonly Binder _binder; + protected int Position { get; private set; } +#pragma warning disable IDE1006 + protected char cc { get { return _src[Position]; } } + protected int ct { get { return cm[cc]; } } + protected string tokenb(int flag) { // Token Whitelist + int sp = Position; + while ((ct & flag) == 0) Position++; + return _src.Substring(sp, Position - sp); + } + protected string tokenw(int flag) { // Token Whitelist + int sp = Position; + while ((ct & flag) != 0) Position++; + return _src.Substring(sp, Position - sp); + } + protected void ws() { + while ((ct & 0x0001) != 0) Position++; + } +#pragma warning restore IDE1006 + + protected char GetChar() { + char r = cc; + Position++; + return r; + } + protected string GetIdentifier() { + if ((ct & 0x0020) == 0) return ""; + return tokenw(0x0010); + } + protected string GetNumber() { + return tokenw(0x0040); + } + protected string GetString() { + int sp = Position; + do { + if (cc == '\\') Position++; + Position++; + } while (ct != 0x0100); + Position++; + return Regex.Replace(_src.Substring(sp + 1, Position - sp - 2), @"\\(.)", "$1"); + } + protected PdtExpression GetExp() { + var ins = new LinkedList(); + int _; + InterpretExp(ins, -2, out _); + return new PdtExpression(ins); + } + + readonly Dictionary defs = new Dictionary(); + /// + /// Creates an instance of the class. + /// + /// The source string. + /// The binder. May be null. + public PdtInterpreter(string src, Binder binder) { + _src = src; + _binder = binder; + if (_binder == null) + _binder = BinderAttribute.CreateBinderOfType(typeof(T)); + } + /// + /// Interprets the source to an object of type . + /// + /// The interpreted object. + public T Interpret() { + InterpretDirectives(); + return (T)InterpretObject(typeof(T)); + } + void InterpretDirectives() { + bool flag = false; + ws(); + while (cc == '#') { + Position++; + switch (GetIdentifier()) { + case "ver": + ws(); + Logger.Log("main", 3, "PDT", "Legacy PDT directive #ver={0} found. Ignoring.", GetNumber()); + break; + case "format": + ws(); + if (GetNumber() != "1") + throw new NotSupportedException("Format not supported"); + flag = true; + break; + case "define": + if (!flag) throw new FormatException("Format directive not found"); + ws(); + string dname = GetIdentifier(); + ws(); + PdtExpression dexp = GetExp(); + defs.Add(dname, dexp); + break; + default: + throw new NotSupportedException("Unsupported directive found"); + } + ws(); + } + if (!flag) throw new FormatException("Format directive not found"); + } + object InterpretObject(Type type) { + var result = ReflectionHelper.InvokeEmptyConstructor(type); + bool dictflag = ReflectionHelper.IsGenericDictionary(type); + while (true) { + try { ws(); } + catch (IndexOutOfRangeException) { return result; } + object pkey = InterpretKey(type); + char c = GetChar(); + switch (c) { + case '{': + if (dictflag) { + var ktype = type.GetGenericArguments()[0]; + var ptype = type.GetGenericArguments()[1]; + object key = _binder.ChangeType(pkey, ktype, null); + object value = InterpretObject(ptype); + ((IDictionary)result).Add(key, value); + } + else { + MemberInfo prop; + bool flag = ReflectionHelper.TryFindMemberWithAttribute(type, out prop); + if (!flag && pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey); + Type ptype = ReflectionHelper.GetMemberType(prop); + if (ReflectionHelper.IsGenericDictionary(ptype)) { + var ktype = ptype.GetGenericArguments()[0]; + var vtype = ptype.GetGenericArguments()[1]; + if (flag) { + object key = _binder.ChangeType(pkey, ktype, null); + object value = InterpretObject(vtype); + ((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value); + } + else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype)); + } + else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype)); + } + break; + case ':': + case ';': + var exp = c == ';' ? _emptyexp : GetExp(); + if (dictflag) { + var ktype = type.GetGenericArguments()[0]; + var vtype = type.GetGenericArguments()[1]; + object key = _binder.ChangeType(pkey, ktype, null); + object value = _binder.ChangeType(exp, vtype, null); + ((IDictionary)result).Add(key, value); + } + else { + MemberInfo prop; + bool flag = ReflectionHelper.TryFindMemberWithAttribute(type, out prop); + if (!flag && pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey); + var ptype = ReflectionHelper.GetMemberType(prop); + if (!typeof(IDictionary).IsAssignableFrom(ptype)) { + object value = _binder.ChangeType(exp, ptype, null); + ReflectionHelper.SetValue(prop, result, value, _binder); + } + else { + var ktype = ptype.GetGenericArguments()[0]; + var vtype = ptype.GetGenericArguments()[1]; + object key = _binder.ChangeType(pkey, ktype, null); + object value = _binder.ChangeType(exp, vtype, null); + ((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value); + } + } + break; + case '}': + return result; + } + } + } + protected virtual object InterpretKey(Type type) { + return tokenb(0x1000).Trim(); + } + } +} diff --git a/Assets/Cryville/Common/Pdt/PdtInterpreter.cs.meta b/Assets/Cryville/Common/Pdt/PdtInterpreter.cs.meta new file mode 100644 index 0000000..720bdd4 --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtInterpreter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2a66a8564bee7c8449417a795cee8729 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Pdt/PdtOperator.cs b/Assets/Cryville/Common/Pdt/PdtOperator.cs new file mode 100644 index 0000000..d759334 --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtOperator.cs @@ -0,0 +1,77 @@ +using System; + +namespace Cryville.Common.Pdt { + /// + /// PDT operator. + /// + public unsafe abstract class PdtOperator { + byte* _prmem; + int _loadindex; + readonly PdtVariableMemory[] _operands; + /// + /// The count of the operands loaded. + /// + protected int LoadedOperandCount { get { return ParamCount - _loadindex; } } + /// + /// Gets the operand at the specified index. + /// + /// The index. + /// The operand at the specified index. + /// is not less than or less than 0. + protected PdtVariableMemory GetOperand(int index) { + if (index >= LoadedOperandCount || index < 0) throw new IndexOutOfRangeException(); + int i = index + _loadindex; + return _operands[i]; + } + internal int ParamCount { get; private set; } + /// + /// Creates an instance of the class. + /// + /// The suggested parameter count. + protected PdtOperator(int pc) { + ParamCount = pc; + _operands = new PdtVariableMemory[pc]; + } + PdtEvaluatorBase _etor; + bool _failure = false; + bool _rfreq = true; + internal void Begin(PdtEvaluatorBase etor) { + _etor = etor; + _failure = false; + _loadindex = ParamCount; + } + internal void LoadOperand(PdtVariableMemory mem) { + if (_loadindex == 0) return; + _operands[--_loadindex] = mem; + } + internal void Call(byte* prmem, bool noset) { + _prmem = prmem; + _rfreq = false; + Execute(); + if (!_rfreq && !noset) throw new InvalidOperationException("Return frame not set"); + if (_failure) { + if (_rfreq) _etor.DiscardStack(); + throw new InvalidOperationException("Evaluation failed"); + } + } + /// + /// Executes the operator. + /// + protected abstract void Execute(); + /// + /// Gets a return frame. + /// + /// The type of the frame. + /// The length of the frame. + /// The return frame. + /// The return frame has already been requested. + protected PdtVariableMemory GetReturnFrame(int type, int len) { + if (_rfreq) { + _failure = true; + throw new InvalidOperationException("Return frame already requested"); + } + _rfreq = true; + return _etor.StackAlloc(type, _prmem, len); + } + } +} \ No newline at end of file diff --git a/Assets/Cryville/Common/Pdt/PdtOperator.cs.meta b/Assets/Cryville/Common/Pdt/PdtOperator.cs.meta new file mode 100644 index 0000000..d9ece16 --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtOperator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dc184c2d84fe5ea449cea78cba46d74d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Pdt/PdtReader.cs b/Assets/Cryville/Common/Pdt/PdtReader.cs new file mode 100644 index 0000000..0aef560 --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtReader.cs @@ -0,0 +1,749 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Cryville.Common.Pdt { +#if false + [Obsolete] + public static class PdtReader { + readonly static char[] ws = { + ' ', '\t', '\n', '\r' + }; + readonly static char[] spunc = { + ' ', '\t', '\n', '\r', + '{', '}', ';' + }; + readonly static char[] ipunc = { + ' ', '\t', '\n', '\r', + '{', '}', ';', + ':' + }; + readonly static char[] vpunc = { + '{', '}', ';' + }; + static int pos; + static string data; + static char cc { + get { + return data[pos]; + } + } + static bool eof { + get { + return pos == data.Length; + } + } + static Dictionary definitions; + public static T Read(string _data, Binder binder = null) { + data = _data; + pos = 0; + definitions = new Dictionary(); + while (true) { + if (cc == '#') { + SkipChar(); + var s = GetIdentifier(); + switch (s) { + case "ver": + var s2 = GetString(); + if (s2 != "1") throw new FormatException("Invalid PDT version"); + continue; + case "define": + var s3 = GetString(); + var s4 = GetValue(); + definitions.Add(s3, new Expression(s4, definitions)); + SkipChar(); + // TODO + continue; + default: + SkipLine(); + continue; + } + } + break; + } + if (binder == null) + binder = BinderAttribute.CreateBinderOfType(typeof(T)); + return (T)ParseObject(typeof(T), binder); + } + + static object ParseObject(Type type, Binder binder) { + // TODO Binder + object obj = type.GetConstructor(new Type[]{}).Invoke(new object[]{}); + while (true) { + if (eof) return obj; + string str = GetValue(); + if (cc == '{') { // List item + SkipChar(); + string strkey = str; + if (typeof(IDictionary).IsAssignableFrom(type)) { + var ktype = type.GetGenericArguments()[0]; + var ptype = type.GetGenericArguments()[1]; + object key = binder.ChangeType(strkey, ktype, null); + object value = ParseObject(ptype, binder); + ((IDictionary)obj).Add(key, value); + } + else { + MemberInfo prop = null; + Type ttype = null; + bool flag = ReflectionHelper.TryFindMemberWithAttribute(type, out prop); + if (!flag) + prop = ReflectionHelper.GetMember(type, strkey); + ttype = ReflectionHelper.GetMemberType(prop); + if (!typeof(IDictionary).IsAssignableFrom(ttype)) { + throw new NotImplementedException(); + } + else { + var ktype = ttype.GetGenericArguments()[0]; + var ptype = ttype.GetGenericArguments()[1]; + if (flag) { + object key = binder.ChangeType(strkey, ktype, null); + object value = ParseObject(ptype, binder); + ((IDictionary)ReflectionHelper.GetValue(prop, obj)).Add(key, value); + } + else { + ReflectionHelper.SetValue(prop, obj, ParseObject(ttype, binder)); + } + } + } + } + else if (cc == ';') { // Single property + SkipChar(); + string strkey; + MemberInfo prop = null; + if (str[0] == '*') { // Component-like property + strkey = str.Substring(1); + prop = ReflectionHelper.FindMemberWithAttribute(type); + var ttype = ReflectionHelper.GetMemberType(prop); + if (!typeof(IList).IsAssignableFrom(ttype)) + throw new Exception(); // TODO + var ktype = ttype.GetGenericArguments()[0]; + object key = binder.ChangeType(strkey, ktype, null); + ((IList)ReflectionHelper.GetValue(prop, obj)).Add(key); + } + else { // Common property + var kv = str.Split(new char[]{':'}, 2); + strkey = kv[0]; + // TODO + if (typeof(IDictionary).IsAssignableFrom(type)) { + var ktype = type.GetGenericArguments()[0]; + var ptype = type.GetGenericArguments()[1]; + object key = binder.ChangeType(strkey, ktype, null); + object value = binder.ChangeType(new Expression( + kv.Length == 1 ? "true" : kv[1], definitions + ), ptype, null); + ((IDictionary)obj).Add(key, value); + } + else { + bool flag = ReflectionHelper.TryFindMemberWithAttribute(type, out prop); + if (!flag) + prop = ReflectionHelper.GetMember(type, strkey); + var ttype = ReflectionHelper.GetMemberType(prop); + if (!typeof(IDictionary).IsAssignableFrom(ttype)) { + object value = binder.ChangeType(new Expression( + kv.Length == 1 ? "true" : kv[1], definitions + ), ttype, null); + ReflectionHelper.SetValue(prop, obj, value, binder); + } + else { + var ktype = ttype.GetGenericArguments()[0]; + var ptype = ttype.GetGenericArguments()[1]; + object key = binder.ChangeType(strkey, ktype, null); + object value = binder.ChangeType(new Expression( + kv.Length == 1 ? "true" : kv[1], definitions + ), ptype, null); + ((IDictionary)ReflectionHelper.GetValue(prop, obj)).Add(key, value); + } + } + } + } + else if (cc == '}') { + try { SkipChar(); } + catch (IndexOutOfRangeException) { } + return obj; + } + else throw new Exception(); // TODO + } + } + + static void SkipChar() { + pos++; + SkipWs(); + } + + static void SkipWs() { + while (true) { + for (; ws.Contains(cc); pos++); + if (data[pos] == '/' && data[pos + 1] == '*') { + for (; data[pos] != '*' || data[pos+1] != '/'; pos++); + pos += 2; + } + else return; + } + } + + static string GetIdentifier() { + SkipWs(); + string r = ""; + for (; !ipunc.Contains(cc); pos++) r += cc; + SkipWs(); + return r; + } + + static string GetString() { + SkipWs(); + string r = ""; + for (; !spunc.Contains(cc); pos++) r += cc; + SkipWs(); + return r; + } + + static string GetValue() { + SkipWs(); + string r = ""; + for (; !vpunc.Contains(cc); pos++) r += cc; + SkipWs(); + return r.Trim(); + } + + static void SkipLine() { + for (; cc != '\n'; pos++); + SkipWs(); + } + } +#endif + + public class ElementListAttribute : Attribute { } + public class ComponentListAttribute : Attribute { } + public class PropertyListAttribute : Attribute { } + +#if false + [Obsolete] + public abstract class ExpBase { + public string exp { + get; + private set; + } + public ExpBase(string s) { + exp = s; + } + public override string ToString() { + return exp; + } + } + [Obsolete] + public abstract class ValueBase : ExpBase { + public ValueBase(string s) : base(s) { } + + object preEvalResult; + byte preEvalDepth = 0; + public bool IsDynamic { + get { return preEvalDepth == 0; } + } + + protected abstract object EvalInternal(IEvaluator etor); + public void PreEval(IEvaluator etor, byte depth = 1) { + if (depth == 0) throw new ArgumentException("depth cannot be 0"); + if (preEvalDepth != 0 && preEvalDepth < depth) return; + try { + preEvalResult = PreEvalInternal(etor, depth); + preEvalDepth = depth; + } + catch (Exception) { } + } + protected virtual object PreEvalInternal(IEvaluator etor, byte depth) { + return Eval(etor); + } + public object Eval(IEvaluator etor) { + if (preEvalDepth != 0) + return preEvalResult; + return EvalInternal(etor); + } + } + [Obsolete] + public class Identifier : ValueBase { + public Identifier(string s) : base(s) { } + protected override object EvalInternal(IEvaluator etor) { + return etor.EvalIdentifier(exp); + } + } + [Obsolete] + public class Operand : ExpBase { + public OperandPriority Priority { + get; + private set; + } + public Operand(string s) : base(s) { + switch (s) { + case ".": Priority = OperandPriority.Prop; break; + case "*": case "/": Priority = OperandPriority.Mul; break; + case "+": case "-": Priority = OperandPriority.Add; break; + case " ": case ",": Priority = OperandPriority.Sep; break; + default: Priority = OperandPriority.None; break; + } + } + public Operand(string s, OperandPriority p) : base(s) { + Priority = p; + } + } + [Obsolete] + public enum OperandPriority { + None = 0, + Prop = 5, + NeibMul = 4, + Mul = 3, + Add = 2, + Sep = 1 + } + [Obsolete] + public abstract class ConstantBase : ValueBase { + public ConstantBase(string s) : base(s) { } + } + [Obsolete] + public class CNumber : ConstantBase { + public CNumber(string s) : base(s) { } + protected override object EvalInternal(IEvaluator etor) { + return etor.ParseNumber(exp); + } + } + [Obsolete] + public class CString : ConstantBase { + public CString(string s) : base(s) { } + protected override object EvalInternal(IEvaluator etor) { + return etor.ParseString(exp); + } + } + [Obsolete] + public class BracketInitial : ExpBase { + public BracketInitial() : base("(") { } + } + [Obsolete] + public class BracketFinal : ExpBase { + public BracketFinal() : base(")") { } + } + [Obsolete] + public class Expression : ValueBase { + List estack = new List(); + List ostack = new List(); + StackType type; + enum StackType { + Root, Unary, Bracketed, Supportive, Function + } + + readonly OperandPriority Priority; + public Expression(string s, Dictionary def) : base("") { + var exp = s.Trim(); + type = StackType.Root; + int pos = 0; + var b = new List(); + while (pos < exp.Length) { + b.Add(Forward(ref exp, ref pos)); + } + var lb = b[b.Count - 1]; + if (def.ContainsKey(lb.exp)) { + b.Add(def[lb.exp]); + b.Remove(lb); + } + for (int i = b.Count - 2; i >= 0; i--) { + // TODO Insertion + var lhb = b[i]; + var rhb = b[i + 1]; + if (lhb is ConstantBase || lhb is Expression || lhb is BracketFinal) { + if (rhb is Identifier || rhb is Expression || rhb is BracketInitial) { + b.Insert(i + 1, new Operand("*", OperandPriority.NeibMul)); + } + } + else if (lhb is Identifier) { + if (rhb is Expression) { + b.Insert(i + 1, new Operand("*", OperandPriority.NeibMul)); + } + if (def.ContainsKey(lhb.exp)) { + b.Insert(i, def[lhb.exp]); + b.Remove(lhb); + } + } + } + int p = 0; + estack.Add(new Expression(b, ref p, StackType.Bracketed, def)); + } + + public Expression Clone() { + var r = (Expression)this.MemberwiseClone(); + + var es = new ValueBase[estack.Count]; + estack.CopyTo(es); + r.estack = es.ToList(); + + var os = new Operand[ostack.Count]; + ostack.CopyTo(os); + r.ostack = os.ToList(); + + return r; + } + + Expression(List b, ref int p, StackType t, Dictionary def) : base("") { + type = t; + if (t == StackType.Unary) { + ostack.Add((Operand)b[p]); + p++; + } + while (p < b.Count - 1) { + if (estack.Count == 0) { + var b0 = b[p]; + if (b0 is Operand) { + var lp = p; + var e = new Expression( + b, + ref p, + StackType.Unary, + def + ); + b.Insert(p, e); + b.RemoveRange(lp, p - lp); + p = lp; + } + else if (b0 is BracketInitial) { + var lp = p; + p++; + var e = new Expression( + b, + ref p, + StackType.Bracketed, + def + ); + b.Insert(p, e); + b.RemoveRange(lp, p - lp); + p = lp; + } + estack.Add((ValueBase)b[p]); + p++; + if (t == StackType.Unary) { + if (estack.Count != 1) + throw new Exception(); // TODO + else return; + } + } + if (p >= b.Count) return; + var b1 = b[p]; + if (b1 is BracketFinal) { + if (t == StackType.Bracketed) p++; + return; + } + var b2 = b[p + 1]; + if (b2 is BracketInitial) { + var lp = p + 1; + p += 2; + var e = new Expression( + b, + ref p, + StackType.Bracketed, + def + ); + b.Insert(p, e); + b.RemoveRange(lp, p - lp); + p = lp - 1; + b2 = b[p + 1]; + } + if (b1 is Operand) { + if (estack.Count == 1) + Priority = ((Operand)b1).Priority; + if (b2 is Operand) { + var lp = p + 1; + p++; + var e = new Expression( + b, + ref p, + StackType.Unary, + def + ); + b.Insert(p, e); + b.RemoveRange(lp, p - lp); + p = lp - 1; + b2 = b[p + 1]; + } + if (p + 2 >= b.Count) { + ostack.Add((Operand)b1); + estack.Add((ValueBase)b2); + p += 2; + return; + } + var b3 = b[p + 2]; + if (b3 is BracketFinal) { + ostack.Add((Operand)b1); + estack.Add((ValueBase)b2); + p += 2; + if (t == StackType.Bracketed) p++; + return; + } + else if (b3 is Operand) { + var o1 = (Operand)b1; var o2 = (Operand)b3; + if (o2.Priority == Priority) { + ostack.Add(o1); estack.Add((ValueBase)b2); + p += 2; + continue; + } + else if (o2.Priority > Priority) { + var lp = p + 1; + p++; + var e = new Expression( + b, ref p, + StackType.Supportive, def + ); + b.Insert(p, e); + b.RemoveRange(lp, p - lp); + p = lp - 1; + continue; + } + else if (o2.Priority < Priority) { + ostack.Add(o1); + estack.Add((ValueBase)b2); + // b.RemoveRange(0, 2); + if (type == StackType.Bracketed) { + Expression cl = this.Clone(); + cl.type = StackType.Supportive; + estack.Clear(); + ostack.Clear(); + estack.Add(cl); + Priority = o2.Priority; + p += 2; + continue; + } + else { + type = StackType.Supportive; + p += 2; + return; + } + } + } + else + throw new Exception(); // TODO + } + else + throw new Exception(); // TODO + throw new Exception(); // TODO + + /*if (lb is Identifier) { + if (def.ContainsKey(lb.exp)) { + b.Add(def[lb.exp]); + b.Remove(lb); + } + } + // Unary + if (estack.Count == 0) { + if (b[0] is Operand) { + b.Add(new Expression( + b, + ref p, + StackType.Unary, + def + )); + b.RemoveAt(0); + } + if (b[0] is ValueBase) { + estack.Add((ValueBase)b[0]); + b.RemoveAt(0); + if (type == StackType.Unary) return; + if (b.Count == 0) continue; + } + } + if (estack.Count == 1) { + if (b[0] is Operand) + Priority = ((Operand)b[0]).Priority; + } + // Bracket + if (lb is BracketInitial) { + b.Remove(lb); + b.Add(new Expression(b, ref p, StackType.Bracketed, def)); + } + else if (lb is BracketFinal) { + if (type != StackType.Bracketed) p--; + foreach (var i in b) { + if (i is Operand) ostack.Add((Operand)i); + else if (i is BracketFinal) return; + else estack.Add((ValueBase)i); + } + } + var c = b.Count; + if (c <= 1) continue; + // Two blocks + lb = b[c - 1]; + var lb1 = b[c - 2]; + if (lb is Operand && lb1 is Operand) { + b.Add(new Expression( + b, + ref p, + StackType.Unary, + def + )); + b.RemoveAt(b.Count - 2); + } + c = b.Count; + if (c <= 2) continue; + // Three blocks + var b0 = b[0]; + var b1 = b[1]; + var b2 = b[2]; + if (!(b0 is Operand)) + throw new Exception(); // TODO + if (!(b1 is ValueBase)) + throw new Exception(); // TODO + if (!(b2 is Operand)) + throw new Exception(); // TODO + var o1 = (Operand)b0; var o2 = (Operand)b2; + if (o2.Priority == Priority) { + ostack.Add(o1); estack.Add((ValueBase)b1); + b.Remove(o1); b.Remove(b1); + continue; + } + if (o2.Priority > Priority) { + b.Add(new Expression( + b, ref p, + StackType.Supportive, def + )); + b.RemoveRange(1, b.Count - 2); + continue; + } + if (o2.Priority < Priority) { + ostack.Add(o1); + estack.Add((ValueBase)b1); + b.RemoveRange(0, 2); + if (type == StackType.Bracketed) { + Expression cl = this.Clone(); + cl.type = StackType.Supportive; + estack.Clear(); + ostack.Clear(); + estack.Add(cl); + Priority = o2.Priority; + } + else { + type = StackType.Supportive; + // p = o2.Index; + return; + } + }*/ + } + estack.Add((ValueBase)b[b.Count - 1]); + p++; + } + ExpBase Forward(ref string s, ref int p) { + char sc = s[p]; + string r = ""; + if (cat(sc) == 3) { + p++; + return new BracketInitial(); + } + else if (cat(sc) == 4) { + p++; + return new BracketFinal(); + } + else if (cat(sc) == 5) { + for (; p < s.Length; p++) { + if (cat(s[p]) != 5) break; + r += s[p]; + } + if (r == ".") return new Operand(r); + else return new CNumber(r); + } + else if (cat(sc) == 2) { + p++; + for (; s[p] != sc; p++) + r += s[p]; + p++; + return new CString(r); + } + else if (cat(sc) == 0) { + for (; p < s.Length; p++) { + if (cat(s[p]) != 0) break; + r += s[p]; + } + if (p == s.Length) return new Identifier(r); + if (s[p] == '(') return new Operand(r); + else return new Identifier(r); + } + else if (cat(sc) == 1) { + p++; + return new Operand(sc.ToString()); + } + else + throw new Exception(); // TODO + } + + protected override object EvalInternal(IEvaluator etor) { + if (type == StackType.Unary) { + if (ostack[0].Priority == OperandPriority.None) + return etor.OperateFunction(ostack[0], estack[0].Eval(etor)); + else + return etor.OperateUnary(ostack[0], estack[0].Eval(etor)); + } + else { + object r = estack[0].Eval(etor); + for (int i = 0; i < ostack.Count; i++) { + r = etor.OperateBinary( + ostack[i], r, estack[i+1].Eval(etor) + ); + } + return r; + } + } + public T Eval(IEvaluator etor) { + return (T)etor.Cast(typeof(T), EvalInternal(etor)); + } + protected override object PreEvalInternal(IEvaluator etor, byte depth) { + try { return EvalInternal(etor); } + catch (Exception) { + foreach (var v in estack) + v.PreEval(etor, depth); + throw; + } + } + + // 0: Other, 1: Operand, 2: String, + // 3: SOE, 4: EOE, 5: Number + static readonly byte[] ctl = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 2, 1, 0, 1, 1, 2, 3, 4, 1, 1, 1, 1, 5, 1, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, + }; + static byte cat(char c) { + if (c >> 7 != 0) + return 0; + else + return ctl[c]; + } + + public override string ToString() { + if (type == StackType.Unary) + return string.Format("{0}{1}", ostack[0], estack[0]); + if (type == StackType.Function) + return string.Format("{0}{1}", ostack[0], estack[0]); + string r = estack[0].ToString(); + for (int i = 0; i < ostack.Count; i++) { + r += ostack[i].ToString(); + r += estack[i + 1].ToString(); + } + if (type == StackType.Bracketed) + r = string.Format("({0})", r); + return r; + } + } + + [Obsolete] + public interface IEvaluator { + object ParseNumber(string exp); + object ParseString(string exp); + object EvalIdentifier(string exp); + object OperateUnary(Operand op, object q); + object OperateBinary(Operand op, object q, object r); + object OperateFunction(Operand op, object q); + // TODO [Obsolete] + object Cast(Type type, object obj); + //public abstract Func GetCastCallback(Type dest, Type source); + } +#endif +} diff --git a/Assets/Cryville/Common/Pdt/PdtReader.cs.meta b/Assets/Cryville/Common/Pdt/PdtReader.cs.meta new file mode 100644 index 0000000..36b655b --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtReader.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 688e46fb4d8e6a041844f592f1333af7 +timeCreated: 1608801352 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Pdt/PdtVariableMemory.cs b/Assets/Cryville/Common/Pdt/PdtVariableMemory.cs new file mode 100644 index 0000000..a8b6360 --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtVariableMemory.cs @@ -0,0 +1,143 @@ +using System; +using System.Text; +using UnityEditor; + +namespace Cryville.Common.Pdt { + /// + /// Span on the memory of a . + /// + public unsafe struct PdtVariableMemory { + byte* _ptr; + /// + /// The length of the span. + /// + public int Length { get; private set; } + /// + /// The type of the span. + /// + public int Type { get; private set; } + internal PdtVariableMemory(int type, byte* ptr, int len) { + Type = type; + _ptr = ptr; + Length = len; + } + /// + /// Copies the memory in the span to a buffer. + /// + /// The destination buffer. + /// The offset on the destination buffer to start copying to. + public void CopyTo(byte[] dest, int destOffset) { + fixed (byte* ptr = dest) { + CopyTo(ptr, destOffset, Length); + } + } + /// + /// Copies the memory in the span to a buffer. + /// + /// The destination buffer. + /// The offset on the destination buffer to start copying to. + /// The length to copy. + public void CopyTo(byte* dest, int destOffset, int length) { + for (int i = 0; i < length; i++) + dest[destOffset + i] = _ptr[i]; + } + /// + /// Gets the memory of the span as a number. + /// + /// A number. + /// The span does not represent a number. + public float AsNumber() { + if (Type != PdtInternalType.Number) + throw new InvalidCastException("Not a number"); + float value; + byte* ptr = (byte*)&value; + for (int i = 0; i < sizeof(float); i++) + ptr[i] = _ptr[i]; + return value; + } + /// + /// Sets the memory of the span to a number. + /// + /// The number. + /// The span does not represent a number. + public void SetNumber(float value) { + if (Type != PdtInternalType.Number) + throw new InvalidCastException("Not a number"); + byte* ptr = (byte*)&value; + for (int i = 0; i < sizeof(float); i++) + _ptr[i] = ptr[i]; + } + /// + /// Gets the memory of the span as a string. + /// + /// The offset on the span to start reading from. + /// A string. + /// The span at the offset does not represent a string. + public string AsString(int offset = 0) { + if (Type != PdtInternalType.String && Type != PdtInternalType.Array) + throw new InvalidCastException("Not a string"); + var len = *(int*)(_ptr + offset); + return new string((char*)(_ptr + offset + sizeof(int)), 0, len); + } + /// + /// Sets the memory of the span to a string. + /// + /// The string. + /// The offset from the start of the span. + /// The span at the offset does not represent a string. + /// The length of the span is not sufficient. + public void SetString(string value, int offset = 0) { + if (Type != PdtInternalType.String && Type != PdtInternalType.Array) + throw new InvalidCastException("Not a string"); + int strlen = value.Length; + if (Length < strlen * sizeof(char) + sizeof(int) + offset) + throw new InvalidOperationException("Frame length not sufficient"); + char* ptr = (char*)(_ptr + offset + sizeof(int)); + *(int*)(_ptr + offset) = strlen; + int i = 0; + foreach (var c in value) ptr[i++] = c; + } + /// + /// Gets the memory of the span as an undefined identifier. + /// + /// The offset on the span to start reading from. + /// The name of an undefined identifier. + /// The span does not represent an undefined identifier. + public string AsIdentifier(int offset = 0) { + if (Type != PdtInternalType.Undefined && Type != PdtInternalType.Array) + throw new InvalidCastException("Not an identifier"); + var len = *(int*)(_ptr + offset); + return new string((char*)(_ptr + offset + sizeof(int)), 0, len); + } + internal void* TrustedAsOfLength(int len) { + if (Length < len) + throw new InvalidCastException("Type not matched"); + return _ptr; + } + /// + /// Gets the array suffix. + /// + /// The type of the array. + /// The item count of the array. + /// The span does not represent an array. + public void GetArraySuffix(out int arrtype, out int pc) { + if (Type != PdtInternalType.Array && Type != PdtInternalType.Array) + throw new InvalidCastException("Not an array or vector"); + arrtype = *(int*)(_ptr + Length - sizeof(int)); + if (Type == PdtInternalType.Array) pc = *(int*)(_ptr + Length - 2 * sizeof(int)); + else pc = -1; + } + /// + /// Sets the array suffix. + /// + /// The type of the array. + /// The item count of the array. + /// The span does not represent an array. + public void SetArraySuffix(int arrtype, int pc = 0) { + if (Type != PdtInternalType.Vector && Type != PdtInternalType.Array) + throw new InvalidCastException("Not an array or vector"); + *(int*)(_ptr + Length - sizeof(int)) = arrtype; + if (Type == PdtInternalType.Array) *(int*)(_ptr + Length - 2 * sizeof(int)) = pc; + } + } +} diff --git a/Assets/Cryville/Common/Pdt/PdtVariableMemory.cs.meta b/Assets/Cryville/Common/Pdt/PdtVariableMemory.cs.meta new file mode 100644 index 0000000..740f536 --- /dev/null +++ b/Assets/Cryville/Common/Pdt/PdtVariableMemory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e710eef537a1ac488ef6bce16625b62 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Plist.meta b/Assets/Cryville/Common/Plist.meta new file mode 100644 index 0000000..7990dfd --- /dev/null +++ b/Assets/Cryville/Common/Plist.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 925f95cb7c6644a4695b2701d42e1ea2 +folderAsset: yes +timeCreated: 1606989037 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Plist/PlistConvert.cs b/Assets/Cryville/Common/Plist/PlistConvert.cs new file mode 100644 index 0000000..2a082c4 --- /dev/null +++ b/Assets/Cryville/Common/Plist/PlistConvert.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; + +namespace Cryville.Common.Plist { + public class PlistConvert { + public static T Deserialize(string file) { + return (T)Deserialize(typeof(T), PlistCS.Plist.readPlist(file)); + } + + public static object Deserialize(Type type, object obj, Binder binder = null) { + if (binder == null) + binder = BinderAttribute.CreateBinderOfType(type); + if (obj is IList) { + var lobj = (List)obj; + foreach (var i in lobj) { + throw new NotImplementedException(); // TODO + } + } + else if (obj is IDictionary) { + var dobj = (Dictionary)obj; + if (typeof(IDictionary).IsAssignableFrom(type)) { + var result = (IDictionary)ReflectionHelper.InvokeEmptyConstructor(type); + var it = type.GetGenericArguments()[1]; + foreach (var i in dobj) { + var value = Deserialize(it, i.Value, binder); + result.Add(i.Key, value); + } + return result; + } + else { + var result = ReflectionHelper.InvokeEmptyConstructor(type); + foreach (var i in dobj) { + var imis = type.GetMember(i.Key); + if (imis.Length == 0) continue; + var imi = imis[0]; + var it = ReflectionHelper.GetMemberType(imi); + var value = Deserialize(it, i.Value, binder); + ReflectionHelper.SetValue(imi, result, value, binder); + } + return result; + } + } + else return obj; + throw new Exception(); // TODO + } + } +} diff --git a/Assets/Cryville/Common/Plist/PlistConvert.cs.meta b/Assets/Cryville/Common/Plist/PlistConvert.cs.meta new file mode 100644 index 0000000..3d43254 --- /dev/null +++ b/Assets/Cryville/Common/Plist/PlistConvert.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3bc71e8b62d4022409aa5518bbf3a7d8 +timeCreated: 1608801352 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/ReflectionHelper.cs b/Assets/Cryville/Common/ReflectionHelper.cs new file mode 100644 index 0000000..4bbcf83 --- /dev/null +++ b/Assets/Cryville/Common/ReflectionHelper.cs @@ -0,0 +1,102 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Linq; + +namespace Cryville.Common { + public static class ReflectionHelper { + static readonly Type[] emptyTypeArray = {}; + public static ConstructorInfo GetEmptyConstructor(Type type) { + return type.GetConstructor(emptyTypeArray); + } + static readonly object[] emptyObjectArray = {}; + public static object InvokeEmptyConstructor(Type type) { + return GetEmptyConstructor(type).Invoke(emptyObjectArray); + } + + public static bool TryFindMemberWithAttribute(Type t, out MemberInfo mi) where T : Attribute { + try { + mi = FindMemberWithAttribute(t); + return true; + } + catch (MissingMemberException) { + mi = null; + return false; + } + } + public static MemberInfo FindMemberWithAttribute(Type type) where T : Attribute { + var mil = type.FindMembers( + MemberTypes.Field | MemberTypes.Property, + BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static, + (m, o) => m.GetCustomAttributes(typeof(T), true).Length != 0, + null + ); + if (mil.Length != 1) + throw new MissingMemberException(type.Name, typeof(T).Name); + return mil[0]; + } + + public static bool IsGenericDictionary(Type type) { + return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>); + } + + public static MemberInfo GetMember(Type type, string name) { + var mil = type.GetMember( + name, + MemberTypes.Field | MemberTypes.Property, + BindingFlags.Public | BindingFlags.Instance + ); + if (mil.Length != 1) + throw new MissingMemberException(type.Name, name); + return mil[0]; + } + + 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(); + } + + public static object GetValue(MemberInfo mi, object obj) { + if (mi is FieldInfo) + return ((FieldInfo)mi).GetValue(obj); + else if (mi is PropertyInfo) + return ((PropertyInfo)mi).GetValue(obj, new object[]{}); + else + throw new ArgumentException(); + } + + 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); + else if (mi is PropertyInfo) + ((PropertyInfo)mi).SetValue(obj, value, BindingFlags.Default, binder, emptyObjectArray, null); + else + throw new ArgumentException(); + } + + public static Type[] GetSubclassesOf() where T : class { + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + IEnumerable r = new List(); + foreach (var a in assemblies) + r = r.Concat(a.GetTypes().Where( + t => t.IsClass + && !t.IsAbstract + && t.IsSubclassOf(typeof(T)) + )); + return r.ToArray(); + } + + public static string GetSimpleName(Type type) { + string result = type.Name; + var typeargs = type.GetGenericArguments(); + if (typeargs.Length > 0) { + result = string.Format("{0}[{1}]", result, string.Join(",", from a in typeargs select GetSimpleName(a))); + } + return result; + } + } +} diff --git a/Assets/Cryville/Common/ReflectionHelper.cs.meta b/Assets/Cryville/Common/ReflectionHelper.cs.meta new file mode 100644 index 0000000..fde53ad --- /dev/null +++ b/Assets/Cryville/Common/ReflectionHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 16857d076fc8d534788424e6c6d180e0 +timeCreated: 1608801352 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/StringUtils.cs b/Assets/Cryville/Common/StringUtils.cs new file mode 100644 index 0000000..dc8c6d4 --- /dev/null +++ b/Assets/Cryville/Common/StringUtils.cs @@ -0,0 +1,23 @@ +using System; +using System.Text; + +namespace Cryville.Common { + public static class StringUtils { + public static string TrimExt(string s) { + return s.Substring(0, s.LastIndexOf(".")); + } + public static string ToString(this TimeSpan timeSpan, int digits) { + var b = new StringBuilder(); + bool flag = false; + if (timeSpan.TotalDays >= 1) { + flag = true; + b.Append(timeSpan.Days.ToString() + ":"); + } + if (flag || timeSpan.TotalHours >= 1) + b.Append((timeSpan.Hours % 24).ToString() + ":"); + b.Append((timeSpan.Minutes % 60).ToString("00") + ":"); + b.Append((timeSpan.TotalSeconds % 60).ToString("00." + new string('0', digits))); + return b.ToString(); + } + } +} diff --git a/Assets/Cryville/Common/StringUtils.cs.meta b/Assets/Cryville/Common/StringUtils.cs.meta new file mode 100644 index 0000000..50d701f --- /dev/null +++ b/Assets/Cryville/Common/StringUtils.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9c45da9ea5560c84b9ecfb5a1161fb77 +timeCreated: 1608801352 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Unity.meta b/Assets/Cryville/Common/Unity.meta new file mode 100644 index 0000000..c08c05e --- /dev/null +++ b/Assets/Cryville/Common/Unity.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2debd5a8bd19dea4f9e8b0aab176881d +folderAsset: yes +timeCreated: 1605323649 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Unity/CallHelper.cs b/Assets/Cryville/Common/Unity/CallHelper.cs new file mode 100644 index 0000000..38b0eff --- /dev/null +++ b/Assets/Cryville/Common/Unity/CallHelper.cs @@ -0,0 +1,34 @@ +using UnityEngine; +using System; + +namespace Cryville.Common.Unity { + static class CallHelper { + public static bool HasFlag(this Enum obj, Enum flag) { + ulong num = Convert.ToUInt64(flag); + ulong num2 = Convert.ToUInt64(obj); + return (num2 & num) == num; + } + + public static void ShowException(Exception ex) { + ShowMessageBox(ex.ToString()); + } + + public static void ShowMessageBox(string message) { + GameObject.Instantiate(Resources.Load("Common/Popup")).GetComponent().Message = message; + } + + public static void Purge(Transform obj) { + foreach (Transform i in obj) + GameObject.Destroy(i.gameObject); + } + + /*public static void DownloadAndUnzip(string url, FileInfo file) { + using (DownloadDialog d = new DownloadDialog()) { + d.Download(url, file); + } + using (ZipFile z = new ZipFile(file.FullName)) { + z.ExtractAll(file.DirectoryName, ExtractExistingFileAction.OverwriteSilently); + } + }*/ + } +} diff --git a/Assets/Cryville/Common/Unity/CallHelper.cs.meta b/Assets/Cryville/Common/Unity/CallHelper.cs.meta new file mode 100644 index 0000000..9c2b67f --- /dev/null +++ b/Assets/Cryville/Common/Unity/CallHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 98b3d4b7cc1ce054598780159356da35 +timeCreated: 1608801352 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Common/Unity/FileDialog.cs b/Assets/Cryville/Common/Unity/FileDialog.cs new file mode 100644 index 0000000..c02952d --- /dev/null +++ b/Assets/Cryville/Common/Unity/FileDialog.cs @@ -0,0 +1,142 @@ +using System; +using System.IO; +using UnityEngine; +using UnityEngine.UI; + +namespace Cryville.Common.Unity { + public class FileDialog : MonoBehaviour { + Transform panel; + Transform title; + Transform drives; + Transform dirs; + Transform files; + + public Action Callback { private get; set; } + +#if UNITY_ANDROID && !UNITY_EDITOR_WIN + string androidStorage = ""; +#endif + + string fileName = ""; + public string FileName { + get { return fileName; } + } + + public string[] m_filter = new string[]{}; + public string[] Filter { + set { m_filter = value; } + } + +#pragma warning disable IDE0051 + void Start() { + panel = gameObject.transform.Find("Panel"); + title = panel.Find("Title/Text"); + drives = panel.Find("Drives/DrivesInner"); + dirs = panel.Find("Directories/DirectoriesInner"); + files = panel.Find("Files/FilesInner"); + if (CurrentDirectory == null) { +#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN + CurrentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory()); +#elif UNITY_ANDROID + using (AndroidJavaClass ajc=new AndroidJavaClass("android.os.Environment")) + using (AndroidJavaObject file=ajc.CallStatic("getExternalStorageDirectory")) { + androidStorage = file.Call("getAbsolutePath"); + CurrentDirectory = new DirectoryInfo(androidStorage); + } +#else +#error No default directory +#endif + } + UpdateGUI(); + } +#pragma warning restore IDE0051 + + public void Show() { + fileName = null; + gameObject.SetActive(true); + } + + public void Close() { + if (Callback != null) Callback.Invoke(); + gameObject.SetActive(false); + } + + public DirectoryInfo CurrentDirectory; + + void OnDriveChanged(string s) { +#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN + CurrentDirectory = new DirectoryInfo(s); +#elif UNITY_ANDROID + switch (s) { + case "?storage": + CurrentDirectory = new DirectoryInfo(androidStorage); + break; + } +#else +#error No change drive logic +#endif + UpdateGUI(); + } + + void OnDirectoryChanged(string s) { + CurrentDirectory = new DirectoryInfo(CurrentDirectory.FullName + "/" + s); + UpdateGUI(); + } + + void OnFileChanged(string s) { + fileName = s; + Close(); + } + + void UpdateGUI() { + title.GetComponent().text = CurrentDirectory.FullName; + + CallHelper.Purge(drives); +#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN + var dl = Directory.GetLogicalDrives(); + foreach (string d in dl) { + GameObject btn = GameObject.Instantiate(Resources.Load("Common/Button")); + btn.GetComponentInChildren().text = d; + var ts = d; + btn.GetComponentInChildren