Эх сурвалжийг харах

调整服务器ThirdParty工程ETTask和Kcp引用方式,避免客户端修改导致服务器报错

johnclot69 1 жил өмнө
parent
commit
ef5189b440

+ 3 - 12
DotNet/ThirdParty/DotNet.ThirdParty.csproj

@@ -29,18 +29,9 @@
     </PropertyGroup>
 
     <ItemGroup>
-
-    <Compile Include="..\..\Unity\Assets\Scripts\ThirdParty\ETTask\**\*.cs">
-        <Link>ETTask/%(RecursiveDir)%(FileName)%(Extension)</Link>
-    </Compile>
-
-    <Compile Include="..\..\Unity\Assets\Scripts\ThirdParty\Kcp\Kcp.cs">
-      <Link>Kcp\Kcp.cs</Link>
-    </Compile>
-
-    <Compile Include="..\..\Unity\Library\PackageCache\com.unity.mathematics*\Unity.Mathematics\**\*.cs">
-        <Link>Unity.Mathematics/$([System.String]::new(%(RecursiveDir)).Substring($([System.String]::new(%(RecursiveDir)).Indexof("Unity.Mathematics"))).Replace("Unity.Mathematics", ""))/%(FileName)%(Extension)</Link>
-    </Compile>
+        <Compile Include="..\..\Unity\Library\PackageCache\com.unity.mathematics*\Unity.Mathematics\**\*.cs">
+            <Link>Unity.Mathematics/$([System.String]::new(%(RecursiveDir)).Substring($([System.String]::new(%(RecursiveDir)).Indexof("Unity.Mathematics"))).Replace("Unity.Mathematics", ""))/%(FileName)%(Extension)</Link>
+        </Compile>
     </ItemGroup>
 
     <ItemGroup>

+ 63 - 0
DotNet/ThirdParty/ETTask/AsyncETTaskCompletedMethodBuilder.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Security;
+
+namespace ET
+{
+    public struct AsyncETTaskCompletedMethodBuilder
+    {
+        // 1. Static Create method.
+        [DebuggerHidden]
+        public static AsyncETTaskCompletedMethodBuilder Create()
+        {
+            AsyncETTaskCompletedMethodBuilder builder = new AsyncETTaskCompletedMethodBuilder();
+            return builder;
+        }
+
+        // 2. TaskLike Task property(void)
+        public ETTaskCompleted Task => default;
+
+        // 3. SetException
+        [DebuggerHidden]
+        public void SetException(Exception e)
+        {
+            ETTask.ExceptionHandler.Invoke(e);
+        }
+
+        // 4. SetResult
+        [DebuggerHidden]
+        public void SetResult()
+        {
+            // do nothing
+        }
+
+        // 5. AwaitOnCompleted
+        [DebuggerHidden]
+        public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine
+        {
+            awaiter.OnCompleted(stateMachine.MoveNext);
+        }
+
+        // 6. AwaitUnsafeOnCompleted
+        [DebuggerHidden]
+        [SecuritySafeCritical]
+        public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
+        {
+            awaiter.UnsafeOnCompleted(stateMachine.MoveNext);
+        }
+
+        // 7. Start
+        [DebuggerHidden]
+        public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
+        {
+            stateMachine.MoveNext();
+        }
+
+        // 8. SetStateMachine
+        [DebuggerHidden]
+        public void SetStateMachine(IAsyncStateMachine stateMachine)
+        {
+        }
+    }
+}

+ 125 - 0
DotNet/ThirdParty/ETTask/AsyncETTaskMethodBuilder.cs

@@ -0,0 +1,125 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Security;
+
+namespace ET
+{
+    public struct ETAsyncTaskMethodBuilder
+    {
+        private ETTask tcs;
+
+        // 1. Static Create method.
+        [DebuggerHidden]
+        public static ETAsyncTaskMethodBuilder Create()
+        {
+            ETAsyncTaskMethodBuilder builder = new ETAsyncTaskMethodBuilder() { tcs = ETTask.Create(true) };
+            return builder;
+        }
+
+        // 2. TaskLike Task property.
+        [DebuggerHidden]
+        public ETTask Task => this.tcs;
+
+        // 3. SetException
+        [DebuggerHidden]
+        public void SetException(Exception exception)
+        {
+            this.tcs.SetException(exception);
+        }
+
+        // 4. SetResult
+        [DebuggerHidden]
+        public void SetResult()
+        {
+            this.tcs.SetResult();
+        }
+
+        // 5. AwaitOnCompleted
+        [DebuggerHidden]
+        public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine
+        {
+            awaiter.OnCompleted(stateMachine.MoveNext);
+        }
+
+        // 6. AwaitUnsafeOnCompleted
+        [DebuggerHidden]
+        [SecuritySafeCritical]
+        public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
+        {
+            awaiter.OnCompleted(stateMachine.MoveNext);
+        }
+
+        // 7. Start
+        [DebuggerHidden]
+        public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
+        {
+            stateMachine.MoveNext();
+        }
+
+        // 8. SetStateMachine
+        [DebuggerHidden]
+        public void SetStateMachine(IAsyncStateMachine stateMachine)
+        {
+        }
+    }
+
+    public struct ETAsyncTaskMethodBuilder<T>
+    {
+        private ETTask<T> tcs;
+
+        // 1. Static Create method.
+        [DebuggerHidden]
+        public static ETAsyncTaskMethodBuilder<T> Create()
+        {
+            ETAsyncTaskMethodBuilder<T> builder = new ETAsyncTaskMethodBuilder<T>() { tcs = ETTask<T>.Create(true) };
+            return builder;
+        }
+
+        // 2. TaskLike Task property.
+        [DebuggerHidden]
+        public ETTask<T> Task => this.tcs;
+
+        // 3. SetException
+        [DebuggerHidden]
+        public void SetException(Exception exception)
+        {
+            this.tcs.SetException(exception);
+        }
+
+        // 4. SetResult
+        [DebuggerHidden]
+        public void SetResult(T ret)
+        {
+            this.tcs.SetResult(ret);
+        }
+
+        // 5. AwaitOnCompleted
+        [DebuggerHidden]
+        public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine
+        {
+            awaiter.OnCompleted(stateMachine.MoveNext);
+        }
+
+        // 6. AwaitUnsafeOnCompleted
+        [DebuggerHidden]
+        [SecuritySafeCritical]
+        public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
+        {
+            awaiter.OnCompleted(stateMachine.MoveNext);
+        }
+
+        // 7. Start
+        [DebuggerHidden]
+        public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
+        {
+            stateMachine.MoveNext();
+        }
+
+        // 8. SetStateMachine
+        [DebuggerHidden]
+        public void SetStateMachine(IAsyncStateMachine stateMachine)
+        {
+        }
+    }
+}

+ 64 - 0
DotNet/ThirdParty/ETTask/AsyncETVoidMethodBuilder.cs

@@ -0,0 +1,64 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Security;
+
+namespace ET
+{
+    internal struct AsyncETVoidMethodBuilder
+    {
+        // 1. Static Create method.
+        [DebuggerHidden]
+        public static AsyncETVoidMethodBuilder Create()
+        {
+            AsyncETVoidMethodBuilder builder = new AsyncETVoidMethodBuilder();
+            return builder;
+        }
+
+        // 2. TaskLike Task property(void)
+        [DebuggerHidden]
+        public ETVoid Task => default;
+
+        // 3. SetException
+        [DebuggerHidden]
+        public void SetException(Exception e)
+        {
+            ETTask.ExceptionHandler.Invoke(e);
+        }
+
+        // 4. SetResult
+        [DebuggerHidden]
+        public void SetResult()
+        {
+            // do nothing
+        }
+
+        // 5. AwaitOnCompleted
+        [DebuggerHidden]
+        public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine
+        {
+            awaiter.OnCompleted(stateMachine.MoveNext);
+        }
+
+        // 6. AwaitUnsafeOnCompleted
+        [DebuggerHidden]
+        [SecuritySafeCritical]
+        public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
+        {
+            awaiter.UnsafeOnCompleted(stateMachine.MoveNext);
+        }
+
+        // 7. Start
+        [DebuggerHidden]
+        public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
+        {
+            stateMachine.MoveNext();
+        }
+
+        // 8. SetStateMachine
+        [DebuggerHidden]
+        public void SetStateMachine(IAsyncStateMachine stateMachine)
+        {
+        }
+    }
+}

+ 53 - 0
DotNet/ThirdParty/ETTask/ETCancellationToken.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+
+namespace ET
+{
+    public class ETCancellationToken
+    {
+        private HashSet<Action> actions = new HashSet<Action>();
+
+        public void Add(Action callback)
+        {
+            // 如果action是null,绝对不能添加,要抛异常,说明有协程泄漏
+            this.actions.Add(callback);
+        }
+        
+        public void Remove(Action callback)
+        {
+            this.actions?.Remove(callback);
+        }
+
+        public bool IsDispose()
+        {
+            return this.actions == null;
+        }
+
+        public void Cancel()
+        {
+            if (this.actions == null)
+            {
+                return;
+            }
+
+            this.Invoke();
+        }
+
+        private void Invoke()
+        {
+            HashSet<Action> runActions = this.actions;
+            this.actions = null;
+            try
+            {
+                foreach (Action action in runActions)
+                {
+                    action.Invoke();
+                }
+            }
+            catch (Exception e)
+            {
+                ETTask.ExceptionHandler.Invoke(e);
+            }
+        }
+    }
+}

+ 313 - 0
DotNet/ThirdParty/ETTask/ETTask.cs

@@ -0,0 +1,313 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.ExceptionServices;
+
+namespace ET
+{
+    [AsyncMethodBuilder(typeof (ETAsyncTaskMethodBuilder))]
+    public class ETTask: ICriticalNotifyCompletion
+    {
+        public static Action<Exception> ExceptionHandler;
+        
+        public static ETTaskCompleted CompletedTask
+        {
+            get
+            {
+                return new ETTaskCompleted();
+            }
+        }
+
+        private static readonly Queue<ETTask> queue = new Queue<ETTask>();
+
+        /// <summary>
+        /// 请不要随便使用ETTask的对象池,除非你完全搞懂了ETTask!!!
+        /// 假如开启了池,await之后不能再操作ETTask,否则可能操作到再次从池中分配出来的ETTask,产生灾难性的后果
+        /// SetResult的时候请现将tcs置空,避免多次对同一个ETTask SetResult
+        /// </summary>
+        public static ETTask Create(bool fromPool = false)
+        {
+            if (!fromPool)
+            {
+                return new ETTask();
+            }
+            
+            if (queue.Count == 0)
+            {
+                return new ETTask() {fromPool = true};    
+            }
+            return queue.Dequeue();
+        }
+
+        private void Recycle()
+        {
+            if (!this.fromPool)
+            {
+                return;
+            }
+            
+            this.state = AwaiterStatus.Pending;
+            this.callback = null;
+            // 太多了
+            if (queue.Count > 1000)
+            {
+                return;
+            }
+            queue.Enqueue(this);
+        }
+
+        private bool fromPool;
+        private AwaiterStatus state;
+        private object callback; // Action or ExceptionDispatchInfo
+
+        private ETTask()
+        {
+        }
+        
+        [DebuggerHidden]
+        private async ETVoid InnerCoroutine()
+        {
+            await this;
+        }
+
+        [DebuggerHidden]
+        public void Coroutine()
+        {
+            InnerCoroutine().Coroutine();
+        }
+
+        [DebuggerHidden]
+        public ETTask GetAwaiter()
+        {
+            return this;
+        }
+
+        
+        public bool IsCompleted
+        {
+            [DebuggerHidden]
+            get
+            {
+                return this.state != AwaiterStatus.Pending;
+            }
+        }
+
+        [DebuggerHidden]
+        public void UnsafeOnCompleted(Action action)
+        {
+            if (this.state != AwaiterStatus.Pending)
+            {
+                action?.Invoke();
+                return;
+            }
+
+            this.callback = action;
+        }
+
+        [DebuggerHidden]
+        public void OnCompleted(Action action)
+        {
+            this.UnsafeOnCompleted(action);
+        }
+
+        [DebuggerHidden]
+        public void GetResult()
+        {
+            switch (this.state)
+            {
+                case AwaiterStatus.Succeeded:
+                    this.Recycle();
+                    break;
+                case AwaiterStatus.Faulted:
+                    ExceptionDispatchInfo c = this.callback as ExceptionDispatchInfo;
+                    this.callback = null;
+                    this.Recycle();
+                    c?.Throw();
+                    break;
+                default:
+                    throw new NotSupportedException("ETTask does not allow call GetResult directly when task not completed. Please use 'await'.");
+            }
+        }
+
+        [DebuggerHidden]
+        public void SetResult()
+        {
+            if (this.state != AwaiterStatus.Pending)
+            {
+                throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
+            }
+
+            this.state = AwaiterStatus.Succeeded;
+
+            Action c = this.callback as Action;
+            this.callback = null;
+            c?.Invoke();
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [DebuggerHidden]
+        public void SetException(Exception e)
+        {
+            if (this.state != AwaiterStatus.Pending)
+            {
+                throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
+            }
+
+            this.state = AwaiterStatus.Faulted;
+
+            Action c = this.callback as Action;
+            this.callback = ExceptionDispatchInfo.Capture(e);
+            c?.Invoke();
+        }
+    }
+
+    [AsyncMethodBuilder(typeof (ETAsyncTaskMethodBuilder<>))]
+    public class ETTask<T>: ICriticalNotifyCompletion
+    {
+        private static readonly Queue<ETTask<T>> queue = new Queue<ETTask<T>>();
+        
+        /// <summary>
+        /// 请不要随便使用ETTask的对象池,除非你完全搞懂了ETTask!!!
+        /// 假如开启了池,await之后不能再操作ETTask,否则可能操作到再次从池中分配出来的ETTask,产生灾难性的后果
+        /// SetResult的时候请现将tcs置空,避免多次对同一个ETTask SetResult
+        /// </summary>
+        public static ETTask<T> Create(bool fromPool = false)
+        {
+            if (!fromPool)
+            {
+                return new ETTask<T>();
+            }
+            
+            if (queue.Count == 0)
+            {
+                return new ETTask<T>() { fromPool = true };    
+            }
+            return queue.Dequeue();
+        }
+        
+        private void Recycle()
+        {
+            if (!this.fromPool)
+            {
+                return;
+            }
+            this.callback = null;
+            this.value = default;
+            this.state = AwaiterStatus.Pending;
+            // 太多了
+            if (queue.Count > 1000)
+            {
+                return;
+            }
+            queue.Enqueue(this);
+        }
+
+        private bool fromPool;
+        private AwaiterStatus state;
+        private T value;
+        private object callback; // Action or ExceptionDispatchInfo
+
+        private ETTask()
+        {
+        }
+
+        [DebuggerHidden]
+        private async ETVoid InnerCoroutine()
+        {
+            await this;
+        }
+
+        [DebuggerHidden]
+        public void Coroutine()
+        {
+            InnerCoroutine().Coroutine();
+        }
+
+        [DebuggerHidden]
+        public ETTask<T> GetAwaiter()
+        {
+            return this;
+        }
+
+        [DebuggerHidden]
+        public T GetResult()
+        {
+            switch (this.state)
+            {
+                case AwaiterStatus.Succeeded:
+                    T v = this.value;
+                    this.Recycle();
+                    return v;
+                case AwaiterStatus.Faulted:
+                    ExceptionDispatchInfo c = this.callback as ExceptionDispatchInfo;
+                    this.callback = null;
+                    this.Recycle();
+                    c?.Throw();
+                    return default;
+                default:
+                    throw new NotSupportedException("ETask does not allow call GetResult directly when task not completed. Please use 'await'.");
+            }
+        }
+
+
+        public bool IsCompleted
+        {
+            [DebuggerHidden]
+            get
+            {
+                return state != AwaiterStatus.Pending;
+            }
+        } 
+
+        [DebuggerHidden]
+        public void UnsafeOnCompleted(Action action)
+        {
+            if (this.state != AwaiterStatus.Pending)
+            {
+                action?.Invoke();
+                return;
+            }
+
+            this.callback = action;
+        }
+
+        [DebuggerHidden]
+        public void OnCompleted(Action action)
+        {
+            this.UnsafeOnCompleted(action);
+        }
+
+        [DebuggerHidden]
+        public void SetResult(T result)
+        {
+            if (this.state != AwaiterStatus.Pending)
+            {
+                throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
+            }
+
+            this.state = AwaiterStatus.Succeeded;
+
+            this.value = result;
+
+            Action c = this.callback as Action;
+            this.callback = null;
+            c?.Invoke();
+        }
+        
+        [DebuggerHidden]
+        public void SetException(Exception e)
+        {
+            if (this.state != AwaiterStatus.Pending)
+            {
+                throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
+            }
+
+            this.state = AwaiterStatus.Faulted;
+
+            Action c = this.callback as Action;
+            this.callback = ExceptionDispatchInfo.Capture(e);
+            c?.Invoke();
+        }
+    }
+}

+ 34 - 0
DotNet/ThirdParty/ETTask/ETTaskCompleted.cs

@@ -0,0 +1,34 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace ET
+{
+    [AsyncMethodBuilder(typeof (AsyncETTaskCompletedMethodBuilder))]
+    public struct ETTaskCompleted: ICriticalNotifyCompletion
+    {
+        [DebuggerHidden]
+        public ETTaskCompleted GetAwaiter()
+        {
+            return this;
+        }
+
+        [DebuggerHidden]
+        public bool IsCompleted => true;
+
+        [DebuggerHidden]
+        public void GetResult()
+        {
+        }
+
+        [DebuggerHidden]
+        public void OnCompleted(Action continuation)
+        {
+        }
+
+        [DebuggerHidden]
+        public void UnsafeOnCompleted(Action continuation)
+        {
+        }
+    }
+}

+ 126 - 0
DotNet/ThirdParty/ETTask/ETTaskHelper.cs

@@ -0,0 +1,126 @@
+using System;
+using System.Collections.Generic;
+
+namespace ET
+{
+    public static class ETTaskHelper
+    {
+        public static bool IsCancel(this ETCancellationToken self)
+        {
+            if (self == null)
+            {
+                return false;
+            }
+            return self.IsDispose();
+        }
+        
+        private class CoroutineBlocker
+        {
+            private int count;
+
+            private ETTask tcs;
+
+            public CoroutineBlocker(int count)
+            {
+                this.count = count;
+            }
+            
+            public async ETTask RunSubCoroutineAsync(ETTask task)
+            {
+                try
+                {
+                    await task;
+                }
+                finally
+                {
+                    --this.count;
+                
+                    if (this.count <= 0 && this.tcs != null)
+                    {
+                        ETTask t = this.tcs;
+                        this.tcs = null;
+                        t.SetResult();
+                    }
+                }
+            }
+
+            public async ETTask WaitAsync()
+            {
+                if (this.count <= 0)
+                {
+                    return;
+                }
+                this.tcs = ETTask.Create(true);
+                await tcs;
+            }
+        }
+
+        public static async ETTask WaitAny(List<ETTask> tasks)
+        {
+            if (tasks.Count == 0)
+            {
+                return;
+            }
+
+            CoroutineBlocker coroutineBlocker = new CoroutineBlocker(1);
+
+            foreach (ETTask task in tasks)
+            {
+                coroutineBlocker.RunSubCoroutineAsync(task).Coroutine();
+            }
+
+            await coroutineBlocker.WaitAsync();
+        }
+
+        public static async ETTask WaitAny(ETTask[] tasks)
+        {
+            if (tasks.Length == 0)
+            {
+                return;
+            }
+
+            CoroutineBlocker coroutineBlocker = new CoroutineBlocker(1);
+
+            foreach (ETTask task in tasks)
+            {
+                coroutineBlocker.RunSubCoroutineAsync(task).Coroutine();
+            }
+
+            await coroutineBlocker.WaitAsync();
+        }
+
+        public static async ETTask WaitAll(ETTask[] tasks)
+        {
+            if (tasks.Length == 0)
+            {
+                return;
+            }
+
+            CoroutineBlocker coroutineBlocker = new CoroutineBlocker(tasks.Length);
+
+            foreach (ETTask task in tasks)
+            {
+                coroutineBlocker.RunSubCoroutineAsync(task).Coroutine();
+            }
+
+            await coroutineBlocker.WaitAsync();
+        }
+
+        public static async ETTask WaitAll(List<ETTask> tasks)
+        {
+            if (tasks.Count == 0)
+            {
+                return;
+            }
+
+            CoroutineBlocker coroutineBlocker = new CoroutineBlocker(tasks.Count);
+
+            foreach (ETTask task in tasks)
+            {
+                coroutineBlocker.RunSubCoroutineAsync(task).Coroutine();
+            }
+
+            await coroutineBlocker.WaitAsync();
+        }
+    }
+}

+ 28 - 0
DotNet/ThirdParty/ETTask/ETVoid.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace ET
+{
+    [AsyncMethodBuilder(typeof (AsyncETVoidMethodBuilder))]
+    internal struct ETVoid: ICriticalNotifyCompletion
+    {
+        [DebuggerHidden]
+        public void Coroutine()
+        {
+        }
+
+        [DebuggerHidden]
+        public bool IsCompleted => true;
+
+        [DebuggerHidden]
+        public void OnCompleted(Action continuation)
+        {
+        }
+
+        [DebuggerHidden]
+        public void UnsafeOnCompleted(Action continuation)
+        {
+        }
+    }
+}

+ 14 - 0
DotNet/ThirdParty/ETTask/IAwaiter.cs

@@ -0,0 +1,14 @@
+namespace ET
+{
+    public enum AwaiterStatus: byte
+    {
+        /// <summary>The operation has not yet completed.</summary>
+        Pending = 0,
+
+        /// <summary>The operation completed successfully.</summary>
+        Succeeded = 1,
+
+        /// <summary>The operation completed with an error.</summary>
+        Faulted = 2,
+    }
+}

+ 231 - 0
DotNet/ThirdParty/Kcp/Kcp.cs

@@ -0,0 +1,231 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace ET
+{
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+    public delegate int KcpOutput(IntPtr buf, int len, IntPtr kcp, IntPtr user);
+    
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+    public delegate void KcpLog(IntPtr buf, int len, IntPtr kcp, IntPtr user);
+
+    public static class Kcp
+    {
+        public const int OneM = 1024 * 1024;
+        public const int InnerMaxWaitSize = 1024 * 1024;
+        public const int OuterMaxWaitSize = 1024 * 1024;
+        
+        
+        private static KcpOutput KcpOutput;
+        private static KcpLog KcpLog;
+        
+#if UNITY_IPHONE && !UNITY_EDITOR
+        const string KcpDLL = "__Internal";
+#else
+        const string KcpDLL = "kcp";
+#endif
+        
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern uint ikcp_check(IntPtr kcp, uint current);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern IntPtr ikcp_create(uint conv, IntPtr user);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern void ikcp_flush(IntPtr kcp);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern uint ikcp_getconv(IntPtr ptr);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern int ikcp_input(IntPtr kcp, byte[] data, int offset, int size);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern int ikcp_nodelay(IntPtr kcp, int nodelay, int interval, int resend, int nc);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern int ikcp_peeksize(IntPtr kcp);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern int ikcp_recv(IntPtr kcp, byte[] buffer, int index, int len);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern void ikcp_release(IntPtr kcp);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern int ikcp_send(IntPtr kcp, byte[] buffer, int offset, int len);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern void ikcp_setminrto(IntPtr ptr, int minrto);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern int ikcp_setmtu(IntPtr kcp, int mtu);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern void ikcp_setoutput(KcpOutput output);
+        
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern void ikcp_setlog(KcpLog log);
+        
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern void ikcp_update(IntPtr kcp, uint current);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern int ikcp_waitsnd(IntPtr kcp);
+        [DllImport(KcpDLL, CallingConvention=CallingConvention.Cdecl)]
+        private static extern int ikcp_wndsize(IntPtr kcp, int sndwnd, int rcvwnd);
+        
+        public static uint KcpCheck(IntPtr kcp, uint current)
+        {
+            if (kcp == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+            uint ret = ikcp_check(kcp, current);
+            return ret;
+        }
+        
+        public static IntPtr KcpCreate(uint conv, IntPtr user)
+        {
+            return ikcp_create(conv, user);
+        }
+
+        public static void KcpFlush(IntPtr kcp)
+        {
+            if (kcp == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+            ikcp_flush(kcp);
+        }
+
+        public static uint KcpGetconv(IntPtr ptr)
+        {
+            if (ptr == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+            return ikcp_getconv(ptr);
+        }
+
+        public static int KcpInput(IntPtr kcp, byte[] buffer, int offset, int len)
+        {
+            if (kcp == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+            if (offset + len > buffer.Length)
+            {
+                throw new Exception($"kcp error, KcpInput {buffer.Length} {offset} {len}");
+            }
+            int ret = ikcp_input(kcp, buffer, offset, len);
+            return ret;
+        }
+
+        public static int KcpNodelay(IntPtr kcp, int nodelay, int interval, int resend, int nc)
+        {
+            if (kcp == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+            return ikcp_nodelay(kcp, nodelay, interval, resend, nc);
+        }
+
+        public static int KcpPeeksize(IntPtr kcp)
+        {
+            if (kcp == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+            int ret = ikcp_peeksize(kcp);
+            return ret;
+        }
+
+        public static int KcpRecv(IntPtr kcp, byte[] buffer, int index, int len)
+        {
+            if (kcp == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+
+            if (buffer.Length < index + len)
+            {
+                throw new Exception($"kcp error, KcpRecv error: {index} {len}");
+            }
+            
+            int ret = ikcp_recv(kcp, buffer, index, len);
+            return ret;
+        }
+
+        public static void KcpRelease(IntPtr kcp)
+        {
+            if (kcp == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+            ikcp_release(kcp);
+        }
+
+        public static int KcpSend(IntPtr kcp, byte[] buffer, int offset, int len)
+        {
+            if (kcp == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+
+            if (offset + len > buffer.Length)
+            {
+                throw new Exception($"kcp error, KcpSend {buffer.Length} {offset} {len}");
+            }
+            
+            int ret = ikcp_send(kcp, buffer, offset, len);
+            return ret;
+        }
+
+        public static void KcpSetminrto(IntPtr kcp, int minrto)
+        {
+            if (kcp == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+            ikcp_setminrto(kcp, minrto);
+        }
+
+        public static int KcpSetmtu(IntPtr kcp, int mtu)
+        {
+            if (kcp == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+            return ikcp_setmtu(kcp, mtu);
+        }
+
+        public static void KcpSetoutput(KcpOutput output)
+        {
+            KcpOutput = output;
+            ikcp_setoutput(KcpOutput);
+        }
+        
+        public static void KcpSetLog(KcpLog kcpLog)
+        {
+            KcpLog = kcpLog;
+            ikcp_setlog(KcpLog);
+        }
+
+        public static void KcpUpdate(IntPtr kcp, uint current)
+        {
+            if (kcp == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+            ikcp_update(kcp, current);
+        }
+
+        public static int KcpWaitsnd(IntPtr kcp)
+        {
+            if (kcp == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+            int ret = ikcp_waitsnd(kcp);
+            return ret;
+        }
+
+        public static int KcpWndsize(IntPtr kcp, int sndwnd, int rcvwnd)
+        {
+            if (kcp == IntPtr.Zero)
+            {
+                throw new Exception($"kcp error, kcp point is zero");
+            }
+            return ikcp_wndsize(kcp, sndwnd, rcvwnd);
+        }
+    }
+}
+