Browse Source

上传工程

zansimple 11 months ago
commit
2a09747eb6
100 changed files with 6699 additions and 0 deletions
  1. 2 0
      .gitignore
  2. BIN
      Dll/BHJD.DEMdll.dll
  3. BIN
      Dll/CesiumForUnityNative-Runtime.dll
  4. BIN
      Dll/Npgsql.dll
  5. BIN
      Dll/Unity.Mathematics.dll
  6. 144 0
      KYFramework/Core/Base/DoubleMap.cs
  7. 10 0
      KYFramework/Core/Base/Event/EventAttribute.cs
  8. 37 0
      KYFramework/Core/Base/Event/IEvent.cs
  9. 26 0
      KYFramework/Core/Base/Event/IInvoke.cs
  10. 11 0
      KYFramework/Core/Base/Event/InvokeAttribute.cs
  11. 12 0
      KYFramework/Core/Base/Helper/ObjectHelper.cs
  12. 93 0
      KYFramework/Core/Base/MultiMap.cs
  13. 15 0
      KYFramework/Core/Base/Object/BaseAttribute.cs
  14. 111 0
      KYFramework/Core/Base/Object/Component.cs
  15. 310 0
      KYFramework/Core/Base/Object/ComponentFactory.cs
  16. 35 0
      KYFramework/Core/Base/Object/ComponentWithId.cs
  17. 252 0
      KYFramework/Core/Base/Object/Entity.cs
  18. 15 0
      KYFramework/Core/Base/Object/EntityEventAttribute.cs
  19. 680 0
      KYFramework/Core/Base/Object/EventSystem.cs
  20. 8 0
      KYFramework/Core/Base/Object/HideInHierarchy.cs
  21. 90 0
      KYFramework/Core/Base/Object/IAwakeSystem.cs
  22. 26 0
      KYFramework/Core/Base/Object/IChangeSystem.cs
  23. 31 0
      KYFramework/Core/Base/Object/IDeserializeSystem.cs
  24. 25 0
      KYFramework/Core/Base/Object/IDestroySystem.cs
  25. 25 0
      KYFramework/Core/Base/Object/ILateUpdateSystem.cs
  26. 25 0
      KYFramework/Core/Base/Object/ILoadSystem.cs
  27. 6 0
      KYFramework/Core/Base/Object/ISerializeToEntity.cs
  28. 25 0
      KYFramework/Core/Base/Object/IStartSystem.cs
  29. 25 0
      KYFramework/Core/Base/Object/IUpdateSystem.cs
  30. 17 0
      KYFramework/Core/Base/Object/Object.cs
  31. 100 0
      KYFramework/Core/Base/Object/ObjectPool.cs
  32. 9 0
      KYFramework/Core/Base/Object/ObjectSystemAttribute.cs
  33. 41 0
      KYFramework/Core/Base/OneThreadSynchronizationContext.cs
  34. 205 0
      KYFramework/Core/Base/RecyclableMemoryStreamManager/Events.cs
  35. 888 0
      KYFramework/Core/Base/RecyclableMemoryStreamManager/RecyclableMemoryStream.cs
  36. 608 0
      KYFramework/Core/Base/RecyclableMemoryStreamManager/RecyclableMemoryStreamManager.cs
  37. 161 0
      KYFramework/Core/Base/UnOrderMultiMap.cs
  38. 15 0
      KYFramework/Core/Component/ListComponent.cs
  39. 18 0
      KYFramework/Core/Component/OptionComponent.cs
  40. 24 0
      KYFramework/Core/Component/OptionComponentSystem.cs
  41. 26 0
      KYFramework/Core/Component/Timer.cs
  42. 72 0
      KYFramework/Core/Component/TimerComponent.cs
  43. 268 0
      KYFramework/Core/Component/TimerComponentSystem.cs
  44. 58 0
      KYFramework/Core/Component/TimerSystem.cs
  45. 62 0
      KYFramework/Core/Entity/Game.cs
  46. 31 0
      KYFramework/Core/Entity/Scene.cs
  47. 95 0
      KYFramework/Core/Helper/ByteHelper.cs
  48. 11 0
      KYFramework/Core/Helper/Define.cs
  49. 107 0
      KYFramework/Core/Helper/FileHelper.cs
  50. 37 0
      KYFramework/Core/Helper/IdGenerater.cs
  51. 31 0
      KYFramework/Core/Helper/JsonHelper.cs
  52. 124 0
      KYFramework/Core/Helper/MongoHelper.cs
  53. 22 0
      KYFramework/Core/Helper/NetworkHelper.cs
  54. 63 0
      KYFramework/Core/Helper/ProcessHelper.cs
  55. 67 0
      KYFramework/Core/Helper/StringHelper.cs
  56. 38 0
      KYFramework/Core/Helper/TimeHelper.cs
  57. 17 0
      KYFramework/Core/Helper/TimerInvokeType.cs
  58. 62 0
      KYFramework/Core/Module/Config/ACategory.cs
  59. 10 0
      KYFramework/Core/Module/Config/ConfigAttribute.cs
  60. 10 0
      KYFramework/Core/Module/Config/ConfigComponent.cs
  61. 90 0
      KYFramework/Core/Module/Config/ConfigComponentSystem.cs
  62. 24 0
      KYFramework/Core/Module/Config/ConfigHelper.cs
  63. 7 0
      KYFramework/Core/Module/Config/IConfig.cs
  64. 16 0
      KYFramework/Core/Module/Log/ILog.cs
  65. 69 0
      KYFramework/Core/Module/Log/Log.cs
  66. 158 0
      KYFramework/Core/Module/Log/Logger.cs
  67. 78 0
      KYFramework/Core/Module/Log/NLogger.cs
  68. 11 0
      KYFramework/Core/Module/Timer/ATimer.cs
  69. 28 0
      KYFramework/KYFramework.csproj
  70. 621 0
      KYFramework/bin/Debug/net7.0/KYFramework.deps.json
  71. BIN
      KYFramework/bin/Debug/net7.0/KYFramework.dll
  72. BIN
      KYFramework/bin/Debug/net7.0/KYFramework.pdb
  73. BIN
      KYFramework/bin/Debug/net7.0/ThirdParty.dll
  74. BIN
      KYFramework/bin/Debug/net7.0/ThirdParty.pdb
  75. 4 0
      KYFramework/obj/Debug/net47/.NETFramework,Version=v4.7.AssemblyAttributes.cs
  76. 22 0
      KYFramework/obj/Debug/net47/KYFramework.AssemblyInfo.cs
  77. 1 0
      KYFramework/obj/Debug/net47/KYFramework.AssemblyInfoInputs.cache
  78. 3 0
      KYFramework/obj/Debug/net47/KYFramework.GeneratedMSBuildEditorConfig.editorconfig
  79. 8 0
      KYFramework/obj/Debug/net47/KYFramework.GlobalUsings.g.cs
  80. BIN
      KYFramework/obj/Debug/net47/KYFramework.assets.cache
  81. BIN
      KYFramework/obj/Debug/net47/KYFramework.csproj.AssemblyReference.cache
  82. 4 0
      KYFramework/obj/Debug/net7.0/.NETCoreApp,Version=v7.0.AssemblyAttributes.cs
  83. 0 0
      KYFramework/obj/Debug/net7.0/KYFramew.00291D58.Up2Date
  84. 22 0
      KYFramework/obj/Debug/net7.0/KYFramework.AssemblyInfo.cs
  85. 1 0
      KYFramework/obj/Debug/net7.0/KYFramework.AssemblyInfoInputs.cache
  86. 13 0
      KYFramework/obj/Debug/net7.0/KYFramework.GeneratedMSBuildEditorConfig.editorconfig
  87. 13 0
      KYFramework/obj/Debug/net7.0/KYFramework.GeneratedMSBuildEditorConfig.editorconfig.mine
  88. 13 0
      KYFramework/obj/Debug/net7.0/KYFramework.GeneratedMSBuildEditorConfig.editorconfig.r14
  89. 13 0
      KYFramework/obj/Debug/net7.0/KYFramework.GeneratedMSBuildEditorConfig.editorconfig.r5
  90. 8 0
      KYFramework/obj/Debug/net7.0/KYFramework.GlobalUsings.g.cs
  91. BIN
      KYFramework/obj/Debug/net7.0/KYFramework.assets.cache
  92. BIN
      KYFramework/obj/Debug/net7.0/KYFramework.assets.cache.r14
  93. BIN
      KYFramework/obj/Debug/net7.0/KYFramework.assets.cache.r5
  94. BIN
      KYFramework/obj/Debug/net7.0/KYFramework.csproj.AssemblyReference.cache
  95. BIN
      KYFramework/obj/Debug/net7.0/KYFramework.csproj.AssemblyReference.cache.r14
  96. BIN
      KYFramework/obj/Debug/net7.0/KYFramework.csproj.AssemblyReference.cache.r5
  97. 0 0
      KYFramework/obj/Debug/net7.0/KYFramework.csproj.BuildWithSkipAnalyzers
  98. 0 0
      KYFramework/obj/Debug/net7.0/KYFramework.csproj.CopyComplete
  99. 1 0
      KYFramework/obj/Debug/net7.0/KYFramework.csproj.CoreCompileInputs.cache
  100. 135 0
      KYFramework/obj/Debug/net7.0/KYFramework.csproj.FileListAbsolute.txt

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+.vs
+.idea

BIN
Dll/BHJD.DEMdll.dll


BIN
Dll/CesiumForUnityNative-Runtime.dll


BIN
Dll/Npgsql.dll


BIN
Dll/Unity.Mathematics.dll


+ 144 - 0
KYFramework/Core/Base/DoubleMap.cs

@@ -0,0 +1,144 @@
+using System;
+using System.Collections.Generic;
+
+namespace KYFramework
+{
+    public class DoubleMap<K, V>
+    {
+        private readonly Dictionary<K, V> kv = new Dictionary<K, V>();
+        private readonly Dictionary<V, K> vk = new Dictionary<V, K>();
+
+        public DoubleMap()
+        {
+        }
+
+        public DoubleMap(int capacity)
+        {
+            kv = new Dictionary<K, V>(capacity);
+            vk = new Dictionary<V, K>(capacity);
+        }
+
+        public void ForEach(Action<K, V> action)
+        {
+            if (action == null)
+            {
+                return;
+            }
+            Dictionary<K, V>.KeyCollection keys = kv.Keys;
+            foreach (K key in keys)
+            {
+                action(key, kv[key]);
+            }
+        }
+
+        public List<K> Keys
+        {
+            get
+            {
+                return new List<K>(kv.Keys);
+            }
+        }
+
+        public List<V> Values
+        {
+            get
+            {
+                return new List<V>(vk.Keys);
+            }
+        }
+
+        public void Add(K key, V value)
+        {
+            if (key == null || value == null || kv.ContainsKey(key) || vk.ContainsKey(value))
+            {
+                return;
+            }
+            kv.Add(key, value);
+            vk.Add(value, key);
+        }
+
+        public V GetValueByKey(K key)
+        {
+            if (key != null && kv.ContainsKey(key))
+            {
+                return kv[key];
+            }
+            return default(V);
+        }
+
+        public K GetKeyByValue(V value)
+        {
+            if (value != null && vk.ContainsKey(value))
+            {
+                return vk[value];
+            }
+            return default(K);
+        }
+
+        public void RemoveByKey(K key)
+        {
+            if (key == null)
+            {
+                return;
+            }
+            V value;
+            if (!kv.TryGetValue(key, out value))
+            {
+                return;
+            }
+
+            kv.Remove(key);
+            vk.Remove(value);
+        }
+
+        public void RemoveByValue(V value)
+        {
+            if (value == null)
+            {
+                return;
+            }
+
+            K key;
+            if (!vk.TryGetValue(value, out key))
+            {
+                return;
+            }
+
+            kv.Remove(key);
+            vk.Remove(value);
+        }
+
+        public void Clear()
+        {
+            kv.Clear();
+            vk.Clear();
+        }
+
+        public bool ContainsKey(K key)
+        {
+            if (key == null)
+            {
+                return false;
+            }
+            return kv.ContainsKey(key);
+        }
+
+        public bool ContainsValue(V value)
+        {
+            if (value == null)
+            {
+                return false;
+            }
+            return vk.ContainsKey(value);
+        }
+
+        public bool Contains(K key, V value)
+        {
+            if (key == null || value == null)
+            {
+                return false;
+            }
+            return kv.ContainsKey(key) && vk.ContainsKey(value);
+        }
+    }
+}

+ 10 - 0
KYFramework/Core/Base/Event/EventAttribute.cs

@@ -0,0 +1,10 @@
+using System;
+
+namespace KYFramework
+{
+    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+    public class EventAttribute : BaseAttribute
+    {
+      
+    }
+}

+ 37 - 0
KYFramework/Core/Base/Event/IEvent.cs

@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Cysharp.Threading.Tasks;
+
+namespace KYFramework
+{
+    public interface IEvent
+    {
+        Type GetEventType();
+    }
+
+    public abstract class AEvent<A> : IEvent where A: struct
+    {
+        public Type GetEventType()
+        {
+            return typeof (A);
+        }
+
+        protected abstract UniTask Run( A a);
+
+        public async UniTask Handle( A a)
+        {
+            try
+            {
+                await Run(a);
+            }
+            catch (Exception e)
+            {
+                Log.Error(e);
+            }
+        }
+    }
+   
+}

+ 26 - 0
KYFramework/Core/Base/Event/IInvoke.cs

@@ -0,0 +1,26 @@
+namespace KYFramework;
+
+public interface IInvoke
+{
+    Type Type { get; }
+}
+
+public abstract class AInvokeHandler<A> : IInvoke where A : struct
+{
+    public Type Type
+    {
+        get { return typeof(A); }
+    }
+
+    public abstract void Handle(A a);
+}
+
+public abstract class AInvokeHandler<A, T> : IInvoke where A : struct
+{
+    public Type Type
+    {
+        get { return typeof(A); }
+    }
+
+    public abstract T Handle(A a);
+}

+ 11 - 0
KYFramework/Core/Base/Event/InvokeAttribute.cs

@@ -0,0 +1,11 @@
+namespace KYFramework;
+
+public class InvokeAttribute: BaseAttribute
+{
+    public int Type { get; }
+
+    public InvokeAttribute(int type = 0)
+    {
+        this.Type = type;
+    }
+}

+ 12 - 0
KYFramework/Core/Base/Helper/ObjectHelper.cs

@@ -0,0 +1,12 @@
+namespace KYFramework
+{
+    public static class ObjectHelper
+    {
+        public static void Swap<T>(ref T t1, ref T t2)
+        {
+            T t3 = t1;
+            t1 = t2;
+            t2 = t3;
+        }
+    }
+}

+ 93 - 0
KYFramework/Core/Base/MultiMap.cs

@@ -0,0 +1,93 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace KYFramework
+{
+    public class MultiMap<T, K>: SortedDictionary<T, List<K>>
+    {
+        private readonly List<K> Empty = new List<K>();
+
+        public void Add(T t, K k)
+        {
+            List<K> list;
+            this.TryGetValue(t, out list);
+            if (list == null)
+            {
+                list = new List<K>();
+                this.Add(t, list);
+            }
+            list.Add(k);
+        }
+
+        public bool Remove(T t, K k)
+        {
+            List<K> list;
+            this.TryGetValue(t, out list);
+            if (list == null)
+            {
+                return false;
+            }
+            if (!list.Remove(k))
+            {
+                return false;
+            }
+            if (list.Count == 0)
+            {
+                this.Remove(t);
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// 不返回内部的list,copy一份出来
+        /// </summary>
+        /// <param name="t"></param>
+        /// <returns></returns>
+        public K[] GetAll(T t)
+        {
+            List<K> list;
+            this.TryGetValue(t, out list);
+            if (list == null)
+            {
+                return Array.Empty<K>();
+            }
+            return list.ToArray();
+        }
+
+        /// <summary>
+        /// 返回内部的list
+        /// </summary>
+        /// <param name="t"></param>
+        /// <returns></returns>
+        public new List<K> this[T t]
+        {
+            get
+            {
+                this.TryGetValue(t, out List<K> list);
+                return list ?? Empty;
+            }
+        }
+
+        public K GetOne(T t)
+        {
+            List<K> list;
+            this.TryGetValue(t, out list);
+            if (list != null && list.Count > 0)
+            {
+                return list[0];
+            }
+            return default;
+        }
+
+        public bool Contains(T t, K k)
+        {
+            List<K> list;
+            this.TryGetValue(t, out list);
+            if (list == null)
+            {
+                return false;
+            }
+            return list.Contains(k);
+        }
+    }
+}

+ 15 - 0
KYFramework/Core/Base/Object/BaseAttribute.cs

@@ -0,0 +1,15 @@
+using System;
+
+namespace KYFramework
+{
+    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+    public class BaseAttribute : Attribute
+    {
+        public Type AttributeType { get; }
+
+        public BaseAttribute()
+        {
+            this.AttributeType = this.GetType();
+        }
+    }
+}

+ 111 - 0
KYFramework/Core/Base/Object/Component.cs

@@ -0,0 +1,111 @@
+using MongoDB.Bson.Serialization.Attributes;
+using System;
+
+namespace KYFramework
+{
+    [BsonIgnoreExtraElements]
+    public abstract class Component : Object , IDisposable
+    {
+        [BsonIgnore]
+        public long InstanceId { get; set; }
+
+
+        [BsonIgnore]
+        protected bool isFromPool;
+
+        [BsonIgnore]
+        public bool IsFromPool
+        {
+            get
+            {
+                return isFromPool;
+            }
+            set
+            {
+                isFromPool = value;
+                if (!this.isFromPool) return;
+                if(InstanceId == 0)
+                    InstanceId = IdGenerater.GenerateInstanceId();
+            }
+        }
+
+        [BsonIgnore]
+        public bool IsDisposed
+        {
+            get
+            {
+                return this.InstanceId == 0;
+            }
+        }
+
+        private Component parent;
+
+        [BsonIgnore]
+        public Component Parent
+        {
+            get
+            {
+                return this.parent;
+            }
+            set
+            {
+                parent = value;
+            }
+        }
+
+      
+
+        public T GetParent<T>() where T : Component
+        {
+            return this.Parent as T;
+        }
+
+        [BsonIgnore]
+        public Entity Entity
+        {
+            get
+            {
+                return this.Parent as Entity;
+            }
+        }
+
+        protected Component()
+        {
+            this.InstanceId = IdGenerater.GenerateInstanceId();
+        }
+
+        public virtual void Dispose()
+        {
+            if (this.IsDisposed)
+            {
+                return;
+            }
+
+            // 触发Destroy事件
+            Game.EventSystem.Destroy(this);
+
+            Game.EventSystem.Remove(this.InstanceId);
+
+            this.InstanceId = 0;
+
+            if (this.IsFromPool)
+            {
+                Game.ObjectPool.Recycle(this);
+            }
+            else
+            {
+         
+            }
+        }
+
+        public override void EndInit()
+        {
+            Game.EventSystem.Deserialize(this);
+        }
+
+        public override string ToString()
+        {
+            return MongoHelper.ToJson(this);
+        }
+    }
+}

+ 310 - 0
KYFramework/Core/Base/Object/ComponentFactory.cs

@@ -0,0 +1,310 @@
+using System;
+
+namespace KYFramework
+{
+    public static class ComponentFactory
+    {
+        public static Component CreateWithParent(Type type, Component parent, bool fromPool = true)
+        {
+            Component component;
+            if (fromPool)
+            {
+                component = Game.ObjectPool.Fetch(type) as Component;
+            }
+            else
+            {
+                component = (Component)Activator.CreateInstance(type);
+            }
+
+            Game.EventSystem.Add(component);
+
+            component.Parent = parent;
+            if (component is ComponentWithId componentWithId)
+            {
+                componentWithId.Id = component.InstanceId;
+            }
+            Game.EventSystem.Awake(component);
+            return component;
+        }
+
+        public static T CreateWithParent<T>(Component parent, bool fromPool = true) where T : Component
+        {
+            Type type = typeof(T);
+
+            T component;
+            if (fromPool)
+            {
+                component = (T)Game.ObjectPool.Fetch(type);
+            }
+            else
+            {
+                component = (T)Activator.CreateInstance(type);
+            }
+
+            Game.EventSystem.Add(component);
+
+            component.Parent = parent;
+            if (component is ComponentWithId componentWithId)
+            {
+                componentWithId.Id = component.InstanceId;
+            }
+            Game.EventSystem.Awake(component);
+            return component;
+        }
+
+        public static T CreateWithParent<T, A>(Component parent, A a, bool fromPool = true) where T : Component
+        {
+            Type type = typeof(T);
+
+            T component;
+            if (fromPool)
+            {
+                component = (T)Game.ObjectPool.Fetch(type);
+            }
+            else
+            {
+                component = (T)Activator.CreateInstance(type);
+            }
+
+            Game.EventSystem.Add(component);
+
+            component.Parent = parent;
+            if (component is ComponentWithId componentWithId)
+            {
+                componentWithId.Id = component.InstanceId;
+            }
+            Game.EventSystem.Awake(component, a);
+            return component;
+        }
+
+        public static T CreateWithParent<T, A, B>(Component parent, A a, B b, bool fromPool = true) where T : Component
+        {
+            Type type = typeof(T);
+
+            T component;
+            if (fromPool)
+            {
+                component = (T)Game.ObjectPool.Fetch(type);
+            }
+            else
+            {
+                component = (T)Activator.CreateInstance(type);
+            }
+
+            Game.EventSystem.Add(component);
+
+            component.Parent = parent;
+            if (component is ComponentWithId componentWithId)
+            {
+                componentWithId.Id = component.InstanceId;
+            }
+            Game.EventSystem.Awake(component, a, b);
+            return component;
+        }
+
+        public static T CreateWithParent<T, A, B, C>(Component parent, A a, B b, C c, bool fromPool = true) where T : Component
+        {
+            Type type = typeof(T);
+
+            T component;
+            if (fromPool)
+            {
+                component = (T)Game.ObjectPool.Fetch(type);
+            }
+            else
+            {
+                component = (T)Activator.CreateInstance(type);
+            }
+
+            Game.EventSystem.Add(component);
+
+            component.Parent = parent;
+            if (component is ComponentWithId componentWithId)
+            {
+                componentWithId.Id = component.InstanceId;
+            }
+            Game.EventSystem.Awake(component, a, b, c);
+            return component;
+        }
+
+        public static T Create<T>(bool fromPool = true) where T : Component
+        {
+            Type type = typeof(T);
+
+            T component;
+            if (fromPool)
+            {
+                component = (T)Game.ObjectPool.Fetch(type);
+            }
+            else
+            {
+                component = (T)Activator.CreateInstance(type);
+            }
+
+            Game.EventSystem.Add(component);
+
+            if (component is ComponentWithId componentWithId)
+            {
+                componentWithId.Id = component.InstanceId;
+            }
+            Game.EventSystem.Awake(component);
+            return component;
+        }
+
+        public static T Create<T, A>(A a, bool fromPool = true) where T : Component
+        {
+            Type type = typeof(T);
+
+            T component;
+            if (fromPool)
+            {
+                component = (T)Game.ObjectPool.Fetch(type);
+            }
+            else
+            {
+                component = (T)Activator.CreateInstance(type);
+            }
+
+            Game.EventSystem.Add(component);
+
+            if (component is ComponentWithId componentWithId)
+            {
+                componentWithId.Id = component.InstanceId;
+            }
+            Game.EventSystem.Awake(component, a);
+            return component;
+        }
+
+        public static T Create<T, A, B>(A a, B b, bool fromPool = true) where T : Component
+        {
+            Type type = typeof(T);
+
+            T component;
+            if (fromPool)
+            {
+                component = (T)Game.ObjectPool.Fetch(type);
+            }
+            else
+            {
+                component = (T)Activator.CreateInstance(type);
+            }
+
+            Game.EventSystem.Add(component);
+
+            if (component is ComponentWithId componentWithId)
+            {
+                componentWithId.Id = component.InstanceId;
+            }
+            Game.EventSystem.Awake(component, a, b);
+            return component;
+        }
+
+        public static T Create<T, A, B, C>(A a, B b, C c, bool fromPool = true) where T : Component
+        {
+            Type type = typeof(T);
+
+            T component;
+            if (fromPool)
+            {
+                component = (T)Game.ObjectPool.Fetch(type);
+            }
+            else
+            {
+                component = (T)Activator.CreateInstance(type);
+            }
+
+            Game.EventSystem.Add(component);
+
+            if (component is ComponentWithId componentWithId)
+            {
+                componentWithId.Id = component.InstanceId;
+            }
+            Game.EventSystem.Awake(component, a, b, c);
+            return component;
+        }
+
+        public static T CreateWithId<T>(long id, bool fromPool = true) where T : ComponentWithId
+        {
+            Type type = typeof(T);
+
+            T component;
+            if (fromPool)
+            {
+                component = (T)Game.ObjectPool.Fetch(type);
+            }
+            else
+            {
+                component = (T)Activator.CreateInstance(type);
+            }
+
+            Game.EventSystem.Add(component);
+
+            component.Id = id;
+            Game.EventSystem.Awake(component);
+            return component;
+        }
+
+        public static T CreateWithId<T, A>(long id, A a, bool fromPool = true) where T : ComponentWithId
+        {
+            Type type = typeof(T);
+
+            T component;
+            if (fromPool)
+            {
+                component = (T)Game.ObjectPool.Fetch(type);
+            }
+            else
+            {
+                component = (T)Activator.CreateInstance(type);
+            }
+
+            Game.EventSystem.Add(component);
+
+            component.Id = id;
+            Game.EventSystem.Awake(component, a);
+            return component;
+        }
+
+        public static T CreateWithId<T, A, B>(long id, A a, B b, bool fromPool = true) where T : ComponentWithId
+        {
+            Type type = typeof(T);
+
+            T component;
+            if (fromPool)
+            {
+                component = (T)Game.ObjectPool.Fetch(type);
+            }
+            else
+            {
+                component = (T)Activator.CreateInstance(type);
+            }
+
+            Game.EventSystem.Add(component);
+
+            component.Id = id;
+            Game.EventSystem.Awake(component, a, b);
+            return component;
+        }
+
+        public static T CreateWithId<T, A, B, C>(long id, A a, B b, C c, bool fromPool = true) where T : ComponentWithId
+        {
+            Type type = typeof(T);
+
+            T component;
+            if (fromPool)
+            {
+                component = (T)Game.ObjectPool.Fetch(type);
+            }
+            else
+            {
+                component = (T)Activator.CreateInstance(type);
+            }
+
+            Game.EventSystem.Add(component);
+
+            component.Id = id;
+            Game.EventSystem.Awake(component, a, b, c);
+            return component;
+        }
+    }
+}

+ 35 - 0
KYFramework/Core/Base/Object/ComponentWithId.cs

@@ -0,0 +1,35 @@
+
+using MongoDB.Bson.Serialization.Attributes;
+
+namespace KYFramework
+{
+    [BsonIgnoreExtraElements]
+    public abstract class ComponentWithId : Component
+    {
+        [BsonIgnoreIfDefault]
+        [BsonDefaultValue(0L)]
+        [BsonElement]
+        [BsonId]
+        public long Id { get; set; }
+
+        protected ComponentWithId()
+        {
+            this.Id = this.InstanceId;
+        }
+
+        protected ComponentWithId(long id)
+        {
+            this.Id = id;
+        }
+
+        public override void Dispose()
+        {
+            if (this.IsDisposed)
+            {
+                return;
+            }
+
+            base.Dispose();
+        }
+    }
+}

+ 252 - 0
KYFramework/Core/Base/Object/Entity.cs

@@ -0,0 +1,252 @@
+using MongoDB.Bson.Serialization.Attributes;
+
+namespace KYFramework
+{
+    [BsonIgnoreExtraElements]
+    public class Entity : ComponentWithId
+    {
+        [BsonElement("C")]
+        [BsonIgnoreIfNull]
+        private HashSet<Component> components = new HashSet<Component>();
+
+        [BsonIgnore]
+        private Dictionary<Type, Component> componentDict = new Dictionary<Type, Component>();
+
+        public Entity()
+        {
+        }
+
+        protected Entity(long id) : base(id)
+        {
+        }
+
+        public override void Dispose()
+        {
+            if (this.IsDisposed)
+            {
+                return;
+            }
+
+            base.Dispose();
+
+            foreach (Component component in this.componentDict.Values)
+            {
+                try
+                {
+                    component.Dispose();
+                }
+                catch (Exception e)
+                {
+                    Log.Error(e);
+                }
+            }
+
+            this.components.Clear();
+            this.componentDict.Clear();
+        }
+
+        public virtual Component AddComponent(Component component)
+        {
+            Type type = component.GetType();
+            if (this.componentDict.ContainsKey(type))
+            {
+                throw new Exception($"AddComponent, component already exist, id: {this.Id}, component: {type.Name}");
+            }
+
+            component.Parent = this;
+
+            this.componentDict.Add(type, component);
+
+            if (component is ISerializeToEntity)
+            {
+                this.components.Add(component);
+            }
+
+            return component;
+        }
+
+        public virtual Component AddComponent(Type type)
+        {
+            if (this.componentDict.ContainsKey(type))
+            {
+                throw new Exception($"AddComponent, component already exist, id: {this.Id}, component: {type.Name}");
+            }
+
+            Component component = ComponentFactory.CreateWithParent(type, this, this.IsFromPool);
+
+            this.componentDict.Add(type, component);
+
+            if (component is ISerializeToEntity)
+            {
+                this.components.Add(component);
+            }
+
+            return component;
+        }
+
+        public virtual K AddComponent<K>() where K : Component, new()
+        {
+            Type type = typeof(K);
+            if (this.componentDict.ContainsKey(type))
+            {
+                throw new Exception($"AddComponent, component already exist, id: {this.Id}, component: {typeof(K).Name}");
+            }
+
+            K component = ComponentFactory.CreateWithParent<K>(this, this.IsFromPool);
+
+            this.componentDict.Add(type, component);
+
+            if (component is ISerializeToEntity)
+            {
+                this.components.Add(component);
+            }
+
+            return component;
+        }
+
+        public virtual K AddComponent<K, P1>(P1 p1) where K : Component, new()
+        {
+            Type type = typeof(K);
+            if (this.componentDict.ContainsKey(type))
+            {
+                throw new Exception($"AddComponent, component already exist, id: {this.Id}, component: {typeof(K).Name}");
+            }
+
+            K component = ComponentFactory.CreateWithParent<K, P1>(this, p1, this.IsFromPool);
+
+            this.componentDict.Add(type, component);
+
+            if (component is ISerializeToEntity)
+            {
+                this.components.Add(component);
+            }
+
+            return component;
+        }
+
+        public virtual K AddComponent<K, P1, P2>(P1 p1, P2 p2) where K : Component, new()
+        {
+            Type type = typeof(K);
+            if (this.componentDict.ContainsKey(type))
+            {
+                throw new Exception($"AddComponent, component already exist, id: {this.Id}, component: {typeof(K).Name}");
+            }
+
+            K component = ComponentFactory.CreateWithParent<K, P1, P2>(this, p1, p2, this.IsFromPool);
+
+            this.componentDict.Add(type, component);
+
+            if (component is ISerializeToEntity)
+            {
+                this.components.Add(component);
+            }
+
+            return component;
+        }
+
+        public virtual K AddComponent<K, P1, P2, P3>(P1 p1, P2 p2, P3 p3) where K : Component, new()
+        {
+            Type type = typeof(K);
+            if (this.componentDict.ContainsKey(type))
+            {
+                throw new Exception($"AddComponent, component already exist, id: {this.Id}, component: {typeof(K).Name}");
+            }
+
+            K component = ComponentFactory.CreateWithParent<K, P1, P2, P3>(this, p1, p2, p3, this.IsFromPool);
+
+            this.componentDict.Add(type, component);
+
+            if (component is ISerializeToEntity)
+            {
+                this.components.Add(component);
+            }
+
+            return component;
+        }
+
+        public virtual void RemoveComponent<K>() where K : Component
+        {
+            if (this.IsDisposed)
+            {
+                return;
+            }
+            Type type = typeof(K);
+            Component component;
+            if (!this.componentDict.TryGetValue(type, out component))
+            {
+                return;
+            }
+
+            this.componentDict.Remove(type);
+            this.components.Remove(component);
+
+            component.Dispose();
+        }
+
+        public virtual void RemoveComponent(Type type)
+        {
+            if (this.IsDisposed)
+            {
+                return;
+            }
+            Component component;
+            if (!this.componentDict.TryGetValue(type, out component))
+            {
+                return;
+            }
+
+            this.componentDict.Remove(type);
+            this.components.Remove(component);
+
+            component.Dispose();
+        }
+
+        public K GetComponent<K>() where K : Component
+        {
+            Component component;
+            if (!this.componentDict.TryGetValue(typeof(K), out component))
+            {
+                return default(K);
+            }
+            return (K)component;
+        }
+
+        public Component GetComponent(Type type)
+        {
+            Component component;
+            if (!this.componentDict.TryGetValue(type, out component))
+            {
+                return null;
+            }
+            return component;
+        }
+
+        public Component[] GetComponents()
+        {
+            return this.componentDict.Values.ToArray();
+        }
+
+        public override void EndInit()
+        {
+            try
+            {
+                base.EndInit();
+
+                this.componentDict.Clear();
+
+                if (this.components != null)
+                {
+                    foreach (Component component in this.components)
+                    {
+                        component.Parent = this;
+                        this.componentDict.Add(component.GetType(), component);
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+                Log.Error(e);
+            }
+        }
+    }
+}

+ 15 - 0
KYFramework/Core/Base/Object/EntityEventAttribute.cs

@@ -0,0 +1,15 @@
+using System;
+
+namespace KYFramework
+{
+    [AttributeUsage(AttributeTargets.Class,AllowMultiple =true)]
+    public class EntityEventAttribute : Attribute
+    {
+        public int ClassType;
+
+        public EntityEventAttribute(int classType)
+        {
+            this.ClassType = classType;
+        }
+    }
+}

+ 680 - 0
KYFramework/Core/Base/Object/EventSystem.cs

@@ -0,0 +1,680 @@
+using System.Reflection;
+using Cysharp.Threading.Tasks;
+
+namespace KYFramework
+{
+    public sealed class EventSystem
+    {
+        private readonly Dictionary<long, Component> allComponents = new Dictionary<long, Component>();
+        private readonly UnOrderMultiMap<Type, Type> types = new UnOrderMultiMap<Type, Type>();
+        private readonly Dictionary<Type, List<EventInfo>> allEvents = new Dictionary<Type, List<EventInfo>>();
+        private Dictionary<Type, Dictionary<int, object>> allInvokes = new();
+
+        private readonly UnOrderMultiMap<Type, IAwakeSystem> awakeSystems = new UnOrderMultiMap<Type, IAwakeSystem>();
+
+        private readonly UnOrderMultiMap<Type, IStartSystem> startSystems = new UnOrderMultiMap<Type, IStartSystem>();
+
+        private readonly UnOrderMultiMap<Type, IDestroySystem> destroySystems =
+            new UnOrderMultiMap<Type, IDestroySystem>();
+
+        private readonly UnOrderMultiMap<Type, ILoadSystem> loadSystems = new UnOrderMultiMap<Type, ILoadSystem>();
+
+        private readonly UnOrderMultiMap<Type, IUpdateSystem>
+            updateSystems = new UnOrderMultiMap<Type, IUpdateSystem>();
+
+        private readonly UnOrderMultiMap<Type, ILateUpdateSystem> lateUpdateSystems =
+            new UnOrderMultiMap<Type, ILateUpdateSystem>();
+
+        private readonly UnOrderMultiMap<Type, IChangeSystem>
+            changeSystems = new UnOrderMultiMap<Type, IChangeSystem>();
+
+        private readonly UnOrderMultiMap<Type, IDeserializeSystem> deserializeSystems =
+            new UnOrderMultiMap<Type, IDeserializeSystem>();
+
+        private Queue<long> updates = new Queue<long>();
+        private Queue<long> updates2 = new Queue<long>();
+
+        private readonly Queue<long> starts = new Queue<long>();
+
+        private Queue<long> loaders = new Queue<long>();
+        private Queue<long> loaders2 = new Queue<long>();
+
+        private Queue<long> lateUpdates = new Queue<long>();
+        private Queue<long> lateUpdates2 = new Queue<long>();
+
+        public List<Assembly> assemblies = new List<Assembly>();
+
+        public void Add(Assembly assembly)
+        {
+            this.assemblies.Add(assembly);
+            this.types.Clear();
+            foreach (Assembly assembly1 in assemblies)
+            {
+                foreach (Type type in assembly1.GetTypes())
+                {
+                    object[] objects = type.GetCustomAttributes(typeof(BaseAttribute), false);
+                    if (objects.Length == 0) continue;
+                    BaseAttribute baseAttribute = (BaseAttribute)objects[0];
+                    this.types.Add(baseAttribute.AttributeType, type);
+                }
+            }
+
+            this.awakeSystems.Clear();
+            this.lateUpdateSystems.Clear();
+            this.updateSystems.Clear();
+            this.startSystems.Clear();
+            this.loadSystems.Clear();
+            this.changeSystems.Clear();
+            this.destroySystems.Clear();
+            this.deserializeSystems.Clear();
+
+            if (types.ContainsKey(typeof(ObjectSystemAttribute)))
+            {
+                foreach (Type type in types[typeof(ObjectSystemAttribute)])
+                {
+                    object[] attrs = type.GetCustomAttributes(typeof(ObjectSystemAttribute), false);
+
+                    if (attrs.Length == 0)
+                    {
+                        continue;
+                    }
+
+                    object obj = Activator.CreateInstance(type);
+                    switch (obj)
+                    {
+                        case IAwakeSystem objectSystem:
+                            this.awakeSystems.Add(objectSystem.Type(), objectSystem);
+                            break;
+                        case IUpdateSystem updateSystem:
+                            this.updateSystems.Add(updateSystem.Type(), updateSystem);
+                            break;
+                        case ILateUpdateSystem lateUpdateSystem:
+                            this.lateUpdateSystems.Add(lateUpdateSystem.Type(), lateUpdateSystem);
+                            break;
+                        case IStartSystem startSystem:
+                            this.startSystems.Add(startSystem.Type(), startSystem);
+                            break;
+                        case IDestroySystem destroySystem:
+                            this.destroySystems.Add(destroySystem.Type(), destroySystem);
+                            break;
+                        case ILoadSystem loadSystem:
+                            this.loadSystems.Add(loadSystem.Type(), loadSystem);
+                            break;
+                        case IChangeSystem changeSystem:
+                            this.changeSystems.Add(changeSystem.Type(), changeSystem);
+                            break;
+                        case IDeserializeSystem deserializeSystem:
+                            this.deserializeSystems.Add(deserializeSystem.Type(), deserializeSystem);
+                            break;
+                    }
+                }
+            }
+
+            this.allEvents.Clear();
+            if (types.ContainsKey(typeof(EventAttribute)))
+            {
+                foreach (Type type in types[typeof(EventAttribute)])
+                {
+                    IEvent obj = Activator.CreateInstance(type) as IEvent;
+                    if (obj == null)
+                    {
+                        throw new Exception($"type not is AEvent: {type.Name}");
+                    }
+
+                    object[] attrs = type.GetCustomAttributes(typeof(EventAttribute), false);
+                    foreach (object attr in attrs)
+                    {
+                        EventAttribute eventAttribute = attr as EventAttribute;
+
+                        Type eventType = obj.GetEventType();
+
+                        EventInfo eventInfo = new(obj);
+
+                        if (!this.allEvents.ContainsKey(eventType))
+                        {
+                            this.allEvents.Add(eventType, new List<EventInfo>());
+                        }
+
+                        this.allEvents[eventType].Add(eventInfo);
+                    }
+                }
+            }
+
+            this.allInvokes = new Dictionary<Type, Dictionary<int, object>>();
+            if (types.ContainsKey(typeof(InvokeAttribute)))
+            {
+                foreach (Type type in types[typeof(InvokeAttribute)])
+                {
+                    object obj = Activator.CreateInstance(type);
+                    IInvoke iInvoke = obj as IInvoke;
+                    if (iInvoke == null)
+                    {
+                        throw new Exception($"type not is callback: {type.Name}");
+                    }
+
+                    object[] attrs = type.GetCustomAttributes(typeof(InvokeAttribute), false);
+                    foreach (object attr in attrs)
+                    {
+                        if (!this.allInvokes.TryGetValue(iInvoke.Type, out var dict))
+                        {
+                            dict = new Dictionary<int, object>();
+                            this.allInvokes.Add(iInvoke.Type, dict);
+                        }
+
+                        InvokeAttribute invokeAttribute = attr as InvokeAttribute;
+
+                        try
+                        {
+                            dict.Add(invokeAttribute.Type, obj);
+                        }
+                        catch (Exception e)
+                        {
+                            throw new Exception($"action type duplicate: {iInvoke.Type.Name} {invokeAttribute.Type}",
+                                e);
+                        }
+                    }
+                }
+            }
+
+
+            this.Load();
+        }
+
+        private class EventInfo
+        {
+            public IEvent IEvent { get; }
+
+
+            public EventInfo(IEvent iEvent)
+            {
+                this.IEvent = iEvent;
+            }
+        }
+
+
+        public List<Type> GetTypes(Type systemAttributeType)
+        {
+            if (!this.types.ContainsKey(systemAttributeType))
+            {
+                return new List<Type>();
+            }
+
+            return this.types[systemAttributeType];
+        }
+
+        public void Add(Component component)
+        {
+            this.allComponents.Add(component.InstanceId, component);
+
+            Type type = component.GetType();
+
+            if (this.loadSystems.ContainsKey(type))
+            {
+                this.loaders.Enqueue(component.InstanceId);
+            }
+
+            if (this.updateSystems.ContainsKey(type))
+            {
+                this.updates.Enqueue(component.InstanceId);
+            }
+
+            if (this.startSystems.ContainsKey(type))
+            {
+                this.starts.Enqueue(component.InstanceId);
+            }
+
+            if (this.lateUpdateSystems.ContainsKey(type))
+            {
+                this.lateUpdates.Enqueue(component.InstanceId);
+            }
+        }
+
+        public void Remove(long instanceId)
+        {
+            this.allComponents.Remove(instanceId);
+        }
+
+        public Component Get(long instanceId)
+        {
+            Component component = null;
+            this.allComponents.TryGetValue(instanceId, out component);
+            return component;
+        }
+
+        public void Deserialize(Component component)
+        {
+            List<IDeserializeSystem> iDeserializeSystems = this.deserializeSystems[component.GetType()];
+            if (iDeserializeSystems == null)
+            {
+                return;
+            }
+
+            foreach (IDeserializeSystem deserializeSystem in iDeserializeSystems)
+            {
+                if (deserializeSystem == null)
+                {
+                    continue;
+                }
+
+                try
+                {
+                    deserializeSystem.Run(component);
+                }
+                catch (Exception e)
+                {
+                    Log.Error(e);
+                }
+            }
+        }
+
+        public void Awake(Component component)
+        {
+            List<IAwakeSystem> iAwakeSystems = this.awakeSystems[component.GetType()];
+            if (iAwakeSystems == null)
+            {
+                return;
+            }
+
+            foreach (IAwakeSystem aAwakeSystem in iAwakeSystems)
+            {
+                if (aAwakeSystem == null)
+                {
+                    continue;
+                }
+
+                IAwake iAwake = aAwakeSystem as IAwake;
+                if (iAwake == null)
+                {
+                    continue;
+                }
+
+                try
+                {
+                    iAwake.Run(component);
+                }
+                catch (Exception e)
+                {
+                    Log.Error(e);
+                }
+            }
+        }
+
+        public void Awake<P1>(Component component, P1 p1)
+        {
+            List<IAwakeSystem> iAwakeSystems = this.awakeSystems[component.GetType()];
+            if (iAwakeSystems == null)
+            {
+                return;
+            }
+
+            foreach (IAwakeSystem aAwakeSystem in iAwakeSystems)
+            {
+                if (aAwakeSystem == null)
+                {
+                    continue;
+                }
+
+                IAwake<P1> iAwake = aAwakeSystem as IAwake<P1>;
+                if (iAwake == null)
+                {
+                    continue;
+                }
+
+                try
+                {
+                    iAwake.Run(component, p1);
+                }
+                catch (Exception e)
+                {
+                    Log.Error(e);
+                }
+            }
+        }
+
+        public void Awake<P1, P2>(Component component, P1 p1, P2 p2)
+        {
+            List<IAwakeSystem> iAwakeSystems = this.awakeSystems[component.GetType()];
+            if (iAwakeSystems == null)
+            {
+                return;
+            }
+
+            foreach (IAwakeSystem aAwakeSystem in iAwakeSystems)
+            {
+                if (aAwakeSystem == null)
+                {
+                    continue;
+                }
+
+                IAwake<P1, P2> iAwake = aAwakeSystem as IAwake<P1, P2>;
+                if (iAwake == null)
+                {
+                    continue;
+                }
+
+                try
+                {
+                    iAwake.Run(component, p1, p2);
+                }
+                catch (Exception e)
+                {
+                    Log.Error(e);
+                }
+            }
+        }
+
+        public void Awake<P1, P2, P3>(Component component, P1 p1, P2 p2, P3 p3)
+        {
+            List<IAwakeSystem> iAwakeSystems = this.awakeSystems[component.GetType()];
+            if (iAwakeSystems == null)
+            {
+                return;
+            }
+
+            foreach (IAwakeSystem aAwakeSystem in iAwakeSystems)
+            {
+                if (aAwakeSystem == null)
+                {
+                    continue;
+                }
+
+                IAwake<P1, P2, P3> iAwake = aAwakeSystem as IAwake<P1, P2, P3>;
+                if (iAwake == null)
+                {
+                    continue;
+                }
+
+                try
+                {
+                    iAwake.Run(component, p1, p2, p3);
+                }
+                catch (Exception e)
+                {
+                    Log.Error(e);
+                }
+            }
+        }
+
+        public void Change(Component component)
+        {
+            List<IChangeSystem> iChangeSystems = this.changeSystems[component.GetType()];
+            if (iChangeSystems == null)
+            {
+                return;
+            }
+
+            foreach (IChangeSystem iChangeSystem in iChangeSystems)
+            {
+                if (iChangeSystem == null)
+                {
+                    continue;
+                }
+
+                try
+                {
+                    iChangeSystem.Run(component);
+                }
+                catch (Exception e)
+                {
+                    Log.Error(e);
+                }
+            }
+        }
+
+        public void Load()
+        {
+            while (this.loaders.Count > 0)
+            {
+                long instanceId = this.loaders.Dequeue();
+                Component component;
+                if (!this.allComponents.TryGetValue(instanceId, out component))
+                {
+                    continue;
+                }
+
+                if (component.IsDisposed)
+                {
+                    continue;
+                }
+
+                List<ILoadSystem> iLoadSystems = this.loadSystems[component.GetType()];
+                if (iLoadSystems == null)
+                {
+                    continue;
+                }
+
+                this.loaders2.Enqueue(instanceId);
+
+                foreach (ILoadSystem iLoadSystem in iLoadSystems)
+                {
+                    try
+                    {
+                        iLoadSystem.Run(component);
+                    }
+                    catch (Exception e)
+                    {
+                        Log.Error(e);
+                    }
+                }
+            }
+
+            ObjectHelper.Swap(ref this.loaders, ref this.loaders2);
+        }
+
+        private void Start()
+        {
+            while (this.starts.Count > 0)
+            {
+                long instanceId = this.starts.Dequeue();
+                Component component;
+                if (!this.allComponents.TryGetValue(instanceId, out component))
+                {
+                    continue;
+                }
+
+                List<IStartSystem> iStartSystems = this.startSystems[component.GetType()];
+                if (iStartSystems == null)
+                {
+                    continue;
+                }
+
+                foreach (IStartSystem iStartSystem in iStartSystems)
+                {
+                    try
+                    {
+                        iStartSystem.Run(component);
+                    }
+                    catch (Exception e)
+                    {
+                        Log.Error(e);
+                    }
+                }
+            }
+        }
+
+        public void Destroy(Component component)
+        {
+            List<IDestroySystem> iDestroySystems = this.destroySystems[component.GetType()];
+            if (iDestroySystems == null)
+            {
+                return;
+            }
+
+            foreach (IDestroySystem iDestroySystem in iDestroySystems)
+            {
+                if (iDestroySystem == null)
+                {
+                    continue;
+                }
+
+                try
+                {
+                    iDestroySystem.Run(component);
+                }
+                catch (Exception e)
+                {
+                    Log.Error(e);
+                }
+            }
+        }
+
+        public void Update()
+        {
+            this.Start();
+
+            while (this.updates.Count > 0)
+            {
+                long instanceId = this.updates.Dequeue();
+                Component component;
+                if (!this.allComponents.TryGetValue(instanceId, out component))
+                {
+                    continue;
+                }
+
+                if (component.IsDisposed)
+                {
+                    continue;
+                }
+
+                List<IUpdateSystem> iUpdateSystems = this.updateSystems[component.GetType()];
+                if (iUpdateSystems == null)
+                {
+                    continue;
+                }
+
+                this.updates2.Enqueue(instanceId);
+
+                foreach (IUpdateSystem iUpdateSystem in iUpdateSystems)
+                {
+                    try
+                    {
+                        iUpdateSystem.Run(component);
+                    }
+                    catch (Exception e)
+                    {
+                        Log.Error(e);
+                    }
+                }
+            }
+
+            ObjectHelper.Swap(ref this.updates, ref this.updates2);
+        }
+
+        public void LateUpdate()
+        {
+            while (this.lateUpdates.Count > 0)
+            {
+                long instanceId = this.lateUpdates.Dequeue();
+                Component component;
+                if (!this.allComponents.TryGetValue(instanceId, out component))
+                {
+                    continue;
+                }
+
+                if (component.IsDisposed)
+                {
+                    continue;
+                }
+
+                List<ILateUpdateSystem> iLateUpdateSystems = this.lateUpdateSystems[component.GetType()];
+                if (iLateUpdateSystems == null)
+                {
+                    continue;
+                }
+
+                this.lateUpdates2.Enqueue(instanceId);
+
+                foreach (ILateUpdateSystem iLateUpdateSystem in iLateUpdateSystems)
+                {
+                    try
+                    {
+                        iLateUpdateSystem.Run(component);
+                    }
+                    catch (Exception e)
+                    {
+                        Log.Error(e);
+                    }
+                }
+            }
+
+            ObjectHelper.Swap(ref this.lateUpdates, ref this.lateUpdates2);
+        }
+
+        public void Publish<T>(T a) where T : struct
+        {
+            List<EventInfo> iEvents;
+            if (!this.allEvents.TryGetValue(typeof(T), out iEvents))
+            {
+                return;
+            }
+
+            foreach (EventInfo eventInfo in iEvents)
+            {
+                if (!(eventInfo.IEvent is AEvent<T> aEvent))
+                {
+                    Log.Error($"event error: {eventInfo.IEvent.GetType().Name}");
+                    continue;
+                }
+
+                aEvent.Handle(a).Forget();
+            }
+        }
+
+        // Invoke跟Publish的区别(特别注意)
+        // Invoke类似函数,必须有被调用方,否则异常,调用者跟被调用者属于同一模块,比如MoveComponent中的Timer计时器,调用跟被调用的代码均属于移动模块
+        // 既然Invoke跟函数一样,那么为什么不使用函数呢? 因为有时候不方便直接调用,比如Config加载,在客户端跟服务端加载方式不一样。比如TimerComponent需要根据Id分发
+        // 注意,不要把Invoke当函数使用,这样会造成代码可读性降低,能用函数不要用Invoke
+        // publish是事件,抛出去可以没人订阅,调用者跟被调用者属于两个模块,比如任务系统需要知道道具使用的信息,则订阅道具使用事件
+        public void Invoke<A>(int type, A args) where A : struct
+        {
+            if (!this.allInvokes.TryGetValue(typeof(A), out var invokeHandlers))
+            {
+                throw new Exception($"Invoke error: {typeof(A).Name}");
+            }
+
+            if (!invokeHandlers.TryGetValue(type, out var invokeHandler))
+            {
+                throw new Exception($"Invoke error: {typeof(A).Name} {type}");
+            }
+
+            var aInvokeHandler = invokeHandler as AInvokeHandler<A>;
+            if (aInvokeHandler == null)
+            {
+                throw new Exception($"Invoke error, not AInvokeHandler: {typeof(A).Name} {type}");
+            }
+
+            aInvokeHandler.Handle(args);
+        }
+
+        public T Invoke<A, T>(int type, A args) where A : struct
+        {
+            if (!this.allInvokes.TryGetValue(typeof(A), out var invokeHandlers))
+            {
+                throw new Exception($"Invoke error: {typeof(A).Name}");
+            }
+
+            if (!invokeHandlers.TryGetValue(type, out var invokeHandler))
+            {
+                throw new Exception($"Invoke error: {typeof(A).Name} {type}");
+            }
+
+            var aInvokeHandler = invokeHandler as AInvokeHandler<A, T>;
+            if (aInvokeHandler == null)
+            {
+                throw new Exception($"Invoke error, not AInvokeHandler: {typeof(T).Name} {type}");
+            }
+
+            return aInvokeHandler.Handle(args);
+        }
+
+        public void Invoke<A>(A args) where A : struct
+        {
+            Invoke(0, args);
+        }
+
+        public T Invoke<A, T>(A args) where A : struct
+        {
+            return Invoke<A, T>(0, args);
+        }
+    }
+}

+ 8 - 0
KYFramework/Core/Base/Object/HideInHierarchy.cs

@@ -0,0 +1,8 @@
+using System;
+
+namespace KYFramework
+{
+    public class HideInHierarchy : Attribute
+    {
+    }
+}

+ 90 - 0
KYFramework/Core/Base/Object/IAwakeSystem.cs

@@ -0,0 +1,90 @@
+
+using System;
+
+namespace KYFramework
+{
+    public interface IAwakeSystem
+    {
+        Type Type();
+    }
+
+    public interface IAwake
+    {
+        void Run(object o);
+    }
+
+    public interface IAwake<A>
+    {
+        void Run(object o, A a);
+    }
+
+    public interface IAwake<A, B>
+    {
+        void Run(object o, A a, B b);
+    }
+
+    public interface IAwake<A, B, C>
+    {
+        void Run(object o, A a, B b, C c);
+    }
+
+    public abstract class AwakeSystem<T> : IAwakeSystem, IAwake
+    {
+        public Type Type()
+        {
+            return typeof(T);
+        }
+
+        public void Run(object o)
+        {
+            this.Awake((T)o);
+        }
+
+        public abstract void Awake(T self);
+    }
+
+    public abstract class AwakeSystem<T, A> : IAwakeSystem, IAwake<A>
+    {
+        public Type Type()
+        {
+            return typeof(T);
+        }
+
+        public void Run(object o, A a)
+        {
+            this.Awake((T)o, a);
+        }
+
+        public abstract void Awake(T self, A worldInitSo);
+    }
+
+    public abstract class AwakeSystem<T, A, B> : IAwakeSystem, IAwake<A, B>
+    {
+        public Type Type()
+        {
+            return typeof(T);
+        }
+
+        public void Run(object o, A a, B b)
+        {
+            this.Awake((T)o, a, b);
+        }
+
+        public abstract void Awake(T self, A a, B b);
+    }
+
+    public abstract class AwakeSystem<T, A, B, C> : IAwakeSystem, IAwake<A, B, C>
+    {
+        public Type Type()
+        {
+            return typeof(T);
+        }
+
+        public void Run(object o, A a, B b, C c)
+        {
+            this.Awake((T)o, a, b, c);
+        }
+
+        public abstract void Awake(T self, A a, B b, C c);
+    }
+}

+ 26 - 0
KYFramework/Core/Base/Object/IChangeSystem.cs

@@ -0,0 +1,26 @@
+
+using System;
+
+namespace KYFramework
+{
+    public interface IChangeSystem
+    {
+        Type Type();
+        void Run(object o);
+    }
+
+    public abstract class ChangeSystem<T> : IChangeSystem
+    {
+        public void Run(object o)
+        {
+            this.Change((T)o);
+        }
+
+        public Type Type()
+        {
+            return typeof(T);
+        }
+
+        public abstract void Change(T self);
+    }
+}

+ 31 - 0
KYFramework/Core/Base/Object/IDeserializeSystem.cs

@@ -0,0 +1,31 @@
+
+using System;
+
+namespace KYFramework
+{
+    public interface IDeserializeSystem
+    {
+        Type Type();
+        void Run(object o);
+    }
+
+    /// <summary>
+    /// 反序列化后执行的System
+    /// 要小心使用这个System,因为对象假如要保存到数据库,到dbserver也会进行反序列化,那么也会执行该System
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public abstract class DeserializeSystem<T> : IDeserializeSystem
+    {
+        public void Run(object o)
+        {
+            this.Deserialize((T)o);
+        }
+
+        public Type Type()
+        {
+            return typeof(T);
+        }
+
+        public abstract void Deserialize(T self);
+    }
+}

+ 25 - 0
KYFramework/Core/Base/Object/IDestroySystem.cs

@@ -0,0 +1,25 @@
+using System;
+
+namespace KYFramework
+{
+    public interface IDestroySystem
+    {
+        Type Type();
+        void Run(object o);
+    }
+
+    public abstract class DestroySystem<T> : IDestroySystem
+    {
+        public void Run(object o)
+        {
+            this.Destroy((T)o);
+        }
+
+        public Type Type()
+        {
+            return typeof(T);
+        }
+
+        public abstract void Destroy(T self);
+    }
+}

+ 25 - 0
KYFramework/Core/Base/Object/ILateUpdateSystem.cs

@@ -0,0 +1,25 @@
+using System;
+
+namespace KYFramework
+{
+    public interface ILateUpdateSystem
+    {
+        Type Type();
+        void Run(object o);
+    }
+
+    public abstract class LateUpdateSystem<T> : ILateUpdateSystem
+    {
+        public void Run(object o)
+        {
+            this.LateUpdate((T)o);
+        }
+
+        public Type Type()
+        {
+            return typeof(T);
+        }
+
+        public abstract void LateUpdate(T self);
+    }
+}

+ 25 - 0
KYFramework/Core/Base/Object/ILoadSystem.cs

@@ -0,0 +1,25 @@
+using System;
+
+namespace KYFramework
+{
+    public interface ILoadSystem
+    {
+        Type Type();
+        void Run(object o);
+    }
+
+    public abstract class LoadSystem<T> : ILoadSystem
+    {
+        public void Run(object o)
+        {
+            this.Load((T)o);
+        }
+
+        public Type Type()
+        {
+            return typeof(T);
+        }
+
+        public abstract void Load(T self);
+    }
+}

+ 6 - 0
KYFramework/Core/Base/Object/ISerializeToEntity.cs

@@ -0,0 +1,6 @@
+namespace KYFramework
+{
+    public interface ISerializeToEntity
+    {
+    }
+}

+ 25 - 0
KYFramework/Core/Base/Object/IStartSystem.cs

@@ -0,0 +1,25 @@
+using System;
+
+namespace KYFramework
+{
+    public interface IStartSystem
+    {
+        Type Type();
+        void Run(object o);
+    }
+
+    public abstract class StartSystem<T> : IStartSystem
+    {
+        public void Run(object o)
+        {
+            this.Start((T)o);
+        }
+
+        public Type Type()
+        {
+            return typeof(T);
+        }
+
+        public abstract void Start(T self);
+    }
+}

+ 25 - 0
KYFramework/Core/Base/Object/IUpdateSystem.cs

@@ -0,0 +1,25 @@
+using System;
+
+namespace KYFramework
+{
+    public interface IUpdateSystem
+    {
+        Type Type();
+        void Run(object o);
+    }
+
+    public abstract class UpdateSystem<T> : IUpdateSystem
+    {
+        public void Run(object o)
+        {
+            this.Update((T)o);
+        }
+
+        public Type Type()
+        {
+            return typeof(T);
+        }
+
+        public abstract void Update(T self);
+    }
+}

+ 17 - 0
KYFramework/Core/Base/Object/Object.cs

@@ -0,0 +1,17 @@
+using System.ComponentModel;
+
+namespace KYFramework
+{
+    public abstract class Object : ISupportInitialize
+    {
+        public virtual void BeginInit()
+        {
+           
+        }
+
+        public virtual void EndInit()
+        {
+            
+        }
+    }
+}

+ 100 - 0
KYFramework/Core/Base/Object/ObjectPool.cs

@@ -0,0 +1,100 @@
+using System;
+using System.Collections.Generic;
+
+namespace KYFramework
+{
+    public class ComponentQueue : Component
+    {
+        public string TypeName { get; }
+
+        private readonly Queue<Component> queue = new Queue<Component>();
+
+        public ComponentQueue(string typeName)
+        {
+            this.TypeName = typeName;
+        }
+
+        public void Enqueue(Component component)
+        {
+            component.Parent = this;
+            this.queue.Enqueue(component);
+        }
+
+        public Component Dequeue()
+        {
+            return this.queue.Dequeue();
+        }
+
+        public Component Peek()
+        {
+            return this.queue.Peek();
+        }
+
+        public int Count
+        {
+            get
+            {
+                return this.queue.Count;
+            }
+        }
+
+        public override void Dispose()
+        {
+            if (this.IsDisposed)
+            {
+                return;
+            }
+            base.Dispose();
+
+            while (this.queue.Count > 0)
+            {
+                Component component = this.queue.Dequeue();
+                component.IsFromPool = false;
+                component.Dispose();
+            }
+        }
+    }
+
+    public class ObjectPool : Component
+    {
+        private readonly Dictionary<Type, Queue<object>> pool = new Dictionary<Type, Queue<object>>();
+        
+        public T Fetch<T>() where T: class
+        {
+            return this.Fetch(typeof (T)) as T;
+        }
+
+        public object Fetch(Type type)
+        {
+            Queue<object> queue = null;
+            if (!pool.TryGetValue(type, out queue))
+            {
+                return Activator.CreateInstance(type);
+            }
+
+            if (queue.Count == 0)
+            {
+                return Activator.CreateInstance(type);
+            }
+            return queue.Dequeue();
+        }
+
+        public void Recycle(object obj)
+        {
+            Type type = obj.GetType();
+            Queue<object> queue = null;
+            if (!pool.TryGetValue(type, out queue))
+            {
+                queue = new Queue<object>();
+                pool.Add(type, queue);
+            }
+
+            // 一种对象最大为1000个
+            if (queue.Count > 1000)
+            {
+                return;
+            }
+            queue.Enqueue(obj);
+        }
+    }
+}

+ 9 - 0
KYFramework/Core/Base/Object/ObjectSystemAttribute.cs

@@ -0,0 +1,9 @@
+using System;
+
+namespace KYFramework
+{
+    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+    public class ObjectSystemAttribute : BaseAttribute
+    {
+    }
+}

+ 41 - 0
KYFramework/Core/Base/OneThreadSynchronizationContext.cs

@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Concurrent;
+using System.Threading;
+
+namespace KYFramework
+{
+    public class OneThreadSynchronizationContext : SynchronizationContext
+    {
+        public static OneThreadSynchronizationContext Instance { get; } = new OneThreadSynchronizationContext();
+
+        private readonly int mainThreadId = Thread.CurrentThread.ManagedThreadId;
+
+        // 线程同步队列,发送接收socket回调都放到该队列,由poll线程统一执行
+        private readonly ConcurrentQueue<Action> queue = new ConcurrentQueue<Action>();
+
+        private Action a;
+
+        public void Update()
+        {
+            while (true)
+            {
+                if (!this.queue.TryDequeue(out a))
+                {
+                    return;
+                }
+                a();
+            }
+        }
+
+        public override void Post(SendOrPostCallback callback, object state)
+        {
+            if (Thread.CurrentThread.ManagedThreadId == this.mainThreadId)
+            {
+                callback(state);
+                return;
+            }
+
+            this.queue.Enqueue(() => { callback(state); });
+        }
+    }
+}

+ 205 - 0
KYFramework/Core/Base/RecyclableMemoryStreamManager/Events.cs

@@ -0,0 +1,205 @@
+// ---------------------------------------------------------------------
+// Copyright (c) 2015 Microsoft
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+// ---------------------------------------------------------------------
+
+namespace Microsoft.IO
+{
+    using System;
+    using System.Diagnostics.Tracing;
+
+    public sealed partial class RecyclableMemoryStreamManager
+    {
+        [EventSource(Name = "Microsoft-IO-RecyclableMemoryStream", Guid = "{B80CD4E4-890E-468D-9CBA-90EB7C82DFC7}")]
+        public sealed class Events : EventSource
+        {
+            public static Events Writer = new Events();
+
+            public enum MemoryStreamBufferType
+            {
+                Small,
+                Large
+            }
+
+            public enum MemoryStreamDiscardReason
+            {
+                TooLarge,
+                EnoughFree
+            }
+
+            [Event(1, Level = EventLevel.Verbose)]
+            public void MemoryStreamCreated(Guid guid, string tag, int requestedSize)
+            {
+                if (this.IsEnabled(EventLevel.Verbose, EventKeywords.None))
+                {
+                    WriteEvent(1, guid, tag ?? string.Empty, requestedSize);
+                }
+            }
+
+            [Event(2, Level = EventLevel.Verbose)]
+            public void MemoryStreamDisposed(Guid guid, string tag)
+            {
+                if (this.IsEnabled(EventLevel.Verbose, EventKeywords.None))
+                {
+                    WriteEvent(2, guid, tag ?? string.Empty);
+                }
+            }
+
+            [Event(3, Level = EventLevel.Critical)]
+            public void MemoryStreamDoubleDispose(Guid guid, string tag, string allocationStack, string disposeStack1,
+                                                  string disposeStack2)
+            {
+                if (this.IsEnabled())
+                {
+                    this.WriteEvent(3, guid, tag ?? string.Empty, allocationStack ?? string.Empty,
+                                    disposeStack1 ?? string.Empty, disposeStack2 ?? string.Empty);
+                }
+            }
+
+            [Event(4, Level = EventLevel.Error)]
+            public void MemoryStreamFinalized(Guid guid, string tag, string allocationStack)
+            {
+                if (this.IsEnabled())
+                {
+                    WriteEvent(4, guid, tag ?? string.Empty, allocationStack ?? string.Empty);
+                }
+            }
+
+            [Event(5, Level = EventLevel.Verbose)]
+            public void MemoryStreamToArray(Guid guid, string tag, string stack, int size)
+            {
+                if (this.IsEnabled(EventLevel.Verbose, EventKeywords.None))
+                {
+                    WriteEvent(5, guid, tag ?? string.Empty, stack ?? string.Empty, size);
+                }
+            }
+
+            [Event(6, Level = EventLevel.Informational)]
+            public void MemoryStreamManagerInitialized(int blockSize, int largeBufferMultiple, int maximumBufferSize)
+            {
+                if (this.IsEnabled())
+                {
+                    WriteEvent(6, blockSize, largeBufferMultiple, maximumBufferSize);
+                }
+            }
+
+            [Event(7, Level = EventLevel.Verbose)]
+            public void MemoryStreamNewBlockCreated(long smallPoolInUseBytes)
+            {
+                if (this.IsEnabled(EventLevel.Verbose, EventKeywords.None))
+                {
+                    WriteEvent(7, smallPoolInUseBytes);
+                }
+            }
+
+            [Event(8, Level = EventLevel.Verbose)]
+            public void MemoryStreamNewLargeBufferCreated(int requiredSize, long largePoolInUseBytes)
+            {
+                if (this.IsEnabled(EventLevel.Verbose, EventKeywords.None))
+                {
+                    WriteEvent(8, requiredSize, largePoolInUseBytes);
+                }
+            }
+
+            [Event(9, Level = EventLevel.Verbose)]
+            public void MemoryStreamNonPooledLargeBufferCreated(int requiredSize, string tag, string allocationStack)
+            {
+                if (this.IsEnabled(EventLevel.Verbose, EventKeywords.None))
+                {
+                    WriteEvent(9, requiredSize, tag ?? string.Empty, allocationStack ?? string.Empty);
+                }
+            }
+
+            [Event(10, Level = EventLevel.Warning)]
+            public void MemoryStreamDiscardBuffer(MemoryStreamBufferType bufferType, string tag,
+                                                  MemoryStreamDiscardReason reason)
+            {
+                if (this.IsEnabled())
+                {
+                    WriteEvent(10, bufferType, tag ?? string.Empty, reason);
+                }
+            }
+
+            [Event(11, Level = EventLevel.Error)]
+            public void MemoryStreamOverCapacity(int requestedCapacity, long maxCapacity, string tag,
+                                                 string allocationStack)
+            {
+                if (this.IsEnabled())
+                {
+                    WriteEvent(11, requestedCapacity, maxCapacity, tag ?? string.Empty, allocationStack ?? string.Empty);
+                }
+            }
+        }
+    }
+}
+
+// This is here for .NET frameworks which don't support EventSource. We basically shim bare functionality used above to  
+#if NET40
+namespace System.Diagnostics.Tracing
+{
+    public enum EventLevel
+    {
+        LogAlways = 0,
+        Critical,
+        Error,
+        Warning,
+        Informational,
+        Verbose,
+    }
+
+    public enum EventKeywords : long
+    {
+        None = 0x0,
+    }
+
+    [AttributeUsage(AttributeTargets.Class)]
+    public sealed class EventSourceAttribute : Attribute
+    {
+        public string Name { get; set; }
+        public string Guid { get; set; }
+    }
+
+    [AttributeUsage(AttributeTargets.Method)]
+    public sealed class EventAttribute : Attribute
+    {
+        public EventAttribute(int id) { }
+
+        public EventLevel Level { get; set; }
+    }
+
+    public class EventSource
+    {
+        public void WriteEvent(params object[] unused)
+        {
+            return;
+        }
+
+        public bool IsEnabled()
+        {
+            return false;
+        }
+
+        public bool IsEnabled(EventLevel level, EventKeywords keywords)
+        {
+            return false;
+        }
+    }
+}
+#endif

+ 888 - 0
KYFramework/Core/Base/RecyclableMemoryStreamManager/RecyclableMemoryStream.cs

@@ -0,0 +1,888 @@
+// The MIT License (MIT)
+// 
+// Copyright (c) 2015-2016 Microsoft
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+namespace Microsoft.IO
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics.CodeAnalysis;
+    using System.IO;
+    using System.Threading;
+
+    /// <summary>
+    /// MemoryStream implementation that deals with pooling and managing memory streams which use potentially large
+    /// buffers.
+    /// </summary>
+    /// <remarks>
+    /// This class works in tandem with the RecylableMemoryStreamManager to supply MemoryStream
+    /// objects to callers, while avoiding these specific problems:
+    /// 1. LOH allocations - since all large buffers are pooled, they will never incur a Gen2 GC
+    /// 2. Memory waste - A standard memory stream doubles its size when it runs out of room. This
+    /// leads to continual memory growth as each stream approaches the maximum allowed size.
+    /// 3. Memory copying - Each time a MemoryStream grows, all the bytes are copied into new buffers.
+    /// This implementation only copies the bytes when GetBuffer is called.
+    /// 4. Memory fragmentation - By using homogeneous buffer sizes, it ensures that blocks of memory
+    /// can be easily reused.
+    /// 
+    /// The stream is implemented on top of a series of uniformly-sized blocks. As the stream's length grows,
+    /// additional blocks are retrieved from the memory manager. It is these blocks that are pooled, not the stream
+    /// object itself.
+    /// 
+    /// The biggest wrinkle in this implementation is when GetBuffer() is called. This requires a single 
+    /// contiguous buffer. If only a single block is in use, then that block is returned. If multiple blocks 
+    /// are in use, we retrieve a larger buffer from the memory manager. These large buffers are also pooled, 
+    /// split by size--they are multiples of a chunk size (1 MB by default).
+    /// 
+    /// Once a large buffer is assigned to the stream the blocks are NEVER again used for this stream. All operations take place on the 
+    /// large buffer. The large buffer can be replaced by a larger buffer from the pool as needed. All blocks and large buffers 
+    /// are maintained in the stream until the stream is disposed (unless AggressiveBufferReturn is enabled in the stream manager).
+    /// 
+    /// </remarks>
+    public sealed class RecyclableMemoryStream : MemoryStream
+    {
+        private const long MaxStreamLength = Int32.MaxValue;
+
+        private static readonly byte[] emptyArray = new byte[0];
+
+        /// <summary>
+        /// All of these blocks must be the same size
+        /// </summary>
+        private readonly List<byte[]> blocks = new List<byte[]>(1);
+
+        /// <summary>
+        /// This buffer exists so that WriteByte can forward all of its calls to Write
+        /// without creating a new byte[] buffer on every call.
+        /// </summary>
+        private readonly byte[] byteBuffer = new byte[1];
+
+        private readonly Guid id;
+
+        private readonly RecyclableMemoryStreamManager memoryManager;
+
+        private readonly string tag;
+
+        /// <summary>
+        /// This list is used to store buffers once they're replaced by something larger.
+        /// This is for the cases where you have users of this class that may hold onto the buffers longer
+        /// than they should and you want to prevent race conditions which could corrupt the data.
+        /// </summary>
+        private List<byte[]> dirtyBuffers;
+
+        // long to allow Interlocked.Read (for .NET Standard 1.4 compat)
+        private long disposedState;
+
+        /// <summary>
+        /// This is only set by GetBuffer() if the necessary buffer is larger than a single block size, or on
+        /// construction if the caller immediately requests a single large buffer.
+        /// </summary>
+        /// <remarks>If this field is non-null, it contains the concatenation of the bytes found in the individual
+        /// blocks. Once it is created, this (or a larger) largeBuffer will be used for the life of the stream.
+        /// </remarks>
+        private byte[] largeBuffer;
+
+        /// <summary>
+        /// Unique identifier for this stream across it's entire lifetime
+        /// </summary>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        internal Guid Id
+        {
+            get
+            {
+                this.CheckDisposed();
+                return this.id;
+            }
+        }
+
+        /// <summary>
+        /// A temporary identifier for the current usage of this stream.
+        /// </summary>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        internal string Tag
+        {
+            get
+            {
+                this.CheckDisposed();
+                return this.tag;
+            }
+        }
+
+        /// <summary>
+        /// Gets the memory manager being used by this stream.
+        /// </summary>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        internal RecyclableMemoryStreamManager MemoryManager
+        {
+            get
+            {
+                this.CheckDisposed();
+                return this.memoryManager;
+            }
+        }
+
+        /// <summary>
+        /// Callstack of the constructor. It is only set if MemoryManager.GenerateCallStacks is true,
+        /// which should only be in debugging situations.
+        /// </summary>
+        internal string AllocationStack { get; }
+
+        /// <summary>
+        /// Callstack of the Dispose call. It is only set if MemoryManager.GenerateCallStacks is true,
+        /// which should only be in debugging situations.
+        /// </summary>
+        internal string DisposeStack { get; private set; }
+
+        #region Constructors
+        /// <summary>
+        /// Allocate a new RecyclableMemoryStream object.
+        /// </summary>
+        /// <param name="memoryManager">The memory manager</param>
+        public RecyclableMemoryStream(RecyclableMemoryStreamManager memoryManager)
+            : this(memoryManager, null, 0, null) { }
+
+        /// <summary>
+        /// Allocate a new RecyclableMemoryStream object
+        /// </summary>
+        /// <param name="memoryManager">The memory manager</param>
+        /// <param name="tag">A string identifying this stream for logging and debugging purposes</param>
+        public RecyclableMemoryStream(RecyclableMemoryStreamManager memoryManager, string tag)
+            : this(memoryManager, tag, 0, null) { }
+
+        /// <summary>
+        /// Allocate a new RecyclableMemoryStream object
+        /// </summary>
+        /// <param name="memoryManager">The memory manager</param>
+        /// <param name="tag">A string identifying this stream for logging and debugging purposes</param>
+        /// <param name="requestedSize">The initial requested size to prevent future allocations</param>
+        public RecyclableMemoryStream(RecyclableMemoryStreamManager memoryManager, string tag, int requestedSize)
+            : this(memoryManager, tag, requestedSize, null) { }
+
+        /// <summary>
+        /// Allocate a new RecyclableMemoryStream object
+        /// </summary>
+        /// <param name="memoryManager">The memory manager</param>
+        /// <param name="tag">A string identifying this stream for logging and debugging purposes</param>
+        /// <param name="requestedSize">The initial requested size to prevent future allocations</param>
+        /// <param name="initialLargeBuffer">An initial buffer to use. This buffer will be owned by the stream and returned to the memory manager upon Dispose.</param>
+        internal RecyclableMemoryStream(RecyclableMemoryStreamManager memoryManager, string tag, int requestedSize,
+                                        byte[] initialLargeBuffer)
+            : base(emptyArray)
+        {
+            this.memoryManager = memoryManager;
+            this.id = Guid.NewGuid();
+            this.tag = tag;
+
+            if (requestedSize < memoryManager.BlockSize)
+            {
+                requestedSize = memoryManager.BlockSize;
+            }
+
+            if (initialLargeBuffer == null)
+            {
+                this.EnsureCapacity(requestedSize);
+            }
+            else
+            {
+                this.largeBuffer = initialLargeBuffer;
+            }
+
+            if (this.memoryManager.GenerateCallStacks)
+            {
+                this.AllocationStack = Environment.StackTrace;
+            }
+
+            RecyclableMemoryStreamManager.Events.Writer.MemoryStreamCreated(this.id, this.tag, requestedSize);
+            this.memoryManager.ReportStreamCreated();
+        }
+        #endregion
+
+        #region Dispose and Finalize
+        ~RecyclableMemoryStream()
+        {
+            this.Dispose(false);
+        }
+
+        /// <summary>
+        /// Returns the memory used by this stream back to the pool.
+        /// </summary>
+        /// <param name="disposing">Whether we're disposing (true), or being called by the finalizer (false)</param>
+        [SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly",
+            Justification = "We have different disposal semantics, so SuppressFinalize is in a different spot.")]
+        protected override void Dispose(bool disposing)
+        {
+            if (Interlocked.CompareExchange(ref this.disposedState, 1, 0) != 0)
+            {
+                string doubleDisposeStack = null;
+                if (this.memoryManager.GenerateCallStacks)
+                {
+                    doubleDisposeStack = Environment.StackTrace;
+                }
+
+                RecyclableMemoryStreamManager.Events.Writer.MemoryStreamDoubleDispose(this.id, this.tag,
+                                                                                     this.AllocationStack,
+                                                                                     this.DisposeStack,
+                                                                                     doubleDisposeStack);
+                return;
+            }
+
+            RecyclableMemoryStreamManager.Events.Writer.MemoryStreamDisposed(this.id, this.tag);
+
+            if (this.memoryManager.GenerateCallStacks)
+            {
+                this.DisposeStack = Environment.StackTrace;
+            }
+
+            if (disposing)
+            {
+                this.memoryManager.ReportStreamDisposed();
+
+                GC.SuppressFinalize(this);
+            }
+            else
+            {
+                // We're being finalized.
+
+                RecyclableMemoryStreamManager.Events.Writer.MemoryStreamFinalized(this.id, this.tag, this.AllocationStack);
+
+#if !NETSTANDARD1_4
+                if (AppDomain.CurrentDomain.IsFinalizingForUnload())
+                {
+                    // If we're being finalized because of a shutdown, don't go any further.
+                    // We have no idea what's already been cleaned up. Triggering events may cause
+                    // a crash.
+                    base.Dispose(disposing);
+                    return;
+                }
+#endif
+
+                this.memoryManager.ReportStreamFinalized();
+            }
+
+            this.memoryManager.ReportStreamLength(this.length);
+
+            if (this.largeBuffer != null)
+            {
+                this.memoryManager.ReturnLargeBuffer(this.largeBuffer, this.tag);
+            }
+
+            if (this.dirtyBuffers != null)
+            {
+                foreach (var buffer in this.dirtyBuffers)
+                {
+                    this.memoryManager.ReturnLargeBuffer(buffer, this.tag);
+                }
+            }
+
+            this.memoryManager.ReturnBlocks(this.blocks, this.tag);
+            this.blocks.Clear();
+
+            base.Dispose(disposing);
+        }
+
+        /// <summary>
+        /// Equivalent to Dispose
+        /// </summary>
+#if NETSTANDARD1_4
+        public void Close()
+#else
+        public override void Close()
+#endif
+        {
+            this.Dispose(true);
+        }
+        #endregion
+
+        #region MemoryStream overrides
+        /// <summary>
+        /// Gets or sets the capacity
+        /// </summary>
+        /// <remarks>Capacity is always in multiples of the memory manager's block size, unless
+        /// the large buffer is in use.  Capacity never decreases during a stream's lifetime. 
+        /// Explicitly setting the capacity to a lower value than the current value will have no effect. 
+        /// This is because the buffers are all pooled by chunks and there's little reason to 
+        /// allow stream truncation.
+        /// </remarks>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        public override int Capacity
+        {
+            get
+            {
+                this.CheckDisposed();
+                if (this.largeBuffer != null)
+                {
+                    return this.largeBuffer.Length;
+                }
+
+                long size = (long)this.blocks.Count * this.memoryManager.BlockSize;
+                return (int)Math.Min(int.MaxValue, size);
+            }
+            set
+            {
+                this.CheckDisposed();
+                this.EnsureCapacity(value);
+            }
+        }
+
+        private int length;
+
+        /// <summary>
+        /// Gets the number of bytes written to this stream.
+        /// </summary>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        public override long Length
+        {
+            get
+            {
+                this.CheckDisposed();
+                return this.length;
+            }
+        }
+
+        private int position;
+
+        /// <summary>
+        /// Gets the current position in the stream
+        /// </summary>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        public override long Position
+        {
+            get
+            {
+                this.CheckDisposed();
+                return this.position;
+            }
+            set
+            {
+                this.CheckDisposed();
+                if (value < 0)
+                {
+                    throw new ArgumentOutOfRangeException("value", "value must be non-negative");
+                }
+
+                if (value > MaxStreamLength)
+                {
+                    throw new ArgumentOutOfRangeException("value", "value cannot be more than " + MaxStreamLength);
+                }
+
+                this.position = (int)value;
+            }
+        }
+
+        /// <summary>
+        /// Whether the stream can currently read
+        /// </summary>
+        public override bool CanRead => !this.Disposed;
+
+        /// <summary>
+        /// Whether the stream can currently seek
+        /// </summary>
+        public override bool CanSeek => !this.Disposed;
+
+        /// <summary>
+        /// Always false
+        /// </summary>
+        public override bool CanTimeout => false;
+
+        /// <summary>
+        /// Whether the stream can currently write
+        /// </summary>
+        public override bool CanWrite => !this.Disposed;
+
+        /// <summary>
+        /// Returns a single buffer containing the contents of the stream.
+        /// The buffer may be longer than the stream length.
+        /// </summary>
+        /// <returns>A byte[] buffer</returns>
+        /// <remarks>IMPORTANT: Doing a Write() after calling GetBuffer() invalidates the buffer. The old buffer is held onto
+        /// until Dispose is called, but the next time GetBuffer() is called, a new buffer from the pool will be required.</remarks>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+#if NETSTANDARD1_4
+        public byte[] GetBuffer()
+#else
+        public override byte[] GetBuffer()
+#endif
+        {
+            this.CheckDisposed();
+
+            if (this.largeBuffer != null)
+            {
+                return this.largeBuffer;
+            }
+
+            if (this.blocks.Count == 1)
+            {
+                return this.blocks[0];
+            }
+
+            // Buffer needs to reflect the capacity, not the length, because
+            // it's possible that people will manipulate the buffer directly
+            // and set the length afterward. Capacity sets the expectation
+            // for the size of the buffer.
+            var newBuffer = this.memoryManager.GetLargeBuffer(this.Capacity, this.tag);
+
+            // InternalRead will check for existence of largeBuffer, so make sure we
+            // don't set it until after we've copied the data.
+            this.InternalRead(newBuffer, 0, this.length, 0);
+            this.largeBuffer = newBuffer;
+
+            if (this.blocks.Count > 0 && this.memoryManager.AggressiveBufferReturn)
+            {
+                this.memoryManager.ReturnBlocks(this.blocks, this.tag);
+                this.blocks.Clear();
+            }
+
+            return this.largeBuffer;
+        }
+
+        /// <summary>
+        /// Returns a new array with a copy of the buffer's contents. You should almost certainly be using GetBuffer combined with the Length to 
+        /// access the bytes in this stream. Calling ToArray will destroy the benefits of pooled buffers, but it is included
+        /// for the sake of completeness.
+        /// </summary>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+#pragma warning disable CS0809
+        [Obsolete("This method has degraded performance vs. GetBuffer and should be avoided.")]
+        public override byte[] ToArray()
+        {
+            this.CheckDisposed();
+            var newBuffer = new byte[this.Length];
+
+            this.InternalRead(newBuffer, 0, this.length, 0);
+            string stack = this.memoryManager.GenerateCallStacks ? Environment.StackTrace : null;
+            RecyclableMemoryStreamManager.Events.Writer.MemoryStreamToArray(this.id, this.tag, stack, 0);
+            this.memoryManager.ReportStreamToArray();
+
+            return newBuffer;
+        }
+#pragma warning restore CS0809
+
+        /// <summary>
+        /// Reads from the current position into the provided buffer
+        /// </summary>
+        /// <param name="buffer">Destination buffer</param>
+        /// <param name="offset">Offset into buffer at which to start placing the read bytes.</param>
+        /// <param name="count">Number of bytes to read.</param>
+        /// <returns>The number of bytes read</returns>
+        /// <exception cref="ArgumentNullException">buffer is null</exception>
+        /// <exception cref="ArgumentOutOfRangeException">offset or count is less than 0</exception>
+        /// <exception cref="ArgumentException">offset subtracted from the buffer length is less than count</exception>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            return this.SafeRead(buffer, offset, count, ref this.position);
+        }
+
+        /// <summary>
+        /// Reads from the specified position into the provided buffer
+        /// </summary>
+        /// <param name="buffer">Destination buffer</param>
+        /// <param name="offset">Offset into buffer at which to start placing the read bytes.</param>
+        /// <param name="count">Number of bytes to read.</param>
+        /// <param name="streamPosition">Position in the stream to start reading from</param>
+        /// <returns>The number of bytes read</returns>
+        /// <exception cref="ArgumentNullException">buffer is null</exception>
+        /// <exception cref="ArgumentOutOfRangeException">offset or count is less than 0</exception>
+        /// <exception cref="ArgumentException">offset subtracted from the buffer length is less than count</exception>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        public int SafeRead(byte[] buffer, int offset, int count, ref int streamPosition)
+        {
+            this.CheckDisposed();
+            if (buffer == null)
+            {
+                throw new ArgumentNullException(nameof(buffer));
+            }
+
+            if (offset < 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(offset), "offset cannot be negative");
+            }
+
+            if (count < 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(count), "count cannot be negative");
+            }
+
+            if (offset + count > buffer.Length)
+            {
+                throw new ArgumentException("buffer length must be at least offset + count");
+            }
+
+            int amountRead = this.InternalRead(buffer, offset, count, streamPosition);
+            streamPosition += amountRead;
+            return amountRead;
+        }
+
+        /// <summary>
+        /// Writes the buffer to the stream
+        /// </summary>
+        /// <param name="buffer">Source buffer</param>
+        /// <param name="offset">Start position</param>
+        /// <param name="count">Number of bytes to write</param>
+        /// <exception cref="ArgumentNullException">buffer is null</exception>
+        /// <exception cref="ArgumentOutOfRangeException">offset or count is negative</exception>
+        /// <exception cref="ArgumentException">buffer.Length - offset is not less than count</exception>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            this.CheckDisposed();
+            if (buffer == null)
+            {
+                throw new ArgumentNullException(nameof(buffer));
+            }
+
+            if (offset < 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(offset), offset,
+                                                      "Offset must be in the range of 0 - buffer.Length-1");
+            }
+
+            if (count < 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(count), count, "count must be non-negative");
+            }
+
+            if (count + offset > buffer.Length)
+            {
+                throw new ArgumentException("count must be greater than buffer.Length - offset");
+            }
+
+            int blockSize = this.memoryManager.BlockSize;
+            long end = (long)this.position + count;
+            // Check for overflow
+            if (end > MaxStreamLength)
+            {
+                throw new IOException("Maximum capacity exceeded");
+            }
+
+            long requiredBuffers = (end + blockSize - 1) / blockSize;
+
+            if (requiredBuffers * blockSize > MaxStreamLength)
+            {
+                throw new IOException("Maximum capacity exceeded");
+            }
+
+            this.EnsureCapacity((int)end);
+
+            if (this.largeBuffer == null)
+            {
+                int bytesRemaining = count;
+                int bytesWritten = 0;
+                var blockAndOffset = this.GetBlockAndRelativeOffset(this.position);
+
+                while (bytesRemaining > 0)
+                {
+                    byte[] currentBlock = this.blocks[blockAndOffset.Block];
+                    int remainingInBlock = blockSize - blockAndOffset.Offset;
+                    int amountToWriteInBlock = Math.Min(remainingInBlock, bytesRemaining);
+
+                    Buffer.BlockCopy(buffer, offset + bytesWritten, currentBlock, blockAndOffset.Offset,
+                                     amountToWriteInBlock);
+
+                    bytesRemaining -= amountToWriteInBlock;
+                    bytesWritten += amountToWriteInBlock;
+
+                    ++blockAndOffset.Block;
+                    blockAndOffset.Offset = 0;
+                }
+            }
+            else
+            {
+                Buffer.BlockCopy(buffer, offset, this.largeBuffer, this.position, count);
+            }
+            this.position = (int)end;
+            this.length = Math.Max(this.position, this.length);
+        }
+
+        /// <summary>
+        /// Returns a useful string for debugging. This should not normally be called in actual production code.
+        /// </summary>
+        public override string ToString()
+        {
+            return $"Id = {this.Id}, Tag = {this.Tag}, Length = {this.Length:N0} bytes";
+        }
+
+        /// <summary>
+        /// Writes a single byte to the current position in the stream.
+        /// </summary>
+        /// <param name="value">byte value to write</param>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        public override void WriteByte(byte value)
+        {
+            this.CheckDisposed();
+            this.byteBuffer[0] = value;
+            this.Write(this.byteBuffer, 0, 1);
+        }
+
+        /// <summary>
+        /// Reads a single byte from the current position in the stream.
+        /// </summary>
+        /// <returns>The byte at the current position, or -1 if the position is at the end of the stream.</returns>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        public override int ReadByte()
+        {
+            return this.SafeReadByte(ref this.position);
+        }
+
+        /// <summary>
+        /// Reads a single byte from the specified position in the stream.
+        /// </summary>
+        /// <param name="streamPosition">The position in the stream to read from</param>
+        /// <returns>The byte at the current position, or -1 if the position is at the end of the stream.</returns>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        public int SafeReadByte(ref int streamPosition)
+        {
+            this.CheckDisposed();
+            if (streamPosition == this.length)
+            {
+                return -1;
+            }
+            byte value;
+            if (this.largeBuffer == null)
+            {
+                var blockAndOffset = this.GetBlockAndRelativeOffset(streamPosition);
+                value = this.blocks[blockAndOffset.Block][blockAndOffset.Offset];
+            }
+            else
+            {
+                value = this.largeBuffer[streamPosition];
+            }
+            streamPosition++;
+            return value;
+        }
+
+        /// <summary>
+        /// Sets the length of the stream
+        /// </summary>
+        /// <exception cref="ArgumentOutOfRangeException">value is negative or larger than MaxStreamLength</exception>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        public override void SetLength(long value)
+        {
+            this.CheckDisposed();
+            if (value < 0 || value > MaxStreamLength)
+            {
+                throw new ArgumentOutOfRangeException(nameof(value),
+                                                      "value must be non-negative and at most " + MaxStreamLength);
+            }
+
+            this.EnsureCapacity((int)value);
+
+            this.length = (int)value;
+            if (this.position > value)
+            {
+                this.position = (int)value;
+            }
+        }
+
+        /// <summary>
+        /// Sets the position to the offset from the seek location
+        /// </summary>
+        /// <param name="offset">How many bytes to move</param>
+        /// <param name="loc">From where</param>
+        /// <returns>The new position</returns>
+        /// <exception cref="ObjectDisposedException">Object has been disposed</exception>
+        /// <exception cref="ArgumentOutOfRangeException">offset is larger than MaxStreamLength</exception>
+        /// <exception cref="ArgumentException">Invalid seek origin</exception>
+        /// <exception cref="IOException">Attempt to set negative position</exception>
+        public override long Seek(long offset, SeekOrigin loc)
+        {
+            this.CheckDisposed();
+            if (offset > MaxStreamLength)
+            {
+                throw new ArgumentOutOfRangeException(nameof(offset), "offset cannot be larger than " + MaxStreamLength);
+            }
+
+            int newPosition;
+            switch (loc)
+            {
+                case SeekOrigin.Begin:
+                    newPosition = (int)offset;
+                    break;
+                case SeekOrigin.Current:
+                    newPosition = (int)offset + this.position;
+                    break;
+                case SeekOrigin.End:
+                    newPosition = (int)offset + this.length;
+                    break;
+                default:
+                    throw new ArgumentException("Invalid seek origin", nameof(loc));
+            }
+            if (newPosition < 0)
+            {
+                throw new IOException("Seek before beginning");
+            }
+            this.position = newPosition;
+            return this.position;
+        }
+
+        /// <summary>
+        /// Synchronously writes this stream's bytes to the parameter stream.
+        /// </summary>
+        /// <param name="stream">Destination stream</param>
+        /// <remarks>Important: This does a synchronous write, which may not be desired in some situations</remarks>
+        public override void WriteTo(Stream stream)
+        {
+            this.CheckDisposed();
+            if (stream == null)
+            {
+                throw new ArgumentNullException(nameof(stream));
+            }
+
+            if (this.largeBuffer == null)
+            {
+                int currentBlock = 0;
+                int bytesRemaining = this.length;
+
+                while (bytesRemaining > 0)
+                {
+                    int amountToCopy = Math.Min(this.blocks[currentBlock].Length, bytesRemaining);
+                    stream.Write(this.blocks[currentBlock], 0, amountToCopy);
+
+                    bytesRemaining -= amountToCopy;
+
+                    ++currentBlock;
+                }
+            }
+            else
+            {
+                stream.Write(this.largeBuffer, 0, this.length);
+            }
+        }
+        #endregion
+
+        #region Helper Methods
+        private bool Disposed => Interlocked.Read(ref this.disposedState) != 0;
+
+        private void CheckDisposed()
+        {
+            if (this.Disposed)
+            {
+                throw new ObjectDisposedException($"The stream with Id {this.id} and Tag {this.tag} is disposed.");
+            }
+        }
+
+        private int InternalRead(byte[] buffer, int offset, int count, int fromPosition)
+        {
+            if (this.length - fromPosition <= 0)
+            {
+                return 0;
+            }
+
+            int amountToCopy;
+
+            if (this.largeBuffer == null)
+            {
+                var blockAndOffset = this.GetBlockAndRelativeOffset(fromPosition);
+                int bytesWritten = 0;
+                int bytesRemaining = Math.Min(count, this.length - fromPosition);
+
+                while (bytesRemaining > 0)
+                {
+                    amountToCopy = Math.Min(this.blocks[blockAndOffset.Block].Length - blockAndOffset.Offset,
+                                                bytesRemaining);
+                    Buffer.BlockCopy(this.blocks[blockAndOffset.Block], blockAndOffset.Offset, buffer,
+                                     bytesWritten + offset, amountToCopy);
+
+                    bytesWritten += amountToCopy;
+                    bytesRemaining -= amountToCopy;
+
+                    ++blockAndOffset.Block;
+                    blockAndOffset.Offset = 0;
+                }
+                return bytesWritten;
+            }
+            amountToCopy = Math.Min(count, this.length - fromPosition);
+            Buffer.BlockCopy(this.largeBuffer, fromPosition, buffer, offset, amountToCopy);
+            return amountToCopy;
+        }
+
+        private struct BlockAndOffset
+        {
+            public int Block;
+            public int Offset;
+
+            public BlockAndOffset(int block, int offset)
+            {
+                this.Block = block;
+                this.Offset = offset;
+            }
+        }
+
+        private BlockAndOffset GetBlockAndRelativeOffset(int offset)
+        {
+            var blockSize = this.memoryManager.BlockSize;
+            return new BlockAndOffset(offset / blockSize, offset % blockSize);
+        }
+
+        private void EnsureCapacity(int newCapacity)
+        {
+            if (newCapacity > this.memoryManager.MaximumStreamCapacity && this.memoryManager.MaximumStreamCapacity > 0)
+            {
+                RecyclableMemoryStreamManager.Events.Writer.MemoryStreamOverCapacity(newCapacity,
+                                                                                    this.memoryManager
+                                                                                        .MaximumStreamCapacity, this.tag,
+                                                                                    this.AllocationStack);
+                throw new InvalidOperationException("Requested capacity is too large: " + newCapacity + ". Limit is " +
+                                                    this.memoryManager.MaximumStreamCapacity);
+            }
+
+            if (this.largeBuffer != null)
+            {
+                if (newCapacity > this.largeBuffer.Length)
+                {
+                    var newBuffer = this.memoryManager.GetLargeBuffer(newCapacity, this.tag);
+                    this.InternalRead(newBuffer, 0, this.length, 0);
+                    this.ReleaseLargeBuffer();
+                    this.largeBuffer = newBuffer;
+                }
+            }
+            else
+            {
+                while (this.Capacity < newCapacity)
+                {
+                    blocks.Add((this.memoryManager.GetBlock()));
+                }
+            }
+        }
+
+        /// <summary>
+        /// Release the large buffer (either stores it for eventual release or returns it immediately).
+        /// </summary>
+        private void ReleaseLargeBuffer()
+        {
+            if (this.memoryManager.AggressiveBufferReturn)
+            {
+                this.memoryManager.ReturnLargeBuffer(this.largeBuffer, this.tag);
+            }
+            else
+            {
+                if (this.dirtyBuffers == null)
+                {
+                    // We most likely will only ever need space for one
+                    this.dirtyBuffers = new List<byte[]>(1);
+                }
+                this.dirtyBuffers.Add(this.largeBuffer);
+            }
+
+            this.largeBuffer = null;
+        }
+        #endregion
+    }
+}

+ 608 - 0
KYFramework/Core/Base/RecyclableMemoryStreamManager/RecyclableMemoryStreamManager.cs

@@ -0,0 +1,608 @@
+// ---------------------------------------------------------------------
+// Copyright (c) 2015-2016 Microsoft
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+// ---------------------------------------------------------------------
+
+namespace Microsoft.IO
+{
+    using System;
+    using System.Collections.Concurrent;
+    using System.Collections.Generic;
+    using System.Diagnostics.CodeAnalysis;
+    using System.IO;
+    using System.Linq;
+    using System.Threading;
+
+    /// <summary>
+    /// Manages pools of RecyclableMemoryStream objects.
+    /// </summary>
+    /// <remarks>
+    /// There are two pools managed in here. The small pool contains same-sized buffers that are handed to streams
+    /// as they write more data.
+    /// 
+    /// For scenarios that need to call GetBuffer(), the large pool contains buffers of various sizes, all
+    /// multiples of LargeBufferMultiple (1 MB by default). They are split by size to avoid overly-wasteful buffer
+    /// usage. There should be far fewer 8 MB buffers than 1 MB buffers, for example.
+    /// </remarks>
+    public partial class RecyclableMemoryStreamManager
+    {
+        /// <summary>
+        /// Generic delegate for handling events without any arguments.
+        /// </summary>
+        public delegate void EventHandler();
+
+        /// <summary>
+        /// Delegate for handling large buffer discard reports.
+        /// </summary>
+        /// <param name="reason">Reason the buffer was discarded.</param>
+        public delegate void LargeBufferDiscardedEventHandler(Events.MemoryStreamDiscardReason reason);
+
+        /// <summary>
+        /// Delegate for handling reports of stream size when streams are allocated
+        /// </summary>
+        /// <param name="bytes">Bytes allocated.</param>
+        public delegate void StreamLengthReportHandler(long bytes);
+
+        /// <summary>
+        /// Delegate for handling periodic reporting of memory use statistics.
+        /// </summary>
+        /// <param name="smallPoolInUseBytes">Bytes currently in use in the small pool.</param>
+        /// <param name="smallPoolFreeBytes">Bytes currently free in the small pool.</param>
+        /// <param name="largePoolInUseBytes">Bytes currently in use in the large pool.</param>
+        /// <param name="largePoolFreeBytes">Bytes currently free in the large pool.</param>
+        public delegate void UsageReportEventHandler(
+            long smallPoolInUseBytes, long smallPoolFreeBytes, long largePoolInUseBytes, long largePoolFreeBytes);
+
+        public const int DefaultBlockSize = 128 * 1024;
+        public const int DefaultLargeBufferMultiple = 1024 * 1024;
+        public const int DefaultMaximumBufferSize = 128 * 1024 * 1024;
+
+        private readonly int blockSize;
+        private readonly long[] largeBufferFreeSize;
+        private readonly long[] largeBufferInUseSize;
+
+        private readonly int largeBufferMultiple;
+
+        /// <summary>
+        /// pools[0] = 1x largeBufferMultiple buffers
+        /// pools[1] = 2x largeBufferMultiple buffers
+        /// etc., up to maximumBufferSize
+        /// </summary>
+        private readonly ConcurrentStack<byte[]>[] largePools;
+
+        private readonly int maximumBufferSize;
+        private readonly ConcurrentStack<byte[]> smallPool;
+
+        private long smallPoolFreeSize;
+        private long smallPoolInUseSize;
+
+        /// <summary>
+        /// Initializes the memory manager with the default block/buffer specifications.
+        /// </summary>
+        public RecyclableMemoryStreamManager()
+            : this(DefaultBlockSize, DefaultLargeBufferMultiple, DefaultMaximumBufferSize) { }
+
+        /// <summary>
+        /// Initializes the memory manager with the given block requiredSize.
+        /// </summary>
+        /// <param name="blockSize">Size of each block that is pooled. Must be > 0.</param>
+        /// <param name="largeBufferMultiple">Each large buffer will be a multiple of this value.</param>
+        /// <param name="maximumBufferSize">Buffers larger than this are not pooled</param>
+        /// <exception cref="ArgumentOutOfRangeException">blockSize is not a positive number, or largeBufferMultiple is not a positive number, or maximumBufferSize is less than blockSize.</exception>
+        /// <exception cref="ArgumentException">maximumBufferSize is not a multiple of largeBufferMultiple</exception>
+        public RecyclableMemoryStreamManager(int blockSize, int largeBufferMultiple, int maximumBufferSize)
+        {
+            if (blockSize <= 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(blockSize), blockSize, "blockSize must be a positive number");
+            }
+
+            if (largeBufferMultiple <= 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(largeBufferMultiple),
+                                                      "largeBufferMultiple must be a positive number");
+            }
+
+            if (maximumBufferSize < blockSize)
+            {
+                throw new ArgumentOutOfRangeException(nameof(maximumBufferSize),
+                                                      "maximumBufferSize must be at least blockSize");
+            }
+
+            this.blockSize = blockSize;
+            this.largeBufferMultiple = largeBufferMultiple;
+            this.maximumBufferSize = maximumBufferSize;
+
+            if (!this.IsLargeBufferMultiple(maximumBufferSize))
+            {
+                throw new ArgumentException("maximumBufferSize is not a multiple of largeBufferMultiple",
+                                            nameof(maximumBufferSize));
+            }
+
+            this.smallPool = new ConcurrentStack<byte[]>();
+            var numLargePools = maximumBufferSize / largeBufferMultiple;
+
+            // +1 to store size of bytes in use that are too large to be pooled
+            this.largeBufferInUseSize = new long[numLargePools + 1];
+            this.largeBufferFreeSize = new long[numLargePools];
+
+            this.largePools = new ConcurrentStack<byte[]>[numLargePools];
+
+            for (var i = 0; i < this.largePools.Length; ++i)
+            {
+                this.largePools[i] = new ConcurrentStack<byte[]>();
+            }
+
+            Events.Writer.MemoryStreamManagerInitialized(blockSize, largeBufferMultiple, maximumBufferSize);
+        }
+
+        /// <summary>
+        /// The size of each block. It must be set at creation and cannot be changed.
+        /// </summary>
+        public int BlockSize => this.blockSize;
+
+        /// <summary>
+        /// All buffers are multiples of this number. It must be set at creation and cannot be changed.
+        /// </summary>
+        public int LargeBufferMultiple => this.largeBufferMultiple;
+
+        /// <summary>
+        /// Gets or sets the maximum buffer size.
+        /// </summary>
+        /// <remarks>Any buffer that is returned to the pool that is larger than this will be
+        /// discarded and garbage collected.</remarks>
+        public int MaximumBufferSize => this.maximumBufferSize;
+
+        /// <summary>
+        /// Number of bytes in small pool not currently in use
+        /// </summary>
+        public long SmallPoolFreeSize => this.smallPoolFreeSize;
+
+        /// <summary>
+        /// Number of bytes currently in use by stream from the small pool
+        /// </summary>
+        public long SmallPoolInUseSize => this.smallPoolInUseSize;
+
+        /// <summary>
+        /// Number of bytes in large pool not currently in use
+        /// </summary>
+        public long LargePoolFreeSize => this.largeBufferFreeSize.Sum();
+
+        /// <summary>
+        /// Number of bytes currently in use by streams from the large pool
+        /// </summary>
+        public long LargePoolInUseSize => this.largeBufferInUseSize.Sum();
+
+        /// <summary>
+        /// How many blocks are in the small pool
+        /// </summary>
+        public long SmallBlocksFree => this.smallPool.Count;
+
+        /// <summary>
+        /// How many buffers are in the large pool
+        /// </summary>
+        public long LargeBuffersFree
+        {
+            get
+            {
+                long free = 0;
+                foreach (var pool in this.largePools)
+                {
+                    free += pool.Count;
+                }
+                return free;
+            }
+        }
+
+        /// <summary>
+        /// How many bytes of small free blocks to allow before we start dropping
+        /// those returned to us.
+        /// </summary>
+        public long MaximumFreeSmallPoolBytes { get; set; }
+
+        /// <summary>
+        /// How many bytes of large free buffers to allow before we start dropping
+        /// those returned to us.
+        /// </summary>
+        public long MaximumFreeLargePoolBytes { get; set; }
+
+        /// <summary>
+        /// Maximum stream capacity in bytes. Attempts to set a larger capacity will
+        /// result in an exception.
+        /// </summary>
+        /// <remarks>A value of 0 indicates no limit.</remarks>
+        public long MaximumStreamCapacity { get; set; }
+
+        /// <summary>
+        /// Whether to save callstacks for stream allocations. This can help in debugging.
+        /// It should NEVER be turned on generally in production.
+        /// </summary>
+        public bool GenerateCallStacks { get; set; }
+
+        /// <summary>
+        /// Whether dirty buffers can be immediately returned to the buffer pool. E.g. when GetBuffer() is called on
+        /// a stream and creates a single large buffer, if this setting is enabled, the other blocks will be returned
+        /// to the buffer pool immediately.
+        /// Note when enabling this setting that the user is responsible for ensuring that any buffer previously
+        /// retrieved from a stream which is subsequently modified is not used after modification (as it may no longer
+        /// be valid).
+        /// </summary>
+        public bool AggressiveBufferReturn { get; set; }
+
+        /// <summary>
+        /// Removes and returns a single block from the pool.
+        /// </summary>
+        /// <returns>A byte[] array</returns>
+        internal byte[] GetBlock()
+        {
+            byte[] block;
+            if (!this.smallPool.TryPop(out block))
+            {
+                // We'll add this back to the pool when the stream is disposed
+                // (unless our free pool is too large)
+                block = new byte[this.BlockSize];
+                Events.Writer.MemoryStreamNewBlockCreated(this.smallPoolInUseSize);
+                ReportBlockCreated();
+            }
+            else
+            {
+                Interlocked.Add(ref this.smallPoolFreeSize, -this.BlockSize);
+            }
+
+            Interlocked.Add(ref this.smallPoolInUseSize, this.BlockSize);
+            return block;
+        }
+
+        /// <summary>
+        /// Returns a buffer of arbitrary size from the large buffer pool. This buffer
+        /// will be at least the requiredSize and always be a multiple of largeBufferMultiple.
+        /// </summary>
+        /// <param name="requiredSize">The minimum length of the buffer</param>
+        /// <param name="tag">The tag of the stream returning this buffer, for logging if necessary.</param>
+        /// <returns>A buffer of at least the required size.</returns>
+        internal byte[] GetLargeBuffer(int requiredSize, string tag)
+        {
+            requiredSize = this.RoundToLargeBufferMultiple(requiredSize);
+
+            var poolIndex = requiredSize / this.largeBufferMultiple - 1;
+
+            byte[] buffer;
+            if (poolIndex < this.largePools.Length)
+            {
+                if (!this.largePools[poolIndex].TryPop(out buffer))
+                {
+                    buffer = new byte[requiredSize];
+
+                    Events.Writer.MemoryStreamNewLargeBufferCreated(requiredSize, this.LargePoolInUseSize);
+                    ReportLargeBufferCreated();
+                }
+                else
+                {
+                    Interlocked.Add(ref this.largeBufferFreeSize[poolIndex], -buffer.Length);
+                }
+            }
+            else
+            {
+                // Buffer is too large to pool. They get a new buffer.
+
+                // We still want to track the size, though, and we've reserved a slot
+                // in the end of the inuse array for nonpooled bytes in use.
+                poolIndex = this.largeBufferInUseSize.Length - 1;
+
+                // We still want to round up to reduce heap fragmentation.
+                buffer = new byte[requiredSize];
+                string callStack = null;
+                if (this.GenerateCallStacks)
+                {
+                    // Grab the stack -- we want to know who requires such large buffers
+                    callStack = Environment.StackTrace;
+                }
+                Events.Writer.MemoryStreamNonPooledLargeBufferCreated(requiredSize, tag, callStack);
+                ReportLargeBufferCreated();
+            }
+
+            Interlocked.Add(ref this.largeBufferInUseSize[poolIndex], buffer.Length);
+
+            return buffer;
+        }
+
+        private int RoundToLargeBufferMultiple(int requiredSize)
+        {
+            return ((requiredSize + this.LargeBufferMultiple - 1) / this.LargeBufferMultiple) * this.LargeBufferMultiple;
+        }
+
+        private bool IsLargeBufferMultiple(int value)
+        {
+            return (value != 0) && (value % this.LargeBufferMultiple) == 0;
+        }
+
+        /// <summary>
+        /// Returns the buffer to the large pool
+        /// </summary>
+        /// <param name="buffer">The buffer to return.</param>
+        /// <param name="tag">The tag of the stream returning this buffer, for logging if necessary.</param>
+        /// <exception cref="ArgumentNullException">buffer is null</exception>
+        /// <exception cref="ArgumentException">buffer.Length is not a multiple of LargeBufferMultiple (it did not originate from this pool)</exception>
+        internal void ReturnLargeBuffer(byte[] buffer, string tag)
+        {
+            if (buffer == null)
+            {
+                throw new ArgumentNullException(nameof(buffer));
+            }
+
+            if (!this.IsLargeBufferMultiple(buffer.Length))
+            {
+                throw new ArgumentException(
+                    "buffer did not originate from this memory manager. The size is not a multiple of " +
+                    this.LargeBufferMultiple);
+            }
+
+            var poolIndex = buffer.Length / this.largeBufferMultiple - 1;
+
+            if (poolIndex < this.largePools.Length)
+            {
+                if ((this.largePools[poolIndex].Count + 1) * buffer.Length <= this.MaximumFreeLargePoolBytes ||
+                    this.MaximumFreeLargePoolBytes == 0)
+                {
+                    this.largePools[poolIndex].Push(buffer);
+                    Interlocked.Add(ref this.largeBufferFreeSize[poolIndex], buffer.Length);
+                }
+                else
+                {
+                    Events.Writer.MemoryStreamDiscardBuffer(Events.MemoryStreamBufferType.Large, tag,
+                                                           Events.MemoryStreamDiscardReason.EnoughFree);
+                    ReportLargeBufferDiscarded(Events.MemoryStreamDiscardReason.EnoughFree);
+                }
+            }
+            else
+            {
+                // This is a non-poolable buffer, but we still want to track its size for inuse
+                // analysis. We have space in the inuse array for this.
+                poolIndex = this.largeBufferInUseSize.Length - 1;
+
+                Events.Writer.MemoryStreamDiscardBuffer(Events.MemoryStreamBufferType.Large, tag,
+                                                       Events.MemoryStreamDiscardReason.TooLarge);
+                ReportLargeBufferDiscarded(Events.MemoryStreamDiscardReason.TooLarge);
+            }
+
+            Interlocked.Add(ref this.largeBufferInUseSize[poolIndex], -buffer.Length);
+
+            ReportUsageReport(this.smallPoolInUseSize, this.smallPoolFreeSize, this.LargePoolInUseSize,
+                              this.LargePoolFreeSize);
+        }
+
+        /// <summary>
+        /// Returns the blocks to the pool
+        /// </summary>
+        /// <param name="blocks">Collection of blocks to return to the pool</param>
+        /// <param name="tag">The tag of the stream returning these blocks, for logging if necessary.</param>
+        /// <exception cref="ArgumentNullException">blocks is null</exception>
+        /// <exception cref="ArgumentException">blocks contains buffers that are the wrong size (or null) for this memory manager</exception>
+        internal void ReturnBlocks(ICollection<byte[]> blocks, string tag)
+        {
+            if (blocks == null)
+            {
+                throw new ArgumentNullException(nameof(blocks));
+            }
+
+            var bytesToReturn = blocks.Count * this.BlockSize;
+            Interlocked.Add(ref this.smallPoolInUseSize, -bytesToReturn);
+
+            foreach (var block in blocks)
+            {
+                if (block == null || block.Length != this.BlockSize)
+                {
+                    throw new ArgumentException("blocks contains buffers that are not BlockSize in length");
+                }
+            }
+
+            foreach (var block in blocks)
+            {
+                if (this.MaximumFreeSmallPoolBytes == 0 || this.SmallPoolFreeSize < this.MaximumFreeSmallPoolBytes)
+                {
+                    Interlocked.Add(ref this.smallPoolFreeSize, this.BlockSize);
+                    this.smallPool.Push(block);
+                }
+                else
+                {
+                    Events.Writer.MemoryStreamDiscardBuffer(Events.MemoryStreamBufferType.Small, tag,
+                                                           Events.MemoryStreamDiscardReason.EnoughFree);
+                    ReportBlockDiscarded();
+                    break;
+                }
+            }
+
+            ReportUsageReport(this.smallPoolInUseSize, this.smallPoolFreeSize, this.LargePoolInUseSize,
+                              this.LargePoolFreeSize);
+        }
+
+        internal void ReportBlockCreated()
+        {
+            this.BlockCreated?.Invoke();
+        }
+
+        internal void ReportBlockDiscarded()
+        {
+            this.BlockDiscarded?.Invoke();
+        }
+
+        internal void ReportLargeBufferCreated()
+        {
+            this.LargeBufferCreated?.Invoke();
+        }
+
+        internal void ReportLargeBufferDiscarded(Events.MemoryStreamDiscardReason reason)
+        {
+            this.LargeBufferDiscarded?.Invoke(reason);
+        }
+
+        internal void ReportStreamCreated()
+        {
+            this.StreamCreated?.Invoke();
+        }
+
+        internal void ReportStreamDisposed()
+        {
+            this.StreamDisposed?.Invoke();
+        }
+
+        internal void ReportStreamFinalized()
+        {
+            this.StreamFinalized?.Invoke();
+        }
+
+        internal void ReportStreamLength(long bytes)
+        {
+            this.StreamLength?.Invoke(bytes);
+        }
+
+        internal void ReportStreamToArray()
+        {
+            this.StreamConvertedToArray?.Invoke();
+        }
+
+        internal void ReportUsageReport(
+            long smallPoolInUseBytes, long smallPoolFreeBytes, long largePoolInUseBytes, long largePoolFreeBytes)
+        {
+            this.UsageReport?.Invoke(smallPoolInUseBytes, smallPoolFreeBytes, largePoolInUseBytes, largePoolFreeBytes);
+        }
+
+        /// <summary>
+        /// Retrieve a new MemoryStream object with no tag and a default initial capacity.
+        /// </summary>
+        /// <returns>A MemoryStream.</returns>
+        public MemoryStream GetStream()
+        {
+            return new RecyclableMemoryStream(this);
+        }
+
+        /// <summary>
+        /// Retrieve a new MemoryStream object with the given tag and a default initial capacity.
+        /// </summary>
+        /// <param name="tag">A tag which can be used to track the source of the stream.</param>
+        /// <returns>A MemoryStream.</returns>
+        public MemoryStream GetStream(string tag)
+        {
+            return new RecyclableMemoryStream(this, tag);
+        }
+
+        /// <summary>
+        /// Retrieve a new MemoryStream object with the given tag and at least the given capacity.
+        /// </summary>
+        /// <param name="tag">A tag which can be used to track the source of the stream.</param>
+        /// <param name="requiredSize">The minimum desired capacity for the stream.</param>
+        /// <returns>A MemoryStream.</returns>
+        public MemoryStream GetStream(string tag, int requiredSize)
+        {
+            return new RecyclableMemoryStream(this, tag, requiredSize);
+        }
+
+        /// <summary>
+        /// Retrieve a new MemoryStream object with the given tag and at least the given capacity, possibly using
+        /// a single continugous underlying buffer.
+        /// </summary>
+        /// <remarks>Retrieving a MemoryStream which provides a single contiguous buffer can be useful in situations
+        /// where the initial size is known and it is desirable to avoid copying data between the smaller underlying
+        /// buffers to a single large one. This is most helpful when you know that you will always call GetBuffer
+        /// on the underlying stream.</remarks>
+        /// <param name="tag">A tag which can be used to track the source of the stream.</param>
+        /// <param name="requiredSize">The minimum desired capacity for the stream.</param>
+        /// <param name="asContiguousBuffer">Whether to attempt to use a single contiguous buffer.</param>
+        /// <returns>A MemoryStream.</returns>
+        public MemoryStream GetStream(string tag, int requiredSize, bool asContiguousBuffer)
+        {
+            if (!asContiguousBuffer || requiredSize <= this.BlockSize)
+            {
+                return this.GetStream(tag, requiredSize);
+            }
+
+            return new RecyclableMemoryStream(this, tag, requiredSize, this.GetLargeBuffer(requiredSize, tag));
+        }
+
+        /// <summary>
+        /// Retrieve a new MemoryStream object with the given tag and with contents copied from the provided
+        /// buffer. The provided buffer is not wrapped or used after construction.
+        /// </summary>
+        /// <remarks>The new stream's position is set to the beginning of the stream when returned.</remarks>
+        /// <param name="tag">A tag which can be used to track the source of the stream.</param>
+        /// <param name="buffer">The byte buffer to copy data from.</param>
+        /// <param name="offset">The offset from the start of the buffer to copy from.</param>
+        /// <param name="count">The number of bytes to copy from the buffer.</param>
+        /// <returns>A MemoryStream.</returns>
+        [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
+        public MemoryStream GetStream(string tag, byte[] buffer, int offset, int count)
+        {
+            var stream = new RecyclableMemoryStream(this, tag, count);
+            stream.Write(buffer, offset, count);
+            stream.Position = 0;
+            return stream;
+        }
+
+        /// <summary>
+        /// Triggered when a new block is created.
+        /// </summary>
+        public event EventHandler BlockCreated;
+
+        /// <summary>
+        /// Triggered when a new block is created.
+        /// </summary>
+        public event EventHandler BlockDiscarded;
+
+        /// <summary>
+        /// Triggered when a new large buffer is created.
+        /// </summary>
+        public event EventHandler LargeBufferCreated;
+
+        /// <summary>
+        /// Triggered when a new stream is created.
+        /// </summary>
+        public event EventHandler StreamCreated;
+
+        /// <summary>
+        /// Triggered when a stream is disposed.
+        /// </summary>
+        public event EventHandler StreamDisposed;
+
+        /// <summary>
+        /// Triggered when a stream is finalized.
+        /// </summary>
+        public event EventHandler StreamFinalized;
+
+        /// <summary>
+        /// Triggered when a stream is finalized.
+        /// </summary>
+        public event StreamLengthReportHandler StreamLength;
+
+        /// <summary>
+        /// Triggered when a user converts a stream to array.
+        /// </summary>
+        public event EventHandler StreamConvertedToArray;
+
+        /// <summary>
+        /// Triggered when a large buffer is discarded, along with the reason for the discard.
+        /// </summary>
+        public event LargeBufferDiscardedEventHandler LargeBufferDiscarded;
+
+        /// <summary>
+        /// Periodically triggered to report usage statistics.
+        /// </summary>
+        public event UsageReportEventHandler UsageReport;
+    }
+}

+ 161 - 0
KYFramework/Core/Base/UnOrderMultiMap.cs

@@ -0,0 +1,161 @@
+
+namespace KYFramework
+{
+    public class UnOrderMultiMap<T, K>
+    {
+        private readonly Dictionary<T, List<K>> dictionary = new Dictionary<T, List<K>>();
+
+        // 重用list
+        private readonly Queue<List<K>> queue = new Queue<List<K>>();
+
+        public Dictionary<T, List<K>> GetDictionary()
+        {
+            return this.dictionary;
+        }
+
+        public void Add(T t, K k)
+        {
+            List<K> list;
+            this.dictionary.TryGetValue(t, out list);
+            if (list == null)
+            {
+                list = this.FetchList();
+                this.dictionary[t] = list;
+            }
+            list.Add(k);
+        }
+
+        public KeyValuePair<T, List<K>> First()
+        {
+            return this.dictionary.First();
+        }
+
+        public int Count
+        {
+            get
+            {
+                return this.dictionary.Count;
+            }
+        }
+
+        private List<K> FetchList()
+        {
+            if (this.queue.Count > 0)
+            {
+                List<K> list = this.queue.Dequeue();
+                list.Clear();
+                return list;
+            }
+            return new List<K>();
+        }
+
+        private void RecycleList(List<K> list)
+        {
+            // 防止暴涨
+            if (this.queue.Count > 100)
+            {
+                return;
+            }
+            list.Clear();
+            this.queue.Enqueue(list);
+        }
+
+        public bool Remove(T t, K k)
+        {
+            List<K> list;
+            this.dictionary.TryGetValue(t, out list);
+            if (list == null)
+            {
+                return false;
+            }
+            if (!list.Remove(k))
+            {
+                return false;
+            }
+            if (list.Count == 0)
+            {
+                this.RecycleList(list);
+                this.dictionary.Remove(t);
+            }
+            return true;
+        }
+
+        public bool Remove(T t)
+        {
+            List<K> list = null;
+            this.dictionary.TryGetValue(t, out list);
+            if (list != null)
+            {
+                this.RecycleList(list);
+            }
+            return this.dictionary.Remove(t);
+        }
+
+        /// <summary>
+        /// 不返回内部的list,copy一份出来
+        /// </summary>
+        /// <param name="t"></param>
+        /// <returns></returns>
+        public K[] GetAll(T t)
+        {
+            List<K> list;
+            this.dictionary.TryGetValue(t, out list);
+            if (list == null)
+            {
+                return new K[0];
+            }
+            return list.ToArray();
+        }
+
+        /// <summary>
+        /// 返回内部的list
+        /// </summary>
+        /// <param name="t"></param>
+        /// <returns></returns>
+        public List<K> this[T t]
+        {
+            get
+            {
+                List<K> list;
+                this.dictionary.TryGetValue(t, out list);
+                return list;
+            }
+        }
+
+        public K GetOne(T t)
+        {
+            List<K> list;
+            this.dictionary.TryGetValue(t, out list);
+            if (list != null && list.Count > 0)
+            {
+                return list[0];
+            }
+            return default(K);
+        }
+
+        public bool Contains(T t, K k)
+        {
+            List<K> list;
+            this.dictionary.TryGetValue(t, out list);
+            if (list == null)
+            {
+                return false;
+            }
+            return list.Contains(k);
+        }
+
+        public bool ContainsKey(T t)
+        {
+            return this.dictionary.ContainsKey(t);
+        }
+
+        public void Clear()
+        {
+            foreach (KeyValuePair<T, List<K>> keyValuePair in this.dictionary)
+            {
+                this.RecycleList(keyValuePair.Value);
+            }
+            this.dictionary.Clear();
+        }
+    }
+}

+ 15 - 0
KYFramework/Core/Component/ListComponent.cs

@@ -0,0 +1,15 @@
+namespace KYFramework;
+
+public class ListComponent<T>: List<T>, IDisposable
+{
+    public static ListComponent<T> Create()
+    {
+        return Game.ObjectPool.Fetch(typeof (ListComponent<T>)) as ListComponent<T>;
+    }
+
+    public void Dispose()
+    {
+        this.Clear();
+        Game.ObjectPool.Recycle(this);
+    }
+}

+ 18 - 0
KYFramework/Core/Component/OptionComponent.cs

@@ -0,0 +1,18 @@
+
+using System;
+
+namespace KYFramework
+{
+    public class OptionComponent : Component
+    {
+        public static OptionComponent Instance;
+        
+        public Option option;
+    }
+
+    [Serializable]
+    public class Option
+    {
+        public int LogLevel { get; set; } = 2;
+    }
+}

+ 24 - 0
KYFramework/Core/Component/OptionComponentSystem.cs

@@ -0,0 +1,24 @@
+using System.IO;
+using Newtonsoft.Json;
+
+namespace KYFramework
+{
+    [ObjectSystem]
+    public class OptionComponentAwakeSystem : AwakeSystem<OptionComponent>
+    {
+        public override void Awake(OptionComponent self)
+        {
+            OptionComponent.Instance = self;
+            
+            string content = File.ReadAllText("Setting.json");
+
+            self.option =JsonConvert.DeserializeObject<Option>(content);
+        }
+    }
+
+
+    public static class OptionComponentSystem
+    {
+        
+    }
+}

+ 26 - 0
KYFramework/Core/Component/Timer.cs

@@ -0,0 +1,26 @@
+namespace KYFramework;
+
+public class Timer : Component
+{
+    private int timeZone;
+        
+    public int TimeZone
+    {
+        get
+        {
+            return this.timeZone;
+        }
+        set
+        {
+            this.timeZone = value;
+            dt = dt1970.AddHours(TimeZone);
+        }
+    }
+        
+    public DateTime dt1970;
+    public DateTime dt;
+        
+    public long ServerMinusClientTime { get; set; }
+
+    public long FrameTime;
+}

+ 72 - 0
KYFramework/Core/Component/TimerComponent.cs

@@ -0,0 +1,72 @@
+namespace KYFramework;
+
+public enum TimerClass
+{
+    None,
+    OnceTimer,
+    OnceWaitTimer,
+    RepeatedTimer,
+}
+
+public class TimerAction
+{
+    public static TimerAction Create(long id, TimerClass timerClass, long startTime, long time, int type, object obj)
+    {
+        TimerAction timerAction = Game.ObjectPool.Fetch<TimerAction>();
+        timerAction.Id = id;
+        timerAction.TimerClass = timerClass;
+        timerAction.StartTime = startTime;
+        timerAction.Object = obj;
+        timerAction.Time = time;
+        timerAction.Type = type;
+        return timerAction;
+    }
+
+    public long Id;
+        
+    public TimerClass TimerClass;
+
+    public object Object;
+
+    public long StartTime;
+
+    public long Time;
+
+    public int Type;
+        
+    public void Recycle()
+    {
+        this.Id = 0;
+        this.Object = null;
+        this.StartTime = 0;
+        this.Time = 0;
+        this.TimerClass = TimerClass.None;
+        this.Type = 0;
+        Game.ObjectPool.Recycle(this);
+    }
+}
+
+public struct TimerCallback
+{
+    public object Args;
+}
+
+public class TimerComponent : Component
+{
+    public static TimerComponent Instance;
+    /// <summary>
+    /// key: time, value: timer id
+    /// </summary>
+    public readonly MultiMap<long, long> TimeId = new();
+
+    public readonly Queue<long> timeOutTime = new();
+
+    public readonly Queue<long> timeOutTimerIds = new();
+
+    public readonly Dictionary<long, TimerAction> timerActions = new();
+
+    public long idGenerator;
+
+    // 记录最小时间,不用每次都去MultiMap取第一个值
+    public long minTime = long.MaxValue;
+}

+ 268 - 0
KYFramework/Core/Component/TimerComponentSystem.cs

@@ -0,0 +1,268 @@
+using ET;
+
+namespace KYFramework;
+
+[ObjectSystem]
+public class TimerComponentAwakeSystem : AwakeSystem<TimerComponent>
+{
+    public override void Awake(TimerComponent self)
+    {
+        TimerComponent.Instance = self;
+    }
+}
+
+[ObjectSystem]
+public class TimerComponentUpdateSystem : UpdateSystem<TimerComponent>
+{
+    public override void Update(TimerComponent self)
+    {
+        if (self.TimeId.Count == 0)
+        {
+            return;
+        }
+
+        long timeNow = self.GetNow();
+
+        if (timeNow < self.minTime)
+        {
+            return;
+        }
+
+        foreach (KeyValuePair<long, List<long>> kv in self.TimeId)
+        {
+            long k = kv.Key;
+            if (k > timeNow)
+            {
+                self.minTime = k;
+                break;
+            }
+
+            self.timeOutTime.Enqueue(k);
+        }
+
+        while (self.timeOutTime.Count > 0)
+        {
+            long time = self.timeOutTime.Dequeue();
+            var list = self.TimeId[time];
+            for (int i = 0; i < list.Count; ++i)
+            {
+                long timerId = list[i];
+                self.timeOutTimerIds.Enqueue(timerId);
+            }
+
+            self.TimeId.Remove(time);
+        }
+
+        while (self.timeOutTimerIds.Count > 0)
+        {
+            long timerId = self.timeOutTimerIds.Dequeue();
+
+            if (!self.timerActions.Remove(timerId, out TimerAction timerAction))
+            {
+                continue;
+            }
+
+            self.Run(timerAction);
+        }
+    }
+}
+
+public static class TimerComponentSystem
+{
+    public static long GetNow(this TimerComponent self)
+    {
+        return TimeHelper.ClientFrameTime();
+    }
+
+    public static void Run(this TimerComponent self, TimerAction timerAction)
+    {
+        switch (timerAction.TimerClass)
+        {
+            case TimerClass.OnceTimer:
+            {
+                Game.EventSystem.Invoke(timerAction.Type, new TimerCallback() { Args = timerAction.Object });
+                timerAction.Recycle();
+                break;
+            }
+            case TimerClass.OnceWaitTimer:
+            {
+                ETTask tcs = timerAction.Object as ETTask;
+                tcs.SetResult();
+                timerAction.Recycle();
+                break;
+            }
+            case TimerClass.RepeatedTimer:
+            {
+                long timeNow = self.GetNow();
+                timerAction.StartTime = timeNow;
+                self.AddTimer(timerAction);
+                Game.EventSystem.Invoke(timerAction.Type, new TimerCallback() { Args = timerAction.Object });
+                break;
+            }
+        }
+    }
+
+    private static void AddTimer(this TimerComponent self, TimerAction timer)
+    {
+        long tillTime = timer.StartTime + timer.Time;
+        self.TimeId.Add(tillTime, timer.Id);
+        self.timerActions.Add(timer.Id, timer);
+        if (tillTime < self.minTime)
+        {
+            self.minTime = tillTime;
+        }
+    }
+
+    public static bool Remove(this TimerComponent self, ref long id)
+    {
+        long i = id;
+        id = 0;
+        return self.Remove(i);
+    }
+
+    private static bool Remove(this TimerComponent self, long id)
+    {
+        if (id == 0)
+        {
+            return false;
+        }
+
+        if (!self.timerActions.Remove(id, out TimerAction timerAction))
+        {
+            return false;
+        }
+
+        timerAction.Recycle();
+        return true;
+    }
+
+    public static async ETTask WaitTillAsync(this TimerComponent self, long tillTime,
+        ETCancellationToken cancellationToken = null)
+    {
+        long timeNow = self.GetNow();
+        if (timeNow >= tillTime)
+        {
+            return;
+        }
+
+        ETTask tcs = ETTask.Create(true);
+        TimerAction timer =
+            TimerAction.Create(self.GetId(), TimerClass.OnceWaitTimer, timeNow, tillTime - timeNow, 0, tcs);
+        self.AddTimer(timer);
+        long timerId = timer.Id;
+
+        void CancelAction()
+        {
+            if (self.Remove(timerId))
+            {
+                tcs.SetResult();
+            }
+        }
+
+        try
+        {
+            cancellationToken?.Add(CancelAction);
+            await tcs;
+        }
+        finally
+        {
+            cancellationToken?.Remove(CancelAction);
+        }
+    }
+
+    public static async ETTask WaitFrameAsync(this TimerComponent self, ETCancellationToken cancellationToken = null)
+    {
+        await self.WaitAsync(1, cancellationToken);
+    }
+
+    public static async ETTask WaitAsync(this TimerComponent self, long time,
+        ETCancellationToken cancellationToken = null)
+    {
+        if (time == 0)
+        {
+            return;
+        }
+
+        long timeNow = self.GetNow();
+
+        ETTask tcs = ETTask.Create(true);
+        TimerAction timer = TimerAction.Create(self.GetId(), TimerClass.OnceWaitTimer, timeNow, time, 0, tcs);
+        self.AddTimer(timer);
+        long timerId = timer.Id;
+
+        void CancelAction()
+        {
+            if (self.Remove(timerId))
+            {
+                tcs.SetResult();
+            }
+        }
+
+        try
+        {
+            cancellationToken?.Add(CancelAction);
+            await tcs;
+        }
+        finally
+        {
+            cancellationToken?.Remove(CancelAction);
+        }
+    }
+
+    // 用这个优点是可以热更,缺点是回调式的写法,逻辑不连贯。WaitTillAsync不能热更,优点是逻辑连贯。
+    // wait时间短并且逻辑需要连贯的建议WaitTillAsync
+    // wait时间长不需要逻辑连贯的建议用NewOnceTimer
+    public static long NewOnceTimer(this TimerComponent self, long tillTime, int type, object args)
+    {
+        long timeNow = self.GetNow();
+        if (tillTime < timeNow)
+        {
+            Log.Error($"new once time too small: {tillTime}");
+        }
+
+        TimerAction timer =
+            TimerAction.Create(self.GetId(), TimerClass.OnceTimer, timeNow, tillTime - timeNow, type, args);
+        self.AddTimer(timer);
+        return timer.Id;
+    }
+
+    public static long NewFrameTimer(this TimerComponent self, int type, object args)
+    {
+        return self.NewRepeatedTimerInner(100, type, args);
+    }
+
+    /// <summary>
+    /// 创建一个RepeatedTimer
+    /// </summary>
+    private static long NewRepeatedTimerInner(this TimerComponent self, long time, int type, object args)
+    {
+        if (time < 100)
+        {
+            throw new Exception($"repeated timer < 100, timerType: time: {time}");
+        }
+
+
+        long timeNow = self.GetNow();
+        TimerAction timer = TimerAction.Create(self.GetId(), TimerClass.RepeatedTimer, timeNow, time, type, args);
+
+        // 每帧执行的不用加到timerId中,防止遍历
+        self.AddTimer(timer);
+        return timer.Id;
+    }
+
+    public static long NewRepeatedTimer(this TimerComponent self, long time, int type, object args)
+    {
+        if (time < 100)
+        {
+            Log.Error($"time too small: {time}");
+            return 0;
+        }
+
+        return self.NewRepeatedTimerInner(time, type, args);
+    }
+
+    private static long GetId(this TimerComponent self)
+    {
+        return ++self.idGenerator;
+    }
+}

+ 58 - 0
KYFramework/Core/Component/TimerSystem.cs

@@ -0,0 +1,58 @@
+namespace KYFramework;
+
+[ObjectSystem]
+public class TimerAwakeSystem: AwakeSystem<Timer>
+{
+    public override void Awake(Timer self)
+    {
+        self.dt1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+        self.dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+        self.FrameTime = self.ClientNow();
+    }
+}
+
+[ObjectSystem]
+public class TimerUpdateSystem : UpdateSystem<Timer>
+{
+    public override void Update(Timer self)
+    {
+        self.FrameTime = self.ClientNow();
+    }
+}
+
+public static class TimerSystem
+{
+    /// <summary> 
+    /// 根据时间戳获取时间 
+    /// </summary>  
+    public static DateTime ToDateTime(this Timer self,long timeStamp)
+    {
+        return self.dt.AddTicks(timeStamp * 10000);
+    }
+        
+    // 线程安全
+    public static long ClientNow(this Timer self)
+    {
+        return (DateTime.UtcNow.Ticks - self.dt1970.Ticks) / 10000;
+    }
+        
+    public static long ServerNow(this Timer self)
+    {
+        return self.ClientNow() + self.ServerMinusClientTime;
+    }
+        
+    public static long ClientFrameTime(this Timer self)
+    {
+        return self.FrameTime;
+    }
+        
+    public static long ServerFrameTime(this Timer self)
+    {
+        return self.FrameTime + self.ServerMinusClientTime;
+    }
+        
+    public static long Transition(this Timer self,DateTime d)
+    {
+        return (d.Ticks - self.dt.Ticks) / 10000;
+    }
+}

+ 62 - 0
KYFramework/Core/Entity/Game.cs

@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace KYFramework
+{
+    public static class Game
+    {
+        private static EventSystem eventSystem;
+
+        public static EventSystem EventSystem
+        {
+            get
+            {
+                return eventSystem ?? (eventSystem = new EventSystem());
+            }
+        }
+
+        private static Scene scene;
+
+        public static Scene Scene
+        {
+            get
+            {
+                if (scene != null)
+                {
+                    return scene;
+                }
+                scene = new Scene() { Name = "ClientM" };
+                return scene;
+            }
+        }
+
+        private static ObjectPool objectPool;
+
+        public static ObjectPool ObjectPool
+        {
+            get
+            {
+                if (objectPool != null)
+                {
+                    return objectPool;
+                }
+                objectPool = new ObjectPool();
+                return objectPool;
+            }
+        }
+
+        public static void Close()
+        {
+            scene?.Dispose();
+            scene = null;
+
+            objectPool?.Dispose();
+            objectPool = null;
+
+            eventSystem = null;
+        }
+    }
+}

+ 31 - 0
KYFramework/Core/Entity/Scene.cs

@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace KYFramework
+{
+    public sealed class Scene : Entity
+    {
+        public string Name { get; set; }
+
+        public Scene()
+        {
+        }
+
+        public Scene(long id) : base(id)
+        {
+        }
+
+        public override void Dispose()
+        {
+            if (this.IsDisposed)
+            {
+                return;
+            }
+
+            base.Dispose();
+        }
+    }
+}

+ 95 - 0
KYFramework/Core/Helper/ByteHelper.cs

@@ -0,0 +1,95 @@
+using System.Text;
+
+namespace KYFramework
+{
+    public static class ByteHelper
+    {
+        public static string ToHex(this byte b)
+        {
+            return b.ToString("X2");
+        }
+
+        public static string ToHex(this byte[] bytes)
+        {
+            StringBuilder stringBuilder = new StringBuilder();
+            foreach (byte b in bytes)
+            {
+                stringBuilder.Append(b.ToString("X2"));
+            }
+            return stringBuilder.ToString();
+        }
+
+        public static string ToHex(this byte[] bytes, string format)
+        {
+            StringBuilder stringBuilder = new StringBuilder();
+            foreach (byte b in bytes)
+            {
+                stringBuilder.Append(b.ToString(format));
+            }
+            return stringBuilder.ToString();
+        }
+
+        public static string ToHex(this byte[] bytes, int offset, int count)
+        {
+            StringBuilder stringBuilder = new StringBuilder();
+            for (int i = offset; i < offset + count; ++i)
+            {
+                stringBuilder.Append(bytes[i].ToString("X2"));
+            }
+            return stringBuilder.ToString();
+        }
+
+        public static string ToStr(this byte[] bytes)
+        {
+            return Encoding.Default.GetString(bytes);
+        }
+
+        public static string ToStr(this byte[] bytes, int index, int count)
+        {
+            return Encoding.Default.GetString(bytes, index, count);
+        }
+
+        public static string Utf8ToStr(this byte[] bytes)
+        {
+            return Encoding.UTF8.GetString(bytes);
+        }
+
+        public static string Utf8ToStr(this byte[] bytes, int index, int count)
+        {
+            return Encoding.UTF8.GetString(bytes, index, count);
+        }
+
+        public static void WriteTo(this byte[] bytes, int offset, uint num)
+        {
+            bytes[offset] = (byte)(num & 0xff);
+            bytes[offset + 1] = (byte)((num & 0xff00) >> 8);
+            bytes[offset + 2] = (byte)((num & 0xff0000) >> 16);
+            bytes[offset + 3] = (byte)((num & 0xff000000) >> 24);
+        }
+
+        public static void WriteTo(this byte[] bytes, int offset, int num)
+        {
+            bytes[offset] = (byte)(num & 0xff);
+            bytes[offset + 1] = (byte)((num & 0xff00) >> 8);
+            bytes[offset + 2] = (byte)((num & 0xff0000) >> 16);
+            bytes[offset + 3] = (byte)((num & 0xff000000) >> 24);
+        }
+
+        public static void WriteTo(this byte[] bytes, int offset, byte num)
+        {
+            bytes[offset] = num;
+        }
+
+        public static void WriteTo(this byte[] bytes, int offset, short num)
+        {
+            bytes[offset] = (byte)(num & 0xff);
+            bytes[offset + 1] = (byte)((num & 0xff00) >> 8);
+        }
+
+        public static void WriteTo(this byte[] bytes, int offset, ushort num)
+        {
+            bytes[offset] = (byte)(num & 0xff);
+            bytes[offset + 1] = (byte)((num & 0xff00) >> 8);
+        }
+    }
+}

+ 11 - 0
KYFramework/Core/Helper/Define.cs

@@ -0,0 +1,11 @@
+namespace KYFramework
+{
+    public static class Define
+    {
+#if UNITY_EDITOR
+        public static bool IsAsync = false;
+#else
+        public static bool IsAsync = true;
+#endif
+    }
+}

+ 107 - 0
KYFramework/Core/Helper/FileHelper.cs

@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace KYFramework
+{
+    public static class FileHelper
+	{
+		public static List<string> GetAllFiles(string dir, string searchPattern = "*")
+		{
+			List<string> list = new List<string>();
+			GetAllFiles(list, dir, searchPattern);
+			return list;
+		}
+		
+		public static void GetAllFiles(List<string> files, string dir, string searchPattern = "*")
+		{
+			string[] fls = Directory.GetFiles(dir);
+			foreach (string fl in fls)
+			{
+				files.Add(fl);
+			}
+
+			string[] subDirs = Directory.GetDirectories(dir);
+			foreach (string subDir in subDirs)
+			{
+				GetAllFiles(files, subDir, searchPattern);
+			}
+		}
+		
+		public static void CleanDirectory(string dir)
+		{
+			if (!Directory.Exists(dir))
+			{
+				return;
+			}
+			foreach (string subdir in Directory.GetDirectories(dir))
+			{
+				Directory.Delete(subdir, true);		
+			}
+
+			foreach (string subFile in Directory.GetFiles(dir))
+			{
+				File.Delete(subFile);
+			}
+		}
+
+		public static void CopyDirectory(string srcDir, string tgtDir)
+		{
+			DirectoryInfo source = new DirectoryInfo(srcDir);
+			DirectoryInfo target = new DirectoryInfo(tgtDir);
+	
+			if (target.FullName.StartsWith(source.FullName, StringComparison.CurrentCultureIgnoreCase))
+			{
+				throw new Exception("父目录不能拷贝到子目录!");
+			}
+	
+			if (!source.Exists)
+			{
+				return;
+			}
+	
+			if (!target.Exists)
+			{
+				target.Create();
+			}
+	
+			FileInfo[] files = source.GetFiles();
+	
+			for (int i = 0; i < files.Length; i++)
+			{
+				File.Copy(files[i].FullName, Path.Combine(target.FullName, files[i].Name), true);
+			}
+	
+			DirectoryInfo[] dirs = source.GetDirectories();
+	
+			for (int j = 0; j < dirs.Length; j++)
+			{
+				CopyDirectory(dirs[j].FullName, Path.Combine(target.FullName, dirs[j].Name));
+			}
+		}
+		
+		public static void ReplaceExtensionName(string srcDir, string extensionName, string newExtensionName)
+		{
+			if (Directory.Exists(srcDir))
+			{
+				string[] fls = Directory.GetFiles(srcDir);
+
+				foreach (string fl in fls)
+				{
+					if (fl.EndsWith(extensionName))
+					{
+						File.Move(fl, fl.Substring(0, fl.IndexOf(extensionName)) + newExtensionName);
+						File.Delete(fl);
+					}
+				}
+
+				string[] subDirs = Directory.GetDirectories(srcDir);
+
+				foreach (string subDir in subDirs)
+				{
+					ReplaceExtensionName(subDir, extensionName, newExtensionName);
+				}
+			}
+		}
+	}
+}

+ 37 - 0
KYFramework/Core/Helper/IdGenerater.cs

@@ -0,0 +1,37 @@
+namespace KYFramework
+{
+    public static class IdGenerater
+    {
+        private static long instanceIdGenerator;
+
+        private static long appId;
+
+        public static long AppId
+        {
+            set
+            {
+                appId = value;
+                instanceIdGenerator = appId << 48;
+            }
+        }
+
+        private static ushort value;
+
+        public static long GenerateId()
+        {
+            long time = TimeHelper.ClientNow();
+
+            return (appId << 48) + (time << 16) + ++value;
+        }
+
+        public static long GenerateInstanceId()
+        {
+            return ++instanceIdGenerator;
+        }
+
+        public static int GetAppId(long v)
+        {
+            return (int)(v >> 48);
+        }
+    }
+}

+ 31 - 0
KYFramework/Core/Helper/JsonHelper.cs

@@ -0,0 +1,31 @@
+using Newtonsoft.Json;
+using System.ComponentModel;
+
+namespace KYFramework
+{
+    public static class JsonHelper
+    {
+        public static string ToJson(object obj, Formatting formatting = Formatting.Indented)
+        {
+            return JsonConvert.SerializeObject(obj,formatting);
+        }
+
+        public static T FromJson<T>(string str)
+        {
+            T t = JsonConvert.DeserializeObject<T>(str);
+            
+            ISupportInitialize iSupportInitialize = t as ISupportInitialize;
+            if (iSupportInitialize == null)
+            {
+                return t;
+            }
+            iSupportInitialize.EndInit();
+            return t;
+        }
+
+        public static T Clone<T>(T t)
+        {
+            return FromJson<T>(ToJson(t));
+        }
+    }
+}

+ 124 - 0
KYFramework/Core/Helper/MongoHelper.cs

@@ -0,0 +1,124 @@
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace KYFramework
+{
+    public static class MongoHelper
+    {
+        static MongoHelper()
+        {
+            Type[] types = typeof(Game).Assembly.GetTypes();
+            foreach (Type type in types)
+            {
+                if (!type.IsSubclassOf(typeof(Component)))
+                {
+                    continue;
+                }
+
+                BsonClassMap.LookupClassMap(type);
+            }
+        }
+
+        public static string ToJson(object obj)
+        {
+            return obj.ToJson();
+        }
+
+        public static string ToJson(object obj, JsonWriterSettings settings)
+        {
+            return obj.ToJson(settings);
+        }
+
+        public static T FromJson<T>(string str)
+        {
+            return BsonSerializer.Deserialize<T>(str);
+        }
+
+        public static object FromJson(Type type, string str)
+        {
+            return BsonSerializer.Deserialize(str, type);
+        }
+
+        public static byte[] ToBson(object obj)
+        {
+            return obj.ToBson();
+        }
+
+        public static void ToBson(object obj, MemoryStream stream)
+        {
+            using (BsonBinaryWriter bsonWriter = new BsonBinaryWriter(stream, BsonBinaryWriterSettings.Defaults))
+            {
+                BsonSerializationContext context = BsonSerializationContext.CreateRoot(bsonWriter);
+                BsonSerializationArgs args = default(BsonSerializationArgs);
+                args.NominalType = typeof(object);
+                IBsonSerializer serializer = BsonSerializer.LookupSerializer(args.NominalType);
+                serializer.Serialize(context, args, obj);
+            }
+        }
+
+        public static object FromBson(Type type, byte[] bytes)
+        {
+            return BsonSerializer.Deserialize(bytes, type);
+        }
+
+        public static object FromBson(Type type, byte[] bytes, int index, int count)
+        {
+            using (MemoryStream memoryStream = new MemoryStream(bytes, index, count))
+            {
+                return BsonSerializer.Deserialize(memoryStream, type);
+            }
+        }
+
+        public static object FromBson(object instance, byte[] bytes, int index, int count)
+        {
+            using (MemoryStream memoryStream = new MemoryStream(bytes, index, count))
+            {
+                return BsonSerializer.Deserialize(memoryStream, instance.GetType());
+            }
+        }
+
+        public static object FromBson(object instance, Stream stream)
+        {
+            return BsonSerializer.Deserialize(stream, instance.GetType());
+        }
+
+        public static object FromStream(Type type, Stream stream)
+        {
+            return BsonSerializer.Deserialize(stream, type);
+        }
+
+        public static T FromBson<T>(byte[] bytes)
+        {
+            using (MemoryStream memoryStream = new MemoryStream(bytes))
+            {
+                return (T)BsonSerializer.Deserialize(memoryStream, typeof(T));
+            }
+        }
+
+        public static T FromBson<T>(byte[] bytes, int index, int count)
+        {
+            return (T)FromBson(typeof(T), bytes, index, count);
+        }
+
+        public static T Clone<T>(T t)
+        {
+            return FromBson<T>(ToBson(t));
+        }
+
+
+        public static void AvoidAOT()
+        {
+            ArraySerializer<int> aint = new ArraySerializer<int>();
+            ArraySerializer<string> astring = new ArraySerializer<string>();
+            ArraySerializer<long> along = new ArraySerializer<long>();
+            EnumerableInterfaceImplementerSerializer<List<int>> e = new EnumerableInterfaceImplementerSerializer<List<int>>();
+            EnumerableInterfaceImplementerSerializer<List<int>, int> elistint = new EnumerableInterfaceImplementerSerializer<List<int>, int>();
+        }
+
+    }
+}

+ 22 - 0
KYFramework/Core/Helper/NetworkHelper.cs

@@ -0,0 +1,22 @@
+using System.Net;
+
+namespace KYFramework
+{
+    public static class NetworkHelper
+    {
+        public static IPEndPoint ToIPEndPoint(string host, int port)
+        {
+            return new IPEndPoint(IPAddress.Parse(host), port);
+        }
+
+        public static IPEndPoint ToIPEndPoint(string address)
+        {
+            int index = address.LastIndexOf(':');
+            string host = address.Substring(0, index);
+            string p = address.Substring(index + 1);
+            int port = int.Parse(p);
+            return ToIPEndPoint(host, port);
+        }
+
+    }
+}

+ 63 - 0
KYFramework/Core/Helper/ProcessHelper.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace KYFramework
+{
+    public static class ProcessHelper
+    {
+        public static Process Run(string exe, string arguments, string workingDirectory = ".", bool waitExit = false)
+        {
+            try
+            {
+                bool redirectStandardOutput = true;
+                bool redirectStandardError = true;
+                bool useShellExecute = false;
+                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+                {
+                    redirectStandardOutput = false;
+                    redirectStandardError = false;
+                    useShellExecute = true;
+                }
+
+                if (waitExit)
+                {
+                    redirectStandardOutput = true;
+                    redirectStandardError = true;
+                    useShellExecute = false;
+                }
+
+                ProcessStartInfo info = new ProcessStartInfo
+                {
+                    FileName = exe,
+                    Arguments = arguments,
+                    CreateNoWindow = true,
+                    UseShellExecute = useShellExecute,
+                    WorkingDirectory = workingDirectory,
+                    RedirectStandardOutput = redirectStandardOutput,
+                    RedirectStandardError = redirectStandardError,
+                };
+
+                Process process = Process.Start(info);
+
+                if (waitExit)
+                {
+                    process.WaitForExit();
+                    if (process.ExitCode != 0)
+                    {
+                        throw new Exception($"{process.StandardOutput.ReadToEnd()} {process.StandardError.ReadToEnd()}");
+                    }
+                }
+
+                return process;
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"dir: {Path.GetFullPath(workingDirectory)}, command: {exe} {arguments}", e);
+            }
+        }
+    }
+
+
+}

+ 67 - 0
KYFramework/Core/Helper/StringHelper.cs

@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+
+namespace KYFramework
+{
+    public static class StringHelper
+    {
+        public static IEnumerable<byte> ToBytes(this string str)
+        {
+            byte[] byteArray = Encoding.Default.GetBytes(str);
+            return byteArray;
+        }
+
+        public static byte[] ToByteArray(this string str)
+        {
+            byte[] byteArray = Encoding.Default.GetBytes(str);
+            return byteArray;
+        }
+
+        public static byte[] ToUtf8(this string str)
+        {
+            byte[] byteArray = Encoding.UTF8.GetBytes(str);
+            return byteArray;
+        }
+
+        public static byte[] HexToBytes(this string hexString)
+        {
+            if (hexString.Length % 2 != 0)
+            {
+                throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The binary key cannot have an odd number of digits: {0}", hexString));
+            }
+
+            var hexAsBytes = new byte[hexString.Length / 2];
+            for (int index = 0; index < hexAsBytes.Length; index++)
+            {
+                string byteValue = "";
+                byteValue += hexString[index * 2];
+                byteValue += hexString[index * 2 + 1];
+                hexAsBytes[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
+            }
+            return hexAsBytes;
+        }
+
+        public static string Fmt(this string text, params object[] args)
+        {
+            return string.Format(text, args);
+        }
+
+        public static string ListToString<T>(this List<T> list)
+        {
+            StringBuilder sb = new StringBuilder();
+            foreach (T t in list)
+            {
+                sb.Append(t);
+                sb.Append(",");
+            }
+            return sb.ToString();
+        }
+
+        public static string MessageToStr(object message)
+        {
+			return MongoHelper.ToJson(message);
+        }
+    }
+}

+ 38 - 0
KYFramework/Core/Helper/TimeHelper.cs

@@ -0,0 +1,38 @@
+namespace KYFramework
+{
+    public static class TimeHelper
+    {
+        public const long OneDay = 86400000;
+        public const long Hour = 3600000;
+        public const long Minute = 60000;
+        
+        /// <summary>
+        /// 客户端时间
+        /// </summary>
+        /// <returns></returns>
+        public static long ClientNow()
+        {
+            return Game.Scene.GetComponent<Timer>().ClientNow();
+        }
+        
+        public static DateTime DateTimeNow()
+        {
+            return DateTime.Now;
+        }
+        
+        public static long ServerNow()
+        {
+            return  Game.Scene.GetComponent<Timer>().ServerNow();
+        }
+
+        public static long ServerFrameTime()
+        {
+            return Game.Scene.GetComponent<Timer>().ServerFrameTime();
+        }
+        
+        public static long ClientFrameTime()
+        {
+            return Game.Scene.GetComponent<Timer>().ClientFrameTime();
+        }
+    }
+}

+ 17 - 0
KYFramework/Core/Helper/TimerInvokeType.cs

@@ -0,0 +1,17 @@
+namespace KYFramework;
+
+public static class TimerInvokeType
+{
+    // 框架层100-200,逻辑层的timer type从200起
+    public const int WaitTimer = 100;
+    public const int SessionIdleChecker = 101;
+    public const int ActorLocationSenderChecker = 102;
+    public const int ActorMessageSenderChecker = 103;
+        
+    // 框架层100-200,逻辑层的timer type 200-300
+    public const int MoveTimer = 201;
+    public const int AttackTimer = 202;
+    public const int AITimer = 203;
+    public const int SessionAcceptTimeout = 204;
+    public const int CountdownTimer = 205;
+}

+ 62 - 0
KYFramework/Core/Module/Config/ACategory.cs

@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace KYFramework
+{
+    public abstract class ACategory : Object
+    {
+        public abstract Type Config { get; }
+
+        public abstract IConfig GetOne();
+
+        public abstract IConfig[] GetAll();
+
+        public abstract IConfig TryGet(int type);
+    }
+
+    public abstract class ACategory<T> : ACategory where T : IConfig
+    {
+        protected Dictionary<int, IConfig> dict;
+
+        public override void BeginInit()
+        {
+            dict = new Dictionary<int, IConfig>();
+            string configStr = ConfigHelper.GetText(typeof(T).Name);
+
+            JObject configStrSerach = JObject.Parse(configStr);
+            IList<JToken> results = configStrSerach["list"]?.Children().ToList();
+
+            foreach (JToken result in results)
+            {
+                T config = result.ToObject<T>();
+                dict[config.Id] = config;
+            }
+        }
+
+        public override Type Config => typeof(T);
+
+        public override void EndInit()
+        {
+        }
+
+        public override IConfig TryGet(int type)
+        {
+            IConfig t;
+            dict.TryGetValue(type, out t);
+            return t;
+        }
+
+        public override IConfig[] GetAll()
+        {
+            return dict.Values.ToArray();
+        }
+
+        public override IConfig GetOne()
+        {
+            return dict.Values.First();
+        }
+    }
+}

+ 10 - 0
KYFramework/Core/Module/Config/ConfigAttribute.cs

@@ -0,0 +1,10 @@
+using System;
+
+namespace KYFramework
+{
+    [AttributeUsage(AttributeTargets.Class)]
+    public class ConfigAttribute : BaseAttribute
+    {
+        
+    }
+}

+ 10 - 0
KYFramework/Core/Module/Config/ConfigComponent.cs

@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+
+namespace KYFramework
+{
+    public class ConfigComponent : Component
+    {
+        public Dictionary<Type, ACategory> allConfig = new Dictionary<Type, ACategory>();
+    }
+}

+ 90 - 0
KYFramework/Core/Module/Config/ConfigComponentSystem.cs

@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+
+namespace KYFramework
+{
+    [ObjectSystem]
+    public class ConfigComponentAwakeSystem : AwakeSystem<ConfigComponent>
+    {
+        public override void Awake(ConfigComponent self)
+        {
+            self.Load();
+        }
+    }
+
+    public static class ConfigComponentSystem
+    {
+        public static void Load(this ConfigComponent self)
+        {
+            self.allConfig.Clear();
+
+            List<Type> types = Game.EventSystem.GetTypes(typeof(ConfigAttribute));
+            foreach (Type type in types)
+            {
+                object[] attrs = type.GetCustomAttributes(typeof(ConfigAttribute), false);
+                
+                if(attrs.Length == 0) continue;
+
+                object obj = Activator.CreateInstance(type);
+                ACategory icategory = obj as ACategory;
+                if (icategory == null)
+                {
+                    throw new Exception($"class: {type.Name} not inherit from ACategory");
+                }
+                
+                icategory.BeginInit();
+                icategory.EndInit();
+
+                self.allConfig[icategory.Config] = icategory;
+            }
+        }
+
+        public static IConfig GetOne(this ConfigComponent self, Type type)
+        {
+            ACategory configCategory;
+            if (!self.allConfig.TryGetValue(type, out configCategory))
+            {
+                throw new Exception($"ConfigComponent not found key: {type.FullName}");
+            }
+            return configCategory.GetOne();
+        }
+
+        public static IConfig Get(this ConfigComponent self, Type type, int id)
+        {
+            ACategory configCategory;
+            if (!self.allConfig.TryGetValue(type, out configCategory))
+            {
+                throw new Exception($"ConfigComponent not found key: {type.FullName}");
+            }
+
+            return configCategory.TryGet(id);
+        }
+
+        public static IConfig TryGet(this ConfigComponent self, Type type, int id)
+        {
+            ACategory configCategory;
+            if (!self.allConfig.TryGetValue(type, out configCategory))
+            {
+                return null;
+            }
+            return configCategory.TryGet(id);
+        }
+        
+        public static IConfig[] GetAll(this ConfigComponent self, Type type)
+        {
+            ACategory configCategory;
+            if (!self.allConfig.TryGetValue(type, out configCategory))
+            {
+                throw new Exception($"ConfigComponent not found key: {type.FullName}");
+            }
+            return configCategory.GetAll();
+        }
+
+        public static ACategory GetCategory(this ConfigComponent self, Type type)
+        {
+            ACategory configCategory;
+            bool ret = self.allConfig.TryGetValue(type, out configCategory);
+            return ret ? configCategory : null;
+        }
+    }
+}

+ 24 - 0
KYFramework/Core/Module/Config/ConfigHelper.cs

@@ -0,0 +1,24 @@
+namespace KYFramework
+{
+    public static class ConfigHelper
+    {
+        
+        public static string GetText(string key)
+        {
+            try
+            {
+                string configStr = File.ReadAllText("Config/" + key + ".txt");
+                return configStr;
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"load config file fail, key: {key}", e);
+            }
+        }
+        
+        public static T ToObject<T>(string str)
+        {
+            return JsonHelper.FromJson<T>(str);
+        }
+    }
+}

+ 7 - 0
KYFramework/Core/Module/Config/IConfig.cs

@@ -0,0 +1,7 @@
+namespace KYFramework
+{
+    public interface IConfig
+    {
+        int Id { get; set; }
+    }
+}

+ 16 - 0
KYFramework/Core/Module/Log/ILog.cs

@@ -0,0 +1,16 @@
+namespace KYFramework
+{
+    public interface ILog
+    {
+        void Trace(string message);
+        void Warning(string message);
+        void Info(string message);
+        void Debug(string message);
+        void Error(string message);
+        void Trace(string message, params object[] args);
+        void Warning(string message, params object[] args);
+        void Info(string message, params object[] args);
+        void Debug(string message, params object[] args);
+        void Error(string message, params object[] args);
+    }
+}

+ 69 - 0
KYFramework/Core/Module/Log/Log.cs

@@ -0,0 +1,69 @@
+using System;
+
+namespace KYFramework
+{
+    public static class Log
+    {
+        public static void Trace(string msg)
+        {
+            Logger.Instance.Trace(msg);
+        }
+
+        public static void Debug(string msg)
+        {
+            Logger.Instance.Debug(msg);
+        }
+
+        public static void Info(string msg)
+        {
+            Logger.Instance.Info(msg);
+        }
+
+        public static void TraceInfo(string msg)
+        {
+            Logger.Instance.Trace(msg);
+        }
+
+        public static void Warning(string msg)
+        {
+            Logger.Instance.Warning(msg);
+        }
+
+        public static void Error(string msg)
+        {
+            Logger.Instance.Error(msg);
+        }
+
+        public static void Error(Exception e)
+        {
+            Logger.Instance.Error(e);
+        }
+
+        public static void Trace(string message, params object[] args)
+        {
+            Logger.Instance.Trace(message, args);
+        }
+
+        public static void Warning(string message, params object[] args)
+        {
+            Logger.Instance.Warning(string.Format(message, args));
+        }
+
+        public static void Info(string message, params object[] args)
+        {
+            Logger.Instance.Info(string.Format(message, args));
+        }
+
+        public static void Debug(string message, params object[] args)
+        {
+            Logger.Instance.Debug(string.Format(message, args));
+
+        }
+
+        public static void Error(string message, params object[] args)
+        {
+            Logger.Instance.Error(message, args);
+        }
+        
+    }
+}

+ 158 - 0
KYFramework/Core/Module/Log/Logger.cs

@@ -0,0 +1,158 @@
+using System;
+using System.Diagnostics;
+
+namespace KYFramework
+{
+    public class Logger
+    {
+        private static Logger instance;
+
+        public static Logger Instance
+        {
+            get
+            {
+                if (instance == null) instance = new Logger();
+                return instance;
+            }
+        }
+        private ILog iLog;
+
+        public ILog ILog
+        {
+            get
+            {
+                return iLog;
+            }
+            set
+            {
+                this.iLog = value;
+            }
+        }
+        
+        private const int TraceLevel = 1;
+        private const int DebugLevel = 2;
+        private const int InfoLevel = 3;
+        private const int WarningLevel = 4;
+
+        private bool CheckLogLevel(int level)
+        {
+            if (OptionComponent.Instance == null)
+            {
+                return true;
+            }
+            return OptionComponent.Instance.option.LogLevel <= level;
+        }
+        
+        public void Trace(string msg)
+        {
+            if (!CheckLogLevel(DebugLevel))
+            {
+                return;
+            }
+            StackTrace st = new StackTrace(2, true);
+            Logger.Instance.Trace($"{msg}\n{st}");
+        }
+
+        public void Debug(string msg)
+        {
+            if (!CheckLogLevel(DebugLevel))
+            {
+                return;
+            }
+            this.iLog?.Debug(msg);
+        }
+
+        public void Info(string msg)
+        {
+            if (!CheckLogLevel(InfoLevel))
+            {
+                return;
+            }
+            this.iLog?.Info(msg);
+        }
+
+        public void TraceInfo(string msg)
+        {
+            if (!CheckLogLevel(InfoLevel))
+            {
+                return;
+            }
+            StackTrace st = new StackTrace(2, true);
+            this.iLog?.Trace($"{msg}\n{st}");
+        }
+
+        public void Warning(string msg)
+        {
+            if (!CheckLogLevel(WarningLevel))
+            {
+                return;
+            }
+
+            this.iLog?.Warning(msg);
+        }
+
+        public void Error(string msg)
+        {
+            StackTrace st = new StackTrace(2, true);
+            this.iLog?.Error($"{msg}\n{st}");
+        }
+
+        public void Error(Exception e)
+        {
+            if (e.Data.Contains("StackTrace"))
+            {
+                this.iLog?.Error($"{e.Data["StackTrace"]}\n{e}");
+                return;
+            }
+            string str = e.ToString();
+            this.iLog?.Error(str);
+        }
+
+        public void Trace(string message, params object[] args)
+        {
+            if (!CheckLogLevel(TraceLevel))
+            {
+                return;
+            }
+            StackTrace st = new StackTrace(2, true);
+            this.iLog?.Trace($"{string.Format(message, args)}\n{st}");
+        }
+
+        public void Warning(string message, params object[] args)
+        {
+            if (!CheckLogLevel(WarningLevel))
+            {
+                return;
+            }
+            this.iLog?.Warning(string.Format(message, args));
+        }
+
+        public void Info(string message, params object[] args)
+        {
+            if (!CheckLogLevel(InfoLevel))
+            {
+                return;
+            }
+            this.iLog?.Info(string.Format(message, args));
+        }
+
+        public void Debug(string message, params object[] args)
+        {
+            if (!CheckLogLevel(DebugLevel))
+            {
+                return;
+            }
+            this.iLog?.Debug(string.Format(message, args));
+
+        }
+
+        public void Error(string message, params object[] args)
+        {
+            StackTrace st = new StackTrace(2, true);
+            string s = string.Format(message, args) + '\n' + st;
+            this.iLog?.Error(s);
+        }
+        
+      
+    }
+}

+ 78 - 0
KYFramework/Core/Module/Log/NLogger.cs

@@ -0,0 +1,78 @@
+using System;
+using KYFramework;
+using NLog;
+
+namespace KYFramework
+{
+    public class NLogger : ILog
+    {
+        private readonly NLog.Logger logger;
+
+        public NLogger(string name,  string configPath)
+        {
+            LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(configPath);
+            LogManager.Configuration.Variables["currentDir"] = Environment.CurrentDirectory;
+            this.logger = LogManager.GetLogger(name);
+        }
+
+        public void Trace(string message)
+        {
+            this.logger.Trace(message);
+        }
+
+        public void Warning(string message)
+        {
+            this.logger.Warn(message);
+        }
+
+        public void Info(string message)
+        {
+            this.logger.Info(message);
+        }
+
+        public void Debug(string message)
+        {
+            this.logger.Debug(message);
+        }
+
+        public void Error(string message)
+        {
+            this.logger.Error(message);
+        }
+
+        public void Fatal(string message)
+        {
+            this.logger.Fatal(message);
+        }
+
+        public void Trace(string message, params object[] args)
+        {
+            this.logger.Trace(message, args);
+        }
+
+        public void Warning(string message, params object[] args)
+        {
+            this.logger.Warn(message, args);
+        }
+
+        public void Info(string message, params object[] args)
+        {
+            this.logger.Info(message, args);
+        }
+
+        public void Debug(string message, params object[] args)
+        {
+            this.logger.Debug(message, args);
+        }
+
+        public void Error(string message, params object[] args)
+        {
+            this.logger.Error(message, args);
+        }
+
+        public void Fatal(string message, params object[] args)
+        {
+            this.logger.Fatal(message, args);
+        }
+    }
+}

+ 11 - 0
KYFramework/Core/Module/Timer/ATimer.cs

@@ -0,0 +1,11 @@
+namespace KYFramework;
+
+public abstract class ATimer<T>: AInvokeHandler<TimerCallback> where T: class
+{
+    public override void Handle(TimerCallback a)
+    {
+        this.Run(a.Args as T);
+    }
+
+    protected abstract void Run(T t);
+}

+ 28 - 0
KYFramework/KYFramework.csproj

@@ -0,0 +1,28 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+
+  <ItemGroup>
+    <PackageReference Include="MongoDB.Bson" Version="2.0.0" />
+    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
+    <PackageReference Include="NLog" Version="5.1.3" />
+    <PackageReference Include="UniTask" Version="2.5.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Reference Include="MongoDB.Bson">
+      <HintPath>..\Plugins\MongoDB\MongoDB.Bson.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+
+
+  <ItemGroup>
+    <ProjectReference Include="..\ThirdParty\ThirdParty.csproj" />
+  </ItemGroup>
+
+</Project>

+ 621 - 0
KYFramework/bin/Debug/net7.0/KYFramework.deps.json

@@ -0,0 +1,621 @@
+{
+  "runtimeTarget": {
+    "name": ".NETCoreApp,Version=v7.0",
+    "signature": ""
+  },
+  "compilationOptions": {},
+  "targets": {
+    ".NETCoreApp,Version=v7.0": {
+      "KYFramework/1.0.0": {
+        "dependencies": {
+          "MongoDB.Bson": "2.0.0",
+          "NLog": "5.1.3",
+          "Newtonsoft.Json": "13.0.3",
+          "ThirdParty": "1.0.0",
+          "UniTask": "2.5.0"
+        },
+        "runtime": {
+          "KYFramework.dll": {}
+        }
+      },
+      "Google.Protobuf/3.21.9": {
+        "runtime": {
+          "lib/net5.0/Google.Protobuf.dll": {
+            "assemblyVersion": "3.21.9.0",
+            "fileVersion": "3.21.9.0"
+          }
+        }
+      },
+      "K4os.Compression.LZ4/1.3.5": {
+        "runtime": {
+          "lib/net6.0/K4os.Compression.LZ4.dll": {
+            "assemblyVersion": "1.3.5.0",
+            "fileVersion": "1.3.5.0"
+          }
+        }
+      },
+      "K4os.Compression.LZ4.Streams/1.3.5": {
+        "dependencies": {
+          "K4os.Compression.LZ4": "1.3.5",
+          "K4os.Hash.xxHash": "1.0.8",
+          "System.IO.Pipelines": "6.0.3"
+        },
+        "runtime": {
+          "lib/net6.0/K4os.Compression.LZ4.Streams.dll": {
+            "assemblyVersion": "1.3.5.0",
+            "fileVersion": "1.3.5.0"
+          }
+        }
+      },
+      "K4os.Hash.xxHash/1.0.8": {
+        "runtime": {
+          "lib/net6.0/K4os.Hash.xxHash.dll": {
+            "assemblyVersion": "1.0.8.0",
+            "fileVersion": "1.0.8.0"
+          }
+        }
+      },
+      "Microsoft.NETCore.Platforms/3.1.0": {},
+      "Microsoft.NETCore.Targets/1.1.0": {},
+      "Microsoft.Win32.SystemEvents/4.7.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0"
+        },
+        "runtime": {
+          "lib/netstandard2.0/Microsoft.Win32.SystemEvents.dll": {
+            "assemblyVersion": "4.0.2.0",
+            "fileVersion": "4.700.19.56404"
+          }
+        },
+        "runtimeTargets": {
+          "runtimes/win/lib/netcoreapp3.0/Microsoft.Win32.SystemEvents.dll": {
+            "rid": "win",
+            "assetType": "runtime",
+            "assemblyVersion": "4.0.2.0",
+            "fileVersion": "4.700.19.56404"
+          }
+        }
+      },
+      "MongoDB.Bson/2.0.0": {
+        "runtime": {
+          "lib/net45/MongoDB.Bson.dll": {
+            "assemblyVersion": "2.0.0.828",
+            "fileVersion": "2.0.0.828"
+          }
+        }
+      },
+      "MySql.Data/8.1.0": {
+        "dependencies": {
+          "Google.Protobuf": "3.21.9",
+          "K4os.Compression.LZ4.Streams": "1.3.5",
+          "Portable.BouncyCastle": "1.9.0",
+          "System.Buffers": "4.5.1",
+          "System.Configuration.ConfigurationManager": "4.4.1",
+          "System.Diagnostics.DiagnosticSource": "7.0.2",
+          "System.Runtime.CompilerServices.Unsafe": "6.0.0",
+          "System.Runtime.Loader": "4.3.0",
+          "System.Security.Permissions": "4.7.0",
+          "System.Text.Encoding.CodePages": "4.4.0",
+          "System.Text.Json": "7.0.1",
+          "System.Threading.Tasks.Extensions": "4.5.4",
+          "ZstdSharp.Port": "0.7.1"
+        },
+        "runtime": {
+          "lib/net7.0/MySql.Data.dll": {
+            "assemblyVersion": "8.1.0.0",
+            "fileVersion": "8.1.0.0"
+          }
+        },
+        "runtimeTargets": {
+          "runtimes/win-x64/native/comerr64.dll": {
+            "rid": "win-x64",
+            "assetType": "native",
+            "fileVersion": "4.1.0.0"
+          },
+          "runtimes/win-x64/native/gssapi64.dll": {
+            "rid": "win-x64",
+            "assetType": "native",
+            "fileVersion": "4.1.0.0"
+          },
+          "runtimes/win-x64/native/k5sprt64.dll": {
+            "rid": "win-x64",
+            "assetType": "native",
+            "fileVersion": "4.1.0.0"
+          },
+          "runtimes/win-x64/native/krb5_64.dll": {
+            "rid": "win-x64",
+            "assetType": "native",
+            "fileVersion": "4.1.0.0"
+          },
+          "runtimes/win-x64/native/krbcc64.dll": {
+            "rid": "win-x64",
+            "assetType": "native",
+            "fileVersion": "4.1.0.0"
+          }
+        }
+      },
+      "Newtonsoft.Json/13.0.3": {
+        "runtime": {
+          "lib/net6.0/Newtonsoft.Json.dll": {
+            "assemblyVersion": "13.0.0.0",
+            "fileVersion": "13.0.3.27908"
+          }
+        }
+      },
+      "NLog/5.1.3": {
+        "runtime": {
+          "lib/netstandard2.0/NLog.dll": {
+            "assemblyVersion": "5.0.0.0",
+            "fileVersion": "5.1.3.1645"
+          }
+        }
+      },
+      "Portable.BouncyCastle/1.9.0": {
+        "runtime": {
+          "lib/netstandard2.0/BouncyCastle.Crypto.dll": {
+            "assemblyVersion": "1.9.0.0",
+            "fileVersion": "1.9.0.1"
+          }
+        }
+      },
+      "System.Buffers/4.5.1": {},
+      "System.Configuration.ConfigurationManager/4.4.1": {
+        "dependencies": {
+          "System.Security.Cryptography.ProtectedData": "4.4.0"
+        },
+        "runtime": {
+          "lib/netstandard2.0/System.Configuration.ConfigurationManager.dll": {
+            "assemblyVersion": "4.0.0.0",
+            "fileVersion": "4.6.25921.2"
+          }
+        }
+      },
+      "System.Diagnostics.DiagnosticSource/7.0.2": {},
+      "System.Drawing.Common/4.7.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.Win32.SystemEvents": "4.7.0"
+        },
+        "runtime": {
+          "lib/netstandard2.0/System.Drawing.Common.dll": {
+            "assemblyVersion": "4.0.0.1",
+            "fileVersion": "4.6.26919.2"
+          }
+        },
+        "runtimeTargets": {
+          "runtimes/unix/lib/netcoreapp3.0/System.Drawing.Common.dll": {
+            "rid": "unix",
+            "assetType": "runtime",
+            "assemblyVersion": "4.0.2.0",
+            "fileVersion": "4.700.19.56404"
+          },
+          "runtimes/win/lib/netcoreapp3.0/System.Drawing.Common.dll": {
+            "rid": "win",
+            "assetType": "runtime",
+            "assemblyVersion": "4.0.2.0",
+            "fileVersion": "4.700.19.56404"
+          }
+        }
+      },
+      "System.IO/4.3.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.0",
+          "System.Text.Encoding": "4.3.0",
+          "System.Threading.Tasks": "4.3.0"
+        }
+      },
+      "System.IO.Pipelines/6.0.3": {
+        "runtime": {
+          "lib/net6.0/System.IO.Pipelines.dll": {
+            "assemblyVersion": "6.0.0.0",
+            "fileVersion": "6.0.522.21309"
+          }
+        }
+      },
+      "System.Reflection/4.3.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.IO": "4.3.0",
+          "System.Reflection.Primitives": "4.3.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Reflection.Primitives/4.3.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Runtime/4.3.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0"
+        }
+      },
+      "System.Runtime.CompilerServices.Unsafe/6.0.0": {},
+      "System.Runtime.Loader/4.3.0": {
+        "dependencies": {
+          "System.IO": "4.3.0",
+          "System.Reflection": "4.3.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Security.AccessControl/4.7.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "System.Security.Principal.Windows": "4.7.0"
+        }
+      },
+      "System.Security.Cryptography.ProtectedData/4.4.0": {
+        "runtime": {
+          "lib/netstandard2.0/System.Security.Cryptography.ProtectedData.dll": {
+            "assemblyVersion": "4.0.2.0",
+            "fileVersion": "4.6.25519.3"
+          }
+        },
+        "runtimeTargets": {
+          "runtimes/win/lib/netstandard2.0/System.Security.Cryptography.ProtectedData.dll": {
+            "rid": "win",
+            "assetType": "runtime",
+            "assemblyVersion": "4.0.2.0",
+            "fileVersion": "4.6.25519.3"
+          }
+        }
+      },
+      "System.Security.Permissions/4.7.0": {
+        "dependencies": {
+          "System.Security.AccessControl": "4.7.0",
+          "System.Windows.Extensions": "4.7.0"
+        },
+        "runtime": {
+          "lib/netcoreapp3.0/System.Security.Permissions.dll": {
+            "assemblyVersion": "4.0.3.0",
+            "fileVersion": "4.700.19.56404"
+          }
+        }
+      },
+      "System.Security.Principal.Windows/4.7.0": {},
+      "System.Text.Encoding/4.3.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Text.Encoding.CodePages/4.4.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0"
+        }
+      },
+      "System.Text.Encodings.Web/7.0.0": {},
+      "System.Text.Json/7.0.1": {
+        "dependencies": {
+          "System.Text.Encodings.Web": "7.0.0"
+        }
+      },
+      "System.Threading.Tasks/4.3.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Threading.Tasks.Extensions/4.5.4": {},
+      "System.Windows.Extensions/4.7.0": {
+        "dependencies": {
+          "System.Drawing.Common": "4.7.0"
+        },
+        "runtime": {
+          "lib/netcoreapp3.0/System.Windows.Extensions.dll": {
+            "assemblyVersion": "4.0.1.0",
+            "fileVersion": "4.700.19.56404"
+          }
+        },
+        "runtimeTargets": {
+          "runtimes/win/lib/netcoreapp3.0/System.Windows.Extensions.dll": {
+            "rid": "win",
+            "assetType": "runtime",
+            "assemblyVersion": "4.0.1.0",
+            "fileVersion": "4.700.19.56404"
+          }
+        }
+      },
+      "UniTask/2.5.0": {
+        "dependencies": {
+          "System.Threading.Tasks.Extensions": "4.5.4"
+        },
+        "runtime": {
+          "lib/net7.0/UniTask.dll": {
+            "assemblyVersion": "2.5.0.0",
+            "fileVersion": "2.5.0.0"
+          }
+        }
+      },
+      "ZstdSharp.Port/0.7.1": {
+        "runtime": {
+          "lib/net7.0/ZstdSharp.dll": {
+            "assemblyVersion": "0.7.1.0",
+            "fileVersion": "0.7.1.0"
+          }
+        }
+      },
+      "ThirdParty/1.0.0": {
+        "dependencies": {
+          "MySql.Data": "8.1.0",
+          "UniTask": "2.5.0"
+        },
+        "runtime": {
+          "ThirdParty.dll": {}
+        }
+      }
+    }
+  },
+  "libraries": {
+    "KYFramework/1.0.0": {
+      "type": "project",
+      "serviceable": false,
+      "sha512": ""
+    },
+    "Google.Protobuf/3.21.9": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-OTpFujTgkmqMLbg3KT7F/iuKi1rg6s5FCS2M9XcVLDn40zL8wgXm37CY/F6MeOEXKjdcnXGCN/h7oyMkVydVsg==",
+      "path": "google.protobuf/3.21.9",
+      "hashPath": "google.protobuf.3.21.9.nupkg.sha512"
+    },
+    "K4os.Compression.LZ4/1.3.5": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-TS4mqlT0X1OlnvOGNfl02QdVUhuqgWuCnn7UxupIa7C9Pb6qlQ5yZA2sPhRh0OSmVULaQU64KV4wJuu//UyVQQ==",
+      "path": "k4os.compression.lz4/1.3.5",
+      "hashPath": "k4os.compression.lz4.1.3.5.nupkg.sha512"
+    },
+    "K4os.Compression.LZ4.Streams/1.3.5": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-M0NufZI8ym3mm6F6HMSPz1jw7TJGdY74fjAtbIXATmnAva/8xLz50eQZJI9tf9mMeHUaFDg76N1BmEh8GR5zeA==",
+      "path": "k4os.compression.lz4.streams/1.3.5",
+      "hashPath": "k4os.compression.lz4.streams.1.3.5.nupkg.sha512"
+    },
+    "K4os.Hash.xxHash/1.0.8": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-Wp2F7BamQ2Q/7Hk834nV9vRQapgcr8kgv9Jvfm8J3D0IhDqZMMl+a2yxUq5ltJitvXvQfB8W6K4F4fCbw/P6YQ==",
+      "path": "k4os.hash.xxhash/1.0.8",
+      "hashPath": "k4os.hash.xxhash.1.0.8.nupkg.sha512"
+    },
+    "Microsoft.NETCore.Platforms/3.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-z7aeg8oHln2CuNulfhiLYxCVMPEwBl3rzicjvIX+4sUuCwvXw5oXQEtbiU2c0z4qYL5L3Kmx0mMA/+t/SbY67w==",
+      "path": "microsoft.netcore.platforms/3.1.0",
+      "hashPath": "microsoft.netcore.platforms.3.1.0.nupkg.sha512"
+    },
+    "Microsoft.NETCore.Targets/1.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==",
+      "path": "microsoft.netcore.targets/1.1.0",
+      "hashPath": "microsoft.netcore.targets.1.1.0.nupkg.sha512"
+    },
+    "Microsoft.Win32.SystemEvents/4.7.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-mtVirZr++rq+XCDITMUdnETD59XoeMxSpLRIII7JRI6Yj0LEDiO1pPn0ktlnIj12Ix8bfvQqQDMMIF9wC98oCA==",
+      "path": "microsoft.win32.systemevents/4.7.0",
+      "hashPath": "microsoft.win32.systemevents.4.7.0.nupkg.sha512"
+    },
+    "MongoDB.Bson/2.0.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-oij2O4yegOKc6zZByxhbuILQIqT0xbUv9DHAt7HdQTzvlOJ7WgKwsMsoQR6VO4qd8PntGvcC9o/sNAj3KdndKA==",
+      "path": "mongodb.bson/2.0.0",
+      "hashPath": "mongodb.bson.2.0.0.nupkg.sha512"
+    },
+    "MySql.Data/8.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-7kEJLyty7HcqJD0lnfs+2fdMrvCl0RY5oykvZThbmg6QVLT55dwygI69Eqxl0M6IThP9woyjpsezT6m7gKRrLA==",
+      "path": "mysql.data/8.1.0",
+      "hashPath": "mysql.data.8.1.0.nupkg.sha512"
+    },
+    "Newtonsoft.Json/13.0.3": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==",
+      "path": "newtonsoft.json/13.0.3",
+      "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512"
+    },
+    "NLog/5.1.3": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-rB8hwjBf1EZCfG5iPfsv3gPksLoJLr1cOrt7PBbJu6VpJgwYJchDzTUT1dhNDdPv0QakXJQJOhE59ErupcznQQ==",
+      "path": "nlog/5.1.3",
+      "hashPath": "nlog.5.1.3.nupkg.sha512"
+    },
+    "Portable.BouncyCastle/1.9.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-eZZBCABzVOek+id9Xy04HhmgykF0wZg9wpByzrWN7q8qEI0Qen9b7tfd7w8VA3dOeesumMG7C5ZPy0jk7PSRHw==",
+      "path": "portable.bouncycastle/1.9.0",
+      "hashPath": "portable.bouncycastle.1.9.0.nupkg.sha512"
+    },
+    "System.Buffers/4.5.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==",
+      "path": "system.buffers/4.5.1",
+      "hashPath": "system.buffers.4.5.1.nupkg.sha512"
+    },
+    "System.Configuration.ConfigurationManager/4.4.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-jz3TWKMAeuDEyrPCK5Jyt4bzQcmzUIMcY9Ud6PkElFxTfnsihV+9N/UCqvxe1z5gc7jMYAnj7V1COMS9QKIuHQ==",
+      "path": "system.configuration.configurationmanager/4.4.1",
+      "hashPath": "system.configuration.configurationmanager.4.4.1.nupkg.sha512"
+    },
+    "System.Diagnostics.DiagnosticSource/7.0.2": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-hYr3I9N9811e0Bjf2WNwAGGyTuAFbbTgX1RPLt/3Wbm68x3IGcX5Cl75CMmgT6WlNwLQ2tCCWfqYPpypjaf2xA==",
+      "path": "system.diagnostics.diagnosticsource/7.0.2",
+      "hashPath": "system.diagnostics.diagnosticsource.7.0.2.nupkg.sha512"
+    },
+    "System.Drawing.Common/4.7.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-v+XbyYHaZjDfn0ENmJEV1VYLgGgCTx1gnfOBcppowbpOAriglYgGCvFCPr2EEZyBvXlpxbEsTwkOlInl107ahA==",
+      "path": "system.drawing.common/4.7.0",
+      "hashPath": "system.drawing.common.4.7.0.nupkg.sha512"
+    },
+    "System.IO/4.3.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==",
+      "path": "system.io/4.3.0",
+      "hashPath": "system.io.4.3.0.nupkg.sha512"
+    },
+    "System.IO.Pipelines/6.0.3": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-ryTgF+iFkpGZY1vRQhfCzX0xTdlV3pyaTTqRu2ETbEv+HlV7O6y7hyQURnghNIXvctl5DuZ//Dpks6HdL/Txgw==",
+      "path": "system.io.pipelines/6.0.3",
+      "hashPath": "system.io.pipelines.6.0.3.nupkg.sha512"
+    },
+    "System.Reflection/4.3.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==",
+      "path": "system.reflection/4.3.0",
+      "hashPath": "system.reflection.4.3.0.nupkg.sha512"
+    },
+    "System.Reflection.Primitives/4.3.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==",
+      "path": "system.reflection.primitives/4.3.0",
+      "hashPath": "system.reflection.primitives.4.3.0.nupkg.sha512"
+    },
+    "System.Runtime/4.3.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==",
+      "path": "system.runtime/4.3.0",
+      "hashPath": "system.runtime.4.3.0.nupkg.sha512"
+    },
+    "System.Runtime.CompilerServices.Unsafe/6.0.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==",
+      "path": "system.runtime.compilerservices.unsafe/6.0.0",
+      "hashPath": "system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512"
+    },
+    "System.Runtime.Loader/4.3.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-DHMaRn8D8YCK2GG2pw+UzNxn/OHVfaWx7OTLBD/hPegHZZgcZh3H6seWegrC4BYwsfuGrywIuT+MQs+rPqRLTQ==",
+      "path": "system.runtime.loader/4.3.0",
+      "hashPath": "system.runtime.loader.4.3.0.nupkg.sha512"
+    },
+    "System.Security.AccessControl/4.7.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-JECvTt5aFF3WT3gHpfofL2MNNP6v84sxtXxpqhLBCcDRzqsPBmHhQ6shv4DwwN2tRlzsUxtb3G9M3763rbXKDg==",
+      "path": "system.security.accesscontrol/4.7.0",
+      "hashPath": "system.security.accesscontrol.4.7.0.nupkg.sha512"
+    },
+    "System.Security.Cryptography.ProtectedData/4.4.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-cJV7ScGW7EhatRsjehfvvYVBvtiSMKgN8bOVI0bQhnF5bU7vnHVIsH49Kva7i7GWaWYvmEzkYVk1TC+gZYBEog==",
+      "path": "system.security.cryptography.protecteddata/4.4.0",
+      "hashPath": "system.security.cryptography.protecteddata.4.4.0.nupkg.sha512"
+    },
+    "System.Security.Permissions/4.7.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-dkOV6YYVBnYRa15/yv004eCGRBVADXw8qRbbNiCn/XpdJSUXkkUeIvdvFHkvnko4CdKMqG8yRHC4ox83LSlMsQ==",
+      "path": "system.security.permissions/4.7.0",
+      "hashPath": "system.security.permissions.4.7.0.nupkg.sha512"
+    },
+    "System.Security.Principal.Windows/4.7.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-ojD0PX0XhneCsUbAZVKdb7h/70vyYMDYs85lwEI+LngEONe/17A0cFaRFqZU+sOEidcVswYWikYOQ9PPfjlbtQ==",
+      "path": "system.security.principal.windows/4.7.0",
+      "hashPath": "system.security.principal.windows.4.7.0.nupkg.sha512"
+    },
+    "System.Text.Encoding/4.3.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==",
+      "path": "system.text.encoding/4.3.0",
+      "hashPath": "system.text.encoding.4.3.0.nupkg.sha512"
+    },
+    "System.Text.Encoding.CodePages/4.4.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-6JX7ZdaceBiLKLkYt8zJcp4xTJd1uYyXXEkPw6mnlUIjh1gZPIVKPtRXPmY5kLf6DwZmf5YLwR3QUrRonl7l0A==",
+      "path": "system.text.encoding.codepages/4.4.0",
+      "hashPath": "system.text.encoding.codepages.4.4.0.nupkg.sha512"
+    },
+    "System.Text.Encodings.Web/7.0.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-OP6umVGxc0Z0MvZQBVigj4/U31Pw72ITihDWP9WiWDm+q5aoe0GaJivsfYGq53o6dxH7DcXWiCTl7+0o2CGdmg==",
+      "path": "system.text.encodings.web/7.0.0",
+      "hashPath": "system.text.encodings.web.7.0.0.nupkg.sha512"
+    },
+    "System.Text.Json/7.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-OtDEmCCiNl8JAduFKZ/r0Sw6XZNHwIicUYy/mXgMDGeOsZLshH37qi3oPRzFYiryVktiMoQLByMGPtRCEMYbeQ==",
+      "path": "system.text.json/7.0.1",
+      "hashPath": "system.text.json.7.0.1.nupkg.sha512"
+    },
+    "System.Threading.Tasks/4.3.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==",
+      "path": "system.threading.tasks/4.3.0",
+      "hashPath": "system.threading.tasks.4.3.0.nupkg.sha512"
+    },
+    "System.Threading.Tasks.Extensions/4.5.4": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
+      "path": "system.threading.tasks.extensions/4.5.4",
+      "hashPath": "system.threading.tasks.extensions.4.5.4.nupkg.sha512"
+    },
+    "System.Windows.Extensions/4.7.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-CeWTdRNfRaSh0pm2gDTJFwVaXfTq6Xwv/sA887iwPTneW7oMtMlpvDIO+U60+3GWTB7Aom6oQwv5VZVUhQRdPQ==",
+      "path": "system.windows.extensions/4.7.0",
+      "hashPath": "system.windows.extensions.4.7.0.nupkg.sha512"
+    },
+    "UniTask/2.5.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-dHo6NECX3+Aa3ayQFvTVTs0C5NnhPKVpJUZaOjOPlaEUvH1aDLWX2p8gHRzpl8d/nHwLg+yl2/hVB+TDSmuxIA==",
+      "path": "unitask/2.5.0",
+      "hashPath": "unitask.2.5.0.nupkg.sha512"
+    },
+    "ZstdSharp.Port/0.7.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-Idgg+mJEyAujqDPzA3APy9dNoyw0YQcNA65GgYjktDRtJ+nvx/hv+J+m6Eax3JJMGEYGy04oc5YNP6ZvQ3Y1vQ==",
+      "path": "zstdsharp.port/0.7.1",
+      "hashPath": "zstdsharp.port.0.7.1.nupkg.sha512"
+    },
+    "ThirdParty/1.0.0": {
+      "type": "project",
+      "serviceable": false,
+      "sha512": ""
+    }
+  }
+}

BIN
KYFramework/bin/Debug/net7.0/KYFramework.dll


BIN
KYFramework/bin/Debug/net7.0/KYFramework.pdb


BIN
KYFramework/bin/Debug/net7.0/ThirdParty.dll


BIN
KYFramework/bin/Debug/net7.0/ThirdParty.pdb


+ 4 - 0
KYFramework/obj/Debug/net47/.NETFramework,Version=v4.7.AssemblyAttributes.cs

@@ -0,0 +1,4 @@
+// <autogenerated />
+using System;
+using System.Reflection;
+[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7", FrameworkDisplayName = ".NET Framework 4.7")]

+ 22 - 0
KYFramework/obj/Debug/net47/KYFramework.AssemblyInfo.cs

@@ -0,0 +1,22 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+using System;
+using System.Reflection;
+
+[assembly: System.Reflection.AssemblyCompanyAttribute("KYFramework")]
+[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
+[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
+[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
+[assembly: System.Reflection.AssemblyProductAttribute("KYFramework")]
+[assembly: System.Reflection.AssemblyTitleAttribute("KYFramework")]
+[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
+
+// 由 MSBuild WriteCodeFragment 类生成。
+

+ 1 - 0
KYFramework/obj/Debug/net47/KYFramework.AssemblyInfoInputs.cache

@@ -0,0 +1 @@
+6b3e64dc13fce7a3142a97259f18ca363e5fa5d0

+ 3 - 0
KYFramework/obj/Debug/net47/KYFramework.GeneratedMSBuildEditorConfig.editorconfig

@@ -0,0 +1,3 @@
+is_global = true
+build_property.RootNamespace = KYFramework
+build_property.ProjectDir = D:\LEZ\simulation-server\KYFramework\

+ 8 - 0
KYFramework/obj/Debug/net47/KYFramework.GlobalUsings.g.cs

@@ -0,0 +1,8 @@
+// <auto-generated/>
+global using global::System;
+global using global::System.Collections.Generic;
+global using global::System.IO;
+global using global::System.Linq;
+global using global::System.Net.Http;
+global using global::System.Threading;
+global using global::System.Threading.Tasks;

BIN
KYFramework/obj/Debug/net47/KYFramework.assets.cache


BIN
KYFramework/obj/Debug/net47/KYFramework.csproj.AssemblyReference.cache


+ 4 - 0
KYFramework/obj/Debug/net7.0/.NETCoreApp,Version=v7.0.AssemblyAttributes.cs

@@ -0,0 +1,4 @@
+// <autogenerated />
+using System;
+using System.Reflection;
+[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v7.0", FrameworkDisplayName = ".NET 7.0")]

+ 0 - 0
KYFramework/obj/Debug/net7.0/KYFramew.00291D58.Up2Date


+ 22 - 0
KYFramework/obj/Debug/net7.0/KYFramework.AssemblyInfo.cs

@@ -0,0 +1,22 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+using System;
+using System.Reflection;
+
+[assembly: System.Reflection.AssemblyCompanyAttribute("KYFramework")]
+[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
+[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
+[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
+[assembly: System.Reflection.AssemblyProductAttribute("KYFramework")]
+[assembly: System.Reflection.AssemblyTitleAttribute("KYFramework")]
+[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
+
+// 由 MSBuild WriteCodeFragment 类生成。
+

+ 1 - 0
KYFramework/obj/Debug/net7.0/KYFramework.AssemblyInfoInputs.cache

@@ -0,0 +1 @@
+1bee492251e7a329c725f8454e2cf72f24ab6d041038ca8dcdd9ea2360e6b48b

+ 13 - 0
KYFramework/obj/Debug/net7.0/KYFramework.GeneratedMSBuildEditorConfig.editorconfig

@@ -0,0 +1,13 @@
+is_global = true
+build_property.TargetFramework = net7.0
+build_property.TargetPlatformMinVersion = 
+build_property.UsingMicrosoftNETSdkWeb = 
+build_property.ProjectTypeGuids = 
+build_property.InvariantGlobalization = 
+build_property.PlatformNeutralAssembly = 
+build_property.EnforceExtendedAnalyzerRules = 
+build_property._SupportedPlatformList = Linux,macOS,Windows
+build_property.RootNamespace = KYFramework
+build_property.ProjectDir = D:\Git\simulation-server\KYFramework\
+build_property.EnableComHosting = 
+build_property.EnableGeneratedComInterfaceComImportInterop = 

+ 13 - 0
KYFramework/obj/Debug/net7.0/KYFramework.GeneratedMSBuildEditorConfig.editorconfig.mine

@@ -0,0 +1,13 @@
+is_global = true
+build_property.TargetFramework = net7.0
+build_property.TargetPlatformMinVersion = 
+build_property.UsingMicrosoftNETSdkWeb = 
+build_property.ProjectTypeGuids = 
+build_property.InvariantGlobalization = 
+build_property.PlatformNeutralAssembly = 
+build_property.EnforceExtendedAnalyzerRules = 
+build_property._SupportedPlatformList = Linux,macOS,Windows
+build_property.RootNamespace = KYFramework
+build_property.ProjectDir = D:\SVN Projects\SimulationServer\simulation-server\KYFramework\
+build_property.EnableComHosting = 
+build_property.EnableGeneratedComInterfaceComImportInterop = 

+ 13 - 0
KYFramework/obj/Debug/net7.0/KYFramework.GeneratedMSBuildEditorConfig.editorconfig.r14

@@ -0,0 +1,13 @@
+is_global = true
+build_property.TargetFramework = net7.0
+build_property.TargetPlatformMinVersion = 
+build_property.UsingMicrosoftNETSdkWeb = 
+build_property.ProjectTypeGuids = 
+build_property.InvariantGlobalization = 
+build_property.PlatformNeutralAssembly = 
+build_property.EnforceExtendedAnalyzerRules = 
+build_property._SupportedPlatformList = Linux,macOS,Windows
+build_property.RootNamespace = KYFramework
+build_property.ProjectDir = D:\SVN\SimulationServer\simulation-server\KYFramework\
+build_property.EnableComHosting = 
+build_property.EnableGeneratedComInterfaceComImportInterop = 

+ 13 - 0
KYFramework/obj/Debug/net7.0/KYFramework.GeneratedMSBuildEditorConfig.editorconfig.r5

@@ -0,0 +1,13 @@
+is_global = true
+build_property.TargetFramework = net7.0
+build_property.TargetPlatformMinVersion = 
+build_property.UsingMicrosoftNETSdkWeb = 
+build_property.ProjectTypeGuids = 
+build_property.InvariantGlobalization = 
+build_property.PlatformNeutralAssembly = 
+build_property.EnforceExtendedAnalyzerRules = 
+build_property._SupportedPlatformList = Linux,macOS,Windows
+build_property.RootNamespace = KYFramework
+build_property.ProjectDir = E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\
+build_property.EnableComHosting = 
+build_property.EnableGeneratedComInterfaceComImportInterop = 

+ 8 - 0
KYFramework/obj/Debug/net7.0/KYFramework.GlobalUsings.g.cs

@@ -0,0 +1,8 @@
+// <auto-generated/>
+global using global::System;
+global using global::System.Collections.Generic;
+global using global::System.IO;
+global using global::System.Linq;
+global using global::System.Net.Http;
+global using global::System.Threading;
+global using global::System.Threading.Tasks;

BIN
KYFramework/obj/Debug/net7.0/KYFramework.assets.cache


BIN
KYFramework/obj/Debug/net7.0/KYFramework.assets.cache.r14


BIN
KYFramework/obj/Debug/net7.0/KYFramework.assets.cache.r5


BIN
KYFramework/obj/Debug/net7.0/KYFramework.csproj.AssemblyReference.cache


BIN
KYFramework/obj/Debug/net7.0/KYFramework.csproj.AssemblyReference.cache.r14


BIN
KYFramework/obj/Debug/net7.0/KYFramework.csproj.AssemblyReference.cache.r5


+ 0 - 0
KYFramework/obj/Debug/net7.0/KYFramework.csproj.BuildWithSkipAnalyzers


+ 0 - 0
KYFramework/obj/Debug/net7.0/KYFramework.csproj.CopyComplete


+ 1 - 0
KYFramework/obj/Debug/net7.0/KYFramework.csproj.CoreCompileInputs.cache

@@ -0,0 +1 @@
+c8d8aafe11b43296d5401712e579b4ce4c8d5403c4d7a67e24d91339e88dcd04

+ 135 - 0
KYFramework/obj/Debug/net7.0/KYFramework.csproj.FileListAbsolute.txt

@@ -0,0 +1,135 @@
+D:/LEZ/simulation-server/KYFramework/bin/Debug/net7.0/KYFramework.deps.json
+D:/LEZ/simulation-server/KYFramework/bin/Debug/net7.0/KYFramework.dll
+D:/LEZ/simulation-server/KYFramework/bin/Debug/net7.0/KYFramework.pdb
+D:/LEZ/simulation-server/KYFramework/bin/Debug/net7.0/ThirdParty.dll
+D:/LEZ/simulation-server/KYFramework/bin/Debug/net7.0/ThirdParty.pdb
+D:/LEZ/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.csproj.AssemblyReference.cache
+D:/LEZ/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.GeneratedMSBuildEditorConfig.editorconfig
+D:/LEZ/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.AssemblyInfoInputs.cache
+D:/LEZ/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.AssemblyInfo.cs
+D:/LEZ/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.csproj.CoreCompileInputs.cache
+D:/LEZ/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.csproj.CopyComplete
+D:/LEZ/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.dll
+D:/LEZ/simulation-server/KYFramework/obj/Debug/net7.0/refint/KYFramework.dll
+D:/LEZ/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.pdb
+D:/LEZ/simulation-server/KYFramework/obj/Debug/net7.0/ref/KYFramework.dll
+G:/simulation-server/KYFramework/bin/Debug/net7.0/KYFramework.deps.json
+G:/simulation-server/KYFramework/bin/Debug/net7.0/KYFramework.dll
+G:/simulation-server/KYFramework/bin/Debug/net7.0/KYFramework.pdb
+G:/simulation-server/KYFramework/bin/Debug/net7.0/ThirdParty.dll
+G:/simulation-server/KYFramework/bin/Debug/net7.0/ThirdParty.pdb
+G:/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.csproj.AssemblyReference.cache
+G:/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.GeneratedMSBuildEditorConfig.editorconfig
+G:/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.AssemblyInfoInputs.cache
+G:/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.AssemblyInfo.cs
+G:/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.csproj.CoreCompileInputs.cache
+G:/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.csproj.CopyComplete
+G:/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.dll
+G:/simulation-server/KYFramework/obj/Debug/net7.0/refint/KYFramework.dll
+G:/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.pdb
+G:/simulation-server/KYFramework/obj/Debug/net7.0/ref/KYFramework.dll
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/bin/Debug/net7.0/KYFramework.deps.json
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/bin/Debug/net7.0/KYFramework.dll
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/bin/Debug/net7.0/KYFramework.pdb
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/bin/Debug/net7.0/ThirdParty.dll
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/bin/Debug/net7.0/ThirdParty.pdb
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.csproj.AssemblyReference.cache
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.GeneratedMSBuildEditorConfig.editorconfig
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.AssemblyInfoInputs.cache
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.AssemblyInfo.cs
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.csproj.CoreCompileInputs.cache
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.csproj.CopyComplete
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.dll
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/obj/Debug/net7.0/refint/KYFramework.dll
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/obj/Debug/net7.0/KYFramework.pdb
+/Users/lienzan/Documents/csharp/simulation-server/KYFramework/obj/Debug/net7.0/ref/KYFramework.dll
+G:\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.deps.json
+G:\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.dll
+G:\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.pdb
+G:\simulation-server\KYFramework\bin\Debug\net7.0\ThirdParty.dll
+G:\simulation-server\KYFramework\bin\Debug\net7.0\ThirdParty.pdb
+G:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.AssemblyReference.cache
+G:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.GeneratedMSBuildEditorConfig.editorconfig
+G:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.AssemblyInfoInputs.cache
+G:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.AssemblyInfo.cs
+G:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.CoreCompileInputs.cache
+G:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.CopyComplete
+G:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.dll
+G:\simulation-server\KYFramework\obj\Debug\net7.0\refint\KYFramework.dll
+G:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.pdb
+G:\simulation-server\KYFramework\obj\Debug\net7.0\ref\KYFramework.dll
+D:\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.deps.json
+D:\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.dll
+D:\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.pdb
+D:\simulation-server\KYFramework\bin\Debug\net7.0\ThirdParty.dll
+D:\simulation-server\KYFramework\bin\Debug\net7.0\ThirdParty.pdb
+D:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.AssemblyReference.cache
+D:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.GeneratedMSBuildEditorConfig.editorconfig
+D:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.AssemblyInfoInputs.cache
+D:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.AssemblyInfo.cs
+D:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.CoreCompileInputs.cache
+D:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.CopyComplete
+D:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.dll
+D:\simulation-server\KYFramework\obj\Debug\net7.0\refint\KYFramework.dll
+D:\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.pdb
+D:\simulation-server\KYFramework\obj\Debug\net7.0\ref\KYFramework.dll
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.deps.json
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.dll
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.pdb
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\ThirdParty.dll
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\ThirdParty.pdb
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.AssemblyReference.cache
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.GeneratedMSBuildEditorConfig.editorconfig
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.AssemblyInfoInputs.cache
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.AssemblyInfo.cs
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.CoreCompileInputs.cache
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.CopyComplete
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.dll
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\refint\KYFramework.dll
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.pdb
+E:\AviationRescue\Svn\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\ref\KYFramework.dll
+D:\SVN\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.deps.json
+D:\SVN\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.dll
+D:\SVN\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.pdb
+D:\SVN\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\ThirdParty.dll
+D:\SVN\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\ThirdParty.pdb
+D:\SVN\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.AssemblyReference.cache
+D:\SVN\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.GeneratedMSBuildEditorConfig.editorconfig
+D:\SVN\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.AssemblyInfoInputs.cache
+D:\SVN\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.AssemblyInfo.cs
+D:\SVN\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.CoreCompileInputs.cache
+D:\SVN\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramew.00291D58.Up2Date
+D:\SVN\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.dll
+D:\SVN\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\refint\KYFramework.dll
+D:\SVN\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.pdb
+D:\SVN\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\ref\KYFramework.dll
+D:\CSProject\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.deps.json
+D:\CSProject\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.dll
+D:\CSProject\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.pdb
+D:\CSProject\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\ThirdParty.dll
+D:\CSProject\SimulationServer\simulation-server\KYFramework\bin\Debug\net7.0\ThirdParty.pdb
+D:\CSProject\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.AssemblyReference.cache
+D:\CSProject\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.GeneratedMSBuildEditorConfig.editorconfig
+D:\CSProject\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.AssemblyInfoInputs.cache
+D:\CSProject\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.AssemblyInfo.cs
+D:\CSProject\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.CoreCompileInputs.cache
+D:\CSProject\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramew.00291D58.Up2Date
+D:\CSProject\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.dll
+D:\CSProject\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\refint\KYFramework.dll
+D:\CSProject\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.pdb
+D:\CSProject\SimulationServer\simulation-server\KYFramework\obj\Debug\net7.0\ref\KYFramework.dll
+D:\Git\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.deps.json
+D:\Git\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.dll
+D:\Git\simulation-server\KYFramework\bin\Debug\net7.0\KYFramework.pdb
+D:\Git\simulation-server\KYFramework\bin\Debug\net7.0\ThirdParty.dll
+D:\Git\simulation-server\KYFramework\bin\Debug\net7.0\ThirdParty.pdb
+D:\Git\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.AssemblyReference.cache
+D:\Git\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.GeneratedMSBuildEditorConfig.editorconfig
+D:\Git\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.AssemblyInfoInputs.cache
+D:\Git\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.AssemblyInfo.cs
+D:\Git\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.csproj.CoreCompileInputs.cache
+D:\Git\simulation-server\KYFramework\obj\Debug\net7.0\KYFramew.00291D58.Up2Date
+D:\Git\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.dll
+D:\Git\simulation-server\KYFramework\obj\Debug\net7.0\refint\KYFramework.dll
+D:\Git\simulation-server\KYFramework\obj\Debug\net7.0\KYFramework.pdb
+D:\Git\simulation-server\KYFramework\obj\Debug\net7.0\ref\KYFramework.dll

Some files were not shown because too many files changed in this diff