Browse Source

医疗场景

liyang 6 months ago
commit
0569fd7d33
100 changed files with 12274 additions and 0 deletions
  1. 11 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. 30 0
      KYFramework/KYFramework.csproj
  70. 1575 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. 27 0
      KYNetwork/KYNetwork.csproj
  76. 3842 0
      KYNetwork/Message/OuterMessage.cs
  77. 137 0
      KYNetwork/Message/OuterOpcode.cs
  78. 42 0
      KYNetwork/Network/Component/SessionComponent.cs
  79. 63 0
      KYNetwork/Network/Helper/ProcessHelper.cs
  80. 30 0
      KYNetwork/Network/Message/AMHandler.cs
  81. 62 0
      KYNetwork/Network/Message/AMRpcHandler.cs
  82. 9 0
      KYNetwork/Network/Message/ClientComponent.cs
  83. 43 0
      KYNetwork/Network/Message/ClientComponentSystem.cs
  84. 43 0
      KYNetwork/Network/Message/ErrorCode.cs
  85. 10 0
      KYNetwork/Network/Message/IMHandler.cs
  86. 25 0
      KYNetwork/Network/Message/IMessage.cs
  87. 7 0
      KYNetwork/Network/Message/IMessageDispatcher.cs
  88. 15 0
      KYNetwork/Network/Message/IMessagePacker.cs
  89. 12 0
      KYNetwork/Network/Message/MessageAttribute.cs
  90. 107 0
      KYNetwork/Network/Message/MessageDispatcherComponent.cs
  91. 16 0
      KYNetwork/Network/Message/MessageHandlerAttribute.cs
  92. 14 0
      KYNetwork/Network/Message/MessageInfo.cs
  93. 53 0
      KYNetwork/Network/Message/MessagePool.cs
  94. 26 0
      KYNetwork/Network/Message/MessageProxy.cs
  95. 140 0
      KYNetwork/Network/Message/NetworkComponent.cs
  96. 9 0
      KYNetwork/Network/Message/Opcode.cs
  97. 21 0
      KYNetwork/Network/Message/OpcodeHelper.cs
  98. 83 0
      KYNetwork/Network/Message/OpcodeTypeComponent.cs
  99. 12 0
      KYNetwork/Network/Message/OuterMessageDispatcher.cs
  100. 23 0
      KYNetwork/Network/Message/RpcException.cs

+ 11 - 0
.gitignore

@@ -0,0 +1,11 @@
+.vs
+.idea
+KYFramework/obj
+KYNetwork/obj
+Models/SimulationCommon/obj
+Proto2CS/obj
+SimulationServer/obj
+ThirdParty/obj
+KYNetwork/bin
+Models/SimulationCommon/bin
+SimulationServer/bin/Debug/net7.0/Logs

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);
+}

+ 30 - 0
KYFramework/KYFramework.csproj

@@ -0,0 +1,30 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+
+  <ItemGroup>
+    <PackageReference Include="GeoCoordinate" Version="2.0.1" />
+    <PackageReference Include="MathNet.Numerics" Version="5.0.0" />
+    <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>

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

@@ -0,0 +1,1575 @@
+{
+  "runtimeTarget": {
+    "name": ".NETCoreApp,Version=v7.0",
+    "signature": ""
+  },
+  "compilationOptions": {},
+  "targets": {
+    ".NETCoreApp,Version=v7.0": {
+      "KYFramework/1.0.0": {
+        "dependencies": {
+          "GeoCoordinate": "2.0.1",
+          "MathNet.Numerics": "5.0.0",
+          "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": {}
+        }
+      },
+      "GeoCoordinate/2.0.1": {
+        "dependencies": {
+          "NETStandard.Library": "1.6.0"
+        }
+      },
+      "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"
+          }
+        }
+      },
+      "MathNet.Numerics/5.0.0": {
+        "runtime": {
+          "lib/net6.0/MathNet.Numerics.dll": {
+            "assemblyVersion": "5.0.0.0",
+            "fileVersion": "5.0.0.0"
+          }
+        }
+      },
+      "Microsoft.NETCore.Platforms/3.1.0": {},
+      "Microsoft.NETCore.Targets/1.1.0": {},
+      "Microsoft.Win32.Primitives/4.0.1": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.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"
+          }
+        }
+      },
+      "NETStandard.Library/1.6.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.Win32.Primitives": "4.0.1",
+          "System.AppContext": "4.1.0",
+          "System.Collections": "4.0.11",
+          "System.Collections.Concurrent": "4.0.12",
+          "System.Console": "4.0.0",
+          "System.Diagnostics.Debug": "4.0.11",
+          "System.Diagnostics.Tools": "4.0.1",
+          "System.Diagnostics.Tracing": "4.1.0",
+          "System.Globalization": "4.0.11",
+          "System.Globalization.Calendars": "4.0.1",
+          "System.IO": "4.3.0",
+          "System.IO.Compression": "4.1.0",
+          "System.IO.Compression.ZipFile": "4.0.1",
+          "System.IO.FileSystem": "4.0.1",
+          "System.IO.FileSystem.Primitives": "4.0.1",
+          "System.Linq": "4.1.0",
+          "System.Linq.Expressions": "4.1.0",
+          "System.Net.Http": "4.1.0",
+          "System.Net.Primitives": "4.0.11",
+          "System.Net.Sockets": "4.1.0",
+          "System.ObjectModel": "4.0.12",
+          "System.Reflection": "4.3.0",
+          "System.Reflection.Extensions": "4.0.1",
+          "System.Reflection.Primitives": "4.3.0",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Runtime.Handles": "4.0.1",
+          "System.Runtime.InteropServices": "4.1.0",
+          "System.Runtime.InteropServices.RuntimeInformation": "4.0.0",
+          "System.Runtime.Numerics": "4.0.1",
+          "System.Security.Cryptography.Algorithms": "4.2.0",
+          "System.Security.Cryptography.Encoding": "4.0.0",
+          "System.Security.Cryptography.Primitives": "4.0.0",
+          "System.Security.Cryptography.X509Certificates": "4.1.0",
+          "System.Text.Encoding": "4.3.0",
+          "System.Text.Encoding.Extensions": "4.0.11",
+          "System.Text.RegularExpressions": "4.1.0",
+          "System.Threading": "4.0.11",
+          "System.Threading.Tasks": "4.3.0",
+          "System.Threading.Timer": "4.0.1",
+          "System.Xml.ReaderWriter": "4.0.11",
+          "System.Xml.XDocument": "4.0.11"
+        }
+      },
+      "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"
+          }
+        }
+      },
+      "runtime.native.System/4.0.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0"
+        }
+      },
+      "runtime.native.System.IO.Compression/4.1.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0"
+        }
+      },
+      "runtime.native.System.Net.Http/4.0.1": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0"
+        }
+      },
+      "runtime.native.System.Security.Cryptography/4.0.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0"
+        }
+      },
+      "System.AppContext/4.1.0": {
+        "dependencies": {
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Buffers/4.5.1": {},
+      "System.Collections/4.0.11": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Collections.Concurrent/4.0.12": {
+        "dependencies": {
+          "System.Collections": "4.0.11",
+          "System.Diagnostics.Debug": "4.0.11",
+          "System.Diagnostics.Tracing": "4.1.0",
+          "System.Globalization": "4.0.11",
+          "System.Reflection": "4.3.0",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Threading": "4.0.11",
+          "System.Threading.Tasks": "4.3.0"
+        }
+      },
+      "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.Console/4.0.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.IO": "4.3.0",
+          "System.Runtime": "4.3.0",
+          "System.Text.Encoding": "4.3.0"
+        }
+      },
+      "System.Diagnostics.Debug/4.0.11": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Diagnostics.DiagnosticSource/7.0.2": {},
+      "System.Diagnostics.Tools/4.0.1": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Diagnostics.Tracing/4.1.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "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.Globalization/4.0.11": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Globalization.Calendars/4.0.1": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Globalization": "4.0.11",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Globalization.Extensions/4.0.1": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "System.Globalization": "4.0.11",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Runtime.InteropServices": "4.1.0"
+        }
+      },
+      "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.Compression/4.1.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "System.Collections": "4.0.11",
+          "System.Diagnostics.Debug": "4.0.11",
+          "System.IO": "4.3.0",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Runtime.Handles": "4.0.1",
+          "System.Runtime.InteropServices": "4.1.0",
+          "System.Text.Encoding": "4.3.0",
+          "System.Threading": "4.0.11",
+          "System.Threading.Tasks": "4.3.0",
+          "runtime.native.System": "4.0.0",
+          "runtime.native.System.IO.Compression": "4.1.0"
+        }
+      },
+      "System.IO.Compression.ZipFile/4.0.1": {
+        "dependencies": {
+          "System.Buffers": "4.5.1",
+          "System.IO": "4.3.0",
+          "System.IO.Compression": "4.1.0",
+          "System.IO.FileSystem": "4.0.1",
+          "System.IO.FileSystem.Primitives": "4.0.1",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Text.Encoding": "4.3.0"
+        }
+      },
+      "System.IO.FileSystem/4.0.1": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.IO": "4.3.0",
+          "System.IO.FileSystem.Primitives": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Handles": "4.0.1",
+          "System.Text.Encoding": "4.3.0",
+          "System.Threading.Tasks": "4.3.0"
+        }
+      },
+      "System.IO.FileSystem.Primitives/4.0.1": {
+        "dependencies": {
+          "System.Runtime": "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.Linq/4.1.0": {
+        "dependencies": {
+          "System.Collections": "4.0.11",
+          "System.Diagnostics.Debug": "4.0.11",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0"
+        }
+      },
+      "System.Linq.Expressions/4.1.0": {
+        "dependencies": {
+          "System.Collections": "4.0.11",
+          "System.Diagnostics.Debug": "4.0.11",
+          "System.Globalization": "4.0.11",
+          "System.IO": "4.3.0",
+          "System.Linq": "4.1.0",
+          "System.ObjectModel": "4.0.12",
+          "System.Reflection": "4.3.0",
+          "System.Reflection.Emit": "4.0.1",
+          "System.Reflection.Emit.ILGeneration": "4.0.1",
+          "System.Reflection.Emit.Lightweight": "4.0.1",
+          "System.Reflection.Extensions": "4.0.1",
+          "System.Reflection.Primitives": "4.3.0",
+          "System.Reflection.TypeExtensions": "4.1.0",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Threading": "4.0.11"
+        }
+      },
+      "System.Net.Http/4.1.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "System.Collections": "4.0.11",
+          "System.Diagnostics.Debug": "4.0.11",
+          "System.Diagnostics.DiagnosticSource": "7.0.2",
+          "System.Diagnostics.Tracing": "4.1.0",
+          "System.Globalization": "4.0.11",
+          "System.Globalization.Extensions": "4.0.1",
+          "System.IO": "4.3.0",
+          "System.IO.FileSystem": "4.0.1",
+          "System.Net.Primitives": "4.0.11",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Runtime.Handles": "4.0.1",
+          "System.Runtime.InteropServices": "4.1.0",
+          "System.Security.Cryptography.Algorithms": "4.2.0",
+          "System.Security.Cryptography.Encoding": "4.0.0",
+          "System.Security.Cryptography.OpenSsl": "4.0.0",
+          "System.Security.Cryptography.Primitives": "4.0.0",
+          "System.Security.Cryptography.X509Certificates": "4.1.0",
+          "System.Text.Encoding": "4.3.0",
+          "System.Threading": "4.0.11",
+          "System.Threading.Tasks": "4.3.0",
+          "runtime.native.System": "4.0.0",
+          "runtime.native.System.Net.Http": "4.0.1",
+          "runtime.native.System.Security.Cryptography": "4.0.0"
+        }
+      },
+      "System.Net.Primitives/4.0.11": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Handles": "4.0.1"
+        }
+      },
+      "System.Net.Sockets/4.1.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.IO": "4.3.0",
+          "System.Net.Primitives": "4.0.11",
+          "System.Runtime": "4.3.0",
+          "System.Threading.Tasks": "4.3.0"
+        }
+      },
+      "System.ObjectModel/4.0.12": {
+        "dependencies": {
+          "System.Collections": "4.0.11",
+          "System.Diagnostics.Debug": "4.0.11",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Threading": "4.0.11"
+        }
+      },
+      "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.Emit/4.0.1": {
+        "dependencies": {
+          "System.IO": "4.3.0",
+          "System.Reflection": "4.3.0",
+          "System.Reflection.Emit.ILGeneration": "4.0.1",
+          "System.Reflection.Primitives": "4.3.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Reflection.Emit.ILGeneration/4.0.1": {
+        "dependencies": {
+          "System.Reflection": "4.3.0",
+          "System.Reflection.Primitives": "4.3.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Reflection.Emit.Lightweight/4.0.1": {
+        "dependencies": {
+          "System.Reflection": "4.3.0",
+          "System.Reflection.Emit.ILGeneration": "4.0.1",
+          "System.Reflection.Primitives": "4.3.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Reflection.Extensions/4.0.1": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Reflection": "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.Reflection.TypeExtensions/4.1.0": {
+        "dependencies": {
+          "System.Reflection": "4.3.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Resources.ResourceManager/4.0.1": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Globalization": "4.0.11",
+          "System.Reflection": "4.3.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.Extensions/4.1.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Runtime.Handles/4.0.1": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "System.Runtime.InteropServices/4.1.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Reflection": "4.3.0",
+          "System.Reflection.Primitives": "4.3.0",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Handles": "4.0.1"
+        }
+      },
+      "System.Runtime.InteropServices.RuntimeInformation/4.0.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "System.Reflection": "4.3.0",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.InteropServices": "4.1.0",
+          "System.Threading": "4.0.11",
+          "runtime.native.System": "4.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.Runtime.Numerics/4.0.1": {
+        "dependencies": {
+          "System.Globalization": "4.0.11",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0"
+        }
+      },
+      "System.Security.AccessControl/4.7.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "System.Security.Principal.Windows": "4.7.0"
+        }
+      },
+      "System.Security.Cryptography.Algorithms/4.2.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "System.Collections": "4.0.11",
+          "System.IO": "4.3.0",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Runtime.Handles": "4.0.1",
+          "System.Runtime.InteropServices": "4.1.0",
+          "System.Runtime.Numerics": "4.0.1",
+          "System.Security.Cryptography.Encoding": "4.0.0",
+          "System.Security.Cryptography.Primitives": "4.0.0",
+          "System.Text.Encoding": "4.3.0",
+          "runtime.native.System.Security.Cryptography": "4.0.0"
+        }
+      },
+      "System.Security.Cryptography.Cng/4.2.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "System.IO": "4.3.0",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Runtime.Handles": "4.0.1",
+          "System.Runtime.InteropServices": "4.1.0",
+          "System.Security.Cryptography.Algorithms": "4.2.0",
+          "System.Security.Cryptography.Encoding": "4.0.0",
+          "System.Security.Cryptography.Primitives": "4.0.0",
+          "System.Text.Encoding": "4.3.0"
+        }
+      },
+      "System.Security.Cryptography.Csp/4.0.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "System.IO": "4.3.0",
+          "System.Reflection": "4.3.0",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Runtime.Handles": "4.0.1",
+          "System.Runtime.InteropServices": "4.1.0",
+          "System.Security.Cryptography.Algorithms": "4.2.0",
+          "System.Security.Cryptography.Encoding": "4.0.0",
+          "System.Security.Cryptography.Primitives": "4.0.0",
+          "System.Text.Encoding": "4.3.0",
+          "System.Threading": "4.0.11"
+        }
+      },
+      "System.Security.Cryptography.Encoding/4.0.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "System.Collections": "4.0.11",
+          "System.Collections.Concurrent": "4.0.12",
+          "System.Linq": "4.1.0",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Runtime.Handles": "4.0.1",
+          "System.Runtime.InteropServices": "4.1.0",
+          "System.Security.Cryptography.Primitives": "4.0.0",
+          "System.Text.Encoding": "4.3.0",
+          "runtime.native.System.Security.Cryptography": "4.0.0"
+        }
+      },
+      "System.Security.Cryptography.OpenSsl/4.0.0": {
+        "dependencies": {
+          "System.Collections": "4.0.11",
+          "System.IO": "4.3.0",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Runtime.Handles": "4.0.1",
+          "System.Runtime.InteropServices": "4.1.0",
+          "System.Runtime.Numerics": "4.0.1",
+          "System.Security.Cryptography.Algorithms": "4.2.0",
+          "System.Security.Cryptography.Encoding": "4.0.0",
+          "System.Security.Cryptography.Primitives": "4.0.0",
+          "System.Text.Encoding": "4.3.0",
+          "runtime.native.System.Security.Cryptography": "4.0.0"
+        }
+      },
+      "System.Security.Cryptography.Primitives/4.0.0": {
+        "dependencies": {
+          "System.Diagnostics.Debug": "4.0.11",
+          "System.Globalization": "4.0.11",
+          "System.IO": "4.3.0",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Threading": "4.0.11",
+          "System.Threading.Tasks": "4.3.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.Cryptography.X509Certificates/4.1.0": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "System.Collections": "4.0.11",
+          "System.Diagnostics.Debug": "4.0.11",
+          "System.Globalization": "4.0.11",
+          "System.Globalization.Calendars": "4.0.1",
+          "System.IO": "4.3.0",
+          "System.IO.FileSystem": "4.0.1",
+          "System.IO.FileSystem.Primitives": "4.0.1",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Runtime.Handles": "4.0.1",
+          "System.Runtime.InteropServices": "4.1.0",
+          "System.Runtime.Numerics": "4.0.1",
+          "System.Security.Cryptography.Algorithms": "4.2.0",
+          "System.Security.Cryptography.Cng": "4.2.0",
+          "System.Security.Cryptography.Csp": "4.0.0",
+          "System.Security.Cryptography.Encoding": "4.0.0",
+          "System.Security.Cryptography.OpenSsl": "4.0.0",
+          "System.Security.Cryptography.Primitives": "4.0.0",
+          "System.Text.Encoding": "4.3.0",
+          "System.Threading": "4.0.11",
+          "runtime.native.System": "4.0.0",
+          "runtime.native.System.Net.Http": "4.0.1",
+          "runtime.native.System.Security.Cryptography": "4.0.0"
+        }
+      },
+      "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.Encoding.Extensions/4.0.11": {
+        "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.Text.Encodings.Web/7.0.0": {},
+      "System.Text.Json/7.0.1": {
+        "dependencies": {
+          "System.Text.Encodings.Web": "7.0.0"
+        }
+      },
+      "System.Text.RegularExpressions/4.1.0": {
+        "dependencies": {
+          "System.Collections": "4.0.11",
+          "System.Globalization": "4.0.11",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Threading": "4.0.11"
+        }
+      },
+      "System.Threading/4.0.11": {
+        "dependencies": {
+          "System.Runtime": "4.3.0",
+          "System.Threading.Tasks": "4.3.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.Threading.Timer/4.0.1": {
+        "dependencies": {
+          "Microsoft.NETCore.Platforms": "3.1.0",
+          "Microsoft.NETCore.Targets": "1.1.0",
+          "System.Runtime": "4.3.0"
+        }
+      },
+      "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"
+          }
+        }
+      },
+      "System.Xml.ReaderWriter/4.0.11": {
+        "dependencies": {
+          "System.Collections": "4.0.11",
+          "System.Diagnostics.Debug": "4.0.11",
+          "System.Globalization": "4.0.11",
+          "System.IO": "4.3.0",
+          "System.IO.FileSystem": "4.0.1",
+          "System.IO.FileSystem.Primitives": "4.0.1",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Runtime.InteropServices": "4.1.0",
+          "System.Text.Encoding": "4.3.0",
+          "System.Text.Encoding.Extensions": "4.0.11",
+          "System.Text.RegularExpressions": "4.1.0",
+          "System.Threading.Tasks": "4.3.0",
+          "System.Threading.Tasks.Extensions": "4.5.4"
+        }
+      },
+      "System.Xml.XDocument/4.0.11": {
+        "dependencies": {
+          "System.Collections": "4.0.11",
+          "System.Diagnostics.Debug": "4.0.11",
+          "System.Diagnostics.Tools": "4.0.1",
+          "System.Globalization": "4.0.11",
+          "System.IO": "4.3.0",
+          "System.Reflection": "4.3.0",
+          "System.Resources.ResourceManager": "4.0.1",
+          "System.Runtime": "4.3.0",
+          "System.Runtime.Extensions": "4.1.0",
+          "System.Text.Encoding": "4.3.0",
+          "System.Threading": "4.0.11",
+          "System.Xml.ReaderWriter": "4.0.11"
+        }
+      },
+      "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": {
+          "GeoCoordinate": "2.0.1",
+          "MathNet.Numerics": "5.0.0",
+          "MySql.Data": "8.1.0",
+          "UniTask": "2.5.0"
+        },
+        "runtime": {
+          "ThirdParty.dll": {}
+        }
+      }
+    }
+  },
+  "libraries": {
+    "KYFramework/1.0.0": {
+      "type": "project",
+      "serviceable": false,
+      "sha512": ""
+    },
+    "GeoCoordinate/2.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-Am5GANF7uS3vlYBHExLtouH/Yrsc+6182nTdxXfnYCCVF/mO6TRO5QQhJVWXd5PjVdNnb6rHbkHiDR9verwnig==",
+      "path": "geocoordinate/2.0.1",
+      "hashPath": "geocoordinate.2.0.1.nupkg.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"
+    },
+    "MathNet.Numerics/5.0.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-pg1W2VwaEQMAiTpGK840hZgzavnqjlCMTVSbtVCXVyT+7AX4mc1o89SPv4TBlAjhgCOo9c1Y+jZ5m3ti2YgGgA==",
+      "path": "mathnet.numerics/5.0.0",
+      "hashPath": "mathnet.numerics.5.0.0.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.Primitives/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-fQnBHO9DgcmkC9dYSJoBqo6sH1VJwJprUHh8F3hbcRlxiQiBUuTntdk8tUwV490OqC2kQUrinGwZyQHTieuXRA==",
+      "path": "microsoft.win32.primitives/4.0.1",
+      "hashPath": "microsoft.win32.primitives.4.0.1.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"
+    },
+    "NETStandard.Library/1.6.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-ypsCvIdCZ4IoYASJHt6tF2fMo7N30NLgV1EbmC+snO490OMl9FvVxmumw14rhReWU3j3g7BYudG6YCrchwHJlA==",
+      "path": "netstandard.library/1.6.0",
+      "hashPath": "netstandard.library.1.6.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"
+    },
+    "runtime.native.System/4.0.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-QfS/nQI7k/BLgmLrw7qm7YBoULEvgWnPI+cYsbfCVFTW8Aj+i8JhccxcFMu1RWms0YZzF+UHguNBK4Qn89e2Sg==",
+      "path": "runtime.native.system/4.0.0",
+      "hashPath": "runtime.native.system.4.0.0.nupkg.sha512"
+    },
+    "runtime.native.System.IO.Compression/4.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-Ob7nvnJBox1aaB222zSVZSkf4WrebPG4qFscfK7vmD7P7NxoSxACQLtO7ytWpqXDn2wcd/+45+EAZ7xjaPip8A==",
+      "path": "runtime.native.system.io.compression/4.1.0",
+      "hashPath": "runtime.native.system.io.compression.4.1.0.nupkg.sha512"
+    },
+    "runtime.native.System.Net.Http/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-Nh0UPZx2Vifh8r+J+H2jxifZUD3sBrmolgiFWJd2yiNrxO0xTa6bAw3YwRn1VOiSen/tUXMS31ttNItCZ6lKuA==",
+      "path": "runtime.native.system.net.http/4.0.1",
+      "hashPath": "runtime.native.system.net.http.4.0.1.nupkg.sha512"
+    },
+    "runtime.native.System.Security.Cryptography/4.0.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-2CQK0jmO6Eu7ZeMgD+LOFbNJSXHFVQbCJJkEyEwowh1SCgYnrn9W9RykMfpeeVGw7h4IBvYikzpGUlmZTUafJw==",
+      "path": "runtime.native.system.security.cryptography/4.0.0",
+      "hashPath": "runtime.native.system.security.cryptography.4.0.0.nupkg.sha512"
+    },
+    "System.AppContext/4.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-3QjO4jNV7PdKkmQAVp9atA+usVnKRwI3Kx1nMwJ93T0LcQfx7pKAYk0nKz5wn1oP5iqlhZuy6RXOFdhr7rDwow==",
+      "path": "system.appcontext/4.1.0",
+      "hashPath": "system.appcontext.4.1.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.Collections/4.0.11": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-YUJGz6eFKqS0V//mLt25vFGrrCvOnsXjlvFQs+KimpwNxug9x0Pzy4PlFMU3Q2IzqAa9G2L4LsK3+9vCBK7oTg==",
+      "path": "system.collections/4.0.11",
+      "hashPath": "system.collections.4.0.11.nupkg.sha512"
+    },
+    "System.Collections.Concurrent/4.0.12": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-2gBcbb3drMLgxlI0fBfxMA31ec6AEyYCHygGse4vxceJan8mRIWeKJ24BFzN7+bi/NFTgdIgufzb94LWO5EERQ==",
+      "path": "system.collections.concurrent/4.0.12",
+      "hashPath": "system.collections.concurrent.4.0.12.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.Console/4.0.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-qSKUSOIiYA/a0g5XXdxFcUFmv1hNICBD7QZ0QhGYVipPIhvpiydY8VZqr1thmCXvmn8aipMg64zuanB4eotK9A==",
+      "path": "system.console/4.0.0",
+      "hashPath": "system.console.4.0.0.nupkg.sha512"
+    },
+    "System.Diagnostics.Debug/4.0.11": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-w5U95fVKHY4G8ASs/K5iK3J5LY+/dLFd4vKejsnI/ZhBsWS9hQakfx3Zr7lRWKg4tAw9r4iktyvsTagWkqYCiw==",
+      "path": "system.diagnostics.debug/4.0.11",
+      "hashPath": "system.diagnostics.debug.4.0.11.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.Diagnostics.Tools/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-xBfJ8pnd4C17dWaC9FM6aShzbJcRNMChUMD42I6772KGGrqaFdumwhn9OdM68erj1ueNo3xdQ1EwiFjK5k8p0g==",
+      "path": "system.diagnostics.tools/4.0.1",
+      "hashPath": "system.diagnostics.tools.4.0.1.nupkg.sha512"
+    },
+    "System.Diagnostics.Tracing/4.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-vDN1PoMZCkkdNjvZLql592oYJZgS7URcJzJ7bxeBgGtx5UtR5leNm49VmfHGqIffX4FKacHbI3H6UyNSHQknBg==",
+      "path": "system.diagnostics.tracing/4.1.0",
+      "hashPath": "system.diagnostics.tracing.4.1.0.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.Globalization/4.0.11": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-B95h0YLEL2oSnwF/XjqSWKnwKOy/01VWkNlsCeMTFJLLabflpGV26nK164eRs5GiaRSBGpOxQ3pKoSnnyZN5pg==",
+      "path": "system.globalization/4.0.11",
+      "hashPath": "system.globalization.4.0.11.nupkg.sha512"
+    },
+    "System.Globalization.Calendars/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-L1c6IqeQ88vuzC1P81JeHmHA8mxq8a18NUBNXnIY/BVb+TCyAaGIFbhpZt60h9FJNmisymoQkHEFSE9Vslja1Q==",
+      "path": "system.globalization.calendars/4.0.1",
+      "hashPath": "system.globalization.calendars.4.0.1.nupkg.sha512"
+    },
+    "System.Globalization.Extensions/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-KKo23iKeOaIg61SSXwjANN7QYDr/3op3OWGGzDzz7mypx0Za0fZSeG0l6cco8Ntp8YMYkIQcAqlk8yhm5/Uhcg==",
+      "path": "system.globalization.extensions/4.0.1",
+      "hashPath": "system.globalization.extensions.4.0.1.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.Compression/4.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-TjnBS6eztThSzeSib+WyVbLzEdLKUcEHN69VtS3u8aAsSc18FU6xCZlNWWsEd8SKcXAE+y1sOu7VbU8sUeM0sg==",
+      "path": "system.io.compression/4.1.0",
+      "hashPath": "system.io.compression.4.1.0.nupkg.sha512"
+    },
+    "System.IO.Compression.ZipFile/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-hBQYJzfTbQURF10nLhd+az2NHxsU6MU7AB8RUf4IolBP5lOAm4Luho851xl+CqslmhI5ZH/el8BlngEk4lBkaQ==",
+      "path": "system.io.compression.zipfile/4.0.1",
+      "hashPath": "system.io.compression.zipfile.4.0.1.nupkg.sha512"
+    },
+    "System.IO.FileSystem/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-IBErlVq5jOggAD69bg1t0pJcHaDbJbWNUZTPI96fkYWzwYbN6D9wRHMULLDd9dHsl7C2YsxXL31LMfPI1SWt8w==",
+      "path": "system.io.filesystem/4.0.1",
+      "hashPath": "system.io.filesystem.4.0.1.nupkg.sha512"
+    },
+    "System.IO.FileSystem.Primitives/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-kWkKD203JJKxJeE74p8aF8y4Qc9r9WQx4C0cHzHPrY3fv/L/IhWnyCHaFJ3H1QPOH6A93whlQ2vG5nHlBDvzWQ==",
+      "path": "system.io.filesystem.primitives/4.0.1",
+      "hashPath": "system.io.filesystem.primitives.4.0.1.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.Linq/4.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-bQ0iYFOQI0nuTnt+NQADns6ucV4DUvMdwN6CbkB1yj8i7arTGiTN5eok1kQwdnnNWSDZfIUySQY+J3d5KjWn0g==",
+      "path": "system.linq/4.1.0",
+      "hashPath": "system.linq.4.1.0.nupkg.sha512"
+    },
+    "System.Linq.Expressions/4.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-I+y02iqkgmCAyfbqOmSDOgqdZQ5tTj80Akm5BPSS8EeB0VGWdy6X1KCoYe8Pk6pwDoAKZUOdLVxnTJcExiv5zw==",
+      "path": "system.linq.expressions/4.1.0",
+      "hashPath": "system.linq.expressions.4.1.0.nupkg.sha512"
+    },
+    "System.Net.Http/4.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-ULq9g3SOPVuupt+Y3U+A37coXzdNisB1neFCSKzBwo182u0RDddKJF8I5+HfyXqK6OhJPgeoAwWXrbiUXuRDsg==",
+      "path": "system.net.http/4.1.0",
+      "hashPath": "system.net.http.4.1.0.nupkg.sha512"
+    },
+    "System.Net.Primitives/4.0.11": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-hVvfl4405DRjA2408luZekbPhplJK03j2Y2lSfMlny7GHXlkByw1iLnc9mgKW0GdQn73vvMcWrWewAhylXA4Nw==",
+      "path": "system.net.primitives/4.0.11",
+      "hashPath": "system.net.primitives.4.0.11.nupkg.sha512"
+    },
+    "System.Net.Sockets/4.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-xAz0N3dAV/aR/9g8r0Y5oEqU1JRsz29F5EGb/WVHmX3jVSLqi2/92M5hTad2aNWovruXrJpJtgZ9fccPMG9uSw==",
+      "path": "system.net.sockets/4.1.0",
+      "hashPath": "system.net.sockets.4.1.0.nupkg.sha512"
+    },
+    "System.ObjectModel/4.0.12": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-tAgJM1xt3ytyMoW4qn4wIqgJYm7L7TShRZG4+Q4Qsi2PCcj96pXN7nRywS9KkB3p/xDUjc2HSwP9SROyPYDYKQ==",
+      "path": "system.objectmodel/4.0.12",
+      "hashPath": "system.objectmodel.4.0.12.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.Emit/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-P2wqAj72fFjpP6wb9nSfDqNBMab+2ovzSDzUZK7MVIm54tBJEPr9jWfSjjoTpPwj1LeKcmX3vr0ttyjSSFM47g==",
+      "path": "system.reflection.emit/4.0.1",
+      "hashPath": "system.reflection.emit.4.0.1.nupkg.sha512"
+    },
+    "System.Reflection.Emit.ILGeneration/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-Ov6dU8Bu15Bc7zuqttgHF12J5lwSWyTf1S+FJouUXVMSqImLZzYaQ+vRr1rQ0OZ0HqsrwWl4dsKHELckQkVpgA==",
+      "path": "system.reflection.emit.ilgeneration/4.0.1",
+      "hashPath": "system.reflection.emit.ilgeneration.4.0.1.nupkg.sha512"
+    },
+    "System.Reflection.Emit.Lightweight/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-sSzHHXueZ5Uh0OLpUQprhr+ZYJrLPA2Cmr4gn0wj9+FftNKXx8RIMKvO9qnjk2ebPYUjZ+F2ulGdPOsvj+MEjA==",
+      "path": "system.reflection.emit.lightweight/4.0.1",
+      "hashPath": "system.reflection.emit.lightweight.4.0.1.nupkg.sha512"
+    },
+    "System.Reflection.Extensions/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-GYrtRsZcMuHF3sbmRHfMYpvxZoIN2bQGrYGerUiWLEkqdEUQZhH3TRSaC/oI4wO0II1RKBPlpIa1TOMxIcOOzQ==",
+      "path": "system.reflection.extensions/4.0.1",
+      "hashPath": "system.reflection.extensions.4.0.1.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.Reflection.TypeExtensions/4.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-tsQ/ptQ3H5FYfON8lL4MxRk/8kFyE0A+tGPXmVP967cT/gzLHYxIejIYSxp4JmIeFHVP78g/F2FE1mUUTbDtrg==",
+      "path": "system.reflection.typeextensions/4.1.0",
+      "hashPath": "system.reflection.typeextensions.4.1.0.nupkg.sha512"
+    },
+    "System.Resources.ResourceManager/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-TxwVeUNoTgUOdQ09gfTjvW411MF+w9MBYL7AtNVc+HtBCFlutPLhUCdZjNkjbhj3bNQWMdHboF0KIWEOjJssbA==",
+      "path": "system.resources.resourcemanager/4.0.1",
+      "hashPath": "system.resources.resourcemanager.4.0.1.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.Extensions/4.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-CUOHjTT/vgP0qGW22U4/hDlOqXmcPq5YicBaXdUR2UiUoLwBT+olO6we4DVbq57jeX5uXH2uerVZhf0qGj+sVQ==",
+      "path": "system.runtime.extensions/4.1.0",
+      "hashPath": "system.runtime.extensions.4.1.0.nupkg.sha512"
+    },
+    "System.Runtime.Handles/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-nCJvEKguXEvk2ymk1gqj625vVnlK3/xdGzx0vOKicQkoquaTBJTP13AIYkocSUwHCLNBwUbXTqTWGDxBTWpt7g==",
+      "path": "system.runtime.handles/4.0.1",
+      "hashPath": "system.runtime.handles.4.0.1.nupkg.sha512"
+    },
+    "System.Runtime.InteropServices/4.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-16eu3kjHS633yYdkjwShDHZLRNMKVi/s0bY8ODiqJ2RfMhDMAwxZaUaWVnZ2P71kr/or+X9o/xFWtNqz8ivieQ==",
+      "path": "system.runtime.interopservices/4.1.0",
+      "hashPath": "system.runtime.interopservices.4.1.0.nupkg.sha512"
+    },
+    "System.Runtime.InteropServices.RuntimeInformation/4.0.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-hWPhJxc453RCa8Z29O91EmfGeZIHX1ZH2A8L6lYQVSaKzku2DfArSfMEb1/MYYzPQRJZeu0c9dmYeJKxW5Fgng==",
+      "path": "system.runtime.interopservices.runtimeinformation/4.0.0",
+      "hashPath": "system.runtime.interopservices.runtimeinformation.4.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.Runtime.Numerics/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-+XbKFuzdmLP3d1o9pdHu2nxjNr2OEPqGzKeegPLCUMM71a0t50A/rOcIRmGs9wR7a8KuHX6hYs/7/TymIGLNqg==",
+      "path": "system.runtime.numerics/4.0.1",
+      "hashPath": "system.runtime.numerics.4.0.1.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.Algorithms/4.2.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-8JQFxbLVdrtIOKMDN38Fn0GWnqYZw/oMlwOUG/qz1jqChvyZlnUmu+0s7wLx7JYua/nAXoESpHA3iw11QFWhXg==",
+      "path": "system.security.cryptography.algorithms/4.2.0",
+      "hashPath": "system.security.cryptography.algorithms.4.2.0.nupkg.sha512"
+    },
+    "System.Security.Cryptography.Cng/4.2.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-cUJ2h+ZvONDe28Szw3st5dOHdjndhJzQ2WObDEXAWRPEQBtVItVoxbXM/OEsTthl3cNn2dk2k0I3y45igCQcLw==",
+      "path": "system.security.cryptography.cng/4.2.0",
+      "hashPath": "system.security.cryptography.cng.4.2.0.nupkg.sha512"
+    },
+    "System.Security.Cryptography.Csp/4.0.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-/i1Usuo4PgAqgbPNC0NjbO3jPW//BoBlTpcWFD1EHVbidH21y4c1ap5bbEMSGAXjAShhMH4abi/K8fILrnu4BQ==",
+      "path": "system.security.cryptography.csp/4.0.0",
+      "hashPath": "system.security.cryptography.csp.4.0.0.nupkg.sha512"
+    },
+    "System.Security.Cryptography.Encoding/4.0.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-FbKgE5MbxSQMPcSVRgwM6bXN3GtyAh04NkV8E5zKCBE26X0vYW0UtTa2FIgkH33WVqBVxRgxljlVYumWtU+HcQ==",
+      "path": "system.security.cryptography.encoding/4.0.0",
+      "hashPath": "system.security.cryptography.encoding.4.0.0.nupkg.sha512"
+    },
+    "System.Security.Cryptography.OpenSsl/4.0.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-HUG/zNUJwEiLkoURDixzkzZdB5yGA5pQhDP93ArOpDPQMteURIGERRNzzoJlmTreLBWr5lkFSjjMSk8ySEpQMw==",
+      "path": "system.security.cryptography.openssl/4.0.0",
+      "hashPath": "system.security.cryptography.openssl.4.0.0.nupkg.sha512"
+    },
+    "System.Security.Cryptography.Primitives/4.0.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-Wkd7QryWYjkQclX0bngpntW5HSlMzeJU24UaLJQ7YTfI8ydAVAaU2J+HXLLABOVJlKTVvAeL0Aj39VeTe7L+oA==",
+      "path": "system.security.cryptography.primitives/4.0.0",
+      "hashPath": "system.security.cryptography.primitives.4.0.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.Cryptography.X509Certificates/4.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-4HEfsQIKAhA1+ApNn729Gi09zh+lYWwyIuViihoMDWp1vQnEkL2ct7mAbhBlLYm+x/L4Rr/pyGge1lIY635e0w==",
+      "path": "system.security.cryptography.x509certificates/4.1.0",
+      "hashPath": "system.security.cryptography.x509certificates.4.1.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.Encoding.Extensions/4.0.11": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-jtbiTDtvfLYgXn8PTfWI+SiBs51rrmO4AAckx4KR6vFK9Wzf6tI8kcRdsYQNwriUeQ1+CtQbM1W4cMbLXnj/OQ==",
+      "path": "system.text.encoding.extensions/4.0.11",
+      "hashPath": "system.text.encoding.extensions.4.0.11.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.Text.RegularExpressions/4.1.0": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-i88YCXpRTjCnoSQZtdlHkAOx4KNNik4hMy83n0+Ftlb7jvV6ZiZWMpnEZHhjBp6hQVh8gWd/iKNPzlPF7iyA2g==",
+      "path": "system.text.regularexpressions/4.1.0",
+      "hashPath": "system.text.regularexpressions.4.1.0.nupkg.sha512"
+    },
+    "System.Threading/4.0.11": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-N+3xqIcg3VDKyjwwCGaZ9HawG9aC6cSDI+s7ROma310GQo8vilFZa86hqKppwTHleR/G0sfOzhvgnUxWCR/DrQ==",
+      "path": "system.threading/4.0.11",
+      "hashPath": "system.threading.4.0.11.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.Threading.Timer/4.0.1": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-saGfUV8uqVW6LeURiqxcGhZ24PzuRNaUBtbhVeuUAvky1naH395A/1nY0P2bWvrw/BreRtIB/EzTDkGBpqCwEw==",
+      "path": "system.threading.timer/4.0.1",
+      "hashPath": "system.threading.timer.4.0.1.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"
+    },
+    "System.Xml.ReaderWriter/4.0.11": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-ZIiLPsf67YZ9zgr31vzrFaYQqxRPX9cVHjtPSnmx4eN6lbS/yEyYNr2vs1doGDEscF0tjCZFsk9yUg1sC9e8tg==",
+      "path": "system.xml.readerwriter/4.0.11",
+      "hashPath": "system.xml.readerwriter.4.0.11.nupkg.sha512"
+    },
+    "System.Xml.XDocument/4.0.11": {
+      "type": "package",
+      "serviceable": true,
+      "sha512": "sha512-Mk2mKmPi0nWaoiYeotq1dgeNK1fqWh61+EK+w4Wu8SWuTYLzpUnschb59bJtGywaPq7SmTuPf44wrXRwbIrukg==",
+      "path": "system.xml.xdocument/4.0.11",
+      "hashPath": "system.xml.xdocument.4.0.11.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


+ 27 - 0
KYNetwork/KYNetwork.csproj

@@ -0,0 +1,27 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+    <PropertyGroup>
+        <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
+        <SatelliteResourceLanguages>en</SatelliteResourceLanguages>
+    </PropertyGroup>
+  
+  <ItemGroup>
+    <ProjectReference Include="..\KYFramework\KYFramework.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Folder Include="Message\" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="GeoCoordinate" Version="2.0.1" />
+    <PackageReference Include="MathNet.Numerics" Version="5.0.0" />
+    <PackageReference Include="UniTask" Version="2.5.0" />
+  </ItemGroup>
+
+</Project>

+ 3842 - 0
KYNetwork/Message/OuterMessage.cs

@@ -0,0 +1,3842 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: OuterMessage.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using scg = global::System.Collections.Generic;
+namespace KYFramework.Network {
+
+  #region Messages
+  public partial class C2R_Ping : pb::IMessage {
+    private static readonly pb::MessageParser<C2R_Ping> _parser = new pb::MessageParser<C2R_Ping>(() => (C2R_Ping)MessagePool.Instance.Fetch(typeof(C2R_Ping)));
+    public static pb::MessageParser<C2R_Ping> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      rpcId_ = 0;
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class R2C_Ping : pb::IMessage {
+    private static readonly pb::MessageParser<R2C_Ping> _parser = new pb::MessageParser<R2C_Ping>(() => (R2C_Ping)MessagePool.Instance.Fetch(typeof(R2C_Ping)));
+    public static pb::MessageParser<R2C_Ping> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private int error_;
+    public int Error {
+      get { return error_; }
+      set {
+        error_ = value;
+      }
+    }
+
+    private string message_ = "";
+    public string Message {
+      get { return message_; }
+      set {
+        message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (Error != 0) {
+        output.WriteRawTag(216, 5);
+        output.WriteInt32(Error);
+      }
+      if (Message.Length != 0) {
+        output.WriteRawTag(226, 5);
+        output.WriteString(Message);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (Error != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(Error);
+      }
+      if (Message.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(Message);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      rpcId_ = 0;
+      error_ = 0;
+      message_ = "";
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 728: {
+            Error = input.ReadInt32();
+            break;
+          }
+          case 738: {
+            Message = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class C2S_Test : pb::IMessage {
+    private static readonly pb::MessageParser<C2S_Test> _parser = new pb::MessageParser<C2S_Test>(() => (C2S_Test)MessagePool.Instance.Fetch(typeof(C2S_Test)));
+    public static pb::MessageParser<C2S_Test> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private string message_ = "";
+    public string Message {
+      get { return message_; }
+      set {
+        message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (Message.Length != 0) {
+        output.WriteRawTag(226, 5);
+        output.WriteString(Message);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (Message.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(Message);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      rpcId_ = 0;
+      message_ = "";
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 738: {
+            Message = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class S2C_Test : pb::IMessage {
+    private static readonly pb::MessageParser<S2C_Test> _parser = new pb::MessageParser<S2C_Test>(() => (S2C_Test)MessagePool.Instance.Fetch(typeof(S2C_Test)));
+    public static pb::MessageParser<S2C_Test> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private int error_;
+    public int Error {
+      get { return error_; }
+      set {
+        error_ = value;
+      }
+    }
+
+    private string message_ = "";
+    public string Message {
+      get { return message_; }
+      set {
+        message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (Error != 0) {
+        output.WriteRawTag(216, 5);
+        output.WriteInt32(Error);
+      }
+      if (Message.Length != 0) {
+        output.WriteRawTag(226, 5);
+        output.WriteString(Message);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (Error != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(Error);
+      }
+      if (Message.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(Message);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      rpcId_ = 0;
+      error_ = 0;
+      message_ = "";
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 728: {
+            Error = input.ReadInt32();
+            break;
+          }
+          case 738: {
+            Message = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class C2S_TestMessage : pb::IMessage {
+    private static readonly pb::MessageParser<C2S_TestMessage> _parser = new pb::MessageParser<C2S_TestMessage>(() => (C2S_TestMessage)MessagePool.Instance.Fetch(typeof(C2S_TestMessage)));
+    public static pb::MessageParser<C2S_TestMessage> Parser { get { return _parser; } }
+
+    private string message_ = "";
+    public string Message {
+      get { return message_; }
+      set {
+        message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Message.Length != 0) {
+        output.WriteRawTag(210, 5);
+        output.WriteString(Message);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Message.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(Message);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      message_ = "";
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 722: {
+            Message = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class S2C_TestMessage : pb::IMessage {
+    private static readonly pb::MessageParser<S2C_TestMessage> _parser = new pb::MessageParser<S2C_TestMessage>(() => (S2C_TestMessage)MessagePool.Instance.Fetch(typeof(S2C_TestMessage)));
+    public static pb::MessageParser<S2C_TestMessage> Parser { get { return _parser; } }
+
+    private string message_ = "";
+    public string Message {
+      get { return message_; }
+      set {
+        message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Message.Length != 0) {
+        output.WriteRawTag(210, 5);
+        output.WriteString(Message);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Message.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(Message);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      message_ = "";
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 722: {
+            Message = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 地理点:经纬高 
+  /// </summary>
+  public partial class Point : pb::IMessage {
+    private static readonly pb::MessageParser<Point> _parser = new pb::MessageParser<Point>(() => (Point)MessagePool.Instance.Fetch(typeof(Point)));
+    public static pb::MessageParser<Point> Parser { get { return _parser; } }
+
+    private double longitude_;
+    public double Longitude {
+      get { return longitude_; }
+      set {
+        longitude_ = value;
+      }
+    }
+
+    private double latitude_;
+    public double Latitude {
+      get { return latitude_; }
+      set {
+        latitude_ = value;
+      }
+    }
+
+    private double altitude_;
+    public double Altitude {
+      get { return altitude_; }
+      set {
+        altitude_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Longitude != 0D) {
+        output.WriteRawTag(9);
+        output.WriteDouble(Longitude);
+      }
+      if (Latitude != 0D) {
+        output.WriteRawTag(17);
+        output.WriteDouble(Latitude);
+      }
+      if (Altitude != 0D) {
+        output.WriteRawTag(25);
+        output.WriteDouble(Altitude);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Longitude != 0D) {
+        size += 1 + 8;
+      }
+      if (Latitude != 0D) {
+        size += 1 + 8;
+      }
+      if (Altitude != 0D) {
+        size += 1 + 8;
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 9: {
+            Longitude = input.ReadDouble();
+            break;
+          }
+          case 17: {
+            Latitude = input.ReadDouble();
+            break;
+          }
+          case 25: {
+            Altitude = input.ReadDouble();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 基地 
+  /// </summary>
+  public partial class Base : pb::IMessage {
+    private static readonly pb::MessageParser<Base> _parser = new pb::MessageParser<Base>(() => (Base)MessagePool.Instance.Fetch(typeof(Base)));
+    public static pb::MessageParser<Base> Parser { get { return _parser; } }
+
+    private string baseName_ = "";
+    public string BaseName {
+      get { return baseName_; }
+      set {
+        baseName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private global::KYFramework.Network.Point baseLocation_;
+    public global::KYFramework.Network.Point BaseLocation {
+      get { return baseLocation_; }
+      set {
+        baseLocation_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (BaseName.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(BaseName);
+      }
+      if (baseLocation_ != null) {
+        output.WriteRawTag(18);
+        output.WriteMessage(BaseLocation);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (BaseName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(BaseName);
+      }
+      if (baseLocation_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(BaseLocation);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      baseName_ = "";
+      if (baseLocation_ != null) MessagePool.Instance.Recycle(baseLocation_); baseLocation_ = null;
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            BaseName = input.ReadString();
+            break;
+          }
+          case 18: {
+            if (baseLocation_ == null) {
+              baseLocation_ = new global::KYFramework.Network.Point();
+            }
+            input.ReadMessage(baseLocation_);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 行政区气象数据 
+  /// </summary>
+  public partial class CityWeather : pb::IMessage {
+    private static readonly pb::MessageParser<CityWeather> _parser = new pb::MessageParser<CityWeather>(() => (CityWeather)MessagePool.Instance.Fetch(typeof(CityWeather)));
+    public static pb::MessageParser<CityWeather> Parser { get { return _parser; } }
+
+    private string cityName_ = "";
+    /// <summary>
+    /// 行政区域名称:XX市 
+    /// </summary>
+    public string CityName {
+      get { return cityName_; }
+      set {
+        cityName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string weatherCondition_ = "";
+    /// <summary>
+    /// 天气状况:晴/多云/雨等 
+    /// </summary>
+    public string WeatherCondition {
+      get { return weatherCondition_; }
+      set {
+        weatherCondition_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string windDirection_ = "";
+    /// <summary>
+    /// 风向:东南西北 
+    /// </summary>
+    public string WindDirection {
+      get { return windDirection_; }
+      set {
+        windDirection_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private double windVelocity_;
+    /// <summary>
+    /// 风速 
+    /// </summary>
+    public double WindVelocity {
+      get { return windVelocity_; }
+      set {
+        windVelocity_ = value;
+      }
+    }
+
+    private double temperature_;
+    /// <summary>
+    /// 温度 
+    /// </summary>
+    public double Temperature {
+      get { return temperature_; }
+      set {
+        temperature_ = value;
+      }
+    }
+
+    private double humidity_;
+    /// <summary>
+    /// 湿度 
+    /// </summary>
+    public double Humidity {
+      get { return humidity_; }
+      set {
+        humidity_ = value;
+      }
+    }
+
+    private double visibility_;
+    /// <summary>
+    /// 能见度 
+    /// </summary>
+    public double Visibility {
+      get { return visibility_; }
+      set {
+        visibility_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (CityName.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(CityName);
+      }
+      if (WeatherCondition.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(WeatherCondition);
+      }
+      if (WindDirection.Length != 0) {
+        output.WriteRawTag(26);
+        output.WriteString(WindDirection);
+      }
+      if (WindVelocity != 0D) {
+        output.WriteRawTag(33);
+        output.WriteDouble(WindVelocity);
+      }
+      if (Temperature != 0D) {
+        output.WriteRawTag(41);
+        output.WriteDouble(Temperature);
+      }
+      if (Humidity != 0D) {
+        output.WriteRawTag(49);
+        output.WriteDouble(Humidity);
+      }
+      if (Visibility != 0D) {
+        output.WriteRawTag(57);
+        output.WriteDouble(Visibility);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (CityName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(CityName);
+      }
+      if (WeatherCondition.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(WeatherCondition);
+      }
+      if (WindDirection.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(WindDirection);
+      }
+      if (WindVelocity != 0D) {
+        size += 1 + 8;
+      }
+      if (Temperature != 0D) {
+        size += 1 + 8;
+      }
+      if (Humidity != 0D) {
+        size += 1 + 8;
+      }
+      if (Visibility != 0D) {
+        size += 1 + 8;
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      cityName_ = "";
+      weatherCondition_ = "";
+      windDirection_ = "";
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            CityName = input.ReadString();
+            break;
+          }
+          case 18: {
+            WeatherCondition = input.ReadString();
+            break;
+          }
+          case 26: {
+            WindDirection = input.ReadString();
+            break;
+          }
+          case 33: {
+            WindVelocity = input.ReadDouble();
+            break;
+          }
+          case 41: {
+            Temperature = input.ReadDouble();
+            break;
+          }
+          case 49: {
+            Humidity = input.ReadDouble();
+            break;
+          }
+          case 57: {
+            Visibility = input.ReadDouble();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 航线 
+  /// </summary>
+  public partial class AirRoute : pb::IMessage {
+    private static readonly pb::MessageParser<AirRoute> _parser = new pb::MessageParser<AirRoute>(() => (AirRoute)MessagePool.Instance.Fetch(typeof(AirRoute)));
+    public static pb::MessageParser<AirRoute> Parser { get { return _parser; } }
+
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.Point> _repeated_pointArr_codec
+        = pb::FieldCodec.ForMessage(18, global::KYFramework.Network.Point.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.Point> pointArr_ = new pbc::RepeatedField<global::KYFramework.Network.Point>();
+    public pbc::RepeatedField<global::KYFramework.Network.Point> PointArr {
+      get { return pointArr_; }
+      set { pointArr_ = value; }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      pointArr_.WriteTo(output, _repeated_pointArr_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += pointArr_.CalculateSize(_repeated_pointArr_codec);
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      name_ = "";
+      for (int i = 0; i < pointArr_.Count; i++) { MessagePool.Instance.Recycle(pointArr_[i]); }
+      pointArr_.Clear();
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            pointArr_.AddEntriesFrom(input, _repeated_pointArr_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 圆形禁飞区 
+  /// </summary>
+  public partial class NoFlyZoneCircle : pb::IMessage {
+    private static readonly pb::MessageParser<NoFlyZoneCircle> _parser = new pb::MessageParser<NoFlyZoneCircle>(() => (NoFlyZoneCircle)MessagePool.Instance.Fetch(typeof(NoFlyZoneCircle)));
+    public static pb::MessageParser<NoFlyZoneCircle> Parser { get { return _parser; } }
+
+    private string noFlyZoneType_ = "";
+    public string NoFlyZoneType {
+      get { return noFlyZoneType_; }
+      set {
+        noFlyZoneType_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private global::KYFramework.Network.Point noFlyZoneCenterLocation_;
+    public global::KYFramework.Network.Point NoFlyZoneCenterLocation {
+      get { return noFlyZoneCenterLocation_; }
+      set {
+        noFlyZoneCenterLocation_ = value;
+      }
+    }
+
+    private double noFlyZoneRadius_;
+    public double NoFlyZoneRadius {
+      get { return noFlyZoneRadius_; }
+      set {
+        noFlyZoneRadius_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (NoFlyZoneType.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(NoFlyZoneType);
+      }
+      if (noFlyZoneCenterLocation_ != null) {
+        output.WriteRawTag(18);
+        output.WriteMessage(NoFlyZoneCenterLocation);
+      }
+      if (NoFlyZoneRadius != 0D) {
+        output.WriteRawTag(25);
+        output.WriteDouble(NoFlyZoneRadius);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (NoFlyZoneType.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(NoFlyZoneType);
+      }
+      if (noFlyZoneCenterLocation_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(NoFlyZoneCenterLocation);
+      }
+      if (NoFlyZoneRadius != 0D) {
+        size += 1 + 8;
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      noFlyZoneType_ = "";
+      if (noFlyZoneCenterLocation_ != null) MessagePool.Instance.Recycle(noFlyZoneCenterLocation_); noFlyZoneCenterLocation_ = null;
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            NoFlyZoneType = input.ReadString();
+            break;
+          }
+          case 18: {
+            if (noFlyZoneCenterLocation_ == null) {
+              noFlyZoneCenterLocation_ = new global::KYFramework.Network.Point();
+            }
+            input.ReadMessage(noFlyZoneCenterLocation_);
+            break;
+          }
+          case 25: {
+            NoFlyZoneRadius = input.ReadDouble();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 矩形禁飞区 
+  /// </summary>
+  public partial class NoFlyZoneRect : pb::IMessage {
+    private static readonly pb::MessageParser<NoFlyZoneRect> _parser = new pb::MessageParser<NoFlyZoneRect>(() => (NoFlyZoneRect)MessagePool.Instance.Fetch(typeof(NoFlyZoneRect)));
+    public static pb::MessageParser<NoFlyZoneRect> Parser { get { return _parser; } }
+
+    private string noFlyZoneType_ = "";
+    public string NoFlyZoneType {
+      get { return noFlyZoneType_; }
+      set {
+        noFlyZoneType_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.Point> _repeated_noFlyZoneRectangleLocation_codec
+        = pb::FieldCodec.ForMessage(18, global::KYFramework.Network.Point.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.Point> noFlyZoneRectangleLocation_ = new pbc::RepeatedField<global::KYFramework.Network.Point>();
+    public pbc::RepeatedField<global::KYFramework.Network.Point> NoFlyZoneRectangleLocation {
+      get { return noFlyZoneRectangleLocation_; }
+      set { noFlyZoneRectangleLocation_ = value; }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (NoFlyZoneType.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(NoFlyZoneType);
+      }
+      noFlyZoneRectangleLocation_.WriteTo(output, _repeated_noFlyZoneRectangleLocation_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (NoFlyZoneType.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(NoFlyZoneType);
+      }
+      size += noFlyZoneRectangleLocation_.CalculateSize(_repeated_noFlyZoneRectangleLocation_codec);
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      noFlyZoneType_ = "";
+      for (int i = 0; i < noFlyZoneRectangleLocation_.Count; i++) { MessagePool.Instance.Recycle(noFlyZoneRectangleLocation_[i]); }
+      noFlyZoneRectangleLocation_.Clear();
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            NoFlyZoneType = input.ReadString();
+            break;
+          }
+          case 18: {
+            noFlyZoneRectangleLocation_.AddEntriesFrom(input, _repeated_noFlyZoneRectangleLocation_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 爬升航段 
+  /// </summary>
+  public partial class ClimbSegment : pb::IMessage {
+    private static readonly pb::MessageParser<ClimbSegment> _parser = new pb::MessageParser<ClimbSegment>(() => (ClimbSegment)MessagePool.Instance.Fetch(typeof(ClimbSegment)));
+    public static pb::MessageParser<ClimbSegment> Parser { get { return _parser; } }
+
+    private double climbVelocity_;
+    public double ClimbVelocity {
+      get { return climbVelocity_; }
+      set {
+        climbVelocity_ = value;
+      }
+    }
+
+    private double climbFuelConsumptionRate_;
+    public double ClimbFuelConsumptionRate {
+      get { return climbFuelConsumptionRate_; }
+      set {
+        climbFuelConsumptionRate_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (ClimbVelocity != 0D) {
+        output.WriteRawTag(9);
+        output.WriteDouble(ClimbVelocity);
+      }
+      if (ClimbFuelConsumptionRate != 0D) {
+        output.WriteRawTag(17);
+        output.WriteDouble(ClimbFuelConsumptionRate);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (ClimbVelocity != 0D) {
+        size += 1 + 8;
+      }
+      if (ClimbFuelConsumptionRate != 0D) {
+        size += 1 + 8;
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 9: {
+            ClimbVelocity = input.ReadDouble();
+            break;
+          }
+          case 17: {
+            ClimbFuelConsumptionRate = input.ReadDouble();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 下降航段 
+  /// </summary>
+  public partial class DescentSegment : pb::IMessage {
+    private static readonly pb::MessageParser<DescentSegment> _parser = new pb::MessageParser<DescentSegment>(() => (DescentSegment)MessagePool.Instance.Fetch(typeof(DescentSegment)));
+    public static pb::MessageParser<DescentSegment> Parser { get { return _parser; } }
+
+    private double descentVelocity_;
+    public double DescentVelocity {
+      get { return descentVelocity_; }
+      set {
+        descentVelocity_ = value;
+      }
+    }
+
+    private double descentFuelConsumptionRate_;
+    public double DescentFuelConsumptionRate {
+      get { return descentFuelConsumptionRate_; }
+      set {
+        descentFuelConsumptionRate_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (DescentVelocity != 0D) {
+        output.WriteRawTag(9);
+        output.WriteDouble(DescentVelocity);
+      }
+      if (DescentFuelConsumptionRate != 0D) {
+        output.WriteRawTag(17);
+        output.WriteDouble(DescentFuelConsumptionRate);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (DescentVelocity != 0D) {
+        size += 1 + 8;
+      }
+      if (DescentFuelConsumptionRate != 0D) {
+        size += 1 + 8;
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 9: {
+            DescentVelocity = input.ReadDouble();
+            break;
+          }
+          case 17: {
+            DescentFuelConsumptionRate = input.ReadDouble();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 巡航航段 
+  /// </summary>
+  public partial class CruiseSegment : pb::IMessage {
+    private static readonly pb::MessageParser<CruiseSegment> _parser = new pb::MessageParser<CruiseSegment>(() => (CruiseSegment)MessagePool.Instance.Fetch(typeof(CruiseSegment)));
+    public static pb::MessageParser<CruiseSegment> Parser { get { return _parser; } }
+
+    private double cruiseAltitude_;
+    public double CruiseAltitude {
+      get { return cruiseAltitude_; }
+      set {
+        cruiseAltitude_ = value;
+      }
+    }
+
+    private double cruiseVelocity_;
+    public double CruiseVelocity {
+      get { return cruiseVelocity_; }
+      set {
+        cruiseVelocity_ = value;
+      }
+    }
+
+    private double cruiseFuelConsumptionRate_;
+    public double CruiseFuelConsumptionRate {
+      get { return cruiseFuelConsumptionRate_; }
+      set {
+        cruiseFuelConsumptionRate_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (CruiseAltitude != 0D) {
+        output.WriteRawTag(9);
+        output.WriteDouble(CruiseAltitude);
+      }
+      if (CruiseVelocity != 0D) {
+        output.WriteRawTag(17);
+        output.WriteDouble(CruiseVelocity);
+      }
+      if (CruiseFuelConsumptionRate != 0D) {
+        output.WriteRawTag(25);
+        output.WriteDouble(CruiseFuelConsumptionRate);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (CruiseAltitude != 0D) {
+        size += 1 + 8;
+      }
+      if (CruiseVelocity != 0D) {
+        size += 1 + 8;
+      }
+      if (CruiseFuelConsumptionRate != 0D) {
+        size += 1 + 8;
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 9: {
+            CruiseAltitude = input.ReadDouble();
+            break;
+          }
+          case 17: {
+            CruiseVelocity = input.ReadDouble();
+            break;
+          }
+          case 25: {
+            CruiseFuelConsumptionRate = input.ReadDouble();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 转弯航段 
+  /// </summary>
+  public partial class TurningSegment : pb::IMessage {
+    private static readonly pb::MessageParser<TurningSegment> _parser = new pb::MessageParser<TurningSegment>(() => (TurningSegment)MessagePool.Instance.Fetch(typeof(TurningSegment)));
+    public static pb::MessageParser<TurningSegment> Parser { get { return _parser; } }
+
+    private double turningRadius_;
+    public double TurningRadius {
+      get { return turningRadius_; }
+      set {
+        turningRadius_ = value;
+      }
+    }
+
+    private double turningVelocity_;
+    public double TurningVelocity {
+      get { return turningVelocity_; }
+      set {
+        turningVelocity_ = value;
+      }
+    }
+
+    private double climbFuelConsumptionRate_;
+    public double ClimbFuelConsumptionRate {
+      get { return climbFuelConsumptionRate_; }
+      set {
+        climbFuelConsumptionRate_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (TurningRadius != 0D) {
+        output.WriteRawTag(9);
+        output.WriteDouble(TurningRadius);
+      }
+      if (TurningVelocity != 0D) {
+        output.WriteRawTag(17);
+        output.WriteDouble(TurningVelocity);
+      }
+      if (ClimbFuelConsumptionRate != 0D) {
+        output.WriteRawTag(25);
+        output.WriteDouble(ClimbFuelConsumptionRate);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (TurningRadius != 0D) {
+        size += 1 + 8;
+      }
+      if (TurningVelocity != 0D) {
+        size += 1 + 8;
+      }
+      if (ClimbFuelConsumptionRate != 0D) {
+        size += 1 + 8;
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 9: {
+            TurningRadius = input.ReadDouble();
+            break;
+          }
+          case 17: {
+            TurningVelocity = input.ReadDouble();
+            break;
+          }
+          case 25: {
+            ClimbFuelConsumptionRate = input.ReadDouble();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 飞行计划编辑器(输入) 
+  /// </summary>
+  public partial class C2S_FlyPlanInput : pb::IMessage {
+    private static readonly pb::MessageParser<C2S_FlyPlanInput> _parser = new pb::MessageParser<C2S_FlyPlanInput>(() => (C2S_FlyPlanInput)MessagePool.Instance.Fetch(typeof(C2S_FlyPlanInput)));
+    public static pb::MessageParser<C2S_FlyPlanInput> Parser { get { return _parser; } }
+
+    private string missionName_ = "";
+    /// <summary>
+    /// 任务名称 
+    /// </summary>
+    public string MissionName {
+      get { return missionName_; }
+      set {
+        missionName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string missionType_ = "";
+    /// <summary>
+    /// 任务类型 
+    /// </summary>
+    public string MissionType {
+      get { return missionType_; }
+      set {
+        missionType_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.Point> _repeated_missionRectangle_codec
+        = pb::FieldCodec.ForMessage(26, global::KYFramework.Network.Point.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.Point> missionRectangle_ = new pbc::RepeatedField<global::KYFramework.Network.Point>();
+    /// <summary>
+    /// 任务矩形区域顶点集合 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.Point> MissionRectangle {
+      get { return missionRectangle_; }
+      set { missionRectangle_ = value; }
+    }
+
+    private double maxTakeoffWeight_;
+    /// <summary>
+    /// 最大起飞重量 
+    /// </summary>
+    public double MaxTakeoffWeight {
+      get { return maxTakeoffWeight_; }
+      set {
+        maxTakeoffWeight_ = value;
+      }
+    }
+
+    private double takeoffEmptyWeight_;
+    /// <summary>
+    /// 起飞空重 
+    /// </summary>
+    public double TakeoffEmptyWeight {
+      get { return takeoffEmptyWeight_; }
+      set {
+        takeoffEmptyWeight_ = value;
+      }
+    }
+
+    private double maxFlightRange_;
+    /// <summary>
+    /// 最大航程 
+    /// </summary>
+    public double MaxFlightRange {
+      get { return maxFlightRange_; }
+      set {
+        maxFlightRange_ = value;
+      }
+    }
+
+    private double maxFlightTime_;
+    /// <summary>
+    /// 续航时间 
+    /// </summary>
+    public double MaxFlightTime {
+      get { return maxFlightTime_; }
+      set {
+        maxFlightTime_ = value;
+      }
+    }
+
+    private double serviceCeiling_;
+    /// <summary>
+    /// 实用升限 
+    /// </summary>
+    public double ServiceCeiling {
+      get { return serviceCeiling_; }
+      set {
+        serviceCeiling_ = value;
+      }
+    }
+
+    private double maxFuelCapacity_;
+    /// <summary>
+    /// 最大载油量 
+    /// </summary>
+    public double MaxFuelCapacity {
+      get { return maxFuelCapacity_; }
+      set {
+        maxFuelCapacity_ = value;
+      }
+    }
+
+    private double maxWeightCapacity_;
+    /// <summary>
+    /// 最大商载量 
+    /// </summary>
+    public double MaxWeightCapacity {
+      get { return maxWeightCapacity_; }
+      set {
+        maxWeightCapacity_ = value;
+      }
+    }
+
+    private string loadName_ = "";
+    /// <summary>
+    /// 载荷名称 
+    /// </summary>
+    public string LoadName {
+      get { return loadName_; }
+      set {
+        loadName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private int loadQuantity_;
+    /// <summary>
+    /// 载荷数量 
+    /// </summary>
+    public int LoadQuantity {
+      get { return loadQuantity_; }
+      set {
+        loadQuantity_ = value;
+      }
+    }
+
+    private double loadWeight_;
+    /// <summary>
+    /// 载荷重量 
+    /// </summary>
+    public double LoadWeight {
+      get { return loadWeight_; }
+      set {
+        loadWeight_ = value;
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.CityWeather> _repeated_cityWeatherArr_codec
+        = pb::FieldCodec.ForMessage(114, global::KYFramework.Network.CityWeather.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.CityWeather> cityWeatherArr_ = new pbc::RepeatedField<global::KYFramework.Network.CityWeather>();
+    /// <summary>
+    /// 行政区气象集合 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.CityWeather> CityWeatherArr {
+      get { return cityWeatherArr_; }
+      set { cityWeatherArr_ = value; }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.Base> _repeated_baseArr_codec
+        = pb::FieldCodec.ForMessage(122, global::KYFramework.Network.Base.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.Base> baseArr_ = new pbc::RepeatedField<global::KYFramework.Network.Base>();
+    /// <summary>
+    /// 基地集合 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.Base> BaseArr {
+      get { return baseArr_; }
+      set { baseArr_ = value; }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.AirRoute> _repeated_airRouteArr_codec
+        = pb::FieldCodec.ForMessage(130, global::KYFramework.Network.AirRoute.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.AirRoute> airRouteArr_ = new pbc::RepeatedField<global::KYFramework.Network.AirRoute>();
+    /// <summary>
+    /// 航线集合 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.AirRoute> AirRouteArr {
+      get { return airRouteArr_; }
+      set { airRouteArr_ = value; }
+    }
+
+    private string endSelection_ = "";
+    /// <summary>
+    /// 任务终点选择:Base代表返回基地,Point代表前往定点,Hover代表原地盘旋等待 
+    /// </summary>
+    public string EndSelection {
+      get { return endSelection_; }
+      set {
+        endSelection_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.Point> _repeated_terminusLocation_codec
+        = pb::FieldCodec.ForMessage(146, global::KYFramework.Network.Point.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.Point> terminusLocation_ = new pbc::RepeatedField<global::KYFramework.Network.Point>();
+    /// <summary>
+    /// 终点位置集合 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.Point> TerminusLocation {
+      get { return terminusLocation_; }
+      set { terminusLocation_ = value; }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.NoFlyZoneCircle> _repeated_noFlyZoneCircleArr_codec
+        = pb::FieldCodec.ForMessage(154, global::KYFramework.Network.NoFlyZoneCircle.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.NoFlyZoneCircle> noFlyZoneCircleArr_ = new pbc::RepeatedField<global::KYFramework.Network.NoFlyZoneCircle>();
+    /// <summary>
+    /// 圆形禁飞区集合 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.NoFlyZoneCircle> NoFlyZoneCircleArr {
+      get { return noFlyZoneCircleArr_; }
+      set { noFlyZoneCircleArr_ = value; }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.NoFlyZoneRect> _repeated_noFlyZoneRectArr_codec
+        = pb::FieldCodec.ForMessage(162, global::KYFramework.Network.NoFlyZoneRect.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.NoFlyZoneRect> noFlyZoneRectArr_ = new pbc::RepeatedField<global::KYFramework.Network.NoFlyZoneRect>();
+    /// <summary>
+    /// 矩形禁飞区集合 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.NoFlyZoneRect> NoFlyZoneRectArr {
+      get { return noFlyZoneRectArr_; }
+      set { noFlyZoneRectArr_ = value; }
+    }
+
+    private double visualDistance_;
+    /// <summary>
+    /// 目视距离 
+    /// </summary>
+    public double VisualDistance {
+      get { return visualDistance_; }
+      set {
+        visualDistance_ = value;
+      }
+    }
+
+    private string detourDirection_ = "";
+    /// <summary>
+    /// 火场绕行方向:Clockwise表示顺时针,Anticlockwise表示逆时针 
+    /// </summary>
+    public string DetourDirection {
+      get { return detourDirection_; }
+      set {
+        detourDirection_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private int numberOfDetour_;
+    /// <summary>
+    /// 火场绕行圈数 
+    /// </summary>
+    public int NumberOfDetour {
+      get { return numberOfDetour_; }
+      set {
+        numberOfDetour_ = value;
+      }
+    }
+
+    private double detourIntervalDistance_;
+    /// <summary>
+    /// 绕行间隔距离 
+    /// </summary>
+    public double DetourIntervalDistance {
+      get { return detourIntervalDistance_; }
+      set {
+        detourIntervalDistance_ = value;
+      }
+    }
+
+    private double detourVelocity_;
+    /// <summary>
+    /// 绕行速度 
+    /// </summary>
+    public double DetourVelocity {
+      get { return detourVelocity_; }
+      set {
+        detourVelocity_ = value;
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.Point> _repeated_firePointLocation_codec
+        = pb::FieldCodec.ForMessage(210, global::KYFramework.Network.Point.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.Point> firePointLocation_ = new pbc::RepeatedField<global::KYFramework.Network.Point>();
+    /// <summary>
+    /// 火点位置集合 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.Point> FirePointLocation {
+      get { return firePointLocation_; }
+      set { firePointLocation_ = value; }
+    }
+
+    private double minTurningRadius_;
+    /// <summary>
+    /// 最小转弯半径 
+    /// </summary>
+    public double MinTurningRadius {
+      get { return minTurningRadius_; }
+      set {
+        minTurningRadius_ = value;
+      }
+    }
+
+    private double maxTurningVelocity_;
+    /// <summary>
+    /// 最大转弯速度 
+    /// </summary>
+    public double MaxTurningVelocity {
+      get { return maxTurningVelocity_; }
+      set {
+        maxTurningVelocity_ = value;
+      }
+    }
+
+    private double maxClimbVelocity_;
+    /// <summary>
+    /// 最大爬升速度 
+    /// </summary>
+    public double MaxClimbVelocity {
+      get { return maxClimbVelocity_; }
+      set {
+        maxClimbVelocity_ = value;
+      }
+    }
+
+    private double maxDescentVelocity_;
+    /// <summary>
+    /// 最大下降速度 
+    /// </summary>
+    public double MaxDescentVelocity {
+      get { return maxDescentVelocity_; }
+      set {
+        maxDescentVelocity_ = value;
+      }
+    }
+
+    private double maxCruiseVelocity_;
+    /// <summary>
+    /// 最大巡航速度 
+    /// </summary>
+    public double MaxCruiseVelocity {
+      get { return maxCruiseVelocity_; }
+      set {
+        maxCruiseVelocity_ = value;
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.ClimbSegment> _repeated_climbSegmentArr_codec
+        = pb::FieldCodec.ForMessage(258, global::KYFramework.Network.ClimbSegment.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.ClimbSegment> climbSegmentArr_ = new pbc::RepeatedField<global::KYFramework.Network.ClimbSegment>();
+    /// <summary>
+    /// 爬升航段集合 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.ClimbSegment> ClimbSegmentArr {
+      get { return climbSegmentArr_; }
+      set { climbSegmentArr_ = value; }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.DescentSegment> _repeated_descentSegmentArr_codec
+        = pb::FieldCodec.ForMessage(266, global::KYFramework.Network.DescentSegment.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.DescentSegment> descentSegmentArr_ = new pbc::RepeatedField<global::KYFramework.Network.DescentSegment>();
+    /// <summary>
+    /// 下降航段集合 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.DescentSegment> DescentSegmentArr {
+      get { return descentSegmentArr_; }
+      set { descentSegmentArr_ = value; }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.CruiseSegment> _repeated_cruiseSegmentArr_codec
+        = pb::FieldCodec.ForMessage(274, global::KYFramework.Network.CruiseSegment.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.CruiseSegment> cruiseSegmentArr_ = new pbc::RepeatedField<global::KYFramework.Network.CruiseSegment>();
+    /// <summary>
+    /// 巡航航段集合 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.CruiseSegment> CruiseSegmentArr {
+      get { return cruiseSegmentArr_; }
+      set { cruiseSegmentArr_ = value; }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.TurningSegment> _repeated_turningSegmentArr_codec
+        = pb::FieldCodec.ForMessage(282, global::KYFramework.Network.TurningSegment.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.TurningSegment> turningSegmentArr_ = new pbc::RepeatedField<global::KYFramework.Network.TurningSegment>();
+    /// <summary>
+    /// 转弯航段集合 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.TurningSegment> TurningSegmentArr {
+      get { return turningSegmentArr_; }
+      set { turningSegmentArr_ = value; }
+    }
+
+    private string aircraftID_ = "";
+    /// <summary>
+    /// 飞行器编号:按照“子任务-编队号-机号”方式命名” 
+    /// </summary>
+    public string AircraftID {
+      get { return aircraftID_; }
+      set {
+        aircraftID_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (MissionName.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(MissionName);
+      }
+      if (MissionType.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(MissionType);
+      }
+      missionRectangle_.WriteTo(output, _repeated_missionRectangle_codec);
+      if (MaxTakeoffWeight != 0D) {
+        output.WriteRawTag(33);
+        output.WriteDouble(MaxTakeoffWeight);
+      }
+      if (TakeoffEmptyWeight != 0D) {
+        output.WriteRawTag(41);
+        output.WriteDouble(TakeoffEmptyWeight);
+      }
+      if (MaxFlightRange != 0D) {
+        output.WriteRawTag(49);
+        output.WriteDouble(MaxFlightRange);
+      }
+      if (MaxFlightTime != 0D) {
+        output.WriteRawTag(57);
+        output.WriteDouble(MaxFlightTime);
+      }
+      if (ServiceCeiling != 0D) {
+        output.WriteRawTag(65);
+        output.WriteDouble(ServiceCeiling);
+      }
+      if (MaxFuelCapacity != 0D) {
+        output.WriteRawTag(73);
+        output.WriteDouble(MaxFuelCapacity);
+      }
+      if (MaxWeightCapacity != 0D) {
+        output.WriteRawTag(81);
+        output.WriteDouble(MaxWeightCapacity);
+      }
+      if (LoadName.Length != 0) {
+        output.WriteRawTag(90);
+        output.WriteString(LoadName);
+      }
+      if (LoadQuantity != 0) {
+        output.WriteRawTag(96);
+        output.WriteInt32(LoadQuantity);
+      }
+      if (LoadWeight != 0D) {
+        output.WriteRawTag(105);
+        output.WriteDouble(LoadWeight);
+      }
+      cityWeatherArr_.WriteTo(output, _repeated_cityWeatherArr_codec);
+      baseArr_.WriteTo(output, _repeated_baseArr_codec);
+      airRouteArr_.WriteTo(output, _repeated_airRouteArr_codec);
+      if (EndSelection.Length != 0) {
+        output.WriteRawTag(138, 1);
+        output.WriteString(EndSelection);
+      }
+      terminusLocation_.WriteTo(output, _repeated_terminusLocation_codec);
+      noFlyZoneCircleArr_.WriteTo(output, _repeated_noFlyZoneCircleArr_codec);
+      noFlyZoneRectArr_.WriteTo(output, _repeated_noFlyZoneRectArr_codec);
+      if (VisualDistance != 0D) {
+        output.WriteRawTag(169, 1);
+        output.WriteDouble(VisualDistance);
+      }
+      if (DetourDirection.Length != 0) {
+        output.WriteRawTag(178, 1);
+        output.WriteString(DetourDirection);
+      }
+      if (NumberOfDetour != 0) {
+        output.WriteRawTag(184, 1);
+        output.WriteInt32(NumberOfDetour);
+      }
+      if (DetourIntervalDistance != 0D) {
+        output.WriteRawTag(193, 1);
+        output.WriteDouble(DetourIntervalDistance);
+      }
+      if (DetourVelocity != 0D) {
+        output.WriteRawTag(201, 1);
+        output.WriteDouble(DetourVelocity);
+      }
+      firePointLocation_.WriteTo(output, _repeated_firePointLocation_codec);
+      if (MinTurningRadius != 0D) {
+        output.WriteRawTag(217, 1);
+        output.WriteDouble(MinTurningRadius);
+      }
+      if (MaxTurningVelocity != 0D) {
+        output.WriteRawTag(225, 1);
+        output.WriteDouble(MaxTurningVelocity);
+      }
+      if (MaxClimbVelocity != 0D) {
+        output.WriteRawTag(233, 1);
+        output.WriteDouble(MaxClimbVelocity);
+      }
+      if (MaxDescentVelocity != 0D) {
+        output.WriteRawTag(241, 1);
+        output.WriteDouble(MaxDescentVelocity);
+      }
+      if (MaxCruiseVelocity != 0D) {
+        output.WriteRawTag(249, 1);
+        output.WriteDouble(MaxCruiseVelocity);
+      }
+      climbSegmentArr_.WriteTo(output, _repeated_climbSegmentArr_codec);
+      descentSegmentArr_.WriteTo(output, _repeated_descentSegmentArr_codec);
+      cruiseSegmentArr_.WriteTo(output, _repeated_cruiseSegmentArr_codec);
+      turningSegmentArr_.WriteTo(output, _repeated_turningSegmentArr_codec);
+      if (AircraftID.Length != 0) {
+        output.WriteRawTag(162, 2);
+        output.WriteString(AircraftID);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (MissionName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(MissionName);
+      }
+      if (MissionType.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(MissionType);
+      }
+      size += missionRectangle_.CalculateSize(_repeated_missionRectangle_codec);
+      if (MaxTakeoffWeight != 0D) {
+        size += 1 + 8;
+      }
+      if (TakeoffEmptyWeight != 0D) {
+        size += 1 + 8;
+      }
+      if (MaxFlightRange != 0D) {
+        size += 1 + 8;
+      }
+      if (MaxFlightTime != 0D) {
+        size += 1 + 8;
+      }
+      if (ServiceCeiling != 0D) {
+        size += 1 + 8;
+      }
+      if (MaxFuelCapacity != 0D) {
+        size += 1 + 8;
+      }
+      if (MaxWeightCapacity != 0D) {
+        size += 1 + 8;
+      }
+      if (LoadName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(LoadName);
+      }
+      if (LoadQuantity != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(LoadQuantity);
+      }
+      if (LoadWeight != 0D) {
+        size += 1 + 8;
+      }
+      size += cityWeatherArr_.CalculateSize(_repeated_cityWeatherArr_codec);
+      size += baseArr_.CalculateSize(_repeated_baseArr_codec);
+      size += airRouteArr_.CalculateSize(_repeated_airRouteArr_codec);
+      if (EndSelection.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(EndSelection);
+      }
+      size += terminusLocation_.CalculateSize(_repeated_terminusLocation_codec);
+      size += noFlyZoneCircleArr_.CalculateSize(_repeated_noFlyZoneCircleArr_codec);
+      size += noFlyZoneRectArr_.CalculateSize(_repeated_noFlyZoneRectArr_codec);
+      if (VisualDistance != 0D) {
+        size += 2 + 8;
+      }
+      if (DetourDirection.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(DetourDirection);
+      }
+      if (NumberOfDetour != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(NumberOfDetour);
+      }
+      if (DetourIntervalDistance != 0D) {
+        size += 2 + 8;
+      }
+      if (DetourVelocity != 0D) {
+        size += 2 + 8;
+      }
+      size += firePointLocation_.CalculateSize(_repeated_firePointLocation_codec);
+      if (MinTurningRadius != 0D) {
+        size += 2 + 8;
+      }
+      if (MaxTurningVelocity != 0D) {
+        size += 2 + 8;
+      }
+      if (MaxClimbVelocity != 0D) {
+        size += 2 + 8;
+      }
+      if (MaxDescentVelocity != 0D) {
+        size += 2 + 8;
+      }
+      if (MaxCruiseVelocity != 0D) {
+        size += 2 + 8;
+      }
+      size += climbSegmentArr_.CalculateSize(_repeated_climbSegmentArr_codec);
+      size += descentSegmentArr_.CalculateSize(_repeated_descentSegmentArr_codec);
+      size += cruiseSegmentArr_.CalculateSize(_repeated_cruiseSegmentArr_codec);
+      size += turningSegmentArr_.CalculateSize(_repeated_turningSegmentArr_codec);
+      if (AircraftID.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(AircraftID);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      missionName_ = "";
+      missionType_ = "";
+      for (int i = 0; i < missionRectangle_.Count; i++) { MessagePool.Instance.Recycle(missionRectangle_[i]); }
+      missionRectangle_.Clear();
+      loadName_ = "";
+      loadQuantity_ = 0;
+      for (int i = 0; i < cityWeatherArr_.Count; i++) { MessagePool.Instance.Recycle(cityWeatherArr_[i]); }
+      cityWeatherArr_.Clear();
+      for (int i = 0; i < baseArr_.Count; i++) { MessagePool.Instance.Recycle(baseArr_[i]); }
+      baseArr_.Clear();
+      for (int i = 0; i < airRouteArr_.Count; i++) { MessagePool.Instance.Recycle(airRouteArr_[i]); }
+      airRouteArr_.Clear();
+      endSelection_ = "";
+      for (int i = 0; i < terminusLocation_.Count; i++) { MessagePool.Instance.Recycle(terminusLocation_[i]); }
+      terminusLocation_.Clear();
+      for (int i = 0; i < noFlyZoneCircleArr_.Count; i++) { MessagePool.Instance.Recycle(noFlyZoneCircleArr_[i]); }
+      noFlyZoneCircleArr_.Clear();
+      for (int i = 0; i < noFlyZoneRectArr_.Count; i++) { MessagePool.Instance.Recycle(noFlyZoneRectArr_[i]); }
+      noFlyZoneRectArr_.Clear();
+      detourDirection_ = "";
+      numberOfDetour_ = 0;
+      for (int i = 0; i < firePointLocation_.Count; i++) { MessagePool.Instance.Recycle(firePointLocation_[i]); }
+      firePointLocation_.Clear();
+      for (int i = 0; i < climbSegmentArr_.Count; i++) { MessagePool.Instance.Recycle(climbSegmentArr_[i]); }
+      climbSegmentArr_.Clear();
+      for (int i = 0; i < descentSegmentArr_.Count; i++) { MessagePool.Instance.Recycle(descentSegmentArr_[i]); }
+      descentSegmentArr_.Clear();
+      for (int i = 0; i < cruiseSegmentArr_.Count; i++) { MessagePool.Instance.Recycle(cruiseSegmentArr_[i]); }
+      cruiseSegmentArr_.Clear();
+      for (int i = 0; i < turningSegmentArr_.Count; i++) { MessagePool.Instance.Recycle(turningSegmentArr_[i]); }
+      turningSegmentArr_.Clear();
+      aircraftID_ = "";
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            MissionName = input.ReadString();
+            break;
+          }
+          case 18: {
+            MissionType = input.ReadString();
+            break;
+          }
+          case 26: {
+            missionRectangle_.AddEntriesFrom(input, _repeated_missionRectangle_codec);
+            break;
+          }
+          case 33: {
+            MaxTakeoffWeight = input.ReadDouble();
+            break;
+          }
+          case 41: {
+            TakeoffEmptyWeight = input.ReadDouble();
+            break;
+          }
+          case 49: {
+            MaxFlightRange = input.ReadDouble();
+            break;
+          }
+          case 57: {
+            MaxFlightTime = input.ReadDouble();
+            break;
+          }
+          case 65: {
+            ServiceCeiling = input.ReadDouble();
+            break;
+          }
+          case 73: {
+            MaxFuelCapacity = input.ReadDouble();
+            break;
+          }
+          case 81: {
+            MaxWeightCapacity = input.ReadDouble();
+            break;
+          }
+          case 90: {
+            LoadName = input.ReadString();
+            break;
+          }
+          case 96: {
+            LoadQuantity = input.ReadInt32();
+            break;
+          }
+          case 105: {
+            LoadWeight = input.ReadDouble();
+            break;
+          }
+          case 114: {
+            cityWeatherArr_.AddEntriesFrom(input, _repeated_cityWeatherArr_codec);
+            break;
+          }
+          case 122: {
+            baseArr_.AddEntriesFrom(input, _repeated_baseArr_codec);
+            break;
+          }
+          case 130: {
+            airRouteArr_.AddEntriesFrom(input, _repeated_airRouteArr_codec);
+            break;
+          }
+          case 138: {
+            EndSelection = input.ReadString();
+            break;
+          }
+          case 146: {
+            terminusLocation_.AddEntriesFrom(input, _repeated_terminusLocation_codec);
+            break;
+          }
+          case 154: {
+            noFlyZoneCircleArr_.AddEntriesFrom(input, _repeated_noFlyZoneCircleArr_codec);
+            break;
+          }
+          case 162: {
+            noFlyZoneRectArr_.AddEntriesFrom(input, _repeated_noFlyZoneRectArr_codec);
+            break;
+          }
+          case 169: {
+            VisualDistance = input.ReadDouble();
+            break;
+          }
+          case 178: {
+            DetourDirection = input.ReadString();
+            break;
+          }
+          case 184: {
+            NumberOfDetour = input.ReadInt32();
+            break;
+          }
+          case 193: {
+            DetourIntervalDistance = input.ReadDouble();
+            break;
+          }
+          case 201: {
+            DetourVelocity = input.ReadDouble();
+            break;
+          }
+          case 210: {
+            firePointLocation_.AddEntriesFrom(input, _repeated_firePointLocation_codec);
+            break;
+          }
+          case 217: {
+            MinTurningRadius = input.ReadDouble();
+            break;
+          }
+          case 225: {
+            MaxTurningVelocity = input.ReadDouble();
+            break;
+          }
+          case 233: {
+            MaxClimbVelocity = input.ReadDouble();
+            break;
+          }
+          case 241: {
+            MaxDescentVelocity = input.ReadDouble();
+            break;
+          }
+          case 249: {
+            MaxCruiseVelocity = input.ReadDouble();
+            break;
+          }
+          case 258: {
+            climbSegmentArr_.AddEntriesFrom(input, _repeated_climbSegmentArr_codec);
+            break;
+          }
+          case 266: {
+            descentSegmentArr_.AddEntriesFrom(input, _repeated_descentSegmentArr_codec);
+            break;
+          }
+          case 274: {
+            cruiseSegmentArr_.AddEntriesFrom(input, _repeated_cruiseSegmentArr_codec);
+            break;
+          }
+          case 282: {
+            turningSegmentArr_.AddEntriesFrom(input, _repeated_turningSegmentArr_codec);
+            break;
+          }
+          case 290: {
+            AircraftID = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 飞行计划编辑器(输出) 
+  /// </summary>
+  public partial class S2C_FlyPlanOutput : pb::IMessage {
+    private static readonly pb::MessageParser<S2C_FlyPlanOutput> _parser = new pb::MessageParser<S2C_FlyPlanOutput>(() => (S2C_FlyPlanOutput)MessagePool.Instance.Fetch(typeof(S2C_FlyPlanOutput)));
+    public static pb::MessageParser<S2C_FlyPlanOutput> Parser { get { return _parser; } }
+
+    private string aircraftID_ = "";
+    /// <summary>
+    /// 飞行器编号 
+    /// </summary>
+    public string AircraftID {
+      get { return aircraftID_; }
+      set {
+        aircraftID_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.PlanTurningPoint> _repeated_planTurningPointArr_codec
+        = pb::FieldCodec.ForMessage(18, global::KYFramework.Network.PlanTurningPoint.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.PlanTurningPoint> planTurningPointArr_ = new pbc::RepeatedField<global::KYFramework.Network.PlanTurningPoint>();
+    /// <summary>
+    /// 飞行航路点集合 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.PlanTurningPoint> PlanTurningPointArr {
+      get { return planTurningPointArr_; }
+      set { planTurningPointArr_ = value; }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (AircraftID.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(AircraftID);
+      }
+      planTurningPointArr_.WriteTo(output, _repeated_planTurningPointArr_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (AircraftID.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(AircraftID);
+      }
+      size += planTurningPointArr_.CalculateSize(_repeated_planTurningPointArr_codec);
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      aircraftID_ = "";
+      for (int i = 0; i < planTurningPointArr_.Count; i++) { MessagePool.Instance.Recycle(planTurningPointArr_[i]); }
+      planTurningPointArr_.Clear();
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            AircraftID = input.ReadString();
+            break;
+          }
+          case 18: {
+            planTurningPointArr_.AddEntriesFrom(input, _repeated_planTurningPointArr_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 计划航路点 
+  /// </summary>
+  public partial class PlanTurningPoint : pb::IMessage {
+    private static readonly pb::MessageParser<PlanTurningPoint> _parser = new pb::MessageParser<PlanTurningPoint>(() => (PlanTurningPoint)MessagePool.Instance.Fetch(typeof(PlanTurningPoint)));
+    public static pb::MessageParser<PlanTurningPoint> Parser { get { return _parser; } }
+
+    private string name_ = "";
+    /// <summary>
+    /// 名称:爬升、巡航、转弯、下降、观测火场 
+    /// </summary>
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private global::KYFramework.Network.Point location_;
+    /// <summary>
+    /// 位置 
+    /// </summary>
+    public global::KYFramework.Network.Point Location {
+      get { return location_; }
+      set {
+        location_ = value;
+      }
+    }
+
+    private string type_ = "";
+    /// <summary>
+    /// 类型:普通、转弯、取水任务、灭火任务 
+    /// </summary>
+    public string Type {
+      get { return type_; }
+      set {
+        type_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private double velocity_;
+    /// <summary>
+    /// 速度 
+    /// </summary>
+    public double Velocity {
+      get { return velocity_; }
+      set {
+        velocity_ = value;
+      }
+    }
+
+    private double segmentConsumption_;
+    /// <summary>
+    /// 航段油耗 
+    /// </summary>
+    public double SegmentConsumption {
+      get { return segmentConsumption_; }
+      set {
+        segmentConsumption_ = value;
+      }
+    }
+
+    private double segmentTime_;
+    /// <summary>
+    /// 航段飞行时间 
+    /// </summary>
+    public double SegmentTime {
+      get { return segmentTime_; }
+      set {
+        segmentTime_ = value;
+      }
+    }
+
+    private double radius_;
+    /// <summary>
+    /// 转弯半径 
+    /// </summary>
+    public double Radius {
+      get { return radius_; }
+      set {
+        radius_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (location_ != null) {
+        output.WriteRawTag(18);
+        output.WriteMessage(Location);
+      }
+      if (Type.Length != 0) {
+        output.WriteRawTag(26);
+        output.WriteString(Type);
+      }
+      if (Velocity != 0D) {
+        output.WriteRawTag(33);
+        output.WriteDouble(Velocity);
+      }
+      if (SegmentConsumption != 0D) {
+        output.WriteRawTag(41);
+        output.WriteDouble(SegmentConsumption);
+      }
+      if (SegmentTime != 0D) {
+        output.WriteRawTag(49);
+        output.WriteDouble(SegmentTime);
+      }
+      if (Radius != 0D) {
+        output.WriteRawTag(57);
+        output.WriteDouble(Radius);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (location_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(Location);
+      }
+      if (Type.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Type);
+      }
+      if (Velocity != 0D) {
+        size += 1 + 8;
+      }
+      if (SegmentConsumption != 0D) {
+        size += 1 + 8;
+      }
+      if (SegmentTime != 0D) {
+        size += 1 + 8;
+      }
+      if (Radius != 0D) {
+        size += 1 + 8;
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      name_ = "";
+      if (location_ != null) MessagePool.Instance.Recycle(location_); location_ = null;
+      type_ = "";
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            if (location_ == null) {
+              location_ = new global::KYFramework.Network.Point();
+            }
+            input.ReadMessage(location_);
+            break;
+          }
+          case 26: {
+            Type = input.ReadString();
+            break;
+          }
+          case 33: {
+            Velocity = input.ReadDouble();
+            break;
+          }
+          case 41: {
+            SegmentConsumption = input.ReadDouble();
+            break;
+          }
+          case 49: {
+            SegmentTime = input.ReadDouble();
+            break;
+          }
+          case 57: {
+            Radius = input.ReadDouble();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 航路曲线(输出) 
+  /// </summary>
+  public partial class S2C_TurningPointOutput : pb::IMessage {
+    private static readonly pb::MessageParser<S2C_TurningPointOutput> _parser = new pb::MessageParser<S2C_TurningPointOutput>(() => (S2C_TurningPointOutput)MessagePool.Instance.Fetch(typeof(S2C_TurningPointOutput)));
+    public static pb::MessageParser<S2C_TurningPointOutput> Parser { get { return _parser; } }
+
+    private string aircraftID_ = "";
+    /// <summary>
+    /// 飞行器编号 
+    /// </summary>
+    public string AircraftID {
+      get { return aircraftID_; }
+      set {
+        aircraftID_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string turningPointName_ = "";
+    /// <summary>
+    /// 飞行航路点名称 
+    /// </summary>
+    public string TurningPointName {
+      get { return turningPointName_; }
+      set {
+        turningPointName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.Point> _repeated_turningPointLocation_codec
+        = pb::FieldCodec.ForMessage(26, global::KYFramework.Network.Point.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.Point> turningPointLocation_ = new pbc::RepeatedField<global::KYFramework.Network.Point>();
+    /// <summary>
+    /// 飞行航路点位置列表 
+    /// </summary>
+    public pbc::RepeatedField<global::KYFramework.Network.Point> TurningPointLocation {
+      get { return turningPointLocation_; }
+      set { turningPointLocation_ = value; }
+    }
+
+    private string presentMission_ = "";
+    /// <summary>
+    /// 当前任务阶段 
+    /// </summary>
+    public string PresentMission {
+      get { return presentMission_; }
+      set {
+        presentMission_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string presentTarget_ = "";
+    /// <summary>
+    /// 当前飞行目标点 
+    /// </summary>
+    public string PresentTarget {
+      get { return presentTarget_; }
+      set {
+        presentTarget_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string startDate_ = "";
+    /// <summary>
+    /// 航路开始日期 
+    /// </summary>
+    public string StartDate {
+      get { return startDate_; }
+      set {
+        startDate_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string startTime_ = "";
+    /// <summary>
+    /// 航路开始时间 
+    /// </summary>
+    public string StartTime {
+      get { return startTime_; }
+      set {
+        startTime_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string endDate_ = "";
+    /// <summary>
+    /// 航路结束日期 
+    /// </summary>
+    public string EndDate {
+      get { return endDate_; }
+      set {
+        endDate_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string endTime_ = "";
+    /// <summary>
+    /// 航路结束时间 
+    /// </summary>
+    public string EndTime {
+      get { return endTime_; }
+      set {
+        endTime_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private double elapsedTime_;
+    /// <summary>
+    /// 已飞行时间 
+    /// </summary>
+    public double ElapsedTime {
+      get { return elapsedTime_; }
+      set {
+        elapsedTime_ = value;
+      }
+    }
+
+    private string presentDate_ = "";
+    /// <summary>
+    /// 当前日期 
+    /// </summary>
+    public string PresentDate {
+      get { return presentDate_; }
+      set {
+        presentDate_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string presentTime_ = "";
+    /// <summary>
+    /// 当前时刻 
+    /// </summary>
+    public string PresentTime {
+      get { return presentTime_; }
+      set {
+        presentTime_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private global::KYFramework.Network.Point presentLocation_;
+    /// <summary>
+    /// 当前位置 
+    /// </summary>
+    public global::KYFramework.Network.Point PresentLocation {
+      get { return presentLocation_; }
+      set {
+        presentLocation_ = value;
+      }
+    }
+
+    private double presentFuelConsumption_;
+    /// <summary>
+    /// 当前已消耗油量 
+    /// </summary>
+    public double PresentFuelConsumption {
+      get { return presentFuelConsumption_; }
+      set {
+        presentFuelConsumption_ = value;
+      }
+    }
+
+    private double presentRemainingFuel_;
+    /// <summary>
+    /// 当前剩余油量 
+    /// </summary>
+    public double PresentRemainingFuel {
+      get { return presentRemainingFuel_; }
+      set {
+        presentRemainingFuel_ = value;
+      }
+    }
+
+    private double presentVelocity_;
+    /// <summary>
+    /// 当前飞行速度 
+    /// </summary>
+    public double PresentVelocity {
+      get { return presentVelocity_; }
+      set {
+        presentVelocity_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (AircraftID.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(AircraftID);
+      }
+      if (TurningPointName.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(TurningPointName);
+      }
+      turningPointLocation_.WriteTo(output, _repeated_turningPointLocation_codec);
+      if (PresentMission.Length != 0) {
+        output.WriteRawTag(34);
+        output.WriteString(PresentMission);
+      }
+      if (PresentTarget.Length != 0) {
+        output.WriteRawTag(42);
+        output.WriteString(PresentTarget);
+      }
+      if (StartDate.Length != 0) {
+        output.WriteRawTag(50);
+        output.WriteString(StartDate);
+      }
+      if (StartTime.Length != 0) {
+        output.WriteRawTag(58);
+        output.WriteString(StartTime);
+      }
+      if (EndDate.Length != 0) {
+        output.WriteRawTag(66);
+        output.WriteString(EndDate);
+      }
+      if (EndTime.Length != 0) {
+        output.WriteRawTag(74);
+        output.WriteString(EndTime);
+      }
+      if (ElapsedTime != 0D) {
+        output.WriteRawTag(81);
+        output.WriteDouble(ElapsedTime);
+      }
+      if (PresentDate.Length != 0) {
+        output.WriteRawTag(90);
+        output.WriteString(PresentDate);
+      }
+      if (PresentTime.Length != 0) {
+        output.WriteRawTag(98);
+        output.WriteString(PresentTime);
+      }
+      if (presentLocation_ != null) {
+        output.WriteRawTag(106);
+        output.WriteMessage(PresentLocation);
+      }
+      if (PresentFuelConsumption != 0D) {
+        output.WriteRawTag(113);
+        output.WriteDouble(PresentFuelConsumption);
+      }
+      if (PresentRemainingFuel != 0D) {
+        output.WriteRawTag(121);
+        output.WriteDouble(PresentRemainingFuel);
+      }
+      if (PresentVelocity != 0D) {
+        output.WriteRawTag(129, 1);
+        output.WriteDouble(PresentVelocity);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (AircraftID.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(AircraftID);
+      }
+      if (TurningPointName.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(TurningPointName);
+      }
+      size += turningPointLocation_.CalculateSize(_repeated_turningPointLocation_codec);
+      if (PresentMission.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(PresentMission);
+      }
+      if (PresentTarget.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(PresentTarget);
+      }
+      if (StartDate.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(StartDate);
+      }
+      if (StartTime.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(StartTime);
+      }
+      if (EndDate.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(EndDate);
+      }
+      if (EndTime.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(EndTime);
+      }
+      if (ElapsedTime != 0D) {
+        size += 1 + 8;
+      }
+      if (PresentDate.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(PresentDate);
+      }
+      if (PresentTime.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(PresentTime);
+      }
+      if (presentLocation_ != null) {
+        size += 1 + pb::CodedOutputStream.ComputeMessageSize(PresentLocation);
+      }
+      if (PresentFuelConsumption != 0D) {
+        size += 1 + 8;
+      }
+      if (PresentRemainingFuel != 0D) {
+        size += 1 + 8;
+      }
+      if (PresentVelocity != 0D) {
+        size += 2 + 8;
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      aircraftID_ = "";
+      turningPointName_ = "";
+      for (int i = 0; i < turningPointLocation_.Count; i++) { MessagePool.Instance.Recycle(turningPointLocation_[i]); }
+      turningPointLocation_.Clear();
+      presentMission_ = "";
+      presentTarget_ = "";
+      startDate_ = "";
+      startTime_ = "";
+      endDate_ = "";
+      endTime_ = "";
+      presentDate_ = "";
+      presentTime_ = "";
+      if (presentLocation_ != null) MessagePool.Instance.Recycle(presentLocation_); presentLocation_ = null;
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            AircraftID = input.ReadString();
+            break;
+          }
+          case 18: {
+            TurningPointName = input.ReadString();
+            break;
+          }
+          case 26: {
+            turningPointLocation_.AddEntriesFrom(input, _repeated_turningPointLocation_codec);
+            break;
+          }
+          case 34: {
+            PresentMission = input.ReadString();
+            break;
+          }
+          case 42: {
+            PresentTarget = input.ReadString();
+            break;
+          }
+          case 50: {
+            StartDate = input.ReadString();
+            break;
+          }
+          case 58: {
+            StartTime = input.ReadString();
+            break;
+          }
+          case 66: {
+            EndDate = input.ReadString();
+            break;
+          }
+          case 74: {
+            EndTime = input.ReadString();
+            break;
+          }
+          case 81: {
+            ElapsedTime = input.ReadDouble();
+            break;
+          }
+          case 90: {
+            PresentDate = input.ReadString();
+            break;
+          }
+          case 98: {
+            PresentTime = input.ReadString();
+            break;
+          }
+          case 106: {
+            if (presentLocation_ == null) {
+              presentLocation_ = new global::KYFramework.Network.Point();
+            }
+            input.ReadMessage(presentLocation_);
+            break;
+          }
+          case 113: {
+            PresentFuelConsumption = input.ReadDouble();
+            break;
+          }
+          case 121: {
+            PresentRemainingFuel = input.ReadDouble();
+            break;
+          }
+          case 129: {
+            PresentVelocity = input.ReadDouble();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class C2S_GetReport : pb::IMessage {
+    private static readonly pb::MessageParser<C2S_GetReport> _parser = new pb::MessageParser<C2S_GetReport>(() => (C2S_GetReport)MessagePool.Instance.Fetch(typeof(C2S_GetReport)));
+    public static pb::MessageParser<C2S_GetReport> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      rpcId_ = 0;
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class S2C_GetReport : pb::IMessage {
+    private static readonly pb::MessageParser<S2C_GetReport> _parser = new pb::MessageParser<S2C_GetReport>(() => (S2C_GetReport)MessagePool.Instance.Fetch(typeof(S2C_GetReport)));
+    public static pb::MessageParser<S2C_GetReport> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private int error_;
+    public int Error {
+      get { return error_; }
+      set {
+        error_ = value;
+      }
+    }
+
+    private string message_ = "";
+    public string Message {
+      get { return message_; }
+      set {
+        message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.ResportWithTaskName> _repeated_reports_codec
+        = pb::FieldCodec.ForMessage(746, global::KYFramework.Network.ResportWithTaskName.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.ResportWithTaskName> reports_ = new pbc::RepeatedField<global::KYFramework.Network.ResportWithTaskName>();
+    public pbc::RepeatedField<global::KYFramework.Network.ResportWithTaskName> Reports {
+      get { return reports_; }
+      set { reports_ = value; }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+      if (Error != 0) {
+        output.WriteRawTag(216, 5);
+        output.WriteInt32(Error);
+      }
+      if (Message.Length != 0) {
+        output.WriteRawTag(226, 5);
+        output.WriteString(Message);
+      }
+      reports_.WriteTo(output, _repeated_reports_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (Error != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(Error);
+      }
+      if (Message.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(Message);
+      }
+      size += reports_.CalculateSize(_repeated_reports_codec);
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      rpcId_ = 0;
+      error_ = 0;
+      message_ = "";
+      for (int i = 0; i < reports_.Count; i++) { MessagePool.Instance.Recycle(reports_[i]); }
+      reports_.Clear();
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 728: {
+            Error = input.ReadInt32();
+            break;
+          }
+          case 738: {
+            Message = input.ReadString();
+            break;
+          }
+          case 746: {
+            reports_.AddEntriesFrom(input, _repeated_reports_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class ResportWithTaskName : pb::IMessage {
+    private static readonly pb::MessageParser<ResportWithTaskName> _parser = new pb::MessageParser<ResportWithTaskName>(() => (ResportWithTaskName)MessagePool.Instance.Fetch(typeof(ResportWithTaskName)));
+    public static pb::MessageParser<ResportWithTaskName> Parser { get { return _parser; } }
+
+    private int firePointId_;
+    public int FirePointId {
+      get { return firePointId_; }
+      set {
+        firePointId_ = value;
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.EntitySheetReportValue> _repeated_entitySheetReportValueArr_codec
+        = pb::FieldCodec.ForMessage(18, global::KYFramework.Network.EntitySheetReportValue.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.EntitySheetReportValue> entitySheetReportValueArr_ = new pbc::RepeatedField<global::KYFramework.Network.EntitySheetReportValue>();
+    public pbc::RepeatedField<global::KYFramework.Network.EntitySheetReportValue> EntitySheetReportValueArr {
+      get { return entitySheetReportValueArr_; }
+      set { entitySheetReportValueArr_ = value; }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (FirePointId != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(FirePointId);
+      }
+      entitySheetReportValueArr_.WriteTo(output, _repeated_entitySheetReportValueArr_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (FirePointId != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(FirePointId);
+      }
+      size += entitySheetReportValueArr_.CalculateSize(_repeated_entitySheetReportValueArr_codec);
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      firePointId_ = 0;
+      for (int i = 0; i < entitySheetReportValueArr_.Count; i++) { MessagePool.Instance.Recycle(entitySheetReportValueArr_[i]); }
+      entitySheetReportValueArr_.Clear();
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            FirePointId = input.ReadInt32();
+            break;
+          }
+          case 18: {
+            entitySheetReportValueArr_.AddEntriesFrom(input, _repeated_entitySheetReportValueArr_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 仿真开始 
+  /// </summary>
+  public partial class C2S_StmulationStart : pb::IMessage {
+    private static readonly pb::MessageParser<C2S_StmulationStart> _parser = new pb::MessageParser<C2S_StmulationStart>(() => (C2S_StmulationStart)MessagePool.Instance.Fetch(typeof(C2S_StmulationStart)));
+    public static pb::MessageParser<C2S_StmulationStart> Parser { get { return _parser; } }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 仿真倍速调整 
+  /// </summary>
+  public partial class C2S_StmulationTimeScale : pb::IMessage {
+    private static readonly pb::MessageParser<C2S_StmulationTimeScale> _parser = new pb::MessageParser<C2S_StmulationTimeScale>(() => (C2S_StmulationTimeScale)MessagePool.Instance.Fetch(typeof(C2S_StmulationTimeScale)));
+    public static pb::MessageParser<C2S_StmulationTimeScale> Parser { get { return _parser; } }
+
+    private int timeScale_;
+    public int TimeScale {
+      get { return timeScale_; }
+      set {
+        timeScale_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (TimeScale != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(TimeScale);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (TimeScale != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(TimeScale);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      timeScale_ = 0;
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            TimeScale = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 仿真结束 
+  /// </summary>
+  public partial class S2C_StmulationEnd : pb::IMessage {
+    private static readonly pb::MessageParser<S2C_StmulationEnd> _parser = new pb::MessageParser<S2C_StmulationEnd>(() => (S2C_StmulationEnd)MessagePool.Instance.Fetch(typeof(S2C_StmulationEnd)));
+    public static pb::MessageParser<S2C_StmulationEnd> Parser { get { return _parser; } }
+
+    private int firePointId_;
+    public int FirePointId {
+      get { return firePointId_; }
+      set {
+        firePointId_ = value;
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.EntitySheetReportValue> _repeated_entitySheetReportValueArr_codec
+        = pb::FieldCodec.ForMessage(18, global::KYFramework.Network.EntitySheetReportValue.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.EntitySheetReportValue> entitySheetReportValueArr_ = new pbc::RepeatedField<global::KYFramework.Network.EntitySheetReportValue>();
+    public pbc::RepeatedField<global::KYFramework.Network.EntitySheetReportValue> EntitySheetReportValueArr {
+      get { return entitySheetReportValueArr_; }
+      set { entitySheetReportValueArr_ = value; }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (FirePointId != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(FirePointId);
+      }
+      entitySheetReportValueArr_.WriteTo(output, _repeated_entitySheetReportValueArr_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (FirePointId != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(FirePointId);
+      }
+      size += entitySheetReportValueArr_.CalculateSize(_repeated_entitySheetReportValueArr_codec);
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      firePointId_ = 0;
+      for (int i = 0; i < entitySheetReportValueArr_.Count; i++) { MessagePool.Instance.Recycle(entitySheetReportValueArr_[i]); }
+      entitySheetReportValueArr_.Clear();
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            FirePointId = input.ReadInt32();
+            break;
+          }
+          case 18: {
+            entitySheetReportValueArr_.AddEntriesFrom(input, _repeated_entitySheetReportValueArr_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class EntitySheetReportValue : pb::IMessage {
+    private static readonly pb::MessageParser<EntitySheetReportValue> _parser = new pb::MessageParser<EntitySheetReportValue>(() => (EntitySheetReportValue)MessagePool.Instance.Fetch(typeof(EntitySheetReportValue)));
+    public static pb::MessageParser<EntitySheetReportValue> Parser { get { return _parser; } }
+
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.SheetReportValue> _repeated_sheetReportValueArr_codec
+        = pb::FieldCodec.ForMessage(18, global::KYFramework.Network.SheetReportValue.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.SheetReportValue> sheetReportValueArr_ = new pbc::RepeatedField<global::KYFramework.Network.SheetReportValue>();
+    public pbc::RepeatedField<global::KYFramework.Network.SheetReportValue> SheetReportValueArr {
+      get { return sheetReportValueArr_; }
+      set { sheetReportValueArr_ = value; }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      sheetReportValueArr_.WriteTo(output, _repeated_sheetReportValueArr_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += sheetReportValueArr_.CalculateSize(_repeated_sheetReportValueArr_codec);
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      name_ = "";
+      for (int i = 0; i < sheetReportValueArr_.Count; i++) { MessagePool.Instance.Recycle(sheetReportValueArr_[i]); }
+      sheetReportValueArr_.Clear();
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            sheetReportValueArr_.AddEntriesFrom(input, _repeated_sheetReportValueArr_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class SheetReportValue : pb::IMessage {
+    private static readonly pb::MessageParser<SheetReportValue> _parser = new pb::MessageParser<SheetReportValue>(() => (SheetReportValue)MessagePool.Instance.Fetch(typeof(SheetReportValue)));
+    public static pb::MessageParser<SheetReportValue> Parser { get { return _parser; } }
+
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private static readonly pb::FieldCodec<global::KYFramework.Network.ReportValue> _repeated_valueArr_codec
+        = pb::FieldCodec.ForMessage(18, global::KYFramework.Network.ReportValue.Parser);
+    private pbc::RepeatedField<global::KYFramework.Network.ReportValue> valueArr_ = new pbc::RepeatedField<global::KYFramework.Network.ReportValue>();
+    public pbc::RepeatedField<global::KYFramework.Network.ReportValue> ValueArr {
+      get { return valueArr_; }
+      set { valueArr_ = value; }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      valueArr_.WriteTo(output, _repeated_valueArr_codec);
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      size += valueArr_.CalculateSize(_repeated_valueArr_codec);
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      name_ = "";
+      for (int i = 0; i < valueArr_.Count; i++) { MessagePool.Instance.Recycle(valueArr_[i]); }
+      valueArr_.Clear();
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            valueArr_.AddEntriesFrom(input, _repeated_valueArr_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  public partial class ReportValue : pb::IMessage {
+    private static readonly pb::MessageParser<ReportValue> _parser = new pb::MessageParser<ReportValue>(() => (ReportValue)MessagePool.Instance.Fetch(typeof(ReportValue)));
+    public static pb::MessageParser<ReportValue> Parser { get { return _parser; } }
+
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string value_ = "";
+    public string Value {
+      get { return value_; }
+      set {
+        value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+      if (Value.Length != 0) {
+        output.WriteRawTag(18);
+        output.WriteString(Value);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      if (Value.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Value);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      name_ = "";
+      value_ = "";
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+          case 18: {
+            Value = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 请求 效能评估 
+  /// </summary>
+  public partial class C2S_SimulationResult : pb::IMessage {
+    private static readonly pb::MessageParser<C2S_SimulationResult> _parser = new pb::MessageParser<C2S_SimulationResult>(() => (C2S_SimulationResult)MessagePool.Instance.Fetch(typeof(C2S_SimulationResult)));
+    public static pb::MessageParser<C2S_SimulationResult> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (RpcId != 0) {
+        output.WriteRawTag(208, 5);
+        output.WriteInt32(RpcId);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      rpcId_ = 0;
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 720: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 返回 效能评估 
+  /// </summary>
+  public partial class S2C_SimulatinResult : pb::IMessage {
+    private static readonly pb::MessageParser<S2C_SimulatinResult> _parser = new pb::MessageParser<S2C_SimulatinResult>(() => (S2C_SimulatinResult)MessagePool.Instance.Fetch(typeof(S2C_SimulatinResult)));
+    public static pb::MessageParser<S2C_SimulatinResult> Parser { get { return _parser; } }
+
+    private int rpcId_;
+    public int RpcId {
+      get { return rpcId_; }
+      set {
+        rpcId_ = value;
+      }
+    }
+
+    private int error_;
+    public int Error {
+      get { return error_; }
+      set {
+        error_ = value;
+      }
+    }
+
+    private string message_ = "";
+    public string Message {
+      get { return message_; }
+      set {
+        message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private double taskResponseTime_;
+    /// <summary>
+    /// 任务响应时间(秒) 
+    /// </summary>
+    public double TaskResponseTime {
+      get { return taskResponseTime_; }
+      set {
+        taskResponseTime_ = value;
+      }
+    }
+
+    private double taskTotalTime_;
+    /// <summary>
+    /// 总任务耗时(秒) 
+    /// </summary>
+    public double TaskTotalTime {
+      get { return taskTotalTime_; }
+      set {
+        taskTotalTime_ = value;
+      }
+    }
+
+    private double singleJoinTime_;
+    /// <summary>
+    /// 单机入场时间(秒) 
+    /// </summary>
+    public double SingleJoinTime {
+      get { return singleJoinTime_; }
+      set {
+        singleJoinTime_ = value;
+      }
+    }
+
+    private double singleEffectiveTaskTime_;
+    /// <summary>
+    /// 单机有效任务时长(秒) 
+    /// </summary>
+    public double SingleEffectiveTaskTime {
+      get { return singleEffectiveTaskTime_; }
+      set {
+        singleEffectiveTaskTime_ = value;
+      }
+    }
+
+    private double singleAllPeopeo_;
+    /// <summary>
+    /// 单机总投送人数(人) 
+    /// </summary>
+    public double SingleAllPeopeo {
+      get { return singleAllPeopeo_; }
+      set {
+        singleAllPeopeo_ = value;
+      }
+    }
+
+    private double singleEachPeople_;
+    /// <summary>
+    /// 单机单次投送人数(人) 
+    /// </summary>
+    public double SingleEachPeople {
+      get { return singleEachPeople_; }
+      set {
+        singleEachPeople_ = value;
+      }
+    }
+
+    private double speedPatrol_;
+    /// <summary>
+    /// 巡护速度(km/h) 
+    /// </summary>
+    public double SpeedPatrol {
+      get { return speedPatrol_; }
+      set {
+        speedPatrol_ = value;
+      }
+    }
+
+    private double voyagePatrol_;
+    /// <summary>
+    /// 巡护航程 (km)
+    /// </summary>
+    public double VoyagePatrol {
+      get { return voyagePatrol_; }
+      set {
+        voyagePatrol_ = value;
+      }
+    }
+
+    private double timeAllPatrol_;
+    /// <summary>
+    /// 总巡护耗时 (秒)
+    /// </summary>
+    public double TimeAllPatrol {
+      get { return timeAllPatrol_; }
+      set {
+        timeAllPatrol_ = value;
+      }
+    }
+
+    private double fireJoinTime_;
+    /// <summary>
+    /// 火情入场时间 (秒)
+    /// </summary>
+    public double FireJoinTime {
+      get { return fireJoinTime_; }
+      set {
+        fireJoinTime_ = value;
+      }
+    }
+
+    private double fuelSingle_;
+    /// <summary>
+    /// 单机总油耗 (kg)
+    /// </summary>
+    public double FuelSingle {
+      get { return fuelSingle_; }
+      set {
+        fuelSingle_ = value;
+      }
+    }
+
+    private string airportUseSituation_ = "";
+    /// <summary>
+    /// 单机机场使用情况 
+    /// </summary>
+    public string AirportUseSituation {
+      get { return airportUseSituation_; }
+      set {
+        airportUseSituation_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string navUseSituation_ = "";
+    /// <summary>
+    /// 单机导航使用情况 
+    /// </summary>
+    public string NavUseSituation {
+      get { return navUseSituation_; }
+      set {
+        navUseSituation_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private double fireJoinTimeEconomical_;
+    /// <summary>
+    /// 单机总任务时长(秒) 
+    /// </summary>
+    public double FireJoinTimeEconomical {
+      get { return fireJoinTimeEconomical_; }
+      set {
+        fireJoinTimeEconomical_ = value;
+      }
+    }
+
+    private double fuelSingleEconomical_;
+    /// <summary>
+    /// 单机总油耗(kg) 
+    /// </summary>
+    public double FuelSingleEconomical {
+      get { return fuelSingleEconomical_; }
+      set {
+        fuelSingleEconomical_ = value;
+      }
+    }
+
+    private string airportUseSituationEconomical_ = "";
+    /// <summary>
+    /// 单机机场使用情况 
+    /// </summary>
+    public string AirportUseSituationEconomical {
+      get { return airportUseSituationEconomical_; }
+      set {
+        airportUseSituationEconomical_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private string navUseSituationEconomical_ = "";
+    /// <summary>
+    /// 单机导航使用情况 
+    /// </summary>
+    public string NavUseSituationEconomical {
+      get { return navUseSituationEconomical_; }
+      set {
+        navUseSituationEconomical_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (RpcId != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(RpcId);
+      }
+      if (Error != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(Error);
+      }
+      if (Message.Length != 0) {
+        output.WriteRawTag(26);
+        output.WriteString(Message);
+      }
+      if (TaskResponseTime != 0D) {
+        output.WriteRawTag(33);
+        output.WriteDouble(TaskResponseTime);
+      }
+      if (TaskTotalTime != 0D) {
+        output.WriteRawTag(41);
+        output.WriteDouble(TaskTotalTime);
+      }
+      if (SingleJoinTime != 0D) {
+        output.WriteRawTag(49);
+        output.WriteDouble(SingleJoinTime);
+      }
+      if (SingleEffectiveTaskTime != 0D) {
+        output.WriteRawTag(57);
+        output.WriteDouble(SingleEffectiveTaskTime);
+      }
+      if (SingleAllPeopeo != 0D) {
+        output.WriteRawTag(65);
+        output.WriteDouble(SingleAllPeopeo);
+      }
+      if (SingleEachPeople != 0D) {
+        output.WriteRawTag(73);
+        output.WriteDouble(SingleEachPeople);
+      }
+      if (SpeedPatrol != 0D) {
+        output.WriteRawTag(81);
+        output.WriteDouble(SpeedPatrol);
+      }
+      if (VoyagePatrol != 0D) {
+        output.WriteRawTag(89);
+        output.WriteDouble(VoyagePatrol);
+      }
+      if (TimeAllPatrol != 0D) {
+        output.WriteRawTag(97);
+        output.WriteDouble(TimeAllPatrol);
+      }
+      if (FireJoinTime != 0D) {
+        output.WriteRawTag(105);
+        output.WriteDouble(FireJoinTime);
+      }
+      if (FuelSingle != 0D) {
+        output.WriteRawTag(113);
+        output.WriteDouble(FuelSingle);
+      }
+      if (AirportUseSituation.Length != 0) {
+        output.WriteRawTag(122);
+        output.WriteString(AirportUseSituation);
+      }
+      if (NavUseSituation.Length != 0) {
+        output.WriteRawTag(130, 1);
+        output.WriteString(NavUseSituation);
+      }
+      if (FireJoinTimeEconomical != 0D) {
+        output.WriteRawTag(137, 1);
+        output.WriteDouble(FireJoinTimeEconomical);
+      }
+      if (FuelSingleEconomical != 0D) {
+        output.WriteRawTag(145, 1);
+        output.WriteDouble(FuelSingleEconomical);
+      }
+      if (AirportUseSituationEconomical.Length != 0) {
+        output.WriteRawTag(154, 1);
+        output.WriteString(AirportUseSituationEconomical);
+      }
+      if (NavUseSituationEconomical.Length != 0) {
+        output.WriteRawTag(162, 1);
+        output.WriteString(NavUseSituationEconomical);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (RpcId != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(RpcId);
+      }
+      if (Error != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(Error);
+      }
+      if (Message.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Message);
+      }
+      if (TaskResponseTime != 0D) {
+        size += 1 + 8;
+      }
+      if (TaskTotalTime != 0D) {
+        size += 1 + 8;
+      }
+      if (SingleJoinTime != 0D) {
+        size += 1 + 8;
+      }
+      if (SingleEffectiveTaskTime != 0D) {
+        size += 1 + 8;
+      }
+      if (SingleAllPeopeo != 0D) {
+        size += 1 + 8;
+      }
+      if (SingleEachPeople != 0D) {
+        size += 1 + 8;
+      }
+      if (SpeedPatrol != 0D) {
+        size += 1 + 8;
+      }
+      if (VoyagePatrol != 0D) {
+        size += 1 + 8;
+      }
+      if (TimeAllPatrol != 0D) {
+        size += 1 + 8;
+      }
+      if (FireJoinTime != 0D) {
+        size += 1 + 8;
+      }
+      if (FuelSingle != 0D) {
+        size += 1 + 8;
+      }
+      if (AirportUseSituation.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(AirportUseSituation);
+      }
+      if (NavUseSituation.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(NavUseSituation);
+      }
+      if (FireJoinTimeEconomical != 0D) {
+        size += 2 + 8;
+      }
+      if (FuelSingleEconomical != 0D) {
+        size += 2 + 8;
+      }
+      if (AirportUseSituationEconomical.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(AirportUseSituationEconomical);
+      }
+      if (NavUseSituationEconomical.Length != 0) {
+        size += 2 + pb::CodedOutputStream.ComputeStringSize(NavUseSituationEconomical);
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      rpcId_ = 0;
+      error_ = 0;
+      message_ = "";
+      airportUseSituation_ = "";
+      navUseSituation_ = "";
+      airportUseSituationEconomical_ = "";
+      navUseSituationEconomical_ = "";
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            RpcId = input.ReadInt32();
+            break;
+          }
+          case 16: {
+            Error = input.ReadInt32();
+            break;
+          }
+          case 26: {
+            Message = input.ReadString();
+            break;
+          }
+          case 33: {
+            TaskResponseTime = input.ReadDouble();
+            break;
+          }
+          case 41: {
+            TaskTotalTime = input.ReadDouble();
+            break;
+          }
+          case 49: {
+            SingleJoinTime = input.ReadDouble();
+            break;
+          }
+          case 57: {
+            SingleEffectiveTaskTime = input.ReadDouble();
+            break;
+          }
+          case 65: {
+            SingleAllPeopeo = input.ReadDouble();
+            break;
+          }
+          case 73: {
+            SingleEachPeople = input.ReadDouble();
+            break;
+          }
+          case 81: {
+            SpeedPatrol = input.ReadDouble();
+            break;
+          }
+          case 89: {
+            VoyagePatrol = input.ReadDouble();
+            break;
+          }
+          case 97: {
+            TimeAllPatrol = input.ReadDouble();
+            break;
+          }
+          case 105: {
+            FireJoinTime = input.ReadDouble();
+            break;
+          }
+          case 113: {
+            FuelSingle = input.ReadDouble();
+            break;
+          }
+          case 122: {
+            AirportUseSituation = input.ReadString();
+            break;
+          }
+          case 130: {
+            NavUseSituation = input.ReadString();
+            break;
+          }
+          case 137: {
+            FireJoinTimeEconomical = input.ReadDouble();
+            break;
+          }
+          case 145: {
+            FuelSingleEconomical = input.ReadDouble();
+            break;
+          }
+          case 154: {
+            AirportUseSituationEconomical = input.ReadString();
+            break;
+          }
+          case 162: {
+            NavUseSituationEconomical = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 火焰蔓延输出 
+  /// </summary>
+  public partial class S2C_FireSpread : pb::IMessage {
+    private static readonly pb::MessageParser<S2C_FireSpread> _parser = new pb::MessageParser<S2C_FireSpread>(() => (S2C_FireSpread)MessagePool.Instance.Fetch(typeof(S2C_FireSpread)));
+    public static pb::MessageParser<S2C_FireSpread> Parser { get { return _parser; } }
+
+    private string aircraftId_ = "";
+    public string AircraftId {
+      get { return aircraftId_; }
+      set {
+        aircraftId_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    private int firePointId_;
+    public int FirePointId {
+      get { return firePointId_; }
+      set {
+        firePointId_ = value;
+      }
+    }
+
+    private double fireGrids_;
+    public double FireGrids {
+      get { return fireGrids_; }
+      set {
+        fireGrids_ = value;
+      }
+    }
+
+    private double firedGrids_;
+    public double FiredGrids {
+      get { return firedGrids_; }
+      set {
+        firedGrids_ = value;
+      }
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (AircraftId.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(AircraftId);
+      }
+      if (FirePointId != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(FirePointId);
+      }
+      if (FireGrids != 0D) {
+        output.WriteRawTag(25);
+        output.WriteDouble(FireGrids);
+      }
+      if (FiredGrids != 0D) {
+        output.WriteRawTag(33);
+        output.WriteDouble(FiredGrids);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (AircraftId.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(AircraftId);
+      }
+      if (FirePointId != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(FirePointId);
+      }
+      if (FireGrids != 0D) {
+        size += 1 + 8;
+      }
+      if (FiredGrids != 0D) {
+        size += 1 + 8;
+      }
+      return size;
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      aircraftId_ = "";
+      firePointId_ = 0;
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            AircraftId = input.ReadString();
+            break;
+          }
+          case 16: {
+            FirePointId = input.ReadInt32();
+            break;
+          }
+          case 25: {
+            FireGrids = input.ReadDouble();
+            break;
+          }
+          case 33: {
+            FiredGrids = input.ReadDouble();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code

+ 137 - 0
KYNetwork/Message/OuterOpcode.cs

@@ -0,0 +1,137 @@
+namespace KYFramework.Network
+{
+	[Message(OuterOpcode.C2R_Ping)]
+	public partial class C2R_Ping : IRequest {}
+
+	[Message(OuterOpcode.R2C_Ping)]
+	public partial class R2C_Ping : IResponse {}
+
+	[Message(OuterOpcode.C2S_Test)]
+	public partial class C2S_Test : IRequest {}
+
+	[Message(OuterOpcode.S2C_Test)]
+	public partial class S2C_Test : IResponse {}
+
+	[Message(OuterOpcode.C2S_TestMessage)]
+	public partial class C2S_TestMessage : IMessage {}
+
+	[Message(OuterOpcode.S2C_TestMessage)]
+	public partial class S2C_TestMessage : IMessage {}
+
+	[Message(OuterOpcode.Point)]
+	public partial class Point {}
+
+	[Message(OuterOpcode.Base)]
+	public partial class Base {}
+
+	[Message(OuterOpcode.CityWeather)]
+	public partial class CityWeather {}
+
+	[Message(OuterOpcode.AirRoute)]
+	public partial class AirRoute {}
+
+	[Message(OuterOpcode.NoFlyZoneCircle)]
+	public partial class NoFlyZoneCircle {}
+
+	[Message(OuterOpcode.NoFlyZoneRect)]
+	public partial class NoFlyZoneRect {}
+
+	[Message(OuterOpcode.ClimbSegment)]
+	public partial class ClimbSegment {}
+
+	[Message(OuterOpcode.DescentSegment)]
+	public partial class DescentSegment {}
+
+	[Message(OuterOpcode.CruiseSegment)]
+	public partial class CruiseSegment {}
+
+	[Message(OuterOpcode.TurningSegment)]
+	public partial class TurningSegment {}
+
+	[Message(OuterOpcode.C2S_FlyPlanInput)]
+	public partial class C2S_FlyPlanInput : IMessage {}
+
+	[Message(OuterOpcode.S2C_FlyPlanOutput)]
+	public partial class S2C_FlyPlanOutput : IMessage {}
+
+	[Message(OuterOpcode.PlanTurningPoint)]
+	public partial class PlanTurningPoint {}
+
+	[Message(OuterOpcode.S2C_TurningPointOutput)]
+	public partial class S2C_TurningPointOutput : IMessage {}
+
+	[Message(OuterOpcode.C2S_GetReport)]
+	public partial class C2S_GetReport : IRequest {}
+
+	[Message(OuterOpcode.S2C_GetReport)]
+	public partial class S2C_GetReport : IResponse {}
+
+	[Message(OuterOpcode.ResportWithTaskName)]
+	public partial class ResportWithTaskName {}
+
+	[Message(OuterOpcode.C2S_StmulationStart)]
+	public partial class C2S_StmulationStart : IMessage {}
+
+	[Message(OuterOpcode.C2S_StmulationTimeScale)]
+	public partial class C2S_StmulationTimeScale : IMessage {}
+
+	[Message(OuterOpcode.S2C_StmulationEnd)]
+	public partial class S2C_StmulationEnd : IMessage {}
+
+	[Message(OuterOpcode.EntitySheetReportValue)]
+	public partial class EntitySheetReportValue {}
+
+	[Message(OuterOpcode.SheetReportValue)]
+	public partial class SheetReportValue {}
+
+	[Message(OuterOpcode.ReportValue)]
+	public partial class ReportValue {}
+
+	[Message(OuterOpcode.C2S_SimulationResult)]
+	public partial class C2S_SimulationResult : IRequest {}
+
+	[Message(OuterOpcode.S2C_SimulatinResult)]
+	public partial class S2C_SimulatinResult : IResponse {}
+
+	[Message(OuterOpcode.S2C_FireSpread)]
+	public partial class S2C_FireSpread : IMessage {}
+
+}
+namespace KYFramework.Network
+{
+	public static partial class OuterOpcode
+	{
+		 public const ushort C2R_Ping = 101;
+		 public const ushort R2C_Ping = 102;
+		 public const ushort C2S_Test = 103;
+		 public const ushort S2C_Test = 104;
+		 public const ushort C2S_TestMessage = 105;
+		 public const ushort S2C_TestMessage = 106;
+		 public const ushort Point = 107;
+		 public const ushort Base = 108;
+		 public const ushort CityWeather = 109;
+		 public const ushort AirRoute = 110;
+		 public const ushort NoFlyZoneCircle = 111;
+		 public const ushort NoFlyZoneRect = 112;
+		 public const ushort ClimbSegment = 113;
+		 public const ushort DescentSegment = 114;
+		 public const ushort CruiseSegment = 115;
+		 public const ushort TurningSegment = 116;
+		 public const ushort C2S_FlyPlanInput = 117;
+		 public const ushort S2C_FlyPlanOutput = 118;
+		 public const ushort PlanTurningPoint = 119;
+		 public const ushort S2C_TurningPointOutput = 120;
+		 public const ushort C2S_GetReport = 121;
+		 public const ushort S2C_GetReport = 122;
+		 public const ushort ResportWithTaskName = 123;
+		 public const ushort C2S_StmulationStart = 124;
+		 public const ushort C2S_StmulationTimeScale = 125;
+		 public const ushort S2C_StmulationEnd = 126;
+		 public const ushort EntitySheetReportValue = 127;
+		 public const ushort SheetReportValue = 128;
+		 public const ushort ReportValue = 129;
+		 public const ushort C2S_SimulationResult = 130;
+		 public const ushort S2C_SimulatinResult = 131;
+		 public const ushort S2C_FireSpread = 132;
+	}
+}

+ 42 - 0
KYNetwork/Network/Component/SessionComponent.cs

@@ -0,0 +1,42 @@
+
+using System.ComponentModel;
+
+namespace KYFramework.Network
+{
+    [ObjectSystem]
+    public class SessionComponentAwakeSystem : AwakeSystem<SessionComponent>
+    {
+        public override void Awake(SessionComponent self)
+        {
+            self.Awake();
+
+            Log.Info("会话组件初始化完毕!");
+        }
+    }
+
+    public class SessionComponent : Component
+    {
+        public static SessionComponent Instance;
+
+        public Session Session;
+
+        public void Awake()
+        {
+            Instance = this;
+        }
+
+        public override void Dispose()
+        {
+            if (this.IsDisposed)
+            {
+                return;
+            }
+
+            base.Dispose();
+
+            this.Session?.Dispose();
+            this.Session = null;
+            Instance = null;
+        }
+    }
+}

+ 63 - 0
KYNetwork/Network/Helper/ProcessHelper.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace KYFramework.Network
+{
+    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);
+            }
+        }
+    }
+
+
+}

+ 30 - 0
KYNetwork/Network/Message/AMHandler.cs

@@ -0,0 +1,30 @@
+using System;
+using Cysharp.Threading.Tasks;
+
+namespace KYFramework.Network
+{
+    public abstract class AMHandler<Message> : IMHandler where Message : class
+    {
+        protected abstract UniTask Run(Session session, Message message);
+        public Type GetMessageType()
+        {
+            return typeof(Message);
+        }
+
+        public void Handle(Session session, object msg)
+        {
+            Message message = msg as Message;
+            if (message == null)
+            {
+                Log.Error($"消息类型转换错误: {msg.GetType().Name} to {typeof(Message).Name}");
+                return;
+            }
+            if (session.IsDisposed)
+            {
+                Log.Error($"session disconnect {msg}");
+                return;
+            }
+            this.Run(session, message).Forget();
+        }
+    }
+}

+ 62 - 0
KYNetwork/Network/Message/AMRpcHandler.cs

@@ -0,0 +1,62 @@
+using System;
+using Cysharp.Threading.Tasks;
+
+namespace KYFramework.Network
+{
+	public abstract class AMRpcHandler<Request, Response>: IMHandler where Request : class, IRequest where Response : class, IResponse 
+	{
+		protected abstract UniTask Run(Session session, Request message, Response response, Action reply);
+		
+		public void Handle(Session session, object message)
+		{
+			HandleAsync(session, message).Forget();
+		}
+
+		public Type GetMessageType()
+		{
+			return typeof (Request);
+		}
+
+		public async UniTask HandleAsync(Session session, object message)
+		{
+			try
+			{
+				Request request = message as Request;
+				if (request == null)
+				{
+					Log.Error($"消息类型转换错误: {message.GetType().Name} to {typeof (Request).Name}");
+				}
+
+				int rpcId = request.RpcId;
+
+				long instanceId = session.InstanceId;
+
+				Response response = Activator.CreateInstance<Response>();
+
+				void Reply()
+				{
+					if(session.InstanceId != instanceId)
+						return;
+					response.RpcId = rpcId;
+					session.Reply(response);
+				}
+
+				try
+				{
+					await this.Run(session, request, response, Reply);
+				}
+				catch (Exception exception)
+				{
+					Log.Error(exception);
+					response.Message = exception.ToString();
+					Reply();
+				}
+			}
+			catch (Exception e)
+			{
+				throw new Exception($"解释消息失败: {message.GetType().FullName}", e);
+			}
+		}
+		
+	}
+}

+ 9 - 0
KYNetwork/Network/Message/ClientComponent.cs

@@ -0,0 +1,9 @@
+
+
+namespace KYFramework.Network
+{
+    public class ClientComponent : NetworkComponent
+    {
+        public NetworkProtocol Protocol = NetworkProtocol.TCP;
+    }
+}

+ 43 - 0
KYNetwork/Network/Message/ClientComponentSystem.cs

@@ -0,0 +1,43 @@
+namespace KYFramework.Network
+{
+    [ObjectSystem]
+    public class ClientComponentAwakeSystem : AwakeSystem<ClientComponent>
+    {
+        public override void Awake(ClientComponent self)
+        {
+            self.Awake(self.Protocol);
+            self.MessagePacker = new ProtobufPacker();
+            self.MessageDispatcher = new OuterMessageDispatcher();
+        }
+    }
+
+    [ObjectSystem]
+    public class ClientComponentAwake1System : AwakeSystem<ClientComponent, string>
+    {
+        public override void Awake(ClientComponent self, string address)
+        {
+            self.Awake(self.Protocol, address);
+            self.MessagePacker = new ProtobufPacker();
+            self.MessageDispatcher = new OuterMessageDispatcher();
+        }
+    }
+
+    [ObjectSystem]
+    public class lientComponentLoadSystem : LoadSystem<ClientComponent>
+    {
+        public override void Load(ClientComponent self)
+        {
+            self.MessagePacker = new ProtobufPacker();
+            self.MessageDispatcher = new OuterMessageDispatcher();
+        }
+    }
+
+    [ObjectSystem]
+    public class ClientrComponentUpdateSystem : UpdateSystem<ClientComponent>
+    {
+        public override void Update(ClientComponent self)
+        {
+            self.Update();
+        }
+    }
+}

+ 43 - 0
KYNetwork/Network/Message/ErrorCode.cs

@@ -0,0 +1,43 @@
+namespace KYFramework.Network
+{
+    public static class ErrorCode
+    {
+        public const int ERR_Success = 0;
+
+        // 1-11004 是SocketError请看SocketError定义
+        //-----------------------------------
+        // 100000 以上,避免跟SocketError冲突
+        public const int ERR_MyErrorCode = 100000;
+
+        public const int ERR_PacketParserError = 100005;
+
+       
+        public const int ERR_PeerDisconnect = 102008;
+        public const int ERR_SocketCantSend = 102009;
+        public const int ERR_SocketError = 102010;
+
+        public const int ERR_RpcFail = 102001;
+        //-----------------------------------
+        // 小于这个Rpc会抛异常,大于这个异常的error需要自己判断处理,也就是说需要处理的错误应该要大于该值
+        public const int ERR_Exception = 200000;
+
+        public const int ERR_NotFoundActor = 200002;
+
+        public const int ERR_AccountOrPasswordError = 200102;
+        //-----------------------------------
+        public static bool IsRpcNeedThrowException(int error)
+        {
+            if (error == 0)
+            {
+                return false;
+            }
+
+            if (error > ERR_Exception)
+            {
+                return false;
+            }
+
+            return true;
+        }
+    }
+}

+ 10 - 0
KYNetwork/Network/Message/IMHandler.cs

@@ -0,0 +1,10 @@
+using System;
+
+namespace KYFramework.Network
+{
+    public interface IMHandler
+    {
+        void Handle(Session session, object message);
+        Type GetMessageType();
+    }
+}

+ 25 - 0
KYNetwork/Network/Message/IMessage.cs

@@ -0,0 +1,25 @@
+namespace KYFramework.Network
+{
+    public interface IMessage
+    {
+    }
+
+    public interface IRequest : IMessage
+    {
+        int RpcId { get; set; }
+    }
+
+    public interface IResponse : IMessage
+    {
+        int Error { get; set; }
+        string Message { get; set; }
+        int RpcId { get; set; }
+    }
+
+    public class ResponseMessage : IResponse
+    {
+        public int Error { get; set; }
+        public string Message { get; set; }
+        public int RpcId { get; set; }
+    }
+}

+ 7 - 0
KYNetwork/Network/Message/IMessageDispatcher.cs

@@ -0,0 +1,7 @@
+namespace KYFramework.Network
+{
+    public interface IMessageDispatcher
+    {
+        void Dispatch(Session session, ushort opcode, object message);
+    }
+}

+ 15 - 0
KYNetwork/Network/Message/IMessagePacker.cs

@@ -0,0 +1,15 @@
+using System;
+using System.IO;
+
+namespace KYFramework.Network
+{
+    public interface IMessagePacker
+    {
+        byte[] SerializeTo(object obj);
+        void SerializeTo(object obj, MemoryStream stream);
+        object DeserializeFrom(Type type, byte[] bytes, int index, int count);
+        object DeserializeFrom(object instance, byte[] bytes, int index, int count);
+        object DeserializeFrom(Type type, MemoryStream stream);
+        object DeserializeFrom(object instance, MemoryStream stream);
+    }
+}

+ 12 - 0
KYNetwork/Network/Message/MessageAttribute.cs

@@ -0,0 +1,12 @@
+namespace KYFramework.Network
+{
+    public class MessageAttribute : BaseAttribute
+    {
+        public ushort Opcode { get; }
+
+        public MessageAttribute(ushort opcode)
+        {
+            this.Opcode = opcode;
+        }
+    }
+}

+ 107 - 0
KYNetwork/Network/Message/MessageDispatcherComponent.cs

@@ -0,0 +1,107 @@
+
+namespace KYFramework.Network
+{
+    [ObjectSystem]
+    public class MessageDispatcherComponentAwakeSystem : AwakeSystem<MessageDispatcherComponent>
+    {
+        public override void Awake(MessageDispatcherComponent t)
+        {
+            t.Awake();
+        }
+    }
+
+    [ObjectSystem]
+    public class MessageDispatcherComponentLoadSystem : LoadSystem<MessageDispatcherComponent>
+    {
+        public override void Load(MessageDispatcherComponent self)
+        {
+            self.Load();
+        }
+    }
+    /// <summary>
+    /// 消息分发组件
+    /// </summary>
+    public class MessageDispatcherComponent : Component
+    {
+        private readonly Dictionary<ushort, List<IMHandler>> handlers = new Dictionary<ushort, List<IMHandler>>();
+
+        public void Awake()
+        {
+            this.Load();
+
+            Log.Info("消息分发组件初始化完毕!");
+        }
+
+        public void Load()
+        {
+            this.handlers.Clear();
+
+            List<Type> types = Game.EventSystem.GetTypes(typeof(MessageHandlerAttribute));
+
+            foreach (Type type in types)
+            {
+                object[] attrs = type.GetCustomAttributes(typeof(MessageHandlerAttribute), false);
+                if (attrs.Length == 0)
+                {
+                    continue;
+                }
+
+                IMHandler iMHandler = Activator.CreateInstance(type) as IMHandler;
+                if (iMHandler == null)
+                {
+                    Log.Error($"message handle {type.Name} 需要继承 IMHandler");
+                    continue;
+                }
+                Type messageType = iMHandler.GetMessageType();
+                ushort opcode = this.Entity.GetComponent<OpcodeTypeComponent>().GetOpcode(messageType);
+                if (opcode == 0)
+                {
+                    Log.Error($"消息opcode为0: {messageType.Name}");
+                    continue;
+                }
+                this.RegisterHandler(opcode, iMHandler);
+            }
+        }
+
+        public void RegisterHandler(ushort opcode, IMHandler handler)
+        {
+            if (!this.handlers.ContainsKey(opcode))
+            {
+                this.handlers.Add(opcode, new List<IMHandler>());
+            }
+            this.handlers[opcode].Add(handler);
+        }
+
+        public void Handle(Session session, MessageInfo messageInfo)
+        {
+            List<IMHandler> actions;
+            if (!this.handlers.TryGetValue(messageInfo.Opcode, out actions))
+            {
+                Log.Error($"消息没有处理: {messageInfo.Opcode} {JsonHelper.ToJson(messageInfo.Message)}");
+                return;
+            }
+
+            foreach (IMHandler ev in actions)
+            {
+                try
+                {
+                    ev.Handle(session, messageInfo.Message);
+                }
+                catch (Exception e)
+                {
+                    Log.Error(e);
+                }
+            }
+        }
+
+        public override void Dispose()
+        {
+            if (this.IsDisposed)
+            {
+                return;
+            }
+
+            base.Dispose();
+        }
+    }
+}

+ 16 - 0
KYNetwork/Network/Message/MessageHandlerAttribute.cs

@@ -0,0 +1,16 @@
+namespace KYFramework.Network
+{
+    public class MessageHandlerAttribute : BaseAttribute
+    {
+        //public string File { get; }
+
+        public MessageHandlerAttribute()
+        {
+        }
+
+        // public MessageHandlerAttribute(string appType)
+        // {
+        //     this.File = appType;
+        // }
+    }
+}

+ 14 - 0
KYNetwork/Network/Message/MessageInfo.cs

@@ -0,0 +1,14 @@
+namespace KYFramework.Network
+{
+    public struct MessageInfo
+    {
+        public ushort Opcode { get; }
+        public object Message { get; }
+
+        public MessageInfo(ushort opcode, object message)
+        {
+            this.Opcode = opcode;
+            this.Message = message;
+        }
+    }
+}

+ 53 - 0
KYNetwork/Network/Message/MessagePool.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+
+namespace KYFramework.Network
+{
+    public class MessagePool
+    {
+        public static MessagePool Instance { get; } = new MessagePool();
+
+        private readonly Dictionary<Type, Queue<object>> dictionary = new Dictionary<Type, Queue<object>>();
+
+        public object Fetch(Type type)
+        {
+
+            Queue<object> queue;
+            if (!this.dictionary.TryGetValue(type, out queue))
+            {
+                queue = new Queue<object>();
+                this.dictionary.Add(type, queue);
+            }
+
+            object obj;
+            if (queue.Count > 0)
+            {
+                obj = queue.Dequeue();
+            }
+            else
+            {
+                obj = Activator.CreateInstance(type);
+            }
+
+            return obj;
+        }
+
+        public T Fetch<T>() where T : class
+        {
+            T t = (T)this.Fetch(typeof(T));
+            return t;
+        }
+
+        public void Recycle(object obj)
+        {
+            Type type = obj.GetType();
+            Queue<object> queue;
+            if (!this.dictionary.TryGetValue(type, out queue))
+            {
+                queue = new Queue<object>();
+                this.dictionary.Add(type, queue);
+            }
+            queue.Enqueue(obj);
+        }
+    }
+}

+ 26 - 0
KYNetwork/Network/Message/MessageProxy.cs

@@ -0,0 +1,26 @@
+using System;
+
+namespace KYFramework.Network
+{
+    public class MessageProxy : IMHandler
+    {
+        private readonly Type type;
+        private readonly Action<Session, object> action;
+
+        public MessageProxy(Type type, Action<Session, object> action)
+        {
+            this.type = type;
+            this.action = action;
+        }
+
+        public void Handle(Session session, object message)
+        {
+            this.action.Invoke(session, message);
+        }
+
+        public Type GetMessageType()
+        {
+            return this.type;
+        }
+    }
+}

+ 140 - 0
KYNetwork/Network/Message/NetworkComponent.cs

@@ -0,0 +1,140 @@
+using System.Net;
+
+namespace KYFramework.Network
+{
+    public abstract class NetworkComponent : Component
+    {
+        protected AService Service;
+
+        private readonly Dictionary<long, Session> sessions = new Dictionary<long, Session>();
+
+        public IMessagePacker MessagePacker { get; set; }
+
+        public IMessageDispatcher MessageDispatcher { get; set; }
+
+        public void Awake(NetworkProtocol protocol, int packetSize = Packet.PacketSizeLength2)
+        {
+            switch (protocol)
+            {
+                case NetworkProtocol.KCP:
+                    //this.Service = new KService() { Parent = this };
+                    break;
+                case NetworkProtocol.TCP:
+                    this.Service = new TService(packetSize) { Parent = this };
+                    
+                    break;
+                case NetworkProtocol.WebSocket:
+                    //this.Service = new WService() { Parent = this };
+                    break;
+            }
+        }
+
+        public void Awake(NetworkProtocol protocol, string address, int packetSize = Packet.PacketSizeLength2)
+        {
+            try
+            {
+                IPEndPoint ipEndPoint;
+                switch (protocol)
+                {
+                    case NetworkProtocol.KCP:
+                        ipEndPoint = NetworkHelper.ToIPEndPoint(address);
+                        //this.Service = new KService(ipEndPoint, this.OnAccept) { Parent = this };
+                        break;
+                    case NetworkProtocol.TCP:
+                        ipEndPoint = NetworkHelper.ToIPEndPoint(address);
+                        this.Service = new TService(packetSize, ipEndPoint, this.OnAccept) { Parent = this };
+                        break;
+                    case NetworkProtocol.WebSocket:
+                        string[] prefixs = address.Split(';');
+                        //this.Service = new WService(prefixs, this.OnAccept) { Parent = this };
+                        break;
+                }
+            }
+            catch (Exception e)
+            {
+                throw new Exception($"NetworkComponent Awake Error {address}", e);
+            }
+        }
+
+        public int Count
+        {
+            get { return this.sessions.Count; }
+        }
+
+        public void OnAccept(AChannel channel)
+        {
+            Log.Debug(channel.Id.ToString());
+            Session session = ComponentFactory.CreateWithParent<Session, AChannel>(this, channel);
+            this.sessions.Add(session.Id, session);
+            session.Start();
+        }
+
+        public virtual void Remove(long id)
+        {
+            Session session;
+            if (!this.sessions.TryGetValue(id, out session))
+            {
+                return;
+            }
+            this.sessions.Remove(id);
+            session.Dispose();
+        }
+
+        public Session Get(long id)
+        {
+            Session session;
+            this.sessions.TryGetValue(id, out session);
+            return session;
+        }
+
+        /// <summary>
+        /// 创建一个新Session
+        /// </summary>
+        public Session Create(IPEndPoint ipEndPoint)
+        {
+            AChannel channel = this.Service.ConnectChannel(ipEndPoint);
+            Session session = ComponentFactory.CreateWithParent<Session, AChannel>(this, channel);
+            this.sessions.Add(session.Id, session);
+            session.Start();
+            return session;
+        }
+
+        /// <summary>
+        /// 创建一个新Session
+        /// </summary>
+        public Session Create(string address)
+        {
+            AChannel channel = this.Service.ConnectChannel(address);
+            Session session = ComponentFactory.CreateWithParent<Session, AChannel>(this, channel);
+            this.sessions.Add(session.Id, session);
+            session.Start();
+            return session;
+        }
+
+        public void Update()
+        {
+            if (this.Service == null)
+            {
+                return;
+            }
+            this.Service.Update();
+        }
+
+        public override void Dispose()
+        {
+            if (this.IsDisposed)
+            {
+                return;
+            }
+
+            base.Dispose();
+
+            foreach (Session session in this.sessions.Values.ToArray())
+            {
+                session.Dispose();
+            }
+
+            this.Service.Dispose();
+        }
+    }
+}

+ 9 - 0
KYNetwork/Network/Message/Opcode.cs

@@ -0,0 +1,9 @@
+namespace KYFramework.Network
+{
+    public static partial class Opcode
+    {
+        public const ushort ActorResponse = 1;
+        public const ushort FrameMessage = 2;
+        public const ushort OneFrameMessage = 3;
+    }
+}

+ 21 - 0
KYNetwork/Network/Message/OpcodeHelper.cs

@@ -0,0 +1,21 @@
+
+namespace KYFramework.Network
+{
+    public static class OpcodeHelper
+    {
+        private static readonly HashSet<ushort> ignoreDebugLogMessageSet = new HashSet<ushort>
+        {
+          
+        };
+
+        public static bool IsNeedDebugLogMessage(ushort opcode)
+        {
+            if (ignoreDebugLogMessageSet.Contains(opcode))
+            {
+                return false;
+            }
+
+            return true;
+        }
+    }
+}

+ 83 - 0
KYNetwork/Network/Message/OpcodeTypeComponent.cs

@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+
+namespace KYFramework.Network
+{
+    [ObjectSystem]
+    public class OpcodeTypeComponentSystem : AwakeSystem<OpcodeTypeComponent>
+    {
+        public override void Awake(OpcodeTypeComponent self)
+        {
+            self.Load();
+
+            Log.Info("操作码类型组件初始化完毕!");
+        }
+    }
+
+    [ObjectSystem]
+    public class OpcodeTypeComponentLoadSystem : LoadSystem<OpcodeTypeComponent>
+    {
+        public override void Load(OpcodeTypeComponent self)
+        {
+            self.Load();
+        }
+    }
+
+    public class OpcodeTypeComponent : Component
+    {
+        private readonly DoubleMap<ushort, Type> opcodeTypes = new DoubleMap<ushort, Type>();
+
+        private readonly Dictionary<ushort, object> typeMessages = new Dictionary<ushort, object>();
+
+        public void Load()
+        {
+            this.opcodeTypes.Clear();
+            this.typeMessages.Clear();
+
+            List<Type> types = Game.EventSystem.GetTypes(typeof(MessageAttribute));
+            foreach (Type type in types)
+            {
+                object[] attrs = type.GetCustomAttributes(typeof(MessageAttribute), false);
+                if (attrs.Length == 0)
+                {
+                    continue;
+                }
+
+                MessageAttribute messageAttribute = attrs[0] as MessageAttribute;
+                if (messageAttribute == null)
+                {
+                    continue;
+                }
+
+                this.opcodeTypes.Add(messageAttribute.Opcode, type);
+                this.typeMessages.Add(messageAttribute.Opcode, Activator.CreateInstance(type));
+            }
+        }
+
+        public ushort GetOpcode(Type type)
+        {
+            return this.opcodeTypes.GetKeyByValue(type);
+        }
+
+        public Type GetType(ushort opcode)
+        {
+            return this.opcodeTypes.GetValueByKey(opcode);
+        }
+
+        // 客户端为了0GC需要消息池,服务端消息需要跨协程不需要消息池
+        public object GetInstance(ushort opcode)
+        {
+            return this.typeMessages[opcode];
+        }
+
+        public override void Dispose()
+        {
+            if (this.IsDisposed)
+            {
+                return;
+            }
+
+            base.Dispose();
+        }
+    }
+}

+ 12 - 0
KYNetwork/Network/Message/OuterMessageDispatcher.cs

@@ -0,0 +1,12 @@
+namespace KYFramework.Network
+{
+    public class OuterMessageDispatcher : IMessageDispatcher
+    {
+        public void Dispatch(Session session, ushort opcode, object message)
+        {
+            // 普通消息或者是Rpc请求消息
+            MessageInfo messageInfo = new MessageInfo(opcode, message);
+            Game.Scene.GetComponent<MessageDispatcherComponent>().Handle(session, messageInfo);
+        }
+    }
+}

+ 23 - 0
KYNetwork/Network/Message/RpcException.cs

@@ -0,0 +1,23 @@
+using System;
+
+namespace KYFramework.Network
+{
+    /// <summary>
+	/// RPC异常,带ErrorCode
+	/// </summary>
+	[Serializable]
+    public class RpcException : Exception
+    {
+        public int Error { get; private set; }
+
+        public RpcException(int error, string message) : base($"Error: {error} Message: {message}")
+        {
+            this.Error = error;
+        }
+
+        public RpcException(int error, string message, Exception e) : base($"Error: {error} Message: {message}", e)
+        {
+            this.Error = error;
+        }
+    }
+}

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