From 35d2012546383d429072c3f1012779071e7ff9c0 Mon Sep 17 00:00:00 2001 From: ALEXTANG <574809918@qq.com> Date: Sun, 23 Jul 2023 00:25:47 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=9B=BF=E6=8D=A2=E4=BA=86KCP=E4=B8=BAC#?= =?UTF-8?q?=E7=89=88=E6=9C=AC=202.KCP=E5=A2=9E=E5=8A=A0=E4=BA=86Memery?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E3=80=82=20=203.=E6=A1=86=E6=9E=B6=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E4=BA=86=E5=AF=B9Memery=E7=9A=84=E6=94=AF=E6=8C=81?= =?UTF-8?q?,=E6=9C=8D=E5=8A=A1=E5=99=A8=E7=BD=91=E7=BB=9C=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E9=87=87=E7=94=A8Memery=EF=BC=8C=E6=80=A7=E8=83=BD?= =?UTF-8?q?=E5=BE=97=E5=A4=A7=E5=B9=85=E5=BA=A6=E7=9A=84=E6=8F=90=E5=8D=87?= =?UTF-8?q?=204.=E4=BC=98=E5=8C=96=E4=BA=86=E6=B6=88=E6=81=AF=E8=B0=83?= =?UTF-8?q?=E5=BA=A6=E6=89=A7=E8=A1=8C=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.替换了KCP为C#版本 2.KCP增加了Memery支持。 3.框架增加了对Memery的支持,服务器网络消息采用Memery,性能得大幅度的提升 4.优化了消息调度执行逻辑 --- .../Collection/CircularBuffer.cs | 33 +- .../Exporter/Excel/ServerConfigTableManage.cs | 6 +- .../DotNet/Core/Helper/Mongo/MongoHelper.cs | 43 + .../Core/Helper/Proto/ProtoBufHelper.cs | 67 +- .../Core/Network/Base/Interface/ANetwork.cs | 1 + .../Entity/Session/ServerInnerSession.cs | 21 +- .../Scheduler/ANetworkMessageScheduler.cs | 69 +- .../Scheduler/ClientMessageScheduler.cs | 24 +- .../Scheduler/InnerMessageScheduler.cs | 110 +- .../Scheduler/OuterMessageScheduler.cs | 34 +- .../Network/NetworkProtocol/KCP/Base/KCP.cs | 218 --- .../NetworkProtocol/KCP/Base/KCPSettings.cs | 6 +- .../KCP/Base/KcpProtocalType.cs | 14 - .../KCP/Base/KcpProtocalType.cs.meta | 3 - .../NetworkProtocol/KCP/Base/kcp2k.meta} | 2 +- .../NetworkProtocol/KCP/Base/kcp2k/LICENSE | 24 + .../KCP/Base/kcp2k/LICENSE.meta} | 2 +- .../KCP/Base/kcp2k/LICENSE.txt | 24 + .../KCP/Base/kcp2k/LICENSE.txt.meta} | 5 +- .../NetworkProtocol/KCP/Base/kcp2k/README.md | 32 + .../KCP/Base/kcp2k/README.md.meta} | 5 +- .../KCP/Base/kcp2k/VERSION.txt | 234 +++ .../KCP/Base/kcp2k/VERSION.txt.meta | 7 + .../NetworkProtocol/KCP/Base/kcp2k/kcp.meta} | 2 +- .../KCP/Base/kcp2k/kcp/AckItem.cs | 8 + .../kcp/AckItem.cs.meta} | 2 +- .../KCP/Base/kcp2k/kcp/AssemblyInfo.cs | 3 + .../KCP/Base/kcp2k/kcp/AssemblyInfo.cs.meta | 11 + .../NetworkProtocol/KCP/Base/kcp2k/kcp/Kcp.cs | 1267 +++++++++++++++++ .../KCP/Base/kcp2k/kcp/Kcp.cs.meta | 11 + .../KCP/Base/kcp2k/kcp/Pool.cs | 46 + .../KCP/Base/kcp2k/kcp/Pool.cs.meta | 11 + .../KCP/Base/kcp2k/kcp/Segment.cs | 78 + .../KCP/Base/kcp2k/kcp/Segment.cs.meta | 11 + .../KCP/Base/kcp2k/kcp/Utils.cs | 76 + .../KCP/Base/kcp2k/kcp/Utils.cs.meta | 11 + .../KCP/Client/KCPClientNetwork.cs | 136 +- .../KCP/Server/KCPServerNetwork.cs | 70 +- .../KCP/Server/KCPServerNetworkChannel.cs | 77 +- .../Network/PacketParser/InnerPacketParser.cs | 217 ++- .../PacketParser/Interface/APackInfo.cs | 26 +- .../PacketParser/Interface/APacketParser.cs | 11 +- .../Network/PacketParser/OuterPacketParser.cs | 120 +- .../Core/Network/PacketParser/Packet.cs | 6 +- .../KCP/Plugins/Android/arm64_v8a/libkcp.so | Bin 32096 -> 0 bytes .../Plugins/Android/arm64_v8a/libkcp.so.meta | 33 - .../KCP/Plugins/Android/armeabi-v7a/libkcp.so | Bin 68152 -> 0 bytes .../Android/armeabi-v7a/libkcp.so.meta | 33 - .../ThirdParty/KCP/Plugins/Android/x86.meta | 8 - .../KCP/Plugins/Android/x86/libkcp.so | Bin 28708 -> 0 bytes .../KCP/Plugins/Android/x86/libkcp.so.meta | 33 - .../ThirdParty/KCP/Plugins/IOS.meta | 8 - .../ThirdParty/KCP/Plugins/IOS/libkcp.a | Bin 43328 -> 0 bytes .../ThirdParty/KCP/Plugins/IOS/libkcp.a.meta | 33 - .../ThirdParty/KCP/Plugins/MacOS.meta | 8 - .../KCP/Plugins/MacOS/kcp.bundle.meta | 33 - .../Plugins/MacOS/kcp.bundle/Contents.meta | 8 - .../MacOS/kcp.bundle/Contents/MacOS.meta | 8 - .../MacOS/kcp.bundle/Contents/MacOS/kcp | Bin 135808 -> 0 bytes .../ThirdParty/KCP/Plugins/x86_64.meta | 8 - .../ThirdParty/KCP/Plugins/x86_64/kcp.dll | Bin 146432 -> 0 bytes .../KCP/Plugins/x86_64/kcp.dll.meta | 52 - Assets/GameScripts/ThirdParty/Kcp.meta | 8 - DotNet/ThirdParty/KCPLibrary/kcp.dll | Bin 146432 -> 0 bytes DotNet/ThirdParty/KCPLibrary/kcp.dylib | Bin 135808 -> 0 bytes DotNet/ThirdParty/KCPLibrary/kcp.so | Bin 31360 -> 0 bytes DotNet/ThirdParty/ThirdParty.csproj | 15 - 67 files changed, 2447 insertions(+), 1025 deletions(-) delete mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KCP.cs delete mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KcpProtocalType.cs delete mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KcpProtocalType.cs.meta rename Assets/GameScripts/{ThirdParty/KCP/Plugins.meta => DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k.meta} (77%) create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE rename Assets/GameScripts/{ThirdParty/KCP/Plugins/MacOS/kcp.bundle/Contents/MacOS/kcp.meta => DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE.meta} (74%) create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE.txt rename Assets/GameScripts/{ThirdParty/KCP/Plugins/Android.meta => DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE.txt.meta} (57%) create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/README.md rename Assets/GameScripts/{ThirdParty/KCP/Plugins/Android/arm64_v8a.meta => DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/README.md.meta} (57%) create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/VERSION.txt create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/VERSION.txt.meta rename Assets/GameScripts/{ThirdParty/KCP/Plugins/Android/armeabi-v7a.meta => DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp.meta} (77%) create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AckItem.cs rename Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/{KCP.cs.meta => kcp2k/kcp/AckItem.cs.meta} (83%) create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AssemblyInfo.cs create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AssemblyInfo.cs.meta create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Kcp.cs create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Kcp.cs.meta create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Pool.cs create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Pool.cs.meta create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Segment.cs create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Segment.cs.meta create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Utils.cs create mode 100644 Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Utils.cs.meta delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/Android/arm64_v8a/libkcp.so delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/Android/arm64_v8a/libkcp.so.meta delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/Android/armeabi-v7a/libkcp.so delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/Android/armeabi-v7a/libkcp.so.meta delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/Android/x86.meta delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/Android/x86/libkcp.so delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/Android/x86/libkcp.so.meta delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/IOS.meta delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/IOS/libkcp.a delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/IOS/libkcp.a.meta delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/MacOS.meta delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/MacOS/kcp.bundle.meta delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/MacOS/kcp.bundle/Contents.meta delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/MacOS/kcp.bundle/Contents/MacOS.meta delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/MacOS/kcp.bundle/Contents/MacOS/kcp delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/x86_64.meta delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/x86_64/kcp.dll delete mode 100644 Assets/GameScripts/ThirdParty/KCP/Plugins/x86_64/kcp.dll.meta delete mode 100644 Assets/GameScripts/ThirdParty/Kcp.meta delete mode 100644 DotNet/ThirdParty/KCPLibrary/kcp.dll delete mode 100644 DotNet/ThirdParty/KCPLibrary/kcp.dylib delete mode 100644 DotNet/ThirdParty/KCPLibrary/kcp.so diff --git a/Assets/GameScripts/DotNet/Core/DataStructure/Collection/CircularBuffer.cs b/Assets/GameScripts/DotNet/Core/DataStructure/Collection/CircularBuffer.cs index 22c86792..d194f49e 100644 --- a/Assets/GameScripts/DotNet/Core/DataStructure/Collection/CircularBuffer.cs +++ b/Assets/GameScripts/DotNet/Core/DataStructure/Collection/CircularBuffer.cs @@ -96,6 +96,38 @@ namespace TEngine.DataStructure } } + public void Read(Memory memory, int count) + { + if (count > Length) + { + throw new Exception($"bufferList length < count, {Length} {count}"); + } + + var copyCount = 0; + while (copyCount < count) + { + var n = count - copyCount; + var asMemory = First.AsMemory(); + + if (ChunkSize - FirstIndex > n) + { + var slice = asMemory.Slice(FirstIndex, n); + slice.CopyTo(memory.Slice(copyCount, n)); + FirstIndex += n; + copyCount += n; + } + else + { + var length = ChunkSize - FirstIndex; + var slice = asMemory.Slice(FirstIndex, length); + slice.CopyTo(memory.Slice(copyCount, length)); + copyCount += ChunkSize - FirstIndex; + FirstIndex = 0; + RemoveFirst(); + } + } + } + public override int Read(byte[] buffer, int offset, int count) { if (buffer.Length < offset + count) @@ -124,7 +156,6 @@ namespace TEngine.DataStructure } Array.Copy(First, FirstIndex, buffer, copyCount + offset, ChunkSize - FirstIndex); - copyCount += ChunkSize - FirstIndex; FirstIndex = 0; diff --git a/Assets/GameScripts/DotNet/Core/Exporter/Excel/ServerConfigTableManage.cs b/Assets/GameScripts/DotNet/Core/Exporter/Excel/ServerConfigTableManage.cs index 5d020cc9..c8b7c2ea 100644 --- a/Assets/GameScripts/DotNet/Core/Exporter/Excel/ServerConfigTableManage.cs +++ b/Assets/GameScripts/DotNet/Core/Exporter/Excel/ServerConfigTableManage.cs @@ -33,7 +33,9 @@ namespace TEngine.Core { var configFile = GetConfigPath(dataConfig); var bytes = File.ReadAllBytes(configFile); - var data = (AProto) ProtoBufHelper.FromBytes(typeof(T), bytes, 0, bytes.Length); + // var data = (AProto) ProtoBufHelper.FromBytes(typeof(T), bytes, 0, bytes.Length); + // var data = ProtoBufHelper.FromBytes(bytes, 0, bytes.Length); + var data = (T)ProtoBufHelper.FromBytes(typeof(T), bytes, 0, bytes.Length); data.AfterDeserialization(); ConfigDic[dataConfig] = data; return (T)data; @@ -65,7 +67,7 @@ namespace TEngine.Core { var configFile = GetConfigPath(type.Name); var bytes = File.ReadAllBytes(configFile); - var data = (AProto) ProtoBufHelper.FromBytes(type, bytes, 0, bytes.Length); + var data = (AProto)ProtoBufHelper.FromBytes(type, bytes, 0, bytes.Length); data.AfterDeserialization(); ConfigDic[dataConfig] = data; return data; diff --git a/Assets/GameScripts/DotNet/Core/Helper/Mongo/MongoHelper.cs b/Assets/GameScripts/DotNet/Core/Helper/Mongo/MongoHelper.cs index 0a12670e..ed4869c8 100644 --- a/Assets/GameScripts/DotNet/Core/Helper/Mongo/MongoHelper.cs +++ b/Assets/GameScripts/DotNet/Core/Helper/Mongo/MongoHelper.cs @@ -95,11 +95,54 @@ public sealed class MongoHelper : Singleton { return BsonSerializer.Deserialize(str, type); } + + public object Deserialize(Span span, Type type) + { + using var stream = MemoryStreamHelper.GetRecyclableMemoryStream(); + stream.Write(span); + stream.Seek(0, SeekOrigin.Begin); + return BsonSerializer.Deserialize(stream, type); + } + + public object Deserialize(Memory memory, Type type) + { + using var stream = MemoryStreamHelper.GetRecyclableMemoryStream(); + stream.Write(memory.Span); + stream.Seek(0, SeekOrigin.Begin); + return BsonSerializer.Deserialize(stream, type); + } + + public object Deserialize(Span span) + { + using var stream = MemoryStreamHelper.GetRecyclableMemoryStream(); + stream.Write(span); + stream.Seek(0, SeekOrigin.Begin); + return BsonSerializer.Deserialize(stream); + } + + public object Deserialize(Memory memory) + { + using var stream = MemoryStreamHelper.GetRecyclableMemoryStream(); + stream.Seek(0, SeekOrigin.Begin); + return BsonSerializer.Deserialize(stream); + } + public T Deserialize(byte[] bytes) { return BsonSerializer.Deserialize(bytes); } + + public void SerializeTo(T t, Memory memory) + { + using var memoryStream = new MemoryStream(); + using (var writer = new BsonBinaryWriter(memoryStream, BsonBinaryWriterSettings.Defaults)) + { + BsonSerializer.Serialize(writer, typeof(T), t); + } + + memoryStream.GetBuffer().AsMemory().CopyTo(memory); + } public object Deserialize(byte[] bytes, Type type) { diff --git a/Assets/GameScripts/DotNet/Core/Helper/Proto/ProtoBufHelper.cs b/Assets/GameScripts/DotNet/Core/Helper/Proto/ProtoBufHelper.cs index 0941302c..63c0f129 100644 --- a/Assets/GameScripts/DotNet/Core/Helper/Proto/ProtoBufHelper.cs +++ b/Assets/GameScripts/DotNet/Core/Helper/Proto/ProtoBufHelper.cs @@ -1,38 +1,89 @@ using System; +using System.Buffers; using System.IO; +using System.Reflection; using ProtoBuf; -#pragma warning disable CS8604 +using ProtoBuf.Meta; namespace TEngine.Core { public static class ProtoBufHelper { + public static object FromSpan(Type type, Span span) + { +#if TENGINE_UNITY + using var recyclableMemoryStream = MemoryStreamHelper.GetRecyclableMemoryStream(); + recyclableMemoryStream.Write(span); + recyclableMemoryStream.Seek(0, SeekOrigin.Begin); + return Serializer.Deserialize(type, recyclableMemoryStream); +#else + return RuntimeTypeModel.Default.Deserialize(type, span); +#endif + } + + public static object FromMemory(Type type, Memory memory) + { +#if TENGINE_UNITY + using var recyclableMemoryStream = MemoryStreamHelper.GetRecyclableMemoryStream(); + recyclableMemoryStream.Write(memory.Span); + recyclableMemoryStream.Seek(0, SeekOrigin.Begin); + return Serializer.Deserialize(type, recyclableMemoryStream); +#else + return RuntimeTypeModel.Default.Deserialize(type, memory); +#endif + } + public static object FromBytes(Type type, byte[] bytes, int index, int count) { - using var stream = new MemoryStream(bytes, index, count); +#if TENGINE_UNITY + using var stream = MemoryStreamHelper.GetRecyclableMemoryStream(); + stream.Write(bytes, index, count); + stream.Seek(0, SeekOrigin.Begin); return Serializer.Deserialize(type, stream); +#else + var memory = new Memory(bytes, index, count); + return RuntimeTypeModel.Default.Deserialize(type, memory); +#endif } public static T FromBytes(byte[] bytes) { - using var stream = new MemoryStream(bytes, 0, bytes.Length); +#if TENGINE_UNITY + using var stream = MemoryStreamHelper.GetRecyclableMemoryStream(); + stream.Write(bytes, 0, bytes.Length); + stream.Seek(0, SeekOrigin.Begin); return Serializer.Deserialize(stream); - // return FromBytes(bytes, 0, bytes.Length); +#else + return Serializer.Deserialize(new Span(bytes)); +#endif } public static T FromBytes(byte[] bytes, int index, int count) { - using var stream = new MemoryStream(bytes, index, count); +#if TENGINE_UNITY + using var stream = MemoryStreamHelper.GetRecyclableMemoryStream(); + stream.Write(bytes, 0, bytes.Length); + stream.Seek(0, SeekOrigin.Begin); return Serializer.Deserialize(stream); +#else + return Serializer.Deserialize(new Span(bytes, index, count)); +#endif } public static byte[] ToBytes(object message) { - using var stream = new MemoryStream(); + using var stream = MemoryStreamHelper.GetRecyclableMemoryStream(); Serializer.Serialize(stream, message); return stream.ToArray(); } + public static void ToMemory(object message, Memory memory) + { + using var stream = MemoryStreamHelper.GetRecyclableMemoryStream(); + Serializer.Serialize(stream, message); + stream.GetBuffer().AsMemory().CopyTo(memory); + } + public static void ToStream(object message, MemoryStream stream) { Serializer.Serialize(stream, message); @@ -50,8 +101,8 @@ namespace TEngine.Core public static T Clone(T t) { - var bytes = ToBytes(t); - using var stream = new MemoryStream(bytes, 0, bytes.Length); + using var stream = MemoryStreamHelper.GetRecyclableMemoryStream(); + Serializer.Serialize(stream, t); return Serializer.Deserialize(stream); } } diff --git a/Assets/GameScripts/DotNet/Core/Network/Base/Interface/ANetwork.cs b/Assets/GameScripts/DotNet/Core/Network/Base/Interface/ANetwork.cs index 8247cdb9..6dde100d 100644 --- a/Assets/GameScripts/DotNet/Core/Network/Base/Interface/ANetwork.cs +++ b/Assets/GameScripts/DotNet/Core/Network/Base/Interface/ANetwork.cs @@ -1,6 +1,7 @@ using System; using System.IO; using TEngine.Core; +using System.Buffers; // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract #pragma warning disable CS8625 #pragma warning disable CS8618 diff --git a/Assets/GameScripts/DotNet/Core/Network/Entity/Session/ServerInnerSession.cs b/Assets/GameScripts/DotNet/Core/Network/Entity/Session/ServerInnerSession.cs index 7d3d52f4..781d9ad4 100644 --- a/Assets/GameScripts/DotNet/Core/Network/Entity/Session/ServerInnerSession.cs +++ b/Assets/GameScripts/DotNet/Core/Network/Entity/Session/ServerInnerSession.cs @@ -1,5 +1,3 @@ -using TEngine.Core; - #if TENGINE_NET namespace TEngine.Core.Network; @@ -11,14 +9,8 @@ public sealed class ServerInnerSession : Session { return; } - - // 序列化消息到流中 - var memoryStream = MemoryStreamHelper.GetRecyclableMemoryStream(); - InnerPacketParser.Serialize(message, memoryStream); - memoryStream.Seek(0, SeekOrigin.Begin); - // 分发消息 - var packInfo = InnerPackInfo.Create(rpcId, routeId, ((IMessage)message).OpCode(), 0, memoryStream); - NetworkMessageScheduler.Scheduler(this, packInfo).Coroutine(); + + NetworkMessageScheduler.InnerScheduler(this, rpcId, routeId, ((IMessage)message).OpCode(), 0, message).Coroutine(); } public override void Send(IRouteMessage routeMessage, uint rpcId = 0, long routeId = 0) @@ -27,13 +19,8 @@ public sealed class ServerInnerSession : Session { return; } - // 序列化消息到流中 - var memoryStream = MemoryStreamHelper.GetRecyclableMemoryStream(); - InnerPacketParser.Serialize(routeMessage, memoryStream); - memoryStream.Seek(0, SeekOrigin.Begin); - // 分发消息 - var packInfo = InnerPackInfo.Create(rpcId, routeId, routeMessage.OpCode(), routeMessage.RouteTypeOpCode(), memoryStream); - NetworkMessageScheduler.Scheduler(this, packInfo).Coroutine(); + + NetworkMessageScheduler.InnerScheduler(this, rpcId, routeId, routeMessage.OpCode(), routeMessage.RouteTypeOpCode(), routeMessage).Coroutine(); } public override void Send(MemoryStream memoryStream, uint rpcId = 0, long routeTypeOpCode = 0, long routeId = 0) diff --git a/Assets/GameScripts/DotNet/Core/Network/Message/Interface/Scheduler/ANetworkMessageScheduler.cs b/Assets/GameScripts/DotNet/Core/Network/Message/Interface/Scheduler/ANetworkMessageScheduler.cs index 46bccd54..8cd2a056 100644 --- a/Assets/GameScripts/DotNet/Core/Network/Message/Interface/Scheduler/ANetworkMessageScheduler.cs +++ b/Assets/GameScripts/DotNet/Core/Network/Message/Interface/Scheduler/ANetworkMessageScheduler.cs @@ -1,18 +1,17 @@ using System; using System.IO; -using TEngine.Core; -#pragma warning disable CS8600 namespace TEngine.Core.Network { public abstract class ANetworkMessageScheduler { + protected bool DisposePackInfo; private readonly PingResponse _pingResponse = new PingResponse(); public async FTask Scheduler(Session session, APackInfo packInfo) { Type messageType = null; - var packInfoMemoryStream = packInfo.MemoryStream; + DisposePackInfo = true; try { @@ -56,17 +55,6 @@ namespace TEngine.Core.Network // 服务器之间发送消息因为走的是MessageHelper、所以接收消息的回调也应该放到MessageHelper里处理 MessageHelper.ResponseHandler(packInfo.RpcId, aResponse); #else - -#if TENGINE_UNITY - if (MessageDispatcherSystem.Instance.MsgHandles.TryGetValue(packInfo.ProtocolCode,out var msgDelegates)) - { - foreach (var msgDelegate in msgDelegates) - { - msgDelegate.Invoke(aResponse); - } - return; - } -#endif // 这个一般是客户端Session.Call发送时使用的、目前这个逻辑只有Unity客户端时使用 if (!session.RequestCallback.TryGetValue(packInfo.RpcId, out var action)) @@ -84,20 +72,57 @@ namespace TEngine.Core.Network } catch (Exception e) { - if (packInfoMemoryStream.CanRead) - { - // ReSharper disable once MethodHasAsyncOverload - packInfoMemoryStream.Dispose(); - } - Log.Error($"NetworkMessageScheduler error messageProtocolCode:{packInfo.ProtocolCode} messageType:{messageType} SessionId {session.Id} IsDispose {session.IsDisposed} {e}"); } finally { - packInfo.Dispose(); + if (DisposePackInfo) + { + packInfo.Dispose(); + } } } - + + public async FTask InnerScheduler(Session session, uint rpcId, long routeId, uint protocolCode, long routeTypeCode, object message) + { + var messageType = message.GetType(); + + try + { + if (session.IsDisposed) + { + return; + } + + switch (protocolCode) + { + case >= Opcode.OuterRouteMessage: + { + await InnerHandler(session, rpcId, routeId, protocolCode, routeTypeCode, messageType, message); + return; + } + case < Opcode.OuterResponse: + { + MessageDispatcherSystem.Instance.MessageHandler(session, messageType, message, rpcId, protocolCode); + return; + } + default: + { +#if TENGINE_NET + // 服务器之间发送消息因为走的是MessageHelper、所以接收消息的回调也应该放到MessageHelper里处理 + MessageHelper.ResponseHandler(rpcId, (IResponse)message); +#endif + return; + } + } + } + catch (Exception e) + { + Log.Error($"NetworkMessageScheduler error messageProtocolCode:{protocolCode} messageType:{messageType} SessionId {session.Id} IsDispose {session.IsDisposed} {e}"); + } + } + protected abstract FTask Handler(Session session, Type messageType, APackInfo packInfo); + protected abstract FTask InnerHandler(Session session, uint rpcId, long routeId, uint protocolCode, long routeTypeCode, Type messageType, object message); } } \ No newline at end of file diff --git a/Assets/GameScripts/DotNet/Core/Network/Message/Scheduler/ClientMessageScheduler.cs b/Assets/GameScripts/DotNet/Core/Network/Message/Scheduler/ClientMessageScheduler.cs index 0c04cf7d..78d022b7 100644 --- a/Assets/GameScripts/DotNet/Core/Network/Message/Scheduler/ClientMessageScheduler.cs +++ b/Assets/GameScripts/DotNet/Core/Network/Message/Scheduler/ClientMessageScheduler.cs @@ -7,8 +7,6 @@ namespace TEngine.Core.Network { protected override async FTask Handler(Session session, Type messageType, APackInfo packInfo) { - var packInfoMemoryStream = packInfo.MemoryStream; - try { switch (packInfo.ProtocolCode) @@ -28,7 +26,7 @@ namespace TEngine.Core.Network Log.Error($"not found rpc {packInfo.RpcId}, response message: {aResponse.GetType().Name}"); return; } - + session.RequestCallback.Remove(packInfo.RpcId); action.SetResult(aResponse); return; @@ -43,19 +41,22 @@ namespace TEngine.Core.Network } catch (Exception e) { - if (packInfoMemoryStream.CanRead) - { - // ReSharper disable once MethodHasAsyncOverload - packInfoMemoryStream.Dispose(); - } - Log.Error(e); return; } + finally + { + packInfo.Dispose(); + } await FTask.CompletedTask; throw new NotSupportedException($"Received unsupported message protocolCode:{packInfo.ProtocolCode} messageType:{messageType}"); } + + protected override FTask InnerHandler(Session session, uint rpcId, long routeId, uint protocolCode, long routeTypeCode, Type messageType, object message) + { + throw new NotImplementedException(); + } } #endif #if TENGINE_NET @@ -65,6 +66,11 @@ namespace TEngine.Core.Network { throw new NotSupportedException($"Received unsupported message protocolCode:{packInfo.ProtocolCode} messageType:{messageType}"); } + + protected override FTask InnerHandler(Session session, uint rpcId, long routeId, uint protocolCode, long routeTypeCode, Type messageType, object message) + { + throw new NotSupportedException($"Received unsupported message protocolCode:{protocolCode} messageType:{messageType}"); + } } #endif } \ No newline at end of file diff --git a/Assets/GameScripts/DotNet/Core/Network/Message/Scheduler/InnerMessageScheduler.cs b/Assets/GameScripts/DotNet/Core/Network/Message/Scheduler/InnerMessageScheduler.cs index 2e9b2695..1cde77dd 100644 --- a/Assets/GameScripts/DotNet/Core/Network/Message/Scheduler/InnerMessageScheduler.cs +++ b/Assets/GameScripts/DotNet/Core/Network/Message/Scheduler/InnerMessageScheduler.cs @@ -7,11 +7,10 @@ namespace TEngine.Core.Network { protected override async FTask Handler(Session session, Type messageType, APackInfo packInfo) { - var disposeMemoryStream = true; - var packInfoMemoryStream = packInfo.MemoryStream; - try { + DisposePackInfo = false; + switch (packInfo.ProtocolCode) { case >= Opcode.InnerBsonRouteResponse: @@ -80,8 +79,7 @@ namespace TEngine.Core.Network case Session gateSession: { // 这里如果是Session只可能是Gate的Session、如果是的话、肯定是转发Address消息 - disposeMemoryStream = false; - gateSession.Send(packInfoMemoryStream, packInfo.RpcId); + gateSession.Send(packInfo.CreateMemoryStream(), packInfo.RpcId); return; } default: @@ -94,20 +92,108 @@ namespace TEngine.Core.Network } default: { - throw new NotSupportedException($"Received unsupported message protocolCode:{packInfo.ProtocolCode} messageType:{messageType}"); + throw new NotSupportedException( + $"Received unsupported message protocolCode:{packInfo.ProtocolCode} messageType:{messageType}"); } } } catch (Exception e) { - if (disposeMemoryStream && packInfoMemoryStream.CanRead) - { - // ReSharper disable once MethodHasAsyncOverload - packInfoMemoryStream.Dispose(); - } - Log.Error($"InnerMessageSchedulerHandler error messageProtocolCode:{packInfo.ProtocolCode} messageType:{messageType} {e}"); } + finally + { + packInfo.Dispose(); + } + } + + protected override async FTask InnerHandler(Session session, uint rpcId, long routeId, uint protocolCode, long routeTypeCode, Type messageType, object message) + { + try + { + switch (protocolCode) + { + case >= Opcode.InnerBsonRouteResponse: + case >= Opcode.InnerRouteResponse: + { + MessageHelper.ResponseHandler(rpcId, (IRouteResponse)message); + return; + } + case >= Opcode.OuterRouteResponse: + { + // 如果Gate服务器、需要转发Addressable协议、所以这里有可能会接收到该类型协议 + MessageHelper.ResponseHandler(rpcId, (IResponse)message); + return; + } + case > Opcode.InnerBsonRouteMessage: + { + var entity = Entity.GetEntity(routeId); + + if (entity == null) + { + if (protocolCode > Opcode.InnerBsonRouteRequest) + { + MessageDispatcherSystem.Instance.FailResponse(session, (IRouteRequest)message, CoreErrorCode.ErrNotFoundRoute, rpcId); + } + + return; + } + + await MessageDispatcherSystem.Instance.RouteMessageHandler(session, messageType, entity, message, rpcId); + return; + } + case > Opcode.InnerRouteMessage: + { + var entity = Entity.GetEntity(routeId); + + if (entity == null) + { + if (protocolCode > Opcode.InnerRouteRequest) + { + MessageDispatcherSystem.Instance.FailResponse(session, (IRouteRequest)message, CoreErrorCode.ErrNotFoundRoute, rpcId); + } + + return; + } + + await MessageDispatcherSystem.Instance.RouteMessageHandler(session, messageType, entity, message, rpcId); + return; + } + case > Opcode.OuterRouteMessage: + { + var entity = Entity.GetEntity(routeId); + + switch (entity) + { + case null: + { + var response = MessageDispatcherSystem.Instance.CreateResponse((IRouteMessage)message, CoreErrorCode.ErrNotFoundRoute); + session.Send(response, rpcId, routeId); + return; + } + case Session gateSession: + { + // 这里如果是Session只可能是Gate的Session、如果是的话、肯定是转发Address消息 + gateSession.Send(message, rpcId); + return; + } + default: + { + await MessageDispatcherSystem.Instance.RouteMessageHandler(session, messageType, entity, message, rpcId); + return; + } + } + } + default: + { + throw new NotSupportedException($"Received unsupported message protocolCode:{protocolCode} messageType:{messageType}"); + } + } + } + catch (Exception e) + { + Log.Error($"InnerMessageSchedulerHandler error messageProtocolCode:{protocolCode} messageType:{messageType} {e}"); + } } } } diff --git a/Assets/GameScripts/DotNet/Core/Network/Message/Scheduler/OuterMessageScheduler.cs b/Assets/GameScripts/DotNet/Core/Network/Message/Scheduler/OuterMessageScheduler.cs index 78b9d120..76ea1c39 100644 --- a/Assets/GameScripts/DotNet/Core/Network/Message/Scheduler/OuterMessageScheduler.cs +++ b/Assets/GameScripts/DotNet/Core/Network/Message/Scheduler/OuterMessageScheduler.cs @@ -11,6 +11,11 @@ namespace TEngine.Core.Network { throw new NotSupportedException($"Received unsupported message protocolCode:{packInfo.ProtocolCode} messageType:{messageType}"); } + + protected override FTask InnerHandler(Session session, uint rpcId, long routeId, uint protocolCode, long routeTypeCode, Type messageType, object message) + { + throw new NotImplementedException(); + } } #endif #if TENGINE_NET @@ -23,10 +28,10 @@ namespace TEngine.Core.Network throw new NotSupportedException($"Received unsupported message protocolCode:{packInfo.ProtocolCode} messageType:{messageType}"); } - var packInfoMemoryStream = packInfo.MemoryStream; - try { + DisposePackInfo = false; + switch (packInfo.RouteTypeCode) { case CoreRouteType.Route: @@ -49,10 +54,8 @@ namespace TEngine.Core.Network case > Opcode.OuterRouteRequest: { var runtimeId = session.RuntimeId; - var response = await addressableRouteComponent.Call(packInfo.RouteTypeCode, messageType, packInfoMemoryStream); - + var response = await addressableRouteComponent.Call(packInfo.RouteTypeCode, messageType, packInfo.CreateMemoryStream()); // session可能已经断开了,所以这里需要判断 - if (session.RuntimeId == runtimeId) { session.Send(response, packInfo.RpcId); @@ -62,7 +65,7 @@ namespace TEngine.Core.Network } case > Opcode.OuterRouteMessage: { - addressableRouteComponent.Send(packInfo.RouteTypeCode, messageType, packInfoMemoryStream); + addressableRouteComponent.Send(packInfo.RouteTypeCode, messageType, packInfo.CreateMemoryStream()); return; } } @@ -90,7 +93,7 @@ namespace TEngine.Core.Network case > Opcode.OuterRouteRequest: { var runtimeId = session.RuntimeId; - var response = await MessageHelper.CallInnerRoute(session.Scene, routeId, packInfo.RouteTypeCode, messageType, packInfoMemoryStream); + var response = await MessageHelper.CallInnerRoute(session.Scene, routeId, packInfo.RouteTypeCode, messageType, packInfo.CreateMemoryStream()); // session可能已经断开了,所以这里需要判断 if (session.RuntimeId == runtimeId) { @@ -101,7 +104,7 @@ namespace TEngine.Core.Network } case > Opcode.OuterRouteMessage: { - MessageHelper.SendInnerRoute(session.Scene, routeId, packInfo.RouteTypeCode, packInfoMemoryStream); + MessageHelper.SendInnerRoute(session.Scene, routeId, packInfo.RouteTypeCode, packInfo.CreateMemoryStream()); return; } } @@ -112,18 +115,21 @@ namespace TEngine.Core.Network } catch (Exception e) { - if (packInfoMemoryStream.CanRead) - { - // ReSharper disable once MethodHasAsyncOverload - packInfoMemoryStream.Dispose(); - } - Log.Error(e); return; } + finally + { + packInfo.Dispose(); + } throw new NotSupportedException($"Received unsupported message protocolCode:{packInfo.ProtocolCode} messageType:{messageType}"); } + + protected override FTask InnerHandler(Session session, uint rpcId, long routeId, uint protocolCode, long routeTypeCode, Type messageType, object message) + { + throw new NotSupportedException($"OuterMessageScheduler NotSupported InnerHandler"); + } } #endif } \ No newline at end of file diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KCP.cs b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KCP.cs deleted file mode 100644 index 10837be4..00000000 --- a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KCP.cs +++ /dev/null @@ -1,218 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace TEngine.Core.Network -{ - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int KcpOutput(IntPtr buf, int len, IntPtr kcp, IntPtr user); - - public static class KCP - { -#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 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 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(IntPtr kcp, KcpOutput output); - - [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"); - } - - return ikcp_check(kcp, current); - } - - 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[] data, int offset, int size) - { - if (kcp == IntPtr.Zero) - { - throw new Exception($"kcp error, kcp point is zero"); - } - - return ikcp_input(kcp, data, offset, size); - } - - 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"); - } - - return ikcp_peeksize(kcp); - } - - public static int KcpRecv(IntPtr kcp, byte[] buffer, int len) - { - if (kcp == IntPtr.Zero) - { - throw new Exception($"kcp error, kcp point is zero"); - } - - return ikcp_recv(kcp, buffer, len); - } - - 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 len) - { - if (kcp == IntPtr.Zero) - { - throw new Exception($"kcp error, kcp point is zero"); - } - - return ikcp_send(kcp, buffer, len); - } - - 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(IntPtr kcp, KcpOutput output) - { - if (kcp == IntPtr.Zero) - { - throw new Exception($"kcp error, kcp point is zero"); - } - - ikcp_setoutput(kcp, output); - } - - 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"); - } - - return ikcp_waitsnd(kcp); - } - - 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); - } - } -} \ No newline at end of file diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KCPSettings.cs b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KCPSettings.cs index 72bd966b..bc1c70ff 100644 --- a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KCPSettings.cs +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KCPSettings.cs @@ -4,9 +4,9 @@ namespace TEngine.Core.Network { public class KCPSettings { - public int Mtu { get; private set; } - public int SendWindowSize { get; private set; } - public int ReceiveWindowSize { get; private set; } + public uint Mtu { get; private set; } + public uint SendWindowSize { get; private set; } + public uint ReceiveWindowSize { get; private set; } public int MaxSendWindowSize { get; private set; } public static KCPSettings Create(NetworkTarget networkTarget) diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KcpProtocalType.cs b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KcpProtocalType.cs deleted file mode 100644 index e58e56f8..00000000 --- a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KcpProtocalType.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace TEngine -{ - public static class KcpProtocalType - { - public const byte SYN = 1; - public const byte ACK = 2; - public const byte FIN = 3; - public const byte MSG = 4; - public const byte RouterReconnectSYN = 5; - public const byte RouterReconnectACK = 6; - public const byte RouterSYN = 7; - public const byte RouterACK = 8; - } -} \ No newline at end of file diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KcpProtocalType.cs.meta b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KcpProtocalType.cs.meta deleted file mode 100644 index f01e12a0..00000000 --- a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KcpProtocalType.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 9bd29f721d3e458d88d43160fd7cca55 -timeCreated: 1689230822 \ No newline at end of file diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins.meta b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k.meta similarity index 77% rename from Assets/GameScripts/ThirdParty/KCP/Plugins.meta rename to Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k.meta index c9ecbff7..fcca0b6e 100644 --- a/Assets/GameScripts/ThirdParty/KCP/Plugins.meta +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 6ec9cf984eeccbb4ba7470e5beeac5a1 +guid: b6517b73296f4564a8411993d86fcafb folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE new file mode 100644 index 00000000..c77582e8 --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE @@ -0,0 +1,24 @@ +MIT License + +Copyright (c) 2016 limpo1989 +Copyright (c) 2020 Paul Pacheco +Copyright (c) 2020 Lymdun +Copyright (c) 2020 vis2k + +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. \ No newline at end of file diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins/MacOS/kcp.bundle/Contents/MacOS/kcp.meta b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE.meta similarity index 74% rename from Assets/GameScripts/ThirdParty/KCP/Plugins/MacOS/kcp.bundle/Contents/MacOS/kcp.meta rename to Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE.meta index a8c588e4..16bff191 100644 --- a/Assets/GameScripts/ThirdParty/KCP/Plugins/MacOS/kcp.bundle/Contents/MacOS/kcp.meta +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 72dcdf060ecf34d279acdee20e77b200 +guid: 60e959aa2b0fc774fb97f3a52197e41b DefaultImporter: externalObjects: {} userData: diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE.txt b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE.txt new file mode 100644 index 00000000..c77582e8 --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE.txt @@ -0,0 +1,24 @@ +MIT License + +Copyright (c) 2016 limpo1989 +Copyright (c) 2020 Paul Pacheco +Copyright (c) 2020 Lymdun +Copyright (c) 2020 vis2k + +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. \ No newline at end of file diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins/Android.meta b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE.txt.meta similarity index 57% rename from Assets/GameScripts/ThirdParty/KCP/Plugins/Android.meta rename to Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE.txt.meta index e8af9edb..90dee819 100644 --- a/Assets/GameScripts/ThirdParty/KCP/Plugins/Android.meta +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/LICENSE.txt.meta @@ -1,7 +1,6 @@ fileFormatVersion: 2 -guid: 479fdc912cd3148078b6596aa438b98d -folderAsset: yes -DefaultImporter: +guid: e29e0db9c79ad6348aa2997ac1326446 +TextScriptImporter: externalObjects: {} userData: assetBundleName: diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/README.md b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/README.md new file mode 100644 index 00000000..d8d6ba56 --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/README.md @@ -0,0 +1,32 @@ +# kcp2k +C# KCP based on the original C [kcp](https://github.com/skywind3000/kcp). + +Works with **netcore** and **Unity**. + +Developed for [Mirror Networking](https://github.com/MirrorNetworking/Mirror). + +# Features +* Kcp.cs based on kcp.c v1.7, line-by-line translation to C# +* Heavy test coverage +* Fixed [WND_RCV bug](https://github.com/skywind3000/kcp/pull/291) from original kcp +* Optional high level C# code for client/server connection handling +* Optional high level Unreliable channel added + +Pull requests for bug fixes & tests welcome. + +# Unity +kcp2k works perfectly with Unity, see the Mirror repository's KcpTransport. + +# Allocations +The client is allocation free. +The server's SendTo/ReceiveFrom still allocate. + +Previously, [where-allocation](https://github.com/vis2k/where-allocation) for a 25x reduction in server allocations. However: +- It only worked with Unity's old Mono version. +- It didn't work in Unity's IL2CPP builds, which are still faster than Mono + NonAlloc +- It didn't work in regular C# projects. +- Overall, the extra complexity is not worth it. Use IL2CPP instead. +- Microsoft is considering to [remove the allocation](https://github.com/dotnet/runtime/issues/30797#issuecomment-1308599410). + +# Remarks +- **Congestion Control** should be left disabled. It seems to be broken in KCP. diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/arm64_v8a.meta b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/README.md.meta similarity index 57% rename from Assets/GameScripts/ThirdParty/KCP/Plugins/Android/arm64_v8a.meta rename to Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/README.md.meta index 100e24cf..bcff4a42 100644 --- a/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/arm64_v8a.meta +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/README.md.meta @@ -1,7 +1,6 @@ fileFormatVersion: 2 -guid: 8626627ffb7484407ad050b63b7a6676 -folderAsset: yes -DefaultImporter: +guid: 2e2e6b3195633174f85b149e87c9312b +TextScriptImporter: externalObjects: {} userData: assetBundleName: diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/VERSION.txt b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/VERSION.txt new file mode 100644 index 00000000..b92a8aed --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/VERSION.txt @@ -0,0 +1,234 @@ +V1.36 [2023-06-08] +- fix: #49 KcpPeer.RawInput message size check now considers cookie as well +- kcp.cs cleanups + +V1.35 [2023-04-05] +- fix: KcpClients now need to validate with a secure cookie in order to protect against + UDP spoofing. fixes: + https://github.com/MirrorNetworking/Mirror/issues/3286 + [disclosed by IncludeSec] +- KcpClient/Server: change callbacks to protected so inheriting classes can use them too +- KcpClient/Server: change config visibility to protected + +V1.34 [2023-03-15] +- Send/SendTo/Receive/ReceiveFrom NonBlocking extensions. + to encapsulate WouldBlock allocations, exceptions, etc. + allows for reuse when overwriting KcpServer/Client (i.e. for relays). + +V1.33 [2023-03-14] +- perf: KcpServer/Client RawReceive now call socket.Poll to avoid non-blocking + socket's allocating a new SocketException in case they WouldBlock. + fixes https://github.com/MirrorNetworking/Mirror/issues/3413 +- perf: KcpServer/Client RawSend now call socket.Poll to avoid non-blocking + socket's allocating a new SocketException in case they WouldBlock. + fixes https://github.com/MirrorNetworking/Mirror/issues/3413 + +V1.32 [2023-03-12] +- fix: KcpPeer RawInput now doesn't disconnect in case of random internet noise + +V1.31 [2023-03-05] +- KcpClient: Tick/Incoming/Outgoing can now be overwritten (virtual) +- breaking: KcpClient now takes KcpConfig in constructor instead of in Connect. + cleaner, and prepares for KcpConfig.MTU setting. +- KcpConfig now includes MTU; KcpPeer now works with KcpConfig's MTU, KcpServer/Client + buffers are now created with config's MTU. + +V1.30 [2023-02-20] +- fix: set send/recv buffer sizes directly instead of iterating to find the limit. + fixes: https://github.com/MirrorNetworking/Mirror/issues/3390 +- fix: server & client sockets are now always non-blocking to ensure main thread never + blocks on socket.recv/send. Send() now also handles WouldBlock. +- fix: socket.Receive/From directly with non-blocking sockets and handle WouldBlock, + instead of socket.Poll. faster, more obvious, and fixes Poll() looping forever while + socket is in error state. fixes: https://github.com/MirrorNetworking/Mirror/issues/2733 + +V1.29 [2023-01-28] +- fix: KcpServer.CreateServerSocket now handles NotSupportedException when setting DualMode + https://github.com/MirrorNetworking/Mirror/issues/3358 + +V1.28 [2023-01-28] +- fix: KcpClient.Connect now resolves hostname before creating peer + https://github.com/MirrorNetworking/Mirror/issues/3361 + +V1.27 [2023-01-08] +- KcpClient.Connect: invoke own events directly instead of going through peer, + which calls our own events anyway +- fix: KcpPeer/Client/Server callbacks are readonly and assigned in constructor + to ensure they are safe to use at all times. + fixes https://github.com/MirrorNetworking/Mirror/issues/3337 + +V1.26 [2022-12-22] +- KcpPeer.RawInput: fix compile error in old Unity Mono versions +- fix: KcpServer sets up a new connection's OnError immediately. + fixes KcpPeer throwing NullReferenceException when attempting to call OnError + after authentication errors. +- improved log messages + +V1.25 [2022-12-14] +- breaking: removed where-allocation. use IL2CPP on servers instead. +- breaking: KcpConfig to simplify configuration +- high level cleanups + +V1.24 [2022-12-14] +- KcpClient: fixed NullReferenceException when connection without a server. + added test coverage to ensure this never happens again. + +V1.23 [2022-12-07] +- KcpClient: rawReceiveBuffer exposed +- fix: KcpServer RawSend uses connection.remoteEndPoint instead of the helper + 'newClientEP'. fixes clients receiving the wrong messages meant for others. + https://github.com/MirrorNetworking/Mirror/issues/3296 + +V1.22 [2022-11-30] +- high level refactor, part two. + +V1.21 [2022-11-24] +- high level refactor, part one. + - KcpPeer instead of KcpConnection, KcpClientConnection, KcpServerConnection + - RawSend/Receive can now easily be overwritten in KcpClient/Server. + for non-alloc, relays, etc. + +V1.20 [2022-11-22] +- perf: KcpClient receive allocation was removed entirely. + reduces Mirror benchmark client sided allocations from 4.9 KB / 1.7 KB (non-alloc) to 0B. +- fix: KcpConnection.Disconnect does not check socket.Connected anymore. + UDP sockets don't have a connection. + fixes Disconnects not being sent to clients in netcore. +- KcpConnection.SendReliable: added OnError instead of logs + +V1.19 [2022-05-12] +- feature: OnError ErrorCodes + +V1.18 [2022-05-08] +- feature: OnError to allow higher level to show popups etc. +- feature: KcpServer.GetClientAddress is now GetClientEndPoint in order to + expose more details +- ResolveHostname: include exception in log for easier debugging +- fix: KcpClientConnection.RawReceive now logs the SocketException even if + it was expected. makes debugging easier. +- fix: KcpServer.TickIncoming now logs the SocketException even if it was + expected. makes debugging easier. +- fix: KcpClientConnection.RawReceive now calls Disconnect() if the other end + has closed the connection. better than just remaining in a state with unusable + sockets. + +V1.17 [2022-01-09] +- perf: server/client MaximizeSendReceiveBuffersToOSLimit option to set send/recv + buffer sizes to OS limit. avoids drops due to small buffers under heavy load. + +V1.16 [2022-01-06] +- fix: SendUnreliable respects ArraySegment.Offset +- fix: potential bug with negative length (see PR #2) +- breaking: removed pause handling because it's not necessary for Mirror anymore + +V1.15 [2021-12-11] +- feature: feature: MaxRetransmits aka dead_link now configurable +- dead_link disconnect message improved to show exact retransmit count + +V1.14 [2021-11-30] +- fix: Send() now throws an exception for messages which require > 255 fragments +- fix: ReliableMaxMessageSize is now limited to messages which require <= 255 fragments + +V1.13 [2021-11-28] +- fix: perf: uncork max message size from 144 KB to as much as we want based on + receive window size. + fixes https://github.com/vis2k/kcp2k/issues/22 + fixes https://github.com/skywind3000/kcp/pull/291 +- feature: OnData now includes channel it was received on + +V1.12 [2021-07-16] +- Tests: don't depend on Unity anymore +- fix: #26 - Kcp now catches exception if host couldn't be resolved, and calls + OnDisconnected to let the user now. +- fix: KcpServer.DualMode is now configurable in the constructor instead of + using #if UNITY_SWITCH. makes it run on all other non dual mode platforms too. +- fix: where-allocation made optional via virtuals and inheriting + KcpServer/Client/Connection NonAlloc classes. fixes a bug where some platforms + might not support where-allocation. + +V1.11 rollback [2021-06-01] +- perf: Segment MemoryStream initial capacity set to MTU to avoid early runtime + resizing/allocations + +V1.10 [2021-05-28] +- feature: configurable Timeout +- allocations explained with comments (C# ReceiveFrom / IPEndPoint.GetHashCode) +- fix: #17 KcpConnection.ReceiveNextReliable now assigns message default so it + works in .net too +- fix: Segment pool is not static anymore. Each kcp instance now has it's own + Pool. fixes #18 concurrency issues + +V1.9 [2021-03-02] +- Tick() split into TickIncoming()/TickOutgoing() to use in Mirror's new update + functions. allows to minimize latency. + => original Tick() is still supported for convenience. simply processes both! + +V1.8 [2021-02-14] +- fix: Unity IPv6 errors on Nintendo Switch +- fix: KcpConnection now disconnects if data message was received without content. + previously it would call OnData with an empty ArraySegment, causing all kinds of + weird behaviour in Mirror/DOTSNET. Added tests too. +- fix: KcpConnection.SendData: don't allow sending empty messages anymore. disconnect + and log a warning to make it completely obvious. + +V1.7 [2021-01-13] +- fix: unreliable messages reset timeout now too +- perf: KcpConnection OnCheckEnabled callback changed to a simple 'paused' boolean. + This is faster than invoking a Func every time and allows us to fix #8 more + easily later by calling .Pause/.Unpause from OnEnable/OnDisable in MirrorTransport. +- fix #8: Unpause now resets timeout to fix a bug where Mirror would pause kcp, + change the scene which took >10s, then unpause and kcp would detect the lack of + any messages for >10s as timeout. Added test to make sure it never happens again. +- MirrorTransport: statistics logging for headless servers +- Mirror Transport: Send/Receive window size increased once more from 2048 to 4096. + +V1.6 [2021-01-10] +- Unreliable channel added! +- perf: KcpHeader byte added to every kcp message to indicate + Handshake/Data/Ping/Disconnect instead of scanning each message for Hello/Byte/Ping + content via SegmentEquals. It's a lot cleaner, should be faster and should avoid + edge cases where a message content would equal Hello/Ping/Bye sequence accidentally. +- Kcp.Input: offset moved to parameters for cases where it's needed +- Kcp.SetMtu from original Kcp.c + +V1.5 [2021-01-07] +- KcpConnection.MaxSend/ReceiveRate calculation based on the article +- MirrorTransport: large send/recv window size defaults to avoid high latencies caused + by packets not being processed fast enough +- MirrorTransport: show MaxSend/ReceiveRate in debug gui +- MirrorTransport: don't Log.Info to console in headless mode if debug log is disabled + +V1.4 [2020-11-27] +- fix: OnCheckEnabled added. KcpConnection message processing while loop can now + be interrupted immediately. fixes Mirror Transport scene changes which need to stop + processing any messages immediately after a scene message) +- perf: Mirror KcpTransport: FastResend enabled by default. turbo mode according to: + https://github.com/skywind3000/kcp/blob/master/README.en.md#protocol-configuration +- perf: Mirror KcpTransport: CongestionControl disabled by default (turbo mode) + +V1.3 [2020-11-17] +- Log.Info/Warning/Error so logging doesn't depend on UnityEngine anymore +- fix: Server.Tick catches SocketException which happens if Android client is killed +- MirrorTransport: debugLog option added that can be checked in Unity Inspector +- Utils.Clamp so Kcp.cs doesn't depend on UnityEngine +- Utils.SegmentsEqual: use Linq SequenceEqual so it doesn't depend on UnityEngine +=> kcp2k can now be used in any C# project even without Unity + +V1.2 [2020-11-10] +- more tests added +- fix: raw receive buffers are now all of MTU size +- fix: raw receive detects error where buffer was too small for msgLength and + result in excess data being dropped silently +- KcpConnection.MaxMessageSize added for use in high level +- KcpConnection.MaxMessageSize increased from 1200 bytes to to maximum allowed + message size of 145KB for kcp (based on mtu, overhead, wnd_rcv) + +V1.1 [2020-10-30] +- high level cleanup, fixes, improvements + +V1.0 [2020-10-22] +- Kcp.cs now mirrors original Kcp.c behaviour + (this fixes dozens of bugs) + +V0.1 +- initial kcp-csharp based version \ No newline at end of file diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/VERSION.txt.meta b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/VERSION.txt.meta new file mode 100644 index 00000000..e736fdac --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/VERSION.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0d1fd9853ebb3d047acd92fae8441350 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/armeabi-v7a.meta b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp.meta similarity index 77% rename from Assets/GameScripts/ThirdParty/KCP/Plugins/Android/armeabi-v7a.meta rename to Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp.meta index aee16a23..a8cad8ed 100644 --- a/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/armeabi-v7a.meta +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1e40c3d1ddee94950b16c1495dfcd31b +guid: d84ce75a45b625749bb2ee11dadf14e9 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AckItem.cs b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AckItem.cs new file mode 100644 index 00000000..820f4511 --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AckItem.cs @@ -0,0 +1,8 @@ +namespace kcp2k +{ + internal struct AckItem + { + internal uint serialNumber; + internal uint timestamp; + } +} diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KCP.cs.meta b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AckItem.cs.meta similarity index 83% rename from Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KCP.cs.meta rename to Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AckItem.cs.meta index 593d8d6e..7df7cf99 100644 --- a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/KCP.cs.meta +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AckItem.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: eb202d4e9e36ea846861fa8378dd1c23 +guid: cbc45820dcb825444a1e4b3a1bcba94a MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AssemblyInfo.cs b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AssemblyInfo.cs new file mode 100644 index 00000000..5fe5547e --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("kcp2k.Tests")] \ No newline at end of file diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AssemblyInfo.cs.meta b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AssemblyInfo.cs.meta new file mode 100644 index 00000000..6aa2576f --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1731c38e547afe045bd600f9082a0f33 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Kcp.cs b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Kcp.cs new file mode 100644 index 00000000..bddfa980 --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Kcp.cs @@ -0,0 +1,1267 @@ +// Kcp based on https://github.com/skywind3000/kcp +// Kept as close to original as possible. +using System; +using System.Collections.Generic; + +namespace kcp2k +{ + public class Kcp + { + // original Kcp has a define option, which is not defined by default: + // #define FASTACK_CONSERVE + + public const int RTO_NDL = 30; // no delay min rto + public const int RTO_MIN = 100; // normal min rto + public const int RTO_DEF = 200; // default RTO + public const int RTO_MAX = 60000; // maximum RTO + public const int CMD_PUSH = 81; // cmd: push data + public const int CMD_ACK = 82; // cmd: ack + public const int CMD_WASK = 83; // cmd: window probe (ask) + public const int CMD_WINS = 84; // cmd: window size (tell/insert) + public const int ASK_SEND = 1; // need to send CMD_WASK + public const int ASK_TELL = 2; // need to send CMD_WINS + public const int WND_SND = 32; // default send window + public const int WND_RCV = 128; // default receive window. must be >= max fragment size + public const int MTU_DEF = 1200; // default MTU (reduced to 1200 to fit all cases: https://en.wikipedia.org/wiki/Maximum_transmission_unit ; steam uses 1200 too!) + public const int ACK_FAST = 3; + public const int INTERVAL = 100; + public const int OVERHEAD = 24; + public const int FRG_MAX = byte.MaxValue; // kcp encodes 'frg' as byte. so we can only ever send up to 255 fragments. + public const int DEADLINK = 20; // default maximum amount of 'xmit' retransmissions until a segment is considered lost + public const int THRESH_INIT = 2; + public const int THRESH_MIN = 2; + public const int PROBE_INIT = 7000; // 7 secs to probe window size + public const int PROBE_LIMIT = 120000; // up to 120 secs to probe window + public const int FASTACK_LIMIT = 5; // max times to trigger fastack + + // kcp members. + internal int state; + readonly uint conv; // conversation + internal uint mtu; + internal uint mss; // maximum segment size := MTU - OVERHEAD + internal uint snd_una; // unacknowledged. e.g. snd_una is 9 it means 8 has been confirmed, 9 and 10 have been sent + internal uint snd_nxt; // forever growing send counter for sequence numbers + internal uint rcv_nxt; // forever growing receive counter for sequence numbers + internal uint ssthresh; // slow start threshold + internal int rx_rttval; // average deviation of rtt, used to measure the jitter of rtt + internal int rx_srtt; // smoothed round trip time (a weighted average of rtt) + internal int rx_rto; + internal int rx_minrto; + internal uint snd_wnd; // send window + internal uint rcv_wnd; // receive window + internal uint rmt_wnd; // remote window + internal uint cwnd; // congestion window + internal uint probe; + internal uint interval; + internal uint ts_flush; // last flush timestamp in milliseconds + internal uint xmit; + internal uint nodelay; // not a bool. original Kcp has '<2 else' check. + internal bool updated; + internal uint ts_probe; // probe timestamp + internal uint probe_wait; + internal uint dead_link; // maximum amount of 'xmit' retransmissions until a segment is considered lost + internal uint incr; + internal uint current; // current time (milliseconds). set by Update. + + internal int fastresend; + internal int fastlimit; + internal bool nocwnd; // congestion control, negated. heavily restricts send/recv window sizes. + internal readonly Queue snd_queue = new Queue(16); // send queue + internal readonly Queue rcv_queue = new Queue(16); // receive queue + // snd_buffer needs index removals. + // C# LinkedList allocates for each entry, so let's keep List for now. + internal readonly List snd_buf = new List(16); // send buffer + // rcv_buffer needs index insertions and backwards iteration. + // C# LinkedList allocates for each entry, so let's keep List for now. + internal readonly List rcv_buf = new List(16); // receive buffer + internal readonly List acklist = new List(16); + + // memory buffer + // size depends on MTU. + // MTU can be changed at runtime, which resizes the buffer. + internal byte[] buffer; + + // output function of type + readonly Action output; + + // segment pool to avoid allocations in C#. + // this is not part of the original C code. + readonly Pool SegmentPool = new Pool( + // create new segment + () => new Segment(), + // reset segment before reuse + (segment) => segment.Reset(), + // initial capacity + 32 + ); + + // ikcp_create + // create a new kcp control object, 'conv' must equal in two endpoint + // from the same connection. + public Kcp(uint conv, Action output) + { + this.conv = conv; + this.output = output; + snd_wnd = WND_SND; + rcv_wnd = WND_RCV; + rmt_wnd = WND_RCV; + mtu = MTU_DEF; + mss = mtu - OVERHEAD; + rx_rto = RTO_DEF; + rx_minrto = RTO_MIN; + interval = INTERVAL; + ts_flush = INTERVAL; + ssthresh = THRESH_INIT; + fastlimit = FASTACK_LIMIT; + dead_link = DEADLINK; + buffer = new byte[(mtu + OVERHEAD) * 3]; + } + + // ikcp_segment_new + // we keep the original function and add our pooling to it. + // this way we'll never miss it anywhere. + Segment SegmentNew() => SegmentPool.Take(); + + // ikcp_segment_delete + // we keep the original function and add our pooling to it. + // this way we'll never miss it anywhere. + void SegmentDelete(Segment seg) => SegmentPool.Return(seg); + + // calculate how many packets are waiting to be sent + public int WaitSnd => snd_buf.Count + snd_queue.Count; + + // ikcp_wnd_unused + // returns the remaining space in receive window (rcv_wnd - rcv_queue) + internal uint WndUnused() + { + if (rcv_queue.Count < rcv_wnd) + return rcv_wnd - (uint)rcv_queue.Count; + return 0; + } + + public int Receive(Memory memory, int len) + { + // kcp's ispeek feature is not supported. + // this makes 'merge fragment' code significantly easier because + // we can iterate while queue.Count > 0 and dequeue each time. + // if we had to consider ispeek then count would always be > 0 and + // we would have to remove only after the loop. + // + //bool ispeek = len < 0; + if (len < 0) + throw new NotSupportedException("Receive ispeek for negative len is not supported!"); + + if (rcv_queue.Count == 0) + return -1; + + if (len < 0) len = -len; + + int peeksize = PeekSize(); + + if (peeksize < 0) + return -2; + + if (peeksize > len) + return -3; + + bool recover = rcv_queue.Count >= rcv_wnd; + + // merge fragment. + int offset = 0; + len = 0; + // original KCP iterates rcv_queue and deletes if !ispeek. + // removing from a c# queue while iterating is not possible, but + // we can change to 'while Count > 0' and remove every time. + // (we can remove every time because we removed ispeek support!) + while (rcv_queue.Count > 0) + { + // unlike original kcp, we dequeue instead of just getting the + // entry. this is fine because we remove it in ANY case. + Segment seg = rcv_queue.Dequeue(); + // copy segment data into our buffer + var asMemory = seg.data.GetBuffer().AsMemory(); + var slice = asMemory.Slice(0, (int)seg.data.Position); + var offsetMemory = memory.Slice(offset); + slice.CopyTo(offsetMemory); + offset += (int)seg.data.Position; + len += (int)seg.data.Position; + uint fragment = seg.frg; + + // note: ispeek is not supported in order to simplify this loop + + // unlike original kcp, we don't need to remove seg from queue + // because we already dequeued it. + // simply delete it + SegmentDelete(seg); + + if (fragment == 0) + break; + } + + // move available data from rcv_buf -> rcv_queue + int removed = 0; + foreach (Segment seg in rcv_buf) + { + if (seg.sn == rcv_nxt && rcv_queue.Count < rcv_wnd) + { + // can't remove while iterating. remember how many to remove + // and do it after the loop. + // note: don't return segment. we only add it to rcv_queue + ++removed; + // add + rcv_queue.Enqueue(seg); + // increase sequence number for next segment + rcv_nxt++; + } + else + { + break; + } + } + + rcv_buf.RemoveRange(0, removed); + + // fast recover + if (rcv_queue.Count < rcv_wnd && recover) + { + // ready to send back CMD_WINS in flush + // tell remote my window size + probe |= ASK_TELL; + } + + return len; + } + + // ikcp_recv + // receive data from kcp state machine + // returns number of bytes read. + // returns negative on error. + // note: pass negative length to peek. + public int Receive(byte[] buffer, int len) + { + // kcp's ispeek feature is not supported. + // this makes 'merge fragment' code significantly easier because + // we can iterate while queue.Count > 0 and dequeue each time. + // if we had to consider ispeek then count would always be > 0 and + // we would have to remove only after the loop. + // + //bool ispeek = len < 0; + if (len < 0) + throw new NotSupportedException("Receive ispeek for negative len is not supported!"); + + if (rcv_queue.Count == 0) + return -1; + + if (len < 0) len = -len; + + int peeksize = PeekSize(); + + if (peeksize < 0) + return -2; + + if (peeksize > len) + return -3; + + bool recover = rcv_queue.Count >= rcv_wnd; + + // merge fragment. + int offset = 0; + len = 0; + // original KCP iterates rcv_queue and deletes if !ispeek. + // removing from a c# queue while iterating is not possible, but + // we can change to 'while Count > 0' and remove every time. + // (we can remove every time because we removed ispeek support!) + while (rcv_queue.Count > 0) + { + // unlike original kcp, we dequeue instead of just getting the + // entry. this is fine because we remove it in ANY case. + Segment seg = rcv_queue.Dequeue(); + + // copy segment data into our buffer + Buffer.BlockCopy(seg.data.GetBuffer(), 0, buffer, offset, (int)seg.data.Position); + offset += (int)seg.data.Position; + + len += (int)seg.data.Position; + uint fragment = seg.frg; + + // note: ispeek is not supported in order to simplify this loop + + // unlike original kcp, we don't need to remove seg from queue + // because we already dequeued it. + // simply delete it + SegmentDelete(seg); + + if (fragment == 0) + break; + } + + // move available data from rcv_buf -> rcv_queue + int removed = 0; + foreach (Segment seg in rcv_buf) + { + if (seg.sn == rcv_nxt && rcv_queue.Count < rcv_wnd) + { + // can't remove while iterating. remember how many to remove + // and do it after the loop. + // note: don't return segment. we only add it to rcv_queue + ++removed; + // add + rcv_queue.Enqueue(seg); + // increase sequence number for next segment + rcv_nxt++; + } + else + { + break; + } + } + rcv_buf.RemoveRange(0, removed); + + // fast recover + if (rcv_queue.Count < rcv_wnd && recover) + { + // ready to send back CMD_WINS in flush + // tell remote my window size + probe |= ASK_TELL; + } + + return len; + } + + // ikcp_peeksize + // check the size of next message in the recv queue. + // returns -1 if there is no message, or if the message is still incomplete. + public int PeekSize() + { + int length = 0; + + // empty queue? + if (rcv_queue.Count == 0) return -1; + + // peek the first segment + Segment seq = rcv_queue.Peek(); + + // seg.frg is 0 if the message requires no fragmentation. + // in that case, the segment's size is the final message size. + if (seq.frg == 0) return (int)seq.data.Position; + + // check if all fragment parts were received yet. + // seg.frg is the n-th fragment, but in reverse. + // this way the first received segment tells us how many fragments there are for the message. + // for example, if a message contains 3 segments: + // first segment: .frg is 2 (index in reverse) + // second segment: .frg is 1 (index in reverse) + // third segment: .frg is 0 (index in reverse) + if (rcv_queue.Count < seq.frg + 1) return -1; + + // recv_queue contains all the fragments necessary to reconstruct the message. + // sum all fragment's sizes to get the full message size. + foreach (Segment seg in rcv_queue) + { + length += (int)seg.data.Position; + if (seg.frg == 0) break; + } + + return length; + } + + public int Send(Memory memory) + { + // fragment count + int count; + var len = memory.Length; + if (len < 0) return -1; + + // streaming mode: removed. we never want to send 'hello' and + // receive 'he' 'll' 'o'. we want to always receive 'hello'. + + // calculate amount of fragments necessary for 'len' + if (len <= mss) count = 1; + else count = (int)((len + mss - 1) / mss); + + // IMPORTANT kcp encodes 'frg' as 1 byte. + // so we can only support up to 255 fragments. + // (which limits max message size to around 288 KB) + // this is difficult to debug. let's make this 100% obvious. + if (count > FRG_MAX) + throw new Exception($"Send len={len} requires {count} fragments, but kcp can only handle up to {FRG_MAX} fragments."); + + // original kcp uses WND_RCV const instead of rcv_wnd runtime: + // https://github.com/skywind3000/kcp/pull/291/files + // which always limits max message size to 144 KB: + //if (count >= WND_RCV) return -2; + // using configured rcv_wnd uncorks max message size to 'any': + if (count >= rcv_wnd) return -2; + + if (count == 0) count = 1; + + // fragment + var offset = 0; + for (int i = 0; i < count; i++) + { + int size = len > (int)mss ? (int)mss : len; + Segment seg = SegmentNew(); + + if (len > 0) + { + var slice = memory.Span.Slice(offset, size); + seg.data.Write(slice); + } + // seg.len = size: WriteBytes sets segment.Position! + + // set fragment number. + // if the message requires no fragmentation, then + // seg.frg becomes 1-0-1 = 0 + seg.frg = (uint)(count - i - 1); + snd_queue.Enqueue(seg); + offset += size; + len -= size; + } + + return 0; + } + + // ikcp_send + // splits message into MTU sized fragments, adds them to snd_queue. + public int Send(byte[] buffer, int offset, int len) + { + // fragment count + int count; + + if (len < 0) return -1; + + // streaming mode: removed. we never want to send 'hello' and + // receive 'he' 'll' 'o'. we want to always receive 'hello'. + + // calculate amount of fragments necessary for 'len' + if (len <= mss) count = 1; + else count = (int)((len + mss - 1) / mss); + + // IMPORTANT kcp encodes 'frg' as 1 byte. + // so we can only support up to 255 fragments. + // (which limits max message size to around 288 KB) + // this is difficult to debug. let's make this 100% obvious. + if (count > FRG_MAX) + throw new Exception($"Send len={len} requires {count} fragments, but kcp can only handle up to {FRG_MAX} fragments."); + + // original kcp uses WND_RCV const instead of rcv_wnd runtime: + // https://github.com/skywind3000/kcp/pull/291/files + // which always limits max message size to 144 KB: + //if (count >= WND_RCV) return -2; + // using configured rcv_wnd uncorks max message size to 'any': + if (count >= rcv_wnd) return -2; + + if (count == 0) count = 1; + + // fragment + for (int i = 0; i < count; i++) + { + int size = len > (int)mss ? (int)mss : len; + Segment seg = SegmentNew(); + + if (len > 0) + { + seg.data.Write(buffer, offset, size); + } + // seg.len = size: WriteBytes sets segment.Position! + + // set fragment number. + // if the message requires no fragmentation, then + // seg.frg becomes 1-0-1 = 0 + seg.frg = (uint)(count - i - 1); + snd_queue.Enqueue(seg); + offset += size; + len -= size; + } + + return 0; + } + + // ikcp_update_ack + void UpdateAck(int rtt) // round trip time + { + // https://tools.ietf.org/html/rfc6298 + if (rx_srtt == 0) + { + rx_srtt = rtt; + rx_rttval = rtt / 2; + } + else + { + int delta = rtt - rx_srtt; + if (delta < 0) delta = -delta; + rx_rttval = (3 * rx_rttval + delta) / 4; + rx_srtt = (7 * rx_srtt + rtt) / 8; + if (rx_srtt < 1) rx_srtt = 1; + } + int rto = rx_srtt + Math.Max((int)interval, 4 * rx_rttval); + rx_rto = Utils.Clamp(rto, rx_minrto, RTO_MAX); + } + + // ikcp_shrink_buf + internal void ShrinkBuf() + { + if (snd_buf.Count > 0) + { + Segment seg = snd_buf[0]; + snd_una = seg.sn; + } + else + { + snd_una = snd_nxt; + } + } + + // ikcp_parse_ack + // removes the segment with 'sn' from send buffer + internal void ParseAck(uint sn) + { + if (Utils.TimeDiff(sn, snd_una) < 0 || Utils.TimeDiff(sn, snd_nxt) >= 0) + return; + + // for-int so we can erase while iterating + for (int i = 0; i < snd_buf.Count; ++i) + { + // is this the segment? + Segment seg = snd_buf[i]; + if (sn == seg.sn) + { + // remove and return + snd_buf.RemoveAt(i); + SegmentDelete(seg); + break; + } + if (Utils.TimeDiff(sn, seg.sn) < 0) + { + break; + } + } + } + + // ikcp_parse_una + // removes all unacknowledged segments with sequence numbers < una from send buffer + internal void ParseUna(uint una) + { + int removed = 0; + foreach (Segment seg in snd_buf) + { + // if (Utils.TimeDiff(una, seg.sn) > 0) + if (seg.sn < una) + { + // can't remove while iterating. remember how many to remove + // and do it after the loop. + ++removed; + SegmentDelete(seg); + } + else + { + break; + } + } + snd_buf.RemoveRange(0, removed); + } + + // ikcp_parse_fastack + internal void ParseFastack(uint sn, uint ts) // serial number, timestamp + { + // sn needs to be between snd_una and snd_nxt + // if !(snd_una <= sn && sn < snd_nxt) return; + + // if (Utils.TimeDiff(sn, snd_una) < 0) + if (sn < snd_una) + return; + + // if (Utils.TimeDiff(sn, snd_nxt) >= 0) + if (sn >= snd_nxt) + return; + + foreach (Segment seg in snd_buf) + { + // if (Utils.TimeDiff(sn, seg.sn) < 0) + if (sn < seg.sn) + { + break; + } + else if (sn != seg.sn) + { +#if !FASTACK_CONSERVE + seg.fastack++; +#else + if (Utils.TimeDiff(ts, seg.ts) >= 0) + seg.fastack++; +#endif + } + } + } + + // ikcp_ack_push + // appends an ack. + void AckPush(uint sn, uint ts) // serial number, timestamp + { + acklist.Add(new AckItem{ serialNumber = sn, timestamp = ts }); + } + + // ikcp_parse_data + void ParseData(Segment newseg) + { + uint sn = newseg.sn; + + if (Utils.TimeDiff(sn, rcv_nxt + rcv_wnd) >= 0 || + Utils.TimeDiff(sn, rcv_nxt) < 0) + { + SegmentDelete(newseg); + return; + } + + InsertSegmentInReceiveBuffer(newseg); + MoveReceiveBufferReadySegmentsToQueue(); + } + + // inserts the segment into rcv_buf, ordered by seg.sn. + // drops the segment if one with the same seg.sn already exists. + // goes through receive buffer in reverse order for performance. + // + // note: see KcpTests.InsertSegmentInReceiveBuffer test! + // note: 'insert or delete' can be done in different ways, but let's + // keep consistency with original C kcp. + internal void InsertSegmentInReceiveBuffer(Segment newseg) + { + bool repeat = false; // 'duplicate' + + // original C iterates backwards, so we need to do that as well. + // note if rcv_buf.Count == 0, i becomes -1 and no looping happens. + int i; + for (i = rcv_buf.Count - 1; i >= 0; i--) + { + Segment seg = rcv_buf[i]; + if (seg.sn == newseg.sn) + { + // duplicate segment found. nothing will be added. + repeat = true; + break; + } + if (Utils.TimeDiff(newseg.sn, seg.sn) > 0) + { + // this entry's sn is < newseg.sn, so let's stop + break; + } + } + + // no duplicate? then insert. + if (!repeat) + { + rcv_buf.Insert(i + 1, newseg); + } + // duplicate. just delete it. + else + { + SegmentDelete(newseg); + } + } + + // move ready segments from rcv_buf -> rcv_queue. + // moves only the ready segments which are in rcv_nxt sequence order. + // some may still be missing an inserted later. + void MoveReceiveBufferReadySegmentsToQueue() + { + int removed = 0; + foreach (Segment seg in rcv_buf) + { + // move segments while they are in 'rcv_nxt' sequence order. + // some may still be missing and inserted later, in this case it stops immediately + // because segments always need to be received in the exact sequence order. + if (seg.sn == rcv_nxt && rcv_queue.Count < rcv_wnd) + { + // can't remove while iterating. remember how many to remove + // and do it after the loop. + ++removed; + rcv_queue.Enqueue(seg); + // increase sequence number for next segment + rcv_nxt++; + } + else + { + break; + } + } + rcv_buf.RemoveRange(0, removed); + } + + // ikcp_input + // used when you receive a low level packet (e.g. UDP packet) + // => original kcp uses offset=0, we made it a parameter so that high + // level can skip the channel byte more easily + public int Input(byte[] data, int offset, int size) + { + uint prev_una = snd_una; + uint maxack = 0; + uint latest_ts = 0; + int flag = 0; + + if (data == null || size < OVERHEAD) return -1; + + while (true) + { + // enough data left to decode segment (aka OVERHEAD bytes)? + if (size < OVERHEAD) break; + + // decode segment + offset += Utils.Decode32U(data, offset, out uint conv_); + if (conv_ != conv) return -1; + + offset += Utils.Decode8u(data, offset, out byte cmd); + // IMPORTANT kcp encodes 'frg' as 1 byte. + // so we can only support up to 255 fragments. + // (which limits max message size to around 288 KB) + offset += Utils.Decode8u(data, offset, out byte frg); + offset += Utils.Decode16U(data, offset, out ushort wnd); + offset += Utils.Decode32U(data, offset, out uint ts); + offset += Utils.Decode32U(data, offset, out uint sn); + offset += Utils.Decode32U(data, offset, out uint una); + offset += Utils.Decode32U(data, offset, out uint len); + + // reduce remaining size by what was read + size -= OVERHEAD; + + // enough remaining to read 'len' bytes of the actual payload? + // note: original kcp casts uint len to int for <0 check. + if (size < len || (int)len < 0) return -2; + + // validate command type + if (cmd != CMD_PUSH && cmd != CMD_ACK && + cmd != CMD_WASK && cmd != CMD_WINS) + return -3; + + rmt_wnd = wnd; + ParseUna(una); + ShrinkBuf(); + + if (cmd == CMD_ACK) + { + if (Utils.TimeDiff(current, ts) >= 0) + { + UpdateAck(Utils.TimeDiff(current, ts)); + } + ParseAck(sn); + ShrinkBuf(); + if (flag == 0) + { + flag = 1; + maxack = sn; + latest_ts = ts; + } + else + { + if (Utils.TimeDiff(sn, maxack) > 0) + { +#if !FASTACK_CONSERVE + maxack = sn; + latest_ts = ts; +#else + if (Utils.TimeDiff(ts, latest_ts) > 0) + { + maxack = sn; + latest_ts = ts; + } +#endif + } + } + } + else if (cmd == CMD_PUSH) + { + if (Utils.TimeDiff(sn, rcv_nxt + rcv_wnd) < 0) + { + AckPush(sn, ts); + if (Utils.TimeDiff(sn, rcv_nxt) >= 0) + { + Segment seg = SegmentNew(); + seg.conv = conv_; + seg.cmd = cmd; + seg.frg = frg; + seg.wnd = wnd; + seg.ts = ts; + seg.sn = sn; + seg.una = una; + if (len > 0) + { + seg.data.Write(data, offset, (int)len); + } + ParseData(seg); + } + } + } + else if (cmd == CMD_WASK) + { + // ready to send back CMD_WINS in flush + // tell remote my window size + probe |= ASK_TELL; + } + else if (cmd == CMD_WINS) + { + // do nothing + } + else + { + return -3; + } + + offset += (int)len; + size -= (int)len; + } + + if (flag != 0) + { + ParseFastack(maxack, latest_ts); + } + + // cwnd update when packet arrived + if (Utils.TimeDiff(snd_una, prev_una) > 0) + { + if (cwnd < rmt_wnd) + { + if (cwnd < ssthresh) + { + cwnd++; + incr += mss; + } + else + { + if (incr < mss) incr = mss; + incr += (mss * mss) / incr + (mss / 16); + if ((cwnd + 1) * mss <= incr) + { + cwnd = (incr + mss - 1) / ((mss > 0) ? mss : 1); + } + } + if (cwnd > rmt_wnd) + { + cwnd = rmt_wnd; + incr = rmt_wnd * mss; + } + } + } + + return 0; + } + + // flush helper function + void MakeSpace(ref int size, int space) + { + if (size + space > mtu) + { + output(buffer, size); + size = 0; + } + } + + // flush helper function + void FlushBuffer(int size) + { + // flush buffer up to 'offset' (<= MTU) + if (size > 0) + { + output(buffer, size); + } + } + + // ikcp_flush + // flush remain ack segments. + // flush may output multiple <= MTU messages from MakeSpace / FlushBuffer. + // the amount of messages depends on the sliding window. + // configured by send/receive window sizes + congestion control. + // with congestion control, the window will be extremely small(!). + public void Flush() + { + int size = 0; // amount of bytes to flush. 'buffer ptr' in C. + bool lost = false; // lost segments + + // update needs to be called before flushing + if (!updated) return; + + // kcp only stack allocates a segment here for performance, leaving + // its data buffer null because this segment's data buffer is never + // used. that's fine in C, but in C# our segment is a class so we + // need to allocate and most importantly, not forget to deallocate + // it before returning. + Segment seg = SegmentNew(); + seg.conv = conv; + seg.cmd = CMD_ACK; + seg.wnd = WndUnused(); + seg.una = rcv_nxt; + + // flush acknowledges + foreach (AckItem ack in acklist) + { + MakeSpace(ref size, OVERHEAD); + // ikcp_ack_get assigns ack[i] to seg.sn, seg.ts + seg.sn = ack.serialNumber; + seg.ts = ack.timestamp; + size += seg.Encode(buffer, size); + } + acklist.Clear(); + + // probe window size (if remote window size equals zero) + if (rmt_wnd == 0) + { + if (probe_wait == 0) + { + probe_wait = PROBE_INIT; + ts_probe = current + probe_wait; + } + else + { + if (Utils.TimeDiff(current, ts_probe) >= 0) + { + if (probe_wait < PROBE_INIT) + probe_wait = PROBE_INIT; + probe_wait += probe_wait / 2; + if (probe_wait > PROBE_LIMIT) + probe_wait = PROBE_LIMIT; + ts_probe = current + probe_wait; + probe |= ASK_SEND; + } + } + } + else + { + ts_probe = 0; + probe_wait = 0; + } + + // flush window probing commands + if ((probe & ASK_SEND) != 0) + { + seg.cmd = CMD_WASK; + MakeSpace(ref size, OVERHEAD); + size += seg.Encode(buffer, size); + } + + // flush window probing commands + if ((probe & ASK_TELL) != 0) + { + seg.cmd = CMD_WINS; + MakeSpace(ref size, OVERHEAD); + size += seg.Encode(buffer, size); + } + + probe = 0; + + // calculate the window size which is currently safe to send. + // it's send window, or remote window, whatever is smaller. + // for our max + uint cwnd_ = Math.Min(snd_wnd, rmt_wnd); + + // double negative: if congestion window is enabled: + // limit window size to cwnd. + // + // note this may heavily limit window sizes. + // for our max message size test with super large windows of 32k, + // 'congestion window' limits it down from 32.000 to 2. + if (!nocwnd) cwnd_ = Math.Min(cwnd, cwnd_); + + // move cwnd_ 'window size' messages from snd_queue to snd_buf + // 'snd_nxt' is what we want to send. + // 'snd_una' is what hasn't been acked yet. + // copy up to 'cwnd_' difference between them (sliding window) + while (Utils.TimeDiff(snd_nxt, snd_una + cwnd_) < 0) + { + if (snd_queue.Count == 0) break; + + Segment newseg = snd_queue.Dequeue(); + + newseg.conv = conv; + newseg.cmd = CMD_PUSH; + newseg.wnd = seg.wnd; + newseg.ts = current; + newseg.sn = snd_nxt; + snd_nxt += 1; // increase sequence number for next segment + newseg.una = rcv_nxt; + newseg.resendts = current; + newseg.rto = rx_rto; + newseg.fastack = 0; + newseg.xmit = 0; + snd_buf.Add(newseg); + } + + // calculate resent + uint resent = fastresend > 0 ? (uint)fastresend : 0xffffffff; + uint rtomin = nodelay == 0 ? (uint)rx_rto >> 3 : 0; + + // flush data segments + int change = 0; + foreach (Segment segment in snd_buf) + { + bool needsend = false; + + // initial transmit + if (segment.xmit == 0) + { + needsend = true; + segment.xmit++; + segment.rto = rx_rto; + segment.resendts = current + (uint)segment.rto + rtomin; + } + // RTO + else if (Utils.TimeDiff(current, segment.resendts) >= 0) + { + needsend = true; + segment.xmit++; + xmit++; + if (nodelay == 0) + { + segment.rto += Math.Max(segment.rto, rx_rto); + } + else + { + int step = (nodelay < 2) ? segment.rto : rx_rto; + segment.rto += step / 2; + } + segment.resendts = current + (uint)segment.rto; + lost = true; + } + // fast retransmit + else if (segment.fastack >= resent) + { + if (segment.xmit <= fastlimit || fastlimit <= 0) + { + needsend = true; + segment.xmit++; + segment.fastack = 0; + segment.resendts = current + (uint)segment.rto; + change++; + } + } + + if (needsend) + { + segment.ts = current; + segment.wnd = seg.wnd; + segment.una = rcv_nxt; + + int need = OVERHEAD + (int)segment.data.Position; + MakeSpace(ref size, need); + + size += segment.Encode(buffer, size); + + if (segment.data.Position > 0) + { + Buffer.BlockCopy(segment.data.GetBuffer(), 0, buffer, size, (int)segment.data.Position); + size += (int)segment.data.Position; + } + + // dead link happens if a message was resent N times, but an + // ack was still not received. + if (segment.xmit >= dead_link) + { + state = -1; + } + } + } + + // kcp stackallocs 'seg'. our C# segment is a class though, so we + // need to properly delete and return it to the pool now that we are + // done with it. + SegmentDelete(seg); + + // flush remaining segments + FlushBuffer(size); + + // update ssthresh + // rate halving, https://tools.ietf.org/html/rfc6937 + if (change > 0) + { + uint inflight = snd_nxt - snd_una; + ssthresh = inflight / 2; + if (ssthresh < THRESH_MIN) + ssthresh = THRESH_MIN; + cwnd = ssthresh + resent; + incr = cwnd * mss; + } + + // congestion control, https://tools.ietf.org/html/rfc5681 + if (lost) + { + // original C uses 'cwnd', not kcp->cwnd! + ssthresh = cwnd_ / 2; + if (ssthresh < THRESH_MIN) + ssthresh = THRESH_MIN; + cwnd = 1; + incr = mss; + } + + if (cwnd < 1) + { + cwnd = 1; + incr = mss; + } + } + + // ikcp_update + // update state (call it repeatedly, every 10ms-100ms), or you can ask + // Check() when to call it again (without Input/Send calling). + // + // 'current' - current timestamp in millisec. pass it to Kcp so that + // Kcp doesn't have to do any stopwatch/deltaTime/etc. code + // + // time as uint, likely to minimize bandwidth. + // uint.max = 4294967295 ms = 1193 hours = 49 days + public void Update(uint currentTimeMilliSeconds) + { + current = currentTimeMilliSeconds; + + // not updated yet? then set updated and last flush time. + if (!updated) + { + updated = true; + ts_flush = current; + } + + // slap is time since last flush in milliseconds + int slap = Utils.TimeDiff(current, ts_flush); + + // hard limit: if 10s elapsed, always flush no matter what + if (slap >= 10000 || slap < -10000) + { + ts_flush = current; + slap = 0; + } + + // last flush is increased by 'interval' each time. + // so slap >= is a strange way to check if interval has elapsed yet. + if (slap >= 0) + { + // increase last flush time by one interval + ts_flush += interval; + + // if last flush is still behind, increase it to current + interval + // if (Utils.TimeDiff(current, ts_flush) >= 0) // original kcp.c + if (current >= ts_flush) // less confusing + { + ts_flush = current + interval; + } + Flush(); + } + } + + // ikcp_check + // Determine when should you invoke update + // Returns when you should invoke update in millisec, if there is no + // input/send calling. you can call update in that time, instead of + // call update repeatly. + // + // Important to reduce unnecessary update invoking. use it to schedule + // update (e.g. implementing an epoll-like mechanism, or optimize update + // when handling massive kcp connections). + public uint Check(uint current_) + { + uint ts_flush_ = ts_flush; + // int tm_flush = 0x7fffffff; original kcp: useless assignment + int tm_packet = 0x7fffffff; + + if (!updated) + { + return current_; + } + + if (Utils.TimeDiff(current_, ts_flush_) >= 10000 || + Utils.TimeDiff(current_, ts_flush_) < -10000) + { + ts_flush_ = current_; + } + + if (Utils.TimeDiff(current_, ts_flush_) >= 0) + { + return current_; + } + + int tm_flush = Utils.TimeDiff(ts_flush_, current_); + + foreach (Segment seg in snd_buf) + { + int diff = Utils.TimeDiff(seg.resendts, current_); + if (diff <= 0) + { + return current_; + } + if (diff < tm_packet) tm_packet = diff; + } + + uint minimal = (uint)(tm_packet < tm_flush ? tm_packet : tm_flush); + if (minimal >= interval) minimal = interval; + + return current_ + minimal; + } + + // ikcp_setmtu + // Change MTU (Maximum Transmission Unit) size. + public void SetMtu(uint mtu) + { + if (mtu < 50 || mtu < OVERHEAD) + throw new ArgumentException("MTU must be higher than 50 and higher than OVERHEAD"); + + buffer = new byte[(mtu + OVERHEAD) * 3]; + this.mtu = mtu; + mss = mtu - OVERHEAD; + } + + // ikcp_interval + public void SetInterval(uint interval) + { + // clamp interval between 10 and 5000 + if (interval > 5000) interval = 5000; + else if (interval < 10) interval = 10; + this.interval = interval; + } + + // ikcp_nodelay + // configuration: https://github.com/skywind3000/kcp/blob/master/README.en.md#protocol-configuration + // nodelay : Whether nodelay mode is enabled, 0 is not enabled; 1 enabled. + // interval :Protocol internal work interval, in milliseconds, such as 10 ms or 20 ms. + // resend :Fast retransmission mode, 0 represents off by default, 2 can be set (2 ACK spans will result in direct retransmission) + // nc :Whether to turn off flow control, 0 represents “Do not turn off” by default, 1 represents “Turn off”. + // Normal Mode: ikcp_nodelay(kcp, 0, 40, 0, 0); + // Turbo Mode: ikcp_nodelay(kcp, 1, 10, 2, 1); + public void SetNoDelay(uint nodelay, uint interval = INTERVAL, int resend = 0, bool nocwnd = false) + { + this.nodelay = nodelay; + if (nodelay != 0) + { + rx_minrto = RTO_NDL; + } + else + { + rx_minrto = RTO_MIN; + } + + if (interval >= 0) + { + // clamp interval between 10 and 5000 + if (interval > 5000) interval = 5000; + else if (interval < 10) interval = 10; + this.interval = interval; + } + + if (resend >= 0) + { + fastresend = resend; + } + + this.nocwnd = nocwnd; + } + + // ikcp_wndsize + public void SetWindowSize(uint sendWindow, uint receiveWindow) + { + if (sendWindow > 0) + { + snd_wnd = sendWindow; + } + + if (receiveWindow > 0) + { + // must >= max fragment size + rcv_wnd = Math.Max(receiveWindow, WND_RCV); + } + } + } +} diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Kcp.cs.meta b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Kcp.cs.meta new file mode 100644 index 00000000..94ac97e2 --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Kcp.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c43eaf92abd8f764bb6f94c9b5a701c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Pool.cs b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Pool.cs new file mode 100644 index 00000000..81b52895 --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Pool.cs @@ -0,0 +1,46 @@ +// Pool to avoid allocations (from libuv2k & Mirror) +using System; +using System.Collections.Generic; + +namespace kcp2k +{ + public class Pool + { + // Mirror is single threaded, no need for concurrent collections + readonly Stack objects = new Stack(); + + // some types might need additional parameters in their constructor, so + // we use a Func generator + readonly Func objectGenerator; + + // some types might need additional cleanup for returned objects + readonly Action objectResetter; + + public Pool(Func objectGenerator, Action objectResetter, int initialCapacity) + { + this.objectGenerator = objectGenerator; + this.objectResetter = objectResetter; + + // allocate an initial pool so we have fewer (if any) + // allocations in the first few frames (or seconds). + for (int i = 0; i < initialCapacity; ++i) + objects.Push(objectGenerator()); + } + + // take an element from the pool, or create a new one if empty + public T Take() => objects.Count > 0 ? objects.Pop() : objectGenerator(); + + // return an element to the pool + public void Return(T item) + { + objectResetter(item); + objects.Push(item); + } + + // clear the pool + public void Clear() => objects.Clear(); + + // count to see how many objects are in the pool. useful for tests. + public int Count => objects.Count; + } +} diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Pool.cs.meta b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Pool.cs.meta new file mode 100644 index 00000000..8bb774ee --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Pool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d78a539c8e8e73a46bd6ffd83d5e9d8c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Segment.cs b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Segment.cs new file mode 100644 index 00000000..d7e41317 --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Segment.cs @@ -0,0 +1,78 @@ +using System.IO; + +namespace kcp2k +{ + // KCP Segment Definition + internal class Segment + { + internal uint conv; // conversation + internal uint cmd; // command, e.g. Kcp.CMD_ACK etc. + // fragment (sent as 1 byte). + // 0 if unfragmented, otherwise fragment numbers in reverse: N,..,32,1,0 + // this way the first received segment tells us how many fragments there are. + internal uint frg; + internal uint wnd; // window size that the receive can currently receive + internal uint ts; // timestamp + internal uint sn; // sequence number + internal uint una; + internal uint resendts; // resend timestamp + internal int rto; + internal uint fastack; + internal uint xmit; // retransmit count + + // we need an auto scaling byte[] with a WriteBytes function. + // MemoryStream does that perfectly, no need to reinvent the wheel. + // note: no need to pool it, because Segment is already pooled. + // -> default MTU as initial capacity to avoid most runtime resizing/allocations + // + // .data is only used for Encode(), which always fits it into a buffer. + // the buffer is always Kcp.buffer. Kcp ctor creates the buffer of size: + // (mtu + OVERHEAD) * 3 bytes. + // in other words, Encode only ever writes up to the above amount of bytes. + internal MemoryStream data = new MemoryStream(Kcp.MTU_DEF); + + // ikcp_encode_seg + // encode a segment into buffer. + // buffer is always Kcp.buffer. Kcp ctor creates the buffer of size: + // (mtu + OVERHEAD) * 3 bytes. + // in other words, Encode only ever writes up to the above amount of bytes. + internal int Encode(byte[] ptr, int offset) + { + int previousPosition = offset; + + offset += Utils.Encode32U(ptr, offset, conv); + offset += Utils.Encode8u(ptr, offset, (byte)cmd); + // IMPORTANT kcp encodes 'frg' as 1 byte. + // so we can only support up to 255 fragments. + // (which limits max message size to around 288 KB) + offset += Utils.Encode8u(ptr, offset, (byte)frg); + offset += Utils.Encode16U(ptr, offset, (ushort)wnd); + offset += Utils.Encode32U(ptr, offset, ts); + offset += Utils.Encode32U(ptr, offset, sn); + offset += Utils.Encode32U(ptr, offset, una); + offset += Utils.Encode32U(ptr, offset, (uint)data.Position); + + int written = offset - previousPosition; + return written; + } + + // reset to return a fresh segment to the pool + internal void Reset() + { + conv = 0; + cmd = 0; + frg = 0; + wnd = 0; + ts = 0; + sn = 0; + una = 0; + rto = 0; + xmit = 0; + resendts = 0; + fastack = 0; + + // keep buffer for next pool usage, but reset length (= bytes written) + data.SetLength(0); + } + } +} diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Segment.cs.meta b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Segment.cs.meta new file mode 100644 index 00000000..3e8f7b42 --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Segment.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8749c094620ccde478c15165010ffbf1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Utils.cs b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Utils.cs new file mode 100644 index 00000000..2cb74628 --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Utils.cs @@ -0,0 +1,76 @@ +using System.Runtime.CompilerServices; + +namespace kcp2k +{ + public static partial class Utils + { + // Clamp so we don't have to depend on UnityEngine + public static int Clamp(int value, int min, int max) + { + if (value < min) return min; + if (value > max) return max; + return value; + } + + // encode 8 bits unsigned int + public static int Encode8u(byte[] p, int offset, byte value) + { + p[0 + offset] = value; + return 1; + } + + // decode 8 bits unsigned int + public static int Decode8u(byte[] p, int offset, out byte value) + { + value = p[0 + offset]; + return 1; + } + + // encode 16 bits unsigned int (lsb) + public static int Encode16U(byte[] p, int offset, ushort value) + { + p[0 + offset] = (byte)(value >> 0); + p[1 + offset] = (byte)(value >> 8); + return 2; + } + + // decode 16 bits unsigned int (lsb) + public static int Decode16U(byte[] p, int offset, out ushort value) + { + ushort result = 0; + result |= p[0 + offset]; + result |= (ushort)(p[1 + offset] << 8); + value = result; + return 2; + } + + // encode 32 bits unsigned int (lsb) + public static int Encode32U(byte[] p, int offset, uint value) + { + p[0 + offset] = (byte)(value >> 0); + p[1 + offset] = (byte)(value >> 8); + p[2 + offset] = (byte)(value >> 16); + p[3 + offset] = (byte)(value >> 24); + return 4; + } + + // decode 32 bits unsigned int (lsb) + public static int Decode32U(byte[] p, int offset, out uint value) + { + uint result = 0; + result |= p[0 + offset]; + result |= (uint)(p[1 + offset] << 8); + result |= (uint)(p[2 + offset] << 16); + result |= (uint)(p[3 + offset] << 24); + value = result; + return 4; + } + + // timediff was a macro in original Kcp. let's inline it if possible. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int TimeDiff(uint later, uint earlier) + { + return (int)(later - earlier); + } + } +} diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Utils.cs.meta b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Utils.cs.meta new file mode 100644 index 00000000..0835b931 --- /dev/null +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Base/kcp2k/kcp/Utils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 927985771e12e4c45b199b20c8477369 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Client/KCPClientNetwork.cs b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Client/KCPClientNetwork.cs index 3f6498f7..dbef82d3 100644 --- a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Client/KCPClientNetwork.cs +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Client/KCPClientNetwork.cs @@ -1,16 +1,15 @@ using System; +using System.Buffers; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Threading; -using TEngine.Core; +using kcp2k; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract // ReSharper disable PossibleNullReferenceException // ReSharper disable InconsistentNaming -#pragma warning disable CS8602 -#pragma warning disable CS8625 -#pragma warning disable CS8618 namespace TEngine.Core.Network { @@ -55,21 +54,22 @@ namespace TEngine.Core.Network { ThreadSynchronizationContext.Main.Post(OnConnectDisconnect); } - + _socket.Disconnect(false); _socket.Close(); } - + + _kcp = null; _maxSndWnd = 0; _updateMinTime = 0; - + _memoryPool.Dispose(); + _memoryPool = null; _sendAction = null; _rawSendBuffer = null; _rawReceiveBuffer = null; _packetParser?.Dispose(); - _receiveMemoryStream?.Dispose(); - + ClearConnectTimeout(ref _connectTimeoutId); if (_messageCache != null) @@ -77,13 +77,6 @@ namespace TEngine.Core.Network _messageCache.Clear(); _messageCache = null; } - - if (_kcpIntPtr != IntPtr.Zero) - { - KCP.KcpRelease(_kcpIntPtr); - ConnectionPtrChannel.Remove(_kcpIntPtr); - _kcpIntPtr = IntPtr.Zero; - } #if NETDEBUG Log.Debug($"KCPClientNetwork ConnectionPtrChannel:{ConnectionPtrChannel.Count}"); #endif @@ -110,6 +103,7 @@ namespace TEngine.Core.Network _maxSndWnd = _kcpSettings.MaxSendWindowSize; _messageCache = new Queue(); _rawReceiveBuffer = new byte[_kcpSettings.Mtu + 5]; + _memoryPool = MemoryPool.Shared; _sendAction = (rpcId, routeTypeOpCode, routeId, memoryStream, message) => { @@ -151,7 +145,7 @@ namespace TEngine.Core.Network private Socket _socket; private int _maxSndWnd; - private IntPtr _kcpIntPtr; + private Kcp _kcp; private bool _isDisconnect; private long _updateMinTime; private byte[] _rawSendBuffer; @@ -159,15 +153,12 @@ namespace TEngine.Core.Network private byte[] _rawReceiveBuffer; private KCPSettings _kcpSettings; private APacketParser _packetParser; - private MemoryStream _receiveMemoryStream; + private MemoryPool _memoryPool; private Queue _messageCache; private Action _sendAction; - private readonly Queue _updateTimeOutTime = new Queue(); private EndPoint _clientEndPoint = new IPEndPoint(IPAddress.Any, 0); - private readonly SortedDictionary _updateTimer = new SortedDictionary(); - private static readonly Dictionary ConnectionPtrChannel = new Dictionary(); - + private readonly SortedSet _updateTimer = new SortedSet(); private uint TimeNow => (uint) (TimeHelper.Now - _startTime); private void Receive() @@ -213,14 +204,11 @@ namespace TEngine.Core.Network SendHeader(KcpHeader.ConfirmConnection); ClearConnectTimeout(ref _connectTimeoutId); // 创建KCP和相关的初始化 - _kcpIntPtr = KCP.KcpCreate(channelId, new IntPtr(channelId)); - KCP.KcpNodelay(_kcpIntPtr, 1, 5, 2, 1); - KCP.KcpWndsize(_kcpIntPtr, _kcpSettings.SendWindowSize, _kcpSettings.ReceiveWindowSize); - KCP.KcpSetmtu(_kcpIntPtr, _kcpSettings.Mtu); - KCP.KcpSetminrto(_kcpIntPtr, 30); - KCP.KcpSetoutput(_kcpIntPtr, KcpOutput); + _kcp = new Kcp(channelId, Output); + _kcp.SetNoDelay(1, 5, 2, true); + _kcp.SetWindowSize(_kcpSettings.SendWindowSize, _kcpSettings.ReceiveWindowSize); + _kcp.SetMtu(_kcpSettings.Mtu); _rawSendBuffer = new byte[ushort.MaxValue]; - _receiveMemoryStream = MemoryStreamHelper.GetRecyclableMemoryStream(); _packetParser = APacketParser.CreatePacketParser(NetworkTarget); // 把缓存的消息全部发送给服务器 @@ -248,7 +236,6 @@ namespace TEngine.Core.Network _messageCache.Clear(); _messageCache = null; - ConnectionPtrChannel.Add(_kcpIntPtr, this); // 调用ChannelId改变事件、就算没有改变也要发下、接收事件的地方会判定下 ThreadSynchronizationContext.Main.Post(() => { @@ -272,8 +259,8 @@ namespace TEngine.Core.Network { break; } - - KCP.KcpInput(_kcpIntPtr, _rawReceiveBuffer, 5, messageLength); + + _kcp.Input(_rawReceiveBuffer, 5, messageLength); AddToUpdate(0); KcpReceive(); break; @@ -284,7 +271,7 @@ namespace TEngine.Core.Network { break; } - + _isDisconnect = true; Dispose(); break; @@ -310,8 +297,8 @@ namespace TEngine.Core.Network } #endif // 检查等待发送的消息,如果超出两倍窗口大小,KCP作者给的建议是要断开连接 - - var waitSendSize = KCP.KcpWaitsnd(_kcpIntPtr); + + var waitSendSize = _kcp.WaitSnd; if (waitSendSize > _maxSndWnd) { @@ -319,15 +306,9 @@ namespace TEngine.Core.Network Dispose(); return; } - - // 发送消息 - - KCP.KcpSend(_kcpIntPtr, memoryStream.GetBuffer(), (int) memoryStream.Length); - - // 因为memoryStream对象池出来的、所以需要手动回收下 + _kcp.Send(memoryStream.GetBuffer(), 0, (int)memoryStream.Length); memoryStream.Dispose(); - AddToUpdate(0); } @@ -365,7 +346,7 @@ namespace TEngine.Core.Network _sendAction(rpcId, routeTypeOpCode, entityId, null, message); } - private void Output(IntPtr bytes, int count) + private void Output(byte[] bytes, int count) { #if TENGINE_DEVELOP if (NetworkThread.Instance.ManagedThreadId != Thread.CurrentThread.ManagedThreadId) @@ -374,7 +355,7 @@ namespace TEngine.Core.Network return; } #endif - if (IsDisposed || _kcpIntPtr == IntPtr.Zero) + if (IsDisposed) { return; } @@ -388,7 +369,7 @@ namespace TEngine.Core.Network _rawSendBuffer.WriteTo(0, (byte) KcpHeader.ReceiveData); _rawSendBuffer.WriteTo(1, ChannelId); - Marshal.Copy(bytes, _rawSendBuffer, 5, count); + Buffer.BlockCopy(bytes, 0, _rawSendBuffer, 5, count); _socket.Send(_rawSendBuffer, 0, count + 5, SocketFlags.None); } catch (Exception e) @@ -406,7 +387,7 @@ namespace TEngine.Core.Network return; } #endif - if (IsDisposed || _kcpIntPtr == IntPtr.Zero) + if (IsDisposed) { return; } @@ -416,8 +397,8 @@ namespace TEngine.Core.Network try { // 获得一个完整消息的长度 - - var peekSize = KCP.KcpPeeksize(_kcpIntPtr); + + var peekSize = _kcp.PeekSize(); // 如果没有接收的消息那就跳出当前循环。 @@ -433,9 +414,8 @@ namespace TEngine.Core.Network throw new Exception("SocketError.NetworkReset"); } - _receiveMemoryStream.SetLength(peekSize); - _receiveMemoryStream.Seek(0, SeekOrigin.Begin); - var receiveCount = KCP.KcpRecv(_kcpIntPtr, _receiveMemoryStream.GetBuffer(), peekSize); + var receiveMemoryOwner = _memoryPool.Rent(Packet.OuterPacketMaxLength); + var receiveCount = _kcp.Receive(receiveMemoryOwner.Memory, peekSize); // 如果接收的长度跟peekSize不一样,不需要处理,因为消息肯定有问题的(虽然不可能出现)。 @@ -445,13 +425,10 @@ namespace TEngine.Core.Network break; } - var packInfo = _packetParser.UnPack(_receiveMemoryStream); - - if (packInfo == null) + if (!_packetParser.UnPack(receiveMemoryOwner, out var packInfo)) { break; } - ThreadSynchronizationContext.Main.Post(() => { @@ -483,15 +460,13 @@ namespace TEngine.Core.Network foreach (var timeId in _updateTimer) { - var key = timeId.Key; - - if (key > nowTime) + if (timeId > nowTime) { - _updateMinTime = key; + _updateMinTime = timeId; break; } - _updateTimeOutTime.Enqueue(key); + _updateTimeOutTime.Enqueue(timeId); } while (_updateTimeOutTime.TryDequeue(out var time)) @@ -521,7 +496,7 @@ namespace TEngine.Core.Network _updateMinTime = tillTime; } - _updateTimer[tillTime] = KcpUpdate; + _updateTimer.Add(tillTime); } private void KcpUpdate() @@ -537,17 +512,14 @@ namespace TEngine.Core.Network try { - KCP.KcpUpdate(_kcpIntPtr, nowTime); + _kcp.Update(nowTime); } catch (Exception e) { Log.Error(e); } - if (_kcpIntPtr != IntPtr.Zero) - { - AddToUpdate(KCP.KcpCheck(_kcpIntPtr, nowTime)); - } + AddToUpdate(_kcp.Check(nowTime)); } public override void RemoveChannel(uint channelId) @@ -590,38 +562,6 @@ namespace TEngine.Core.Network TimerScheduler.Instance.Core.RemoveByRef(ref connectTimeoutId); } - -#if ENABLE_IL2CPP - [AOT.MonoPInvokeCallback(typeof(KcpOutput))] -#endif - private static int KcpOutput(IntPtr bytes, int count, IntPtr kcp, IntPtr user) - { -#if TENGINE_DEVELOP - if (NetworkThread.Instance.ManagedThreadId != Thread.CurrentThread.ManagedThreadId) - { - Log.Error("not in NetworkThread!"); - return 0; - } -#endif - try - { - if (kcp == IntPtr.Zero || !ConnectionPtrChannel.TryGetValue(kcp, out var channel)) - { - return 0; - } - - if (!channel.IsDisposed) - { - channel.Output(bytes, count); - } - } - catch (Exception e) - { - Log.Error(e); - } - - return count; - } #endregion } diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Server/KCPServerNetwork.cs b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Server/KCPServerNetwork.cs index 0439e4d0..57184341 100644 --- a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Server/KCPServerNetwork.cs +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Server/KCPServerNetwork.cs @@ -5,11 +5,10 @@ using System.Linq; using System.Net; using System.Net.Sockets; using TEngine.DataStructure; -using TEngine.Core; +using kcp2k; + // ReSharper disable InconsistentNaming -#pragma warning disable CS8601 -#pragma warning disable CS8625 -#pragma warning disable CS8618 +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract namespace TEngine.Core.Network { @@ -102,7 +101,6 @@ namespace TEngine.Core.Network private readonly SortedOneToManyList _pendingConnectionTimer = new SortedOneToManyList(); private readonly Dictionary _pendingConnection = new Dictionary(); private readonly Dictionary _connectionChannel = new Dictionary(); - public static readonly Dictionary ConnectionPtrChannel = new Dictionary(); private KCPSettings KcpSettings { get; set; } private uint TimeNow => (uint) (TimeHelper.Now - _startTime); @@ -170,6 +168,7 @@ namespace TEngine.Core.Network try { var receiveLength = _socket.ReceiveFrom(_rawReceiveBuffer, ref _clientEndPoint); + if (receiveLength < 1) { continue; @@ -182,7 +181,6 @@ namespace TEngine.Core.Network { case KcpHeader.RequestConnection: { - // Log.Debug("KcpHeader.RequestConnection"); if (receiveLength != 5) { break; @@ -232,17 +230,12 @@ namespace TEngine.Core.Network break; } - var kcpIntPtr = KCP.KcpCreate(channelId, new IntPtr(channelId)); - - KCP.KcpNodelay(kcpIntPtr, 1, 5, 2, 1); - KCP.KcpWndsize(kcpIntPtr, KcpSettings.SendWindowSize, KcpSettings.ReceiveWindowSize); - KCP.KcpSetmtu(kcpIntPtr, KcpSettings.Mtu); - KCP.KcpSetminrto(kcpIntPtr, 30); - KCP.KcpSetoutput(kcpIntPtr, KcpOutput); - + var kcp = new Kcp(channelId, channel.Output); + kcp.SetNoDelay(1, 5, 2, true); + kcp.SetWindowSize(KcpSettings.SendWindowSize, KcpSettings.ReceiveWindowSize); + kcp.SetMtu(KcpSettings.Mtu); _connectionChannel.Add(channel.Id, channel); - ConnectionPtrChannel.Add(kcpIntPtr, channel); - channel.Connect(kcpIntPtr, AddToUpdate, KcpSettings.MaxSendWindowSize, NetworkTarget, NetworkMessageScheduler); + channel.Connect(kcp, AddToUpdate, KcpSettings.MaxSendWindowSize, NetworkTarget, NetworkMessageScheduler); break; } case KcpHeader.ReceiveData: @@ -260,7 +253,7 @@ namespace TEngine.Core.Network break; } - KCP.KcpInput(channel.KcpIntPtr, _rawReceiveBuffer, 5, messageLength); + channel.Kcp.Input(_rawReceiveBuffer, 5, messageLength); AddToUpdate(0, channel.Id); channel.Receive(); break; @@ -279,6 +272,7 @@ namespace TEngine.Core.Network } } } + private bool RemovePendingConnection(uint channelId, EndPoint remoteEndPoint, out KCPServerNetworkChannel channel) { @@ -391,18 +385,19 @@ namespace TEngine.Core.Network continue; } + var channelKcp = channel.Kcp; try { - KCP.KcpUpdate(channel.KcpIntPtr, nowTime); + channelKcp.Update(nowTime); } catch (Exception e) { Log.Error(e); } - - if (channel.KcpIntPtr != IntPtr.Zero) + + if (channelKcp != null) { - AddToUpdate(KCP.KcpCheck(channel.KcpIntPtr, nowTime), channelId); + AddToUpdate(channelKcp.Check(nowTime), channelId); } } @@ -461,39 +456,6 @@ namespace TEngine.Core.Network _updateTimer.Add(tillTime, channelId); } - - -#if ENABLE_IL2CPP - [AOT.MonoPInvokeCallback(typeof(KcpOutput))] -#endif - private static int KcpOutput(IntPtr bytes, int count, IntPtr kcp, IntPtr user) - { -#if TENGINE_DEVELOP - if (NetworkThread.Instance.ManagedThreadId != Thread.CurrentThread.ManagedThreadId) - { - Log.Error("not in NetworkThread!"); - return 0; - } -#endif - try - { - if (kcp == IntPtr.Zero || !ConnectionPtrChannel.TryGetValue(kcp, out var channel)) - { - return 0; - } - - if (!channel.IsDisposed) - { - channel.Output(bytes, count); - } - } - catch (Exception e) - { - Log.Error(e); - } - - return count; - } #endregion } diff --git a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Server/KCPServerNetworkChannel.cs b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Server/KCPServerNetworkChannel.cs index 1e411dbd..ae6c65db 100644 --- a/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Server/KCPServerNetworkChannel.cs +++ b/Assets/GameScripts/DotNet/Core/Network/NetworkProtocol/KCP/Server/KCPServerNetworkChannel.cs @@ -1,12 +1,14 @@ using System; +using System.Buffers; using System.IO; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; -using TEngine.Core; +using TEngine.DataStructure; +using kcp2k; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + // ReSharper disable InconsistentNaming -#pragma warning disable CS8625 -#pragma warning disable CS8618 namespace TEngine.Core.Network { @@ -19,8 +21,8 @@ namespace TEngine.Core.Network public readonly uint CreateTime; private readonly Socket _socket; private Action _addToUpdate; - private MemoryStream _receiveMemoryStream; - public IntPtr KcpIntPtr { get; private set; } + private MemoryPool _memoryPool; + public Kcp Kcp { get; private set; } public override event Action OnDispose; public override event Action OnReceiveMemoryStream; @@ -37,6 +39,7 @@ namespace TEngine.Core.Network _socket = socket; CreateTime = createTime; RemoteEndPoint = remoteEndPoint; + _memoryPool = MemoryPool.Shared; } public override void Dispose() @@ -53,28 +56,23 @@ namespace TEngine.Core.Network return; } + Kcp = null; var buff = new byte[5]; buff.WriteTo(0, (byte) KcpHeader.Disconnect); buff.WriteTo(1, Id); _socket.SendTo(buff, 5, SocketFlags.None, RemoteEndPoint); - - if (KcpIntPtr != IntPtr.Zero) - { - KCPServerNetwork.ConnectionPtrChannel.Remove(KcpIntPtr); - KCP.KcpRelease(KcpIntPtr); - KcpIntPtr = IntPtr.Zero; - } #if NETDEBUG Log.Debug($"KCPServerNetworkChannel ConnectionPtrChannel:{KCPServerNetwork.ConnectionPtrChannel.Count}"); #endif _maxSndWnd = 0; _addToUpdate = null; - _receiveMemoryStream?.Dispose(); + _memoryPool.Dispose(); + _memoryPool = null; ThreadSynchronizationContext.Main.Post(OnDispose); base.Dispose(); } - public void Connect(IntPtr kcpIntPtr, Action addToUpdate, int maxSndWnd, NetworkTarget networkTarget, ANetworkMessageScheduler networkMessageScheduler) + public void Connect(Kcp kcp, Action addToUpdate, int maxSndWnd, NetworkTarget networkTarget, ANetworkMessageScheduler networkMessageScheduler) { #if TENGINE_DEVELOP if (NetworkThread.Instance.ManagedThreadId != Thread.CurrentThread.ManagedThreadId) @@ -83,11 +81,10 @@ namespace TEngine.Core.Network return; } #endif - KcpIntPtr = kcpIntPtr; + Kcp = kcp; _maxSndWnd = maxSndWnd; _addToUpdate = addToUpdate; _rawSendBuffer = new byte[ushort.MaxValue]; - _receiveMemoryStream = MemoryStreamHelper.GetRecyclableMemoryStream(); PacketParser = APacketParser.CreatePacketParser(networkTarget); ThreadSynchronizationContext.Main.Post(() => @@ -110,14 +107,14 @@ namespace TEngine.Core.Network return; } #endif - if (IsDisposed || KcpIntPtr == IntPtr.Zero) + if (IsDisposed) { return; } // 检查等待发送的消息,如果超出两倍窗口大小,KCP作者给的建议是要断开连接 - - var waitSendSize = KCP.KcpWaitsnd(KcpIntPtr); + + var waitSendSize = Kcp.WaitSnd; if (waitSendSize > _maxSndWnd) { @@ -125,15 +122,10 @@ namespace TEngine.Core.Network Dispose(); return; } - // 发送消息 - - KCP.KcpSend(KcpIntPtr, memoryStream.GetBuffer(), (int) memoryStream.Length); - + Kcp.Send(memoryStream.GetBuffer(), 0, (int)memoryStream.Length); // 因为memoryStream对象池出来的、所以需要手动回收下 - memoryStream.Dispose(); - _addToUpdate(0, Id); } @@ -146,7 +138,7 @@ namespace TEngine.Core.Network return; } #endif - if (IsDisposed || KcpIntPtr == IntPtr.Zero) + if (IsDisposed) { return; } @@ -155,32 +147,25 @@ namespace TEngine.Core.Network { try { - if (KcpIntPtr == IntPtr.Zero) - { - return; - } - // 获得一个完整消息的长度 - - var peekSize = KCP.KcpPeeksize(KcpIntPtr); - + + var peekSize = Kcp.PeekSize(); + // 如果没有接收的消息那就跳出当前循环。 - + if (peekSize < 0) { return; } - + // 如果为0,表示当前消息发生错误。提示下、一般情况不会发生的 - if (peekSize == 0) { throw new Exception("SocketError.NetworkReset"); } - - _receiveMemoryStream.SetLength(peekSize); - _receiveMemoryStream.Seek(0, SeekOrigin.Begin); - var receiveCount = KCP.KcpRecv(KcpIntPtr, _receiveMemoryStream.GetBuffer(), peekSize); + + var receiveMemoryOwner = _memoryPool.Rent(Packet.OuterPacketMaxLength); + var receiveCount = Kcp.Receive(receiveMemoryOwner.Memory, peekSize); // 如果接收的长度跟peekSize不一样,不需要处理,因为消息肯定有问题的(虽然不可能出现)。 @@ -190,9 +175,7 @@ namespace TEngine.Core.Network break; } - var packInfo = PacketParser.UnPack(_receiveMemoryStream); - - if (packInfo == null) + if (!PacketParser.UnPack(receiveMemoryOwner,out var packInfo)) { break; } @@ -215,7 +198,7 @@ namespace TEngine.Core.Network } } - public void Output(IntPtr bytes, int count) + public void Output(byte[] bytes, int count) { #if TENGINE_DEVELOP if (NetworkThread.Instance.ManagedThreadId != Thread.CurrentThread.ManagedThreadId) @@ -224,7 +207,7 @@ namespace TEngine.Core.Network return; } #endif - if (IsDisposed || KcpIntPtr == IntPtr.Zero) + if (IsDisposed) { return; } @@ -238,7 +221,7 @@ namespace TEngine.Core.Network _rawSendBuffer.WriteTo(0, (byte) KcpHeader.ReceiveData); _rawSendBuffer.WriteTo(1, Id); - Marshal.Copy(bytes, _rawSendBuffer, 5, count); + Buffer.BlockCopy(bytes, 0, _rawSendBuffer, 5, count); _socket.SendTo(_rawSendBuffer, 0, count + 5, SocketFlags.None, RemoteEndPoint); } catch (Exception e) diff --git a/Assets/GameScripts/DotNet/Core/Network/PacketParser/InnerPacketParser.cs b/Assets/GameScripts/DotNet/Core/Network/PacketParser/InnerPacketParser.cs index ea00b223..63a243d3 100644 --- a/Assets/GameScripts/DotNet/Core/Network/PacketParser/InnerPacketParser.cs +++ b/Assets/GameScripts/DotNet/Core/Network/PacketParser/InnerPacketParser.cs @@ -1,37 +1,25 @@ #if TENGINE_NET +using System.Buffers; using TEngine.DataStructure; -using TEngine.Core; -#pragma warning disable CS8600 -#pragma warning disable CS8625 -#pragma warning disable CS8603 +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract namespace TEngine.Core.Network; public sealed class InnerPackInfo : APackInfo { - public static InnerPackInfo Create() + public static InnerPackInfo Create(IMemoryOwner memoryOwner) { - return Pool.Rent(); - } - - public static InnerPackInfo Create(uint rpcId, long routeId, uint protocolCode) - { - var innerPackInfo = Pool.Rent(); - innerPackInfo.RpcId = rpcId; - innerPackInfo.RouteId = routeId; - innerPackInfo.ProtocolCode = protocolCode; + var innerPackInfo = Rent(); + innerPackInfo.MemoryOwner = memoryOwner; return innerPackInfo; } - public static InnerPackInfo Create(uint rpcId, long routeId, uint protocolCode, long routeTypeCode, MemoryStream memoryStream) + public override MemoryStream CreateMemoryStream() { - var innerPackInfo = Pool.Rent(); - innerPackInfo.RpcId = rpcId; - innerPackInfo.RouteId = routeId; - innerPackInfo.ProtocolCode = protocolCode; - innerPackInfo.RouteTypeCode = routeTypeCode; - innerPackInfo.MemoryStream = memoryStream; - return innerPackInfo; + var recyclableMemoryStream = MemoryStreamHelper.GetRecyclableMemoryStream(); + recyclableMemoryStream.Write(MemoryOwner.Memory.Span.Slice(0, Packet.InnerPacketHeadLength + MessagePacketLength)); + recyclableMemoryStream.Seek(0, SeekOrigin.Begin); + return recyclableMemoryStream; } public override void Dispose() @@ -42,38 +30,36 @@ public sealed class InnerPackInfo : APackInfo public override object Deserialize(Type messageType) { - using (MemoryStream) + var memoryOwnerMemory = MemoryOwner.Memory; + memoryOwnerMemory = memoryOwnerMemory.Slice(Packet.InnerPacketHeadLength, MessagePacketLength); + + switch (ProtocolCode) { - MemoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); - - switch (ProtocolCode) + case >= Opcode.InnerBsonRouteResponse: { - case >= Opcode.InnerBsonRouteResponse: - { - return MongoHelper.Instance.DeserializeFrom(messageType, MemoryStream); - } - case >= Opcode.InnerRouteResponse: - { - return ProtoBufHelper.FromStream(messageType, MemoryStream); - } - case >= Opcode.OuterRouteResponse: - { - return ProtoBufHelper.FromStream(messageType, MemoryStream); - } - case >= Opcode.InnerBsonRouteMessage: - { - return MongoHelper.Instance.DeserializeFrom(messageType, MemoryStream); - } - case >= Opcode.InnerRouteMessage: - case >= Opcode.OuterRouteMessage: - { - return ProtoBufHelper.FromStream(messageType, MemoryStream); - } - default: - { - Log.Error($"protocolCode:{ProtocolCode} Does not support processing protocol"); - return null; - } + return MongoHelper.Instance.Deserialize(memoryOwnerMemory, messageType); + } + case >= Opcode.InnerRouteResponse: + { + return ProtoBufHelper.FromMemory(messageType, memoryOwnerMemory); + } + case >= Opcode.OuterRouteResponse: + { + return ProtoBufHelper.FromMemory(messageType, memoryOwnerMemory); + } + case >= Opcode.InnerBsonRouteMessage: + { + return MongoHelper.Instance.Deserialize(memoryOwnerMemory, messageType); + } + case >= Opcode.InnerRouteMessage: + case >= Opcode.OuterRouteMessage: + { + return ProtoBufHelper.FromMemory(messageType, memoryOwnerMemory); + } + default: + { + Log.Error($"protocolCode:{ProtocolCode} Does not support processing protocol"); + return null; } } } @@ -88,10 +74,15 @@ public sealed class InnerPacketParser : APacketParser private bool _isUnPackHead = true; private readonly byte[] _messageHead = new byte[Packet.InnerPacketHeadLength]; + public InnerPacketParser() + { + MemoryPool = MemoryPool.Shared; + } + public override bool UnPack(CircularBuffer buffer, out APackInfo packInfo) { packInfo = null; - + while (!IsDisposed) { if (_isUnPackHead) @@ -100,48 +91,40 @@ public sealed class InnerPacketParser : APacketParser { return false; } - + _ = buffer.Read(_messageHead, 0, Packet.InnerPacketHeadLength); _messagePacketLength = BitConverter.ToInt32(_messageHead, 0); - + if (_messagePacketLength > Packet.PacketBodyMaxLength) { throw new ScanException($"The received information exceeds the maximum limit = {_messagePacketLength}"); } _protocolCode = BitConverter.ToUInt32(_messageHead, Packet.PacketLength); - _rpcId = BitConverter.ToUInt32(_messageHead, Packet.OuterPacketRpcIdLocation); + _rpcId = BitConverter.ToUInt32(_messageHead, Packet.InnerPacketRpcIdLocation); _routeId = BitConverter.ToInt64(_messageHead, Packet.InnerPacketRouteRouteIdLocation); _isUnPackHead = false; } - + try { if (buffer.Length < _messagePacketLength) { return false; } - + _isUnPackHead = true; - packInfo = InnerPackInfo.Create(_rpcId, _routeId, _protocolCode); - - if (_messagePacketLength > 0) - { - return true; - } - - var memoryStream = MemoryStreamHelper.GetRecyclableMemoryStream(); + // 创建消息包 + var memoryOwner = MemoryPool.Rent(Packet.InnerPacketMaxLength); + packInfo = InnerPackInfo.Create(memoryOwner); + packInfo.RpcId = _rpcId; + packInfo.RouteId = _routeId; + packInfo.ProtocolCode = _protocolCode; + packInfo.MessagePacketLength = _messagePacketLength; // 写入消息体的信息到内存中 - memoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); - buffer.Read(memoryStream, _messagePacketLength); + buffer.Read(memoryOwner.Memory.Slice(Packet.InnerPacketHeadLength), _messagePacketLength); // 写入消息头的信息到内存中 - memoryStream.Seek(0, SeekOrigin.Begin); - memoryStream.Write(BitConverter.GetBytes(_messagePacketLength)); - memoryStream.Write(BitConverter.GetBytes(packInfo.ProtocolCode)); - memoryStream.Write(BitConverter.GetBytes(packInfo.RpcId)); - memoryStream.Write(BitConverter.GetBytes(packInfo.RouteId)); - memoryStream.Seek(0, SeekOrigin.Begin); - packInfo.MemoryStream = memoryStream; + _messageHead.AsMemory().CopyTo( memoryOwner.Memory.Slice(0, Packet.InnerPacketHeadLength)); return true; } catch (Exception e) @@ -151,69 +134,50 @@ public sealed class InnerPacketParser : APacketParser return false; } } - + return false; } - - public override APackInfo UnPack(MemoryStream memoryStream) + + public override bool UnPack(IMemoryOwner memoryOwner, out APackInfo packInfo) { - InnerPackInfo packInfo = null; - + packInfo = null; + try { - if (memoryStream == null || memoryStream.Length < Packet.InnerPacketHeadLength) - { - return null; - } - - _ = memoryStream.Read(_messageHead, 0, Packet.InnerPacketHeadLength); - _messagePacketLength = BitConverter.ToInt32(_messageHead, 0); + var memorySpan = memoryOwner.Memory.Span; + if (memorySpan.Length < Packet.InnerPacketHeadLength) + { + return false; + } + + _messagePacketLength = BitConverter.ToInt32(memorySpan); + if (_messagePacketLength > Packet.PacketBodyMaxLength) { throw new ScanException($"The received information exceeds the maximum limit = {_messagePacketLength}"); } - - packInfo = InnerPackInfo.Create(); - packInfo.ProtocolCode = BitConverter.ToUInt32(_messageHead, Packet.PacketLength); - packInfo.RpcId = BitConverter.ToUInt32(_messageHead, Packet.OuterPacketRpcIdLocation); - packInfo.RouteId = BitConverter.ToInt64(_messageHead, Packet.InnerPacketRouteRouteIdLocation); - - if (memoryStream.Length < _messagePacketLength) - { - return null; - } - - if (_messagePacketLength <= 0) - { - return packInfo; - } - var outMemoryStream = MemoryStreamHelper.GetRecyclableMemoryStream(); - memoryStream.WriteTo(outMemoryStream); - outMemoryStream.Seek(0, SeekOrigin.Begin); - packInfo.MemoryStream = outMemoryStream; - return packInfo; + packInfo = InnerPackInfo.Create(memoryOwner); + packInfo.MessagePacketLength = _messagePacketLength; + packInfo.ProtocolCode = BitConverter.ToUInt32(memorySpan[Packet.PacketLength..]); + packInfo.RpcId = BitConverter.ToUInt32(memorySpan[Packet.OuterPacketRpcIdLocation..]); + packInfo.RouteId = BitConverter.ToInt64(memorySpan[Packet.InnerPacketRouteRouteIdLocation..]); + + if (memorySpan.Length < _messagePacketLength) + { + return false; + } + + return _messagePacketLength >= 0; } catch (Exception e) { - packInfo?.Dispose(); - Log.Error(e); - return null; + Console.WriteLine(e); + throw; } } - - public static void Serialize(object message, MemoryStream stream) - { - if (message is IBsonMessage) - { - MongoHelper.Instance.SerializeTo(message, stream); - return; - } - ProtoBufHelper.ToStream(message, stream); - } - public static MemoryStream Pack(uint rpcId, long routeId, MemoryStream memoryStream) { memoryStream.Seek(Packet.InnerPacketRpcIdLocation, SeekOrigin.Begin); @@ -233,7 +197,15 @@ public sealed class InnerPacketParser : APacketParser if (message != null) { - Serialize(message, memoryStream); + if (message is IBsonMessage) + { + MongoHelper.Instance.SerializeTo(message, memoryStream); + } + else + { + ProtoBufHelper.ToStream(message, memoryStream); + } + opCode = MessageDispatcherSystem.Instance.GetOpCode(message.GetType()); packetBodyCount = (int)(memoryStream.Position - Packet.InnerPacketHeadLength); } @@ -255,7 +227,6 @@ public sealed class InnerPacketParser : APacketParser public override void Dispose() { _messagePacketLength = 0; - Array.Clear(_messageHead, 0, _messageHead.Length); base.Dispose(); } } diff --git a/Assets/GameScripts/DotNet/Core/Network/PacketParser/Interface/APackInfo.cs b/Assets/GameScripts/DotNet/Core/Network/PacketParser/Interface/APackInfo.cs index dd95008e..3f2bee72 100644 --- a/Assets/GameScripts/DotNet/Core/Network/PacketParser/Interface/APackInfo.cs +++ b/Assets/GameScripts/DotNet/Core/Network/PacketParser/Interface/APackInfo.cs @@ -1,7 +1,6 @@ using System; +using System.Buffers; using System.IO; -#pragma warning disable CS8625 -#pragma warning disable CS8618 namespace TEngine.Core.Network { @@ -11,17 +10,34 @@ namespace TEngine.Core.Network public long RouteId; public uint ProtocolCode; public long RouteTypeCode; - public MemoryStream MemoryStream; + public int MessagePacketLength; + public IMemoryOwner MemoryOwner; + public bool IsDisposed; + public static T Rent() where T : APackInfo + { + var aPackInfo = Pool.Rent(); + aPackInfo.IsDisposed = false; + return aPackInfo; + } + public abstract object Deserialize(Type messageType); - + public abstract MemoryStream CreateMemoryStream(); public virtual void Dispose() { + if (IsDisposed) + { + return; + } + RpcId = 0; RouteId = 0; ProtocolCode = 0; RouteTypeCode = 0; - MemoryStream = null; + MessagePacketLength = 0; + MemoryOwner.Dispose(); + MemoryOwner = null; + IsDisposed = true; } } } \ No newline at end of file diff --git a/Assets/GameScripts/DotNet/Core/Network/PacketParser/Interface/APacketParser.cs b/Assets/GameScripts/DotNet/Core/Network/PacketParser/Interface/APacketParser.cs index 6202565b..ba8973ff 100644 --- a/Assets/GameScripts/DotNet/Core/Network/PacketParser/Interface/APacketParser.cs +++ b/Assets/GameScripts/DotNet/Core/Network/PacketParser/Interface/APacketParser.cs @@ -1,12 +1,13 @@ using System; +using System.Buffers; using System.IO; using TEngine.DataStructure; -using TEngine.Core; namespace TEngine.Core.Network { public abstract class APacketParser : IDisposable { + protected MemoryPool MemoryPool; protected bool IsDisposed { get; private set; } public static APacketParser CreatePacketParser(NetworkTarget networkTarget) @@ -17,8 +18,8 @@ namespace TEngine.Core.Network { #if TENGINE_NET return new InnerPacketParser(); - #else - return null; +#else + throw new NotSupportedException($"PacketParserHelper Create NotSupport {networkTarget}"); #endif } case NetworkTarget.Outer: @@ -33,11 +34,11 @@ namespace TEngine.Core.Network } public abstract bool UnPack(CircularBuffer buffer, out APackInfo packInfo); - public abstract APackInfo UnPack(MemoryStream memoryStream); - + public abstract bool UnPack(IMemoryOwner memoryOwner, out APackInfo packInfo); public virtual void Dispose() { IsDisposed = true; + MemoryPool.Dispose(); } } } \ No newline at end of file diff --git a/Assets/GameScripts/DotNet/Core/Network/PacketParser/OuterPacketParser.cs b/Assets/GameScripts/DotNet/Core/Network/PacketParser/OuterPacketParser.cs index 31030c0c..1e5a9203 100644 --- a/Assets/GameScripts/DotNet/Core/Network/PacketParser/OuterPacketParser.cs +++ b/Assets/GameScripts/DotNet/Core/Network/PacketParser/OuterPacketParser.cs @@ -1,42 +1,39 @@ using System; +using System.Buffers; using System.IO; using TEngine.DataStructure; -using TEngine.Core; -#pragma warning disable CS8603 -#pragma warning disable CS8600 -#pragma warning disable CS8625 +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract namespace TEngine.Core.Network { public sealed class OuterPackInfo : APackInfo { - public static OuterPackInfo Create() + public static OuterPackInfo Create(IMemoryOwner memoryOwner) { - return Pool.Rent(); - } - - public static OuterPackInfo Create(uint rpcId, uint protocolCode, long routeTypeCode) - { - var outerPackInfo = Pool.Rent(); - outerPackInfo.RpcId = rpcId; - outerPackInfo.ProtocolCode = protocolCode; - outerPackInfo.RouteTypeCode = routeTypeCode; + var outerPackInfo = Rent();; + outerPackInfo.MemoryOwner = memoryOwner; return outerPackInfo; } + public override MemoryStream CreateMemoryStream() + { + var recyclableMemoryStream = MemoryStreamHelper.GetRecyclableMemoryStream(); + recyclableMemoryStream.Write(MemoryOwner.Memory.Span.Slice(0, Packet.InnerPacketHeadLength + MessagePacketLength)); + recyclableMemoryStream.Seek(0, SeekOrigin.Begin); + return recyclableMemoryStream; + } + public override void Dispose() { base.Dispose(); Pool.Return(this); } - + public override object Deserialize(Type messageType) { - using (MemoryStream) - { - MemoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin); - return ProtoBufHelper.FromStream(messageType, MemoryStream); - } + var memoryOwnerMemory = MemoryOwner.Memory; + var memory = memoryOwnerMemory.Slice(Packet.OuterPacketHeadLength, MessagePacketLength); + return ProtoBufHelper.FromMemory(messageType, memory); } } @@ -49,6 +46,11 @@ namespace TEngine.Core.Network private bool _isUnPackHead = true; private readonly byte[] _messageHead = new byte[Packet.OuterPacketHeadLength]; + public OuterPacketParser() + { + MemoryPool = MemoryPool.Shared; + } + public override bool UnPack(CircularBuffer buffer, out APackInfo packInfo) { packInfo = null; @@ -84,26 +86,18 @@ namespace TEngine.Core.Network } _isUnPackHead = true; - packInfo = OuterPackInfo.Create(_rpcId, _protocolCode, _routeTypeCode); - - if (_messagePacketLength <= 0) - { - return true; - } - - var memoryStream = MemoryStreamHelper.GetRecyclableMemoryStream(); + // 创建消息包 + var memoryOwner = MemoryPool.Rent(Packet.OuterPacketMaxLength); + packInfo = OuterPackInfo.Create(memoryOwner); + packInfo.RpcId = _rpcId; + packInfo.ProtocolCode = _protocolCode; + packInfo.RouteTypeCode = _routeTypeCode; + packInfo.MessagePacketLength = _messagePacketLength; // 写入消息体的信息到内存中 - memoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin); - buffer.Read(memoryStream, _messagePacketLength); + buffer.Read(memoryOwner.Memory.Slice(Packet.OuterPacketHeadLength), _messagePacketLength); // 写入消息头的信息到内存中 - memoryStream.Seek(0, SeekOrigin.Begin); - memoryStream.Write(BitConverter.GetBytes(_messagePacketLength)); - memoryStream.Write(BitConverter.GetBytes(_protocolCode)); - memoryStream.Write(BitConverter.GetBytes(_rpcId)); - memoryStream.Write(BitConverter.GetBytes(_routeTypeCode)); - memoryStream.Seek(0, SeekOrigin.Begin); - packInfo.MemoryStream = memoryStream; - return true; + _messageHead.AsMemory().CopyTo(memoryOwner.Memory.Slice(0, Packet.OuterPacketHeadLength)); + return _messagePacketLength > 0; } catch (Exception e) { @@ -116,60 +110,44 @@ namespace TEngine.Core.Network return false; } - public override APackInfo UnPack(MemoryStream memoryStream) + public override bool UnPack(IMemoryOwner memoryOwner, out APackInfo packInfo) { - OuterPackInfo packInfo = null; - + packInfo = null; + var memory = memoryOwner.Memory; + try { - if (memoryStream == null) + if (memory.Length < Packet.OuterPacketHeadLength) { - return null; + return false; } - if (memoryStream.Length < Packet.OuterPacketHeadLength) - { - return null; - } - - _ = memoryStream.Read(_messageHead, 0, Packet.OuterPacketHeadLength); - _messagePacketLength = BitConverter.ToInt32(_messageHead, 0); + var memorySpan = memory.Span; + _messagePacketLength = BitConverter.ToInt32(memorySpan); #if TENGINE_NET if (_messagePacketLength > Packet.PacketBodyMaxLength) { throw new ScanException($"The received information exceeds the maximum limit = {_messagePacketLength}"); } #endif - packInfo = OuterPackInfo.Create(); - if (packInfo == null) - { - return null; - } - packInfo.ProtocolCode = BitConverter.ToUInt32(_messageHead, Packet.PacketLength); - packInfo.RpcId = BitConverter.ToUInt32(_messageHead, Packet.OuterPacketRpcIdLocation); - packInfo.RouteTypeCode = BitConverter.ToUInt16(_messageHead, Packet.OuterPacketRouteTypeOpCodeLocation); + packInfo = OuterPackInfo.Create(memoryOwner); + packInfo.MessagePacketLength = _messagePacketLength; + packInfo.ProtocolCode = BitConverter.ToUInt32(memorySpan.Slice(Packet.PacketLength)); + packInfo.RpcId = BitConverter.ToUInt32(memorySpan.Slice(Packet.OuterPacketRpcIdLocation)); + packInfo.RouteTypeCode = BitConverter.ToUInt16(memorySpan.Slice(Packet.OuterPacketRouteTypeOpCodeLocation)); - if (memoryStream.Length < _messagePacketLength) + if (memory.Length < _messagePacketLength) { - return null; + return false; } - if (_messagePacketLength <= 0) - { - return packInfo; - } - - var outMemoryStream = MemoryStreamHelper.GetRecyclableMemoryStream(); - memoryStream.WriteTo(outMemoryStream); - outMemoryStream.Seek(0, SeekOrigin.Begin); - packInfo.MemoryStream = outMemoryStream; - return packInfo; + return _messagePacketLength >= 0; } catch (Exception e) { packInfo?.Dispose(); Log.Error(e); - return null; + return false; } } diff --git a/Assets/GameScripts/DotNet/Core/Network/PacketParser/Packet.cs b/Assets/GameScripts/DotNet/Core/Network/PacketParser/Packet.cs index 044d50b5..5809c4cc 100644 --- a/Assets/GameScripts/DotNet/Core/Network/PacketParser/Packet.cs +++ b/Assets/GameScripts/DotNet/Core/Network/PacketParser/Packet.cs @@ -45,7 +45,11 @@ namespace TEngine.Core.Network /// /// 外网消息总长度(消息体最大长度 + 外网消息头长度) /// - public const int PacketMaxLength = OuterPacketHeadLength + PacketBodyMaxLength; + public const int OuterPacketMaxLength = OuterPacketHeadLength + PacketBodyMaxLength; + /// + /// 内网消息总长度(消息体最大长度 + 外网消息头长度) + /// + public const int InnerPacketMaxLength = InnerPacketHeadLength + PacketBodyMaxLength; /// /// 外网消息头长度(消息体长度在消息头占用的长度 + 协议编号在消息头占用的长度 + RPCId长度 + RouteTypeOpCode长度) /// diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/arm64_v8a/libkcp.so b/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/arm64_v8a/libkcp.so deleted file mode 100644 index 966dd3c08b1c2badd3a2d9824fa6d544a6dc4c03..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32096 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 PxABL#hH1SQrT>2bq&_k3 diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/arm64_v8a/libkcp.so.meta b/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/arm64_v8a/libkcp.so.meta deleted file mode 100644 index e9cbfd0e..00000000 --- a/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/arm64_v8a/libkcp.so.meta +++ /dev/null @@ -1,33 +0,0 @@ -fileFormatVersion: 2 -guid: 95cef76c7e8fc924594a2c535022c037 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Android: Android - second: - enabled: 1 - settings: - CPU: ARM64 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/armeabi-v7a/libkcp.so b/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/armeabi-v7a/libkcp.so deleted file mode 100644 index b12f7e3a8e93f9998abafc4895b64e11becddaa0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68152 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 diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/x86/libkcp.so.meta b/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/x86/libkcp.so.meta deleted file mode 100644 index 5d585f6e..00000000 --- a/Assets/GameScripts/ThirdParty/KCP/Plugins/Android/x86/libkcp.so.meta +++ /dev/null @@ -1,33 +0,0 @@ -fileFormatVersion: 2 -guid: 618bbca818d51974ea5aaf2c99cbeb25 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Android: Android - second: - enabled: 1 - settings: - CPU: x86 - - first: - Any: - second: - enabled: 0 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins/IOS.meta b/Assets/GameScripts/ThirdParty/KCP/Plugins/IOS.meta deleted file mode 100644 index 4ae2d49c..00000000 --- a/Assets/GameScripts/ThirdParty/KCP/Plugins/IOS.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b5ee1b6d2f25b4a889ae7286f23a7f93 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins/IOS/libkcp.a b/Assets/GameScripts/ThirdParty/KCP/Plugins/IOS/libkcp.a deleted file mode 100644 index abd42fd1ef70893d241c77dd72854b28d2d7c745..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43328 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 diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins/x86_64.meta b/Assets/GameScripts/ThirdParty/KCP/Plugins/x86_64.meta deleted file mode 100644 index 2504b328..00000000 --- a/Assets/GameScripts/ThirdParty/KCP/Plugins/x86_64.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bd47571478aff4eb6a9fa70ca39031cf -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins/x86_64/kcp.dll b/Assets/GameScripts/ThirdParty/KCP/Plugins/x86_64/kcp.dll deleted file mode 100644 index ce18e81f1515abc702361ee7e25fec5c5d3281f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 146432 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 L|GfS!YvBI?uDJI8 diff --git a/Assets/GameScripts/ThirdParty/KCP/Plugins/x86_64/kcp.dll.meta b/Assets/GameScripts/ThirdParty/KCP/Plugins/x86_64/kcp.dll.meta deleted file mode 100644 index cb81e95f..00000000 --- a/Assets/GameScripts/ThirdParty/KCP/Plugins/x86_64/kcp.dll.meta +++ /dev/null @@ -1,52 +0,0 @@ -fileFormatVersion: 2 -guid: 07d3660260d3a4e46944eeb95bb82783 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - CPU: x86_64 - DefaultValueInitialized: true - - first: - Standalone: Linux64 - second: - enabled: 1 - settings: - CPU: x86_64 - - first: - Standalone: OSXUniversal - second: - enabled: 1 - settings: - CPU: x86_64 - - first: - Standalone: Win - second: - enabled: 0 - settings: - CPU: None - - first: - Standalone: Win64 - second: - enabled: 1 - settings: - CPU: x86_64 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/GameScripts/ThirdParty/Kcp.meta b/Assets/GameScripts/ThirdParty/Kcp.meta deleted file mode 100644 index d92dcfe3..00000000 --- a/Assets/GameScripts/ThirdParty/Kcp.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 96533933eb80840fea1fde1774562a3d -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/DotNet/ThirdParty/KCPLibrary/kcp.dll b/DotNet/ThirdParty/KCPLibrary/kcp.dll deleted file mode 100644 index cf4dbf638b93e8ad4c3c8a14138191991bb91d05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 146432 zcmeFa3wTsTwm;gPPA8p^u$xCP2uLf9MgtlNYGMcJopi`<(+xpDQBiP!fQo`-HxEHb z*okJRXvH(*jLu8OnKR>=$I%%b2%t=N0(tNZC^In58Bs^wv2~21A)v7DZ`I!29Uh+X zo_oLl|K9uEd|$fWRjXF5TD5A`s@lQ3Hd$;IizOBRx^A&F!=*nj|NZZO99D~E;OOlG zEw5(mzr5KR*nj!V#rM~^mMvepX!(5)x#r*Z@WV@G*LN1WmWLj8-T$!5H*JRNp`{BJ zUYnhr={Bo=;KrKK*WNKI5dXiqWO#5a!Z(*(7R={vZtz!dpK|2}3%ENx=;H2W!K--s z$l!Rm*WNKQ@F?83T*HIcad(vIz8f&Yqj~tY`{ysFw$ATaRk_8o;PG_JxZJ0|6Hn{0 zT;Up!GVn6Xz3Ax2My#t4u9N#~5o`EUES5ALm2@qe5J^bIpUpB4S&c$*=fbcNQ#&}t zvJ1I=LsKkyRCrm6rr50O`g-{u)*|Ld?ar$#mPwheJN=@(IxFMp4pW%@mP=%a>0?+=31nxtB{Ro zt=(JX;!a5|9I4&wCAZz1y2?(DV;&qd{z)!ymuQkvld5u@N;E`5HzUKFl!5J~JVW)a z!idD?xCen%H~*5tL96;Moj*~A5K)HQ+jvMTaP?PW8$tFBq1?&#xL z+%!$p9U4zoh(Q7gD7u#T6soom{?#2sHAXji595?(xDwkn;||Q|JEXdgkD^$B{p>iL z^1@DusA_e<&%XAlYuyDtb)!2MHTl$l+vO|vFB9tDa3ILaO3K-rlDhb)$hswUS(nH@ z3#f}beC)y8fVvFSbUpJg@a0E6l_k=Ah5A`8ltq0YnPooJ=g#w~zjZfK%V?k$u7t=c zpZW{8Nj}1p)6lHQ+CvKBkG;mdQO$`WZp1{jT=2QH&&#;DQc{+30sZE8!OUz^Nkf5DZ2?6XG@b*&;NR>EckJTv4~H`Se@a7|`&>eXnqY*lO| ziyqQ!QFtds-n3d)WT6Oon(4>ZqEt#&wM-`T7%knM3K%+gYt>GKlM6~RCoPq*0!Q&MRTYT|JfO#wT0QD&b z@$g}b66s*nge~>%TC~<(yzxpR^u(~^%d6?sWp;Mm{LaZP)~T5Sf<2Eu|kOsiKR&F zR(P$FIzdvGBf@0UNDnJ7Qf?Jl%t)tRxmYio$83`N-ItN3mO9%@hfb%q)LTdT)JI(a zK`nLbWkXq6u38F4_GkesD^N=(qVggniurAxGN;hE1QU-bM7e?Rg9Qzd*Ado*X&UAz zQG0RCl2C@oW?7=AZLt*gXA>6ndz_RdRv>wLg!(05_CBmrd2DJ4Cgia8DJ3Wi-d1i= zr%ViIIlF&Ipn296tolw^w5n4|^s?EkYzfvq7n?FsWI>B3+U|3^sFYCF5guw)Z=YBi z&bm3aNa;hj4@hBT+cpu&%WZzPn^~TVXU}gr)F)a~0p!pOUgC!0hl_*_ze81wuRETO zbq=iSPyGlndOcq!00Wyk5n!}WDMFPN(RNUsTEIRP^FQ*b>s&r{#YjTil)P{-*EV&W z=ouh9xgPl>g|Azd&~UN&Acey@j=QXIvhRnZ&BpTFtI+yqm2W~`;vp7!ypQb?9<&u+;CbOtQoYP58Lle)n1T@9beIRVCu<*t<-@w0vUcWERrd)QPbi*g2FC6{T4KwOi;w|gaa zP zWe)MsKYgCh+RJ=I5Jo1SQ2Loqt#K=BeAWPa)!mGg8Yl7^$!1=uZWob;I9HrA_wIA0 z-F^FnEz?tkEut-Y++k}$z$$FX;C}jvw(j%JAUSvy6P@LSZ;_x;&JOu#B@M7W1ahcohxkoJA4w@!Dh5e!t}C$y1>0Spe}LG^Use25HmYq!y38PT_vLR z6jAvo7aqT@T-b8|0Qepe;Ja@KeD`BH-7-BLK`|}*j>Fa=M&EZJO0-5laF`MQpa?4u z_`qg}^HB~v7Mx9{KhtN^AUl*$e1<>lA4=6Aj>3+9{(-h0ipoaihA%7O8|fE=*FIBvc#|| zs1;ZUtP-0JFW8{{4_PUYMIrv&=}7J*#!moatDJ{PChkBZ7Qg3g=v9)XXa-TUL6#Qu zw8?4ZY_>a=>SK2g^{IC|y|rg<6B=Yb(<%ey`TK>&jU2`qShn*;=A~DLk9_U`sk^5RvH=X;aI_`B;b2 zXMJoyGbeW*4rhf4*5-L1VUek<63Qy8L|bQZWNLpit1+_e&z*^N*#U%PFZE5OBs-2@wZbuaJ&w3lW6NL z;Ar!+G(RCnQX=jc)|Ph6)*=goxabTyvB(q=%)7t1`oPV< z=+SlBITk}%#wr8gB&TOuEm&^F{Qa0_c|LXk6yl<+oset02O%G@KV4{O0}nA)45xf$ zf*p-S0Uzd<3pE`@P1~JjLky(>LRpEYELTulP?+&eiyrYPZz7NI_$&DR6Lr+nz9P-0 zd-|522HDhPV%vLAioRn@c7Fi6FEI@fLVY^wMe7|XXOXKRg8PcO)V<;sb2m{DPR+PA zJhXu_h}cbJrC=9gRkN;<%t$jI5)kS0@Y2g$(6j|jON>#~$+p*AhmiUkid1(H;6^vX zS;)$FFY3fbAfPc-=iT$v?}iC{VCc}D1dY@kvMdiDzSPf`P>6eQHwA_RKQyAAa0 zg`Z}_4jNMv9va&?!wRsC24l@X!ggbEp@nE|73IXj)&2cbx{l^%3Jo`)ywO~(JSN_h zJiMH*<_D&uC2Eygg5MJRUjMdYKjaf#zRI)4x#|khGkNtW@MdDjIiA(-0JE;jmTkIN z1l~f7CdSH~`B*YBU7q|NDg_ty`Bk`2xKT5TAiQzIU#jCs$Ps_^dFv;|7fE-)X z@`i{gly?*!KKU7OS)b_XTp@rz`^trvIhJDhLkEkfik3q2{yX>>=HpZl;LMO<*e!Y_Ef61A?uy3R2U0D7LkC^DUNh^)mtX zx1d^<8&oS@kSyvxmWYio`|ht$vTzrzjs=MEvp&cbrl#;7N!ezI#WVbBjph&6xU^?t zXdV1DPYTZ@S>&KZvOORM(~fY^m_t%Jt(tcc^+Gv{6e%1a)z};Qcd0fB@{*S~zL7U6 z74FkU4?uj~E`lj8DK#8kmD9WcrPb+6#O;^C1C+L?;zS^K)rjWCAvAQ6^#ivCJ))u)Vdyo3i~TO&(k-G)bY>JcL{qU>=+IpKM?!pAV=(V zQ-Rnkv2=rONxtvDsd&Z6GL*8|kR`sUxIkjfM2>{S`VdC5K@SbSP(#>Xj-|~MQ>exB z)QggS{M_L+^ru{PTKJa4PMO{K6BP~T2nLLc;b?QOr>Gxr284~Qr%NtnQZ9Nuka@@T zQ}5}~;%N((C-|jp_Bdr#u0;kb10!t-eG2^}S9vO=?d0A#X(GIDAF1SWXFwr1OS~O| ztb`#7u#ZdxyTs;)49G$Oj^G1uwB1M(S`zOS?-A$R z-O4&7EV`>s9>W~>cZh6CZs8}`p{9xK;c+py9sy4lHvAQB_*t7U+J{-WI0?Vsvn%u| ziZ5&UL}>gYGI_e!4U;evSMj-q*_CXkY(e2CMDSkP@PXM&kS2;STN(*Uk}QPL1Tfke z7-VPt>}-I27Q|{b94pf}DSU_5&-QDRaR@>|CIoDnZRt3JMjUKqt~@ru3P!wBxNOvZKY4$UA?4Fz-cQQkhXW}|y4)@+E8{hU+NJOgLZn%t7?(dJ zcJcbwUaY>8W8)R@`UpSYw!U!}tM6Cm)@Sen-r;`<-`{j#?)?7V(Z4>%j&t}hYT!b0 z4py08QK7_X%GEr#DP|fO9zQ38gJ-ZmLXkLPQEMPI)htk7>7shoS9ta6D;>NQj2zXB zMF*n^wrGrMoBRCr&wKkFIGa#DE>KoGuwL{97=-Q5R$>AWm%s#wRiL$S_Aew%0M9s5 zP^=ypXFCPr+`0F*Dm%YGlYn53yNbBa?8N3ek9O8Bp+1dQ^;14Ro)JR*KaoAawvce^ zW7Q6@Dd?wm3Cf=-BLBGP`PwH0J``=cr1>2{)2g!o;T%DEF#2H#{-FV4^ZTg2`*+j^ zdz|X@le$JNhte?!_nvsPq~=NLe^Q2WG^n-U%pusI%Ogc7g8b|+Xu<2B|2N6DKfqeG zUm!JL`-;-U{IA=~b5RUBwtZ?4c@Ov*PA;Z^ztCna&ChN(S;I#-O^QAJtEX z)~G=jp0ol&Hr3%dwSIuO6Mh^5eGuwTKnMUm9t|w|(Jd)>xYG z|uxJ3~)3PEelgW4a|Sv53!=(p5ntR2rtI5Ajx>tUT*nWkdMnf)`! zhU&ekRDOisC8;|pl?0Y^i)nXKwcnJ=>yOVP*S(28Nb1uh*CfKm`E#c_JrK%l7s(I- zlHW|6Mzfau=p;IXek^-Z&rw}pn+A#Qs#uyx$$QG#bm$`Xcn*oGf95KO7)~85s^UyP z>+F8uJzY;!zmJKFZQ{ISm{`+@hQsS@>hvOrlJ|=Q z@@};%lkNoDwg?S0liTfn1ZXU^*N~|`B2UxyLSWa<+VL|AQDD4#L_Rrw4o6#eH&{p{ zbhUP;k==##4MutmrJufwD*Xa{5);efouD`E)ebn|tJg!5wV_Z06AMs^EV5f-9oh&a zq0!s`Yuio*z|kaT3$W}oR3_?&bbHPz94Hciv6OQ}anQH~T)4!0TeqRF7OewSZNivy zyzqs@+jNTAkMvmq@cL|{uop!N=C#Z!u#9mg)xdJAd&t1SfKUB{- zF&S#Gqu{$ZSQ6_0fD*tOgDU-iwi!FnWYQ1%Cyh@9e7uyRTSGTu>?WXC;bAH^2x(G7 zFQ`gugP4YfPts6=oeYfU(R0?KS#WB*qT52=M2pw z0_c3M6R*YorLa@ac?m~mkWBQPpTeW(yvTzc+cQ!vG_Obw8T(_3gC-Gz$;U<8E&`{D(S=!NZ6_tNveH3hD-{RUx{F?wZD!G=>9N@R_#ypQV0_b zeuk8G`+bO^X4~y|!$)J;ZeM8nnn5iV>A?tzHTO`-_Eam)f@D0)-W{Wg1F5cfBt+Zn z=6ECu2E2e!r{Pm}6#VVwtb_OSUNo;gLIr3` z4(Q9NU+8C^+0P>cAG2Re(W?FVFR5=0_%-^r9zLUQs_Bb^OMRS%|WoCg}yb7qcKFwj7LY>=qEryHHwG2w-`$3F)> zkmP9%$&#`#7rhGR>N(eNpvoa8lsomDp$OsN?|SlE41YN2GQwIh(#l;ZhE?adODcrF zu-qvXMx||}>mfT+X$%5|$)+U17sUuZL?A%4kff849PHH;#LT#-wVB3|=qQ{$9K07Z zpgErQJZKPucKJeyrH(D&Z?t+A8D3#i`tM%i?23)oa_xHccvW69XaS0Fic zLL`>1T{qWadD+T~QW-3KlK?&zzGsa3;&qJy(DjiJ6&kFay^jadwaXD3`?z0u?Ie=4 zOhlWJR33zciN3@QJ}$d+iFRCmc8VA|778tf4`iZAxsv#MEF+1 z04dM5aUfP#zLyrZ*q=h-hRz+pfkp7OHrm%CtgV3jp`C(oWMW{brp@Dl4B+c}6pww> zgrNjmH0B5Ouy&FUMJ?=DXpwTty7B?-2nGQonb+`E$PFlo4`_Zsh^`aVH&VEmhvjR5 z<-%%Vsl5|?Mp8QT6T*7?8R8$RJq`INNG^f`oHqM0q**z}0m3$*0&)a?I2}MVh&Bfy zRa6(-x3xj2S|!cT{umwz9{)j(ZBJb>*%XK7HsgQ_*~Hw?%s_sNuvHu?g{S9Awk~+n zq;OVkAe^-aJjm_$9FlX{tyuw2ba^IhMr_f5Cju)Gr6n)+cHvXx5syynpJVrE= z3A#*!o5IO7x7EOR(=qK&KyBe+;AKGlTcLF6iJUa*CP$@_r*_g;V1AaSV{&T!;ZT?azsN#SRX(u&Xaa*kRVKM^^X!d?R$6hi z^!D;@W2VylG{zxbc7#!O=y_%5d_&n55HPi!WE;-HNMWb&f{#UU@Zw{K#k!t{<%LVc zy3g-_c%k3N_OhPBPCBqR*ml&6h|(TLbVa)>%A*GL;tvl=-@*3_VSYnK##*Ch?;lF%y`Ngl2% zT5oO*-NEc1y$d?%aJ1Wx!9z5z+W!Kd*xTxoib@;cJEhxyv`^sLyjW zgdHDhavv`_9?Dj-pGT@!9rX+x8reMB2#`)n+2!Q&Kw+fVUJDWbJacPse)>!9@9wyr zwD#3lR?C68GJ)-_j>!tup zfsL9^*m`RgOeJm`7*H+PCsg}X35K3k16z@fG-TLvYbMgFk?3obGFyeMnboSJbrZ`( z+0s->PgAL!Hx=n=R4!g`zbdI1vX-Wxtgq3Vl5Bqq_#kf@rL*F#nho;cmRlVNHcAe& zY9n{6*}mB{4{j+<<+Z0mQ;{hFNMTE6qXS6129xMYH@UEX} z?P--fhiV2+4QHkJJ)Ob^5gcWcGU=V;7%^TOl1KpWWe`;~V_`;~5&KflwTe<)~+CNlgS8O-X0 zCvGuED>+`MGZX)}x$twB7eC*bxBJZc4E#@b;pa{-e(sxx_@-J^1oz)I8}1JyhWo;C za?h++YYq45&4&A2#BhIh9IjLsC2*y>7IOS`n&B9IP*#Dj2g4FN@XqldJLZqZ>=o?C zKlE}k`m3nFN1fi7iTgx4eCs!6m_Ee05^<&vao$9n=|kMSM4ahc8py1r$^seWAhg*C zk%Lgg2ythL_4w|y>n*$cR<>4e0tPO`*N4E@hlH;W311(68+?6e;_E{bUmu$I`tW~_ zuLT#y*JB@Eh%btB85l|6i{j457sZ`}ug5;@k1q-(@kOEj_!9oJkE4vZLz3Qz6tQhv z0m@GOC#UQtto@iTDKuY}r1T&|Eht8K{7L*8lr4a=o&71BGOT!npQrJeCM>^bj*QSIBSa2Sm=Piep_h#iIYe(ph#Z8vj1V~p z9XCSUSz;xIVrfnATilfiu)|XRAwP`HoW4Ol65&eGoV`&&z69J_0>FY3X{m#RK@NzS z!Ti=BY@edt>GD$HYHMuhIpZT-Ejop(Gk8^kGcf45RM$;NK>RY{YX3Y+sGY9^@2c znDaR^MPbkYr21Ja$?NCuPmB{?ew5qT@7CD0KCO?~76wLpk zw>-64Wa}lN;cw^*ZF34}n^WZR2+9g@Bz97=^)lay)BtQoH~boT5O7dH`3VBb+7nKT zQ2%d+H_Iwtg5)fc&kFoDX!MWhT~G!;woa~l%rd{`q2nQ_6DCFJs87BOy9PS+)84q8 zi?ai_BNj{aem&=Bh-QHkPLc0L{kDCmNc$R6fS*-(VOYdwo`99wejhBI{Wjc4ftCU( z&{|;G*K>yCqtdg;t+#jIfVm9y+V4@bpRL3q@J09c;fGa(t&{oo8ok;;F}}UjtD4n5 zHY-(B-gU`7SZ+aITT~9hutiFluQe5Rv&&uNgP_<`GYn;%rNzEhXJ`PtS>(;a26AHg-w40z-F1R4XK0E7_a%du!0POVqpcb~eOwTG&8r zh4(uUp5unT@a_UXdk}^*HSoU&Q&oPx4)Md-U+6jGu7O~KHik%~>h92%a2;!_gpJxK z@l74yW4?{SPwauKjX=6K2r|^Udte6Cp~CnUn#y9In1R^DrkLXDJ42b;B2=Rtz)vE{ z*t<_lMv)$WQR7U=!7wtYE9O)%Ls^}h8iMBDHQr_a?r>P8uLP}%{GjkA35t0jevo9F zj=i!!PrC-=6LZBb>$N!L;mDRJ!Gs01X7h7iFZ3cu2?sC=;PXL$7qcS%mz+;`Fj&yh zTsZM-%$y75H}DH#%VGaEtN9lYUfKhh#VI`gIohxG3lB%Dg?SN^3$Ju`KSsiu7&RHCy&yZJa9+g$=^S{EH7z0rXXNZ7?=6pfc!FjkyPXCCi@m zXKYkX>2e`WxPjVVF-=&u7m+yUC_JnU#za60Y$L<=U-O!dl7-G*Z8zp!e0myl1_o1n zBHMWz8f{;xZzg|_>&2Bx?;gR%FGQyXbeyQ?6kZ8#nY|yetWUd(Ca$GQ}T4C8wA3oHA~(%u=@W%B^vI(V!w6;Dp2}#Sk{Dd zzW+YJ?$BaL09XUt?WYhy?Lp&`u0bBMn3_Re56k}GO#|Io8r`i{vX3B)yvDGY;{yAt zaL((fhbwfmek4Kdvwbs^dfHK=nL)a}4as^dbau<%;4P7n8gGd!WQ_4;qc$T~Y!rrW zDP`Y_im0*S6#)&DxoXvw-&qDsX%zr$yaE5ct8)bcl=DllI&;o z`l{g#+R5e( zG$4LhtT&Scspr%II%70Lw_`m-Na?#HG~O33OGhps=O}a*+RtZmoDTz*cxgSypDcG7 z%(4J)1;P77J#Sl5cBlG1A9pX})X<95tNW*7_+XxkBbO6ntbq3j_kRjM(I8lLhyRI< zysNRy;1jQMA8p0SR0HSivuRU4k0wOFB`!J7z==u#b73dUukztRAI4E17)XWc7tk7? zO;A_wrCy*SI^?N9`)Rh%4yrEx3!+1sg z>N$c!{Fn&!M2&h{sGd`FFm`S|H}|V&=M`L+p43UPzXGVuC<*04IOhjcD<&2}r%-jj zMs={v#Hax>ho19Kz!8JSY8~q7r>MG+Pl%BC!r61FVzgkN3J>Wo!Z`tI0&~`)O(jrq zqQ>hU;A3ri&QoUf>51wwEI8^SWf(D|3;z1?XUGJ^qai=ebmKlB>FyX9NK`954T|Z~ z9)trjphFa_>x0E+Oh$_~mSQOm^&|xY8#l06T{hs>`$W5>xPE-ipr4t za~q5dEn3!{I6StG?}Dr#Ut?-?b6s2nPUnZn`>!_S-tD9r6~j`Bwi~q>ir%}uynb2} za%bTj3z}hCV3_@<2Qj{enefYq5pl>)*0QHy7TsJ+S-41!aOU27Ppi@8;lO|a|BogEe(inCHOxtLAi*H(K3+^f;Jp4oq9av2=C^L* z+Cgy3uzfKg!iEM<4q)xouDypWmwF+pHY`PZNT0~5{4caDJw1oGo6s=JNV%Q*0@Es_ ztTaZ`vc;<8Z+BENQ^iQ+u`~%u|%>H?d>P{wmKF_S~a;hc2*Qg;F zPF<-@L5c}Qx>2knS?p@F*e7TS@C~~@fl9$ld4uT2KqW@I45(!L@rVEoeI*V3&`Ppw z*y!$}y7MFAHj+iON5Ceich4C0-j!@|tC_OKNO=_oA||?iVy4`8L5ud6QKzKu#)!!e zSwdgpv?NFtyM$%Q^XUp)(Kr~$?|?eVrcE~C9%0n~X0k_<%=)cHN?S5zjG6KwngJHP zNtiOsl>J7^za`6j%HFP0AnVI$xkn)149*bI_0TZ zh|~~?&I6{x!{xZ=sr}_XG}x&v17>&*QrlE%QDh_EY--cXEo_JpOI)dASb`v7wl+Lo zOnZt-VDIo1j#RaO>mwr|ZoCp?8Mw~~3B$*nc?V)jGw?Oh2ErHl- z#?SOg3eAI|CSR!d`gvN*!Wd$;lMBJxGqs&FjL_Hs>7H=Lf!PC2b&+%ZIe;dSLmNiR zonaGJHg3>sD zrNtA{1@uB#CvYzUMvhqRwI84kb7?<7$GR?zxB;j`y8|^TopiTSf_7q85!Poq@aMST zb(*FP$M_wiOznBF%1w|CwFA&7(e0Z7+Ovov$f(P4nb4r&nd0qGIbJ}=>FxdLxV-Qm zew+z_Du_ERxmq5uYOHPAXHx-Thu#ey4~YpjXE08avF&`O3iQO6L+zK?-~`!8 zA8t(-HO1eT@rW4XFR#jFNC7+*wQZMswV& zeCoeaHC`DT7|$nH`x@P85(`sn+GUlAmVHGF+_SM$ApuqS*^5X$L*pFg+yb0( z=@HH;iJNdvIS1r(4|IZh$gb?wW50_x5PE(Gh*JlqZqj2vF!|9pjHPGyzZ}as(-UJk zHfW4x@i&juFEu=~^LZKbuBF2l9m)BsK@?qwu)FQt|H{prBBORCmS#&x#Dm^B?3{nF^)JO^{=> zJrYqh8THGfB=!_#*H%!R`aJo)Tdb1$5)}c*zZdb|rnrXa980J;ANnRZCnw-M1s;)r zbFRcb0;tjVQ@#bLqb~yL-inKZ`U>K|8Pt8{47X^zQ{)NwwaQnE%Bc)_jHvWw%cGQc zQpM&^b?A4WiBu~e&94?4x-e1kjKTLJFmG#}0JC+I=Z2@x#yaC?8wgWAFmS9g>CF~M zH?iyh48K_&=S7FKAWVY;wn#t~q5Up`HM6}OYM|?Mtf;D3B(m0%Cu&=;Mjx#`UA!(! zY>G~_MvmK4(^F7~C^b4I-7m#<`|?GJShvH6OPG=_LR)UEgRE{I0DxgUbk+n>5){l` zVn)#UZs4FqwG;`rXanI?F{qYGeijkgtwjx;20)Yf4H8i;H9)FXI84>b>EabaKcHHK zon3xbDhWIHz!<@=luEdjS1QF`<-kD#_8;miS4*oXCFPr744jLuelQ-wMo}bm5riTu z<@gE$U)K}92s&u6C62McMKDI7G(xL>s}yS~&o4DF#=+4`jq?RAJDiWRBs||9X9Sct zfinXtLK?vO)<}EhqDaGi3E{~nID;ZXbci~OA?ZNOz>|C24&8-y*eC47g=q~UPa(GM zX%O6^-C4a++(|%4QdT)EGVWXs!|v{Y_CyVYHL@nH_C#SYWn;EjnleDgVoi$NG`-z( zX6+6`E`S&Xv6M_4`sDw3{x>1;y@2}1XHfvoX6}&A1X3Er zHS7cekn899)IYwAB(0sp9j0vTsP?6pDC8?buMI)TWeQ4=+r3Q(v}e%~E;I2iLT2*p zBi#?o2T>P}U2&vbgQM5?a6bW7ge1S?qU)wUKB-b*O69=AI=H%WnXsjcpI-@ETEv?V z$ph(u8*J|pjlxwnNaW3y z_NIDML!Y6#2=c57*(o8#&&aR}4NOm=HZi|YS0lK6DJrN%3a%v4TS8sFMr86@Q78(7 z){hMS3|d;^&Nc72xFmKbhMTmHbS9RiO`$~=G6G%_VfkExri`)d1dxcGmP^|duSLo~ z;0sU5&~ArCw5USlt#HzEn4x9x6}rNy6kUPiIEYbR$y1Sw6FWRc60>*qhGuu*o3G+_=W{g<|^~6@ITJdjTa7} z1}e){*5p})jk72u?3@8Mcf91Tl>;%_$8ioUvOrrZu3L4ovT@<84&@!hq#nS_LrR}R zsK+f_QcTsK1XNH53-w3h9=dl#3gSidb0_`e(a$jKpoIoN0W|K_{x|?Clvd=VfHNI| zEeO<}zJ?B4X86dHbp z%@mDo1?%~oxkFENf^LNm_VV{d`ae8Z9rf`F_Gk|_Q? zk%UlBk0(pTkK}?N-YZK~^jlN}g7_NvK93-9{A_vM1;l|Wrd|fMaZQz4Gp_sRG%`wA zZc1@Yp0M#h5rSc9St-{2NOk^hXlp?k{;;MseVIE{2aOC@}s-Etw78zWyuPCo3h;Eb2E$teh}MSe$Y1(k{| z!>={=K*oawv4!xa#OC4(e1W&I#tSl0Yf9jo8LI@nU;$QWyja!H=to(-Emk@V z*e)iFX@3+G)Us|8C%Z$mzI|J|yCz9@4<>7xh?+ompJU9dxgy-#~RgMnR%F3tUcY@6o^#`E52l@&iP0_nb#{A!H}2dx)qm z(+t#OQg@#rQc(Icq}QS1?EV1J{mCdnbbFCNMAsQFXV6?*|I8-MZAKQN9?qA#|BVWG zj>y-cwK1|Azxi@5e#gsM_$>&nK~_gBL4RT{dPuTfE zpce7$nz!hYT$vM-8^jbF4YI=S4^pH-gbXBwh1Cc^s=YY1&G-gtEBM#cRsn`&D)^ip zgW8O9bX*jH+H(Q00Q#2j6d1wnYbv8%t^xa?TC8^_>`G;x9=j|7yxGY?J_spBNlC{Y zB3$qK%PooaHs74I>Y%gOfUwgqLf&c1rU0SS&uWdlFt5*u2XqLMUMvq#sEdt~=!fnXW^+Te ziAfO86myLW(2hj`rbXP&rAZV^ri6y~S{*pO18ug8?%m(oH5P@RMq&d$-{yV7j;A2k6VKEm{&9h#pF+nA;5CaEG0A zq!!%K?|ud@%3@ksx>fub`4=bi142ve2sZ_Y9Y9X9z>0kb9_mu;PCV9_+mupL7`mkP zQR{>dM1;~5ByyPy&BcmJZsbW56G;#+Ac`Sr)VSFtxNsnCw>meF@Ikj=kiAtP~4f9Oc9t`lI}Qz>nlO(r-7CIno~}K~{b;s}&Z}NOs?hR0HWK0<`Z!Yw!W_ zWQ7VJQ2$fIw^&|<@B?x+ewWBM<5!mR@VinThF=WB$H)hO`7j(e{CpVRH2i!RI^ZX? zRx20>0mro1XI(fDv;w0hJ`mqemRQ`c1mP(5hA|ZTke3g|L-6pSSU^J|Y)t`Rg&{Qd zXo@i$smPERj>$;9(MUB$gi;eDa(T6)%|?!YJt{O;|HYX65lBH@7aNm5W7eBv^8Ahe z|Cs#WH71760Q)?C*aE!)w=pjOuL2tv|3u{D-LlI2$Jyc*v1Gye+lBhq5GCFWyS6rX zO3LK%B|hOvlKo36geU(%?hN@3@6EgAMJ0F1BTMcR>VHC!^YJ(_T$p40m=8*xsG4Ru;tH^olvPAE8hzSMe7(`SW!+1~utrsLu06jn1)3O|^aUsHuQb7^_XKiS)o z6~gWu2bgVtKywGQ1s_9>43`;k?WA9E@#9uX^9@D6DmkWX1Y~ZsJ4LKNn5Y2ykptQo zR6tAlUM&ceE05s?v{61_LyUfuQjVUU(^@Z{Cls6b5#nq*ah*qMsl`~>@SqNM>$LtQ z=nVPTDssDh58Q+UzuEt zuupjWZ6jPEJigEH&5)N?L*!qN>7)K+Z+N z<4+is+%G?j@WXg{Sm|3TPr~mqc{F}&P@&U{c zP~~^A6qr<5lc36KqRL88CC0R%P$$})NJO9N3omuia895Qr_9W7#du0Dh>gJb%IVGd z=v?d*`oIHa%z#>M39fW7okVnT+uJ$`>s(M58=|1o_*6>JX}I)HIQfW*+X_%oKWZI? zngVMJNbF66kSm7p`HU~CRe3Gmb>Q?0S_P3tvqHlH;YvLA+a`s%s3$fZ(Z+U@hK>_5 z9=jsSHk8%`vOqDUv<}&=k6B_PFGA9sT3;XhElBz`El$$6W4t&?j|3(S>X&iLpQaBW zBJ$sayqux~*w;gi_yvyO<5xFu)bOA;acv{{&WWKfGx;cgfiXelM}GCch00HZfD9^k zLU#MVO66;bD*vZcPH&B#N9FYp*+AvL0|zsyd{%86+{z-g|D4a5!N97BM%J&nMpE{q)ADkEn*W~3tSS6WU z`BUP`gMxUdn(YQz!K_3p|IlE|JTl3a3n*F@!d3xGbuR7C4|P*h+5a^V^IWZz zwo!AWR#Yp|l&K<2p46D@A(`e>kvM|&jvoQ99!8xK-EZR^s)%y@loH9tQE+Tz=+fHN z;v(5m7=c?6%7XlZ`C-0_7G6Eueh-4u{4P4mdG~FMI6rU3q`Dl>oYFBc_$OY1jp58j zF;AcEKgS+lErV+I2?sJjEid6IJxMK-5*iNdz^Ux#g45ggIc_0gS%+SG$Iht54j%lktdCq8F78+TttS((7 zXF#%q=UOe`29c2Z0Z`(x&_11s<_k%j>yg|*T zL2bsdAnd5iO3xWtI!#{ovK0eNGn5Z69-cGqm4GE5WBwAd2N_A`Afw0{1Sc%uJoggK zan8fvjsXh@^qVu^r8xs#y95S;w_%K_i1UouvCPDj;FCcLS5|SsT)V_WL?d5|;|OaE z6QFE%fYs8h1S1RxzKB_SrK@RrpV;WcC*}AA3Rli1-tx3De-C5+9+K1v2=LCZ_)V^SYtYx8KtbLvd~qnN~yNE0IlkTD*H^={g|99bk>alb2Z@mcq4+HHS|Ic8s68IlO_-`hm z(HMm4Vk@q%DP$)m|;^)Q?ievb~ zLWwr37l6}QNIw4^iQg1zzb`ekPnwUT0X03AgTqQV1HobQs^PIWmE|?2)69)aDCT@L z^!VqpiLxS`m0|p)J~A>~&t^dB1IC1@OtRTXlFdeuY-VuCf(tn0Wh5pHfQ0lLOi3!{ zpWj7tlQsfM?O1L+^(VO<-oRKs>`>GXspb8+zAGsP*78 zWiViX1qEyY9ArI%k5_=tr&ft|$1SxaLiqOLnE)w#r`6{3(I5`=VZRUi3fL`#SES&z zW0GGWKDo356FHe&k0%K59S|%jSMd!qHVHgkGB(}B(I;xRKwg7|*P5!(3$d&CG0f%o z7$`O`bci%V3WWW6xW!KDC8KWo=r9oq+3{mT{N9Vi4rtW`hhJt&M(62y=xtPdj)ac4 zeMOJpV^D}fH`KVO1L`n@ayRXn1UX&`K++4#?v1J zCst-6bg;F!di0`euwk)}XB+7&4fF6iWpMs+Tn!?mveBGPY0=Ax3Xl5Lbe2CgjKk(J zme^V#3S1&NOEL+8-175wJS?w0?N3gRkdI);%Hq&gpeod(6kQW4M}g!lNEW{Y#kWlc zGPPj8I`Dny^q38ul$18S^o5UItick&W6rbU>fd>Ei3rKK7(S=fYrdm8Ph#Z-xTpcM z=pgRIl!I~2f((nNQ6Ws{Xop;hR+4nK4s-K__>dp_x4 zKD%f>pO*4LGBD<9PiJ3B(NArXXOARQoFT;l3_#+~5DxkPV?@so>TRIf&<8{Y{mB(b zIOk15ehn5?$s^1!kEb&D*i}j7#>ALCrhd&GZ5b-m|bl`@%Z#>?WYv*A_wb=o+kH}x*`}_ zMC9x0ioQ#(tFGwP6u5)xiv9?f{Uzkxj=C(d8@JO*Q|!9!4dmo)ZzAXN?e*kby1kB^ zA=@7(Cu_Sxj(t1vWp##=Ker5Hcs*y@KM=9T8N(a$snk;*c{3s<^+8AX5Kw!3IFd}r z92hxUec7o*so6aJbtfN!9jIXTB^6g%+It(?K|q6VnF;pjPEAqbqrWoz7FgYuR% zU&nyoC%>YrG##UFo z)UUKTyc0gDoqR<|@Ya9g-ExIj_#SSSx5sYs>sV6WlGB^g8)4bsD(t)o(NJBx=keYR zJ}(`K-uhm7Bx(u0?5#cPlGE^;5&8vHlF?SCTVkl@AdG^W(&^&|WF}GKl2c1E@HVgB z-jp8ujG{?Yp-Wone)Tc}&abDsw-dzpB#0gP^hlFXduopSMeV68LIw3LpNuV+s|Ld`Ylqn`)!uytq6qj@zjCF8AU|JLIB&U((^34!*Jym6 z7S9>gOv2Fs7_a|iPXM9o=yR4qeEg2y#XH&M_e58W^xHZ)RAx zApR)^gObd>C_UvsC$;>AbDTB$@P&g;p?(Iiipw~d2`h$alZPWPcbJ;1W#oX;zv?FA zB~85xRfb3X^rv{-wK)|rxc7>?Vh2W%?}iV5NqfLi5pvLJySM0;5H5e5zzmfn^)WAI zu9r*Mpj?C{I`253`N4|<>@ly%xuC>m;oRb&b^=6gTvfxZ(?8@|Ec6I7ItGAt4Z@k% z1HkOma4Lk*H+c2zK%#c-Bv_fKoVA9Av2rg)TpcwDAgT82@LSj!yC1?r5!#1XxmSDQ zHuSCsvv9b?f<@Y5)QxCL)#kv@&O(f3$d0Snc#^F6W~`lIFV_61R9qDLLd|~b->FVs zo0{`y1hldJsu<4w;5@j8OB)F~HOE66{dEG^1Qt)41%%3}plC_E@=oA+_`L)Mt>U-> zdQgvDMWA96Nc_Tx8Ho3|Z$c?Jxo|KDzjJcXwSR|u&b8n3X|us1bQA+Lh?xp$_d=sWh_andDa|`;~Tw z_72X>0=6$>zoCBn_`qxX5eJUJPN1(*_-QIt@i(mKEh4PYd;?=h-tn8+e3{f1VIqKE zLKz`@I5N22l(zb`eK|!JK0CCBsmd_E^=1gpA5+VBnaw2SG02E{e6x_f9j2^!X6#oq z>65mAM%wp{GrZ?Rq?2`&TT>QA( zA-!?XUwBk{1J7zzpu>G>XSiU5@y!{&;ptbQqo9lV;WCF`EyLZ- z%3Ll(1o7D>e|QFcm%hp$u5`kkt*s=Uq!{1rfQXigDS~U<*y9#kLxUl&wLd}g5qD?- zf-0hMtjA&dwbvw$7YylAxwT~UJ{R^@pDYjn%0W($0nU9 zEG|2anoI3~Jh#HagxvN8hCA8h0A&k}a4S^1yewC5wYWhaMqn zCDDE~2=NO@5n%A+o8Wl%%30bSV7p+Te?xq{Dq{|0`w8YEN@m&R@Jq_r8{k+pw-MJ# zRViby=5bCV?sX&XcW^A)*N~x*;YA9VT?D>z>P{d!oc-wM;PThcr~MA$;jMhcVsm1C zDuTzQ<6OWjNa6ZU=!%p{o5)lhGgHN)6i*H3Fiq6*L#KS0;SGS8YJgyKLo+Y`ws$( z4fi$`^EFJhH6w{|K?PBy@GzPZPxj(zl<>5!+EWIQ2bJhKKq7n&kO*@i_lvL%nIL)& z)QlJLs%&;B)w2f=P@+joYyiGn+-v)c?<)J_W4PE^8|B6~&8$rWDZ{S<8tZ;B`jXHU51{UvXP+5kl)?pHzsjWIwQ10>bK z+G2A>Pw&bIuj=5*zsL6Cw%%12Er@HSm;gq>OcB?i#(tY@ZN^Rv>-Azo#S9U66{d=p z*s_?AjpBC{=0;G_^L%OgvmkhBDgHjd2z1scrIQ_rN+P0n1u{k^dOX{yM33|e1N2*~% z2U~@BF&x1(e}L&i*PpjJk$L;PG=z2(0PSLP5B&H7MxM%t$2`!H8)cQ$qW0FEx$2(r+jod z_h>5?$=9QauT~`u(W|Y`d$kpp%jfy@ObT0{Bhkt7Sqc~PP~WD$?pc^c)e~e8(a}<< z0$@rz_-dIz?5>creyHi&ubBZfr zqVyBVv?sdLezB&U`BkOw?Ml^F_`!WE_ktx>X>El>VGirl$h+YBWSVeKYf7L3l6p}x z^;}79g;|o+qGYOrR6wvMn{!4*egsR3U5t z(rs*n_*tm;v|vF3^)|WkH${IX2`=Y5T2Ks9dD^e72=Y{KA>SUsA2M!@{!|hLsTEA- z@)p*?4~3nZ@>`-_`Ceh6mA0a!>pS@20zW`JB043?EO;ZCmfM|HpG=d}rB(NWRmrqA z!2{Lag8S<&+@ePK%0wz_f;mg(ZtRhMO^@_H^+=y4b8O)mHQnFi%jsPu7A&>e)K=uG zH1KTCf}4_Q=~9D*XL}Z0l1%*qY^k^KY|ny8$<#fhf@k52PpQanR9H3^xaMz+ODvER2tcsb*1oEXpTuTl& zu~~5`wnQ{ij`}?}tC`8o3OQ2OX7yfTv-+@WvucvfYM*RYO=`0`z-IMvn!0z=ionKc zqzJ~MtBszU6_;~cdyb}u`Wx$Iv-(0dE2`Ss{w|xd@M?X03?YV;kjzn>-X-$X9a{4}G?3L)^ zcJuuQlr=A$_k8PKEpx{2t&}qEN!Uhq^L!E{1jl@li0R0z*&0OG#ep-PvuuN$Z~u`2 z=7?4w%-ez}Bc5{`>C)wMled5oT0?^8mLzWg6QK&N&Xov+<5i^+e@Il6Vmi!8RrI}Gx?DxE96b5{fgh!|&&WA#Nh*8bCTJ%Ge1$m^X&woLcjrd*@?{Ve z1PcJpi>`Atxk1gPB=e!B+Wlo z4EKD&BYm*!K9b=t#oXLKIe3ICQNpemvWCUWuQ3Dm2^?Z^Q+}{1TzFz%JB>Y=$qp~c@Ju|c1`s=mOXu>D+QeY5CXbK@*5+i9 zT6E}AmAi{C2 z+Q!<3KkLUZzZtN2vP*mNorT=<;z4v&omVNjn4bb~@P-UBWCSiX=OB?cN<G1Yr5Cw5kT}+uL=-S86gZK#C;3S&7k`Y*|8WUhR{d0eD42N zU6HQ$w?=akqmeGFy9<5+kff2}=5APIqdc3nN62}@o(ZyY9SWXtl7OD_np>Ons zvuU?9}>EGer7funB;|u%mwlxJbDIcLTl3X@N5TL^E) zVsXjBGN<;aXJl7BvXm3|t@ild4s)&AaaiAv;UAK6Sx;fyWkiv_5~hqxkzB@pcM*mn z{%jY1U+sGV!qLAIm)>e=f!a?amd!RV2htgEm! zR=7fGY_?pRv`a2cM5VNU!SD)C$Z5`ISW5PU)XKr`hPr4R_F7ZK-Gcx7Q8JY{!)g4& z1~jB`&B20%kwVGwOkUKUj1!w1xf9~8;buFSlN5`+Mhti*7Q>ENxRnpI)lgiubpf=>~2ES4G#6DM5=-fd-HCC#2AZJ8;U!jM-t{ zVNtUp1^=22OB@iS>Y)J5hmDeFUm zC#*`AaGqiyft`P7xOrlafqje(b5h<{Q9PWOY>MMS$ahen&OA;8BOnBf?YYV%AHU6g){Ea1RJf`vAOSXit@uxi+PY4@TE6iM3uV$c~I|6S> z->>UxZY6H%5Wmk2&!clAvv=1tEDKgqu3su#JFySOAXkYkA$r}q?-#){1{k7{s45v)yb8LFjK zjt%V+O+q3P;#JW?3v(?j?R@hvC~k3lVHuU!!tP#Xaj-IMI9MzJ?{s*L4|~Zd0a7w1 zH75WfoT5{V=bZei^ru97s0nC`O<&@+mCs2x{im`yVQ$h_dDq3Jnmfl!LRw&=d2qV; zO!`kX)4j@ha;UcUKu#gr{GC2yy_;?5YBIzInZ-IiG+JUGmuRb-f(?m%=@=`eAN0R4 z>^CsP!hLcdvWWQ;VNC7LX3f{E&udYV(2%`^Os3fW(}9rve0lTA#Z1Mc&)_+5rj>2- za9%_w*DskfTXK%Ea;8g8I}|k*5cOdAoRPP2{tBP-?X6rp6TS#5;s)!opD*1qBKwxbT-3VA8fsVI|>@SM*24R^p^1!g*}qCxKDE*kP}_?daOfcD?>W< z3t4#FQvVeQnxnx#)`k@0iE!3JI-=jwFk81pgh#MwzF7uj%+?tUop6^~7tkr)$Q)p< z@TpFoX}xn2jc}Pn6{bQ~v)|+fwv#=Z&*m7S%A?$}@yu6c=q}me?_K2Q9HE{kt7lNY zmu~ln7u7%f{wBr+Ly4Rn`9G{JxO64T43MkLQRDJ@_>93kMjw)Xu23)16h zG3-&NW>;dx#es%m8HQ`fcH+j1^^v@qCxgur2b5Z;W?+QVm*3oA21`vdZxBfK;&HnA zCN?8*JafHbrrJU8{&KQ)8X3DB=*+VZ=EoO4TUmq^$(={liai(21xrphhDrCw_UL|2 z&+ZRY-Oq?4Cs>yeBRJ{h*$_Fp*jE%&4t3#6f=FN~F6TbZy;85@Yxz?kk?0AW&zVLR zb%7qfSDg>c$H9)+AB}ZWP44@7?CpMX3)u4IWg^H$#F^kROq(uAtd}?$%L$uD% zY)ZQ9s(sB@NQ?Q5i-#DE2~=)WsQdw_Oa&7~Kw|9+GQH(8<#;g2Ho+XL$uAe`U7~Qz zJd@h!raFiJ(7Y~YZ)RS%nj^XHbl&&Sd$9^-*nA`j8Z)Kg}f$R$&Tp!B~5sm_VZ>d@+q+ z+kmJ+NPe5S?=xy4BL0B5{q>(KRekLIL}gM@38aM(!Fs5GXu%mAR;_mA6XetS1V-o? z!MWL3%UM_p6-0ocqyx&FMA>f2dP*8^&ecO@4fMx9&(+@W5;GmR(nUZH|7Ev8O}b1jjSr_H=dX8r_o58Fh7_5S@AN!A-< zZ72;UTF7CfYvY9pg^u)hJrC#1#3OUr+1fqV|1R&JKkUvcc+s2JD=++9?q#sdvtb{r zivS)BtX6#{4<*>m!&PD)H=ehO(5X=eznnw`?+VPB+ja15DW?n zW?hTpxlHIz3u{4w(6um6#ZOBUfzy<+ptibiMaZ^>1lq!fz+ztt56-A>GQBqL6JSBr0Dike-YKhf~dz;C#(t*WnJNmL0yKYDlzm-b0PHro0=J*f;oas z4lcGizp$I5jOZPMc zPLLBKUX~mDX=4Y$JHkk^1Mc(Na4pfRs3LwBW{QurbsvQ0vRqUw3=HP?Z=) z;l9|4c+SSZ$u>_|GNIPT>F?S)`g;YY8|o~?@qcU#@QFT5tv$GOM~bqaRut8+r_B?j z-hf+xcJBl95}AFygI`y$b&QuV@a=obM(*&9+vYVQUgr*6X?A#R8+}gB&F~^H8yJir zf%}q`;N^06=SHpOD^&{uqL#A!My@n%_1PM5O7M?bfAGMD^2s=^Fyd!wuX|KshX7wlgfPT1)~8H&hh&*Q(K5 zz(_Wx;RF!)B3jE^@cl7r1{fu=8`MDe`Nr+>ZjY5Yca~|TZx?Qu5l)|tV8uU>Dma29 ziXZakZ_~FQ^*VQIH6AKLvr~@T+nW#BZEe+Ujo$E(5+6Fn(J~XSM*@MKQ{iPQ_!#(* z%FAQ@D_q6>{QXEwW3T~uLqcXG=K@(^k3rE%`l40KP!ofS@R;n?7f~>_=hXdQ2Nm!$ z7&WH+b<7}RYD87QOCszsom9MR{|Q)NvsDOUge*{bi~ zgC^#|Fl@)=Ct;Q=VK-nqgq_rlD&dUV;we~bzD#-#cJc?ymssUBp*8)?KfpYQbII~! zO8;>CDOUOEw4N=I=vBaX^O{6G=l;j_)FaO98b?TR_)zE*+1!#=go6>NegSTSzjEIc zQ5~eGZ;BYSn{DRq8jI$`%9rhdiP!_f0JB`?SPMSFJ$uZ0I}ag`Lwv=o?=aAKd%!%a zb92ZeP98M2_h&RFZ1lxs%$mAE8j|`lc)LM5!dvKm70X_wtH}J}3yJtbuJ9~;rfWHc zscbwp(!Ma~>T7VN#Hdd(B}y-y+eW{Hi>KAHT=SQ*jj^p+d^%7Vp>&y?|4r;xsBe=w z!eTsNfRp28U*bRzD&v2tD(Ar#>?L}QRK6rfC`SXOiER|FpvBzy0ZkedHoWuASGr$j zo6mK>%r&3ve!0o~b@z*IhPq$M&86KhOU&E5UP6^Jlw<53idR!&)JegOz8cijjRVrCp=uS zO59}LCUeIG-60WwFYWt92|upM&#G3&0$uFAIRSsP#)T8?as{5Bn4h2uu{R31(e~P60PUKVO zdnB+a(*5yP_cyDCHc9t4nVDAi`$_jLX&8Hr@+!LU|uV!D3$980N^#EnzsX{-hBMOvC5i0K%dv5I}a|-F+X5eaD|tjgu3m|U_^93 z`;gbr*2en^SR;DGJX;^v$erj~O%?Ugn8^=;{NRUmIBpWK$tLSgxsRj-e<5L%Mbp?o zvM6!o9z;$)ZcaYzP&P1 zUQ7P@wrB~T>L*A6bW9n_AB?WnRjbTIHB3D_)%9|mwaz6QrWHXEOIy9368vksEAp`& zD;xDsO9?i?=(hxN-L(U7(DpJ$VVgg4RejV+4KZ7j?X1FmzHlH_g2mLWBQ^ntui3g$ z+d*CI1a&F39?qu2w7Y*vf=7EXqOX-^IP78LyZlTlb=9>1JE?l7S>dvYF=O!}TZOI3 zRof@Nl}laq$fxN<$Zz=ej?ERgX)d|YZQQHiD{fccVh3Xl0x@&}654p(pm6D00&z*C zY}5v^13I?QCvbOF0C&Eo^JBK~g4B}QvtqVRSDY^7AaQclZO356*l+%LIs1d{%ffv{ zb5gvT=L=WEKkcr{_2ur`+t}mFxW}Zg%=O7K?{Y491HSi;K3?MuJ-%TP+kU57#+EO=^1+cfZb2dpWJ`+HXSSb#oa&0|=SkySgGLbgO`v`f}dc>U&R2FaC zW26Je(^m-VP>x^Fygi_*rw$T>g5`)db6v2ZpZ*AEp~YvI4?;qchuEv%;o!dR*y*&_#MZLA!h>gx6B7Oi-=XLkz*|ZX$Z|5_d^{#x-l)IvZ%m+ zx!ah=jaz2w9erKxdzz-EPC!U^{nC;3V`^d-yV}jjQM*9^%rUlYDVL^!#BSX8f*t+I zAn2A{!tDrqu}o4tw)5ELPkbSdK@bK`tKwKPvp=`El_G9$(z z-?NGO@@-4EY8*d=NQszmEfN2_u)e3vIOt-RSn{B1VSb8t-bLyD5xAlfi}wW4@XKs8 z=(cqg&F<7Vau5;%eVS|&#LITxG%Po^0<62dfh?~Do`BqVm^QJ2{?1SF_lJ~8{Mppl z82O8M%$iMGVm3vWz1jTq_ISL>R-ha2#%#K653zxk{EOT#lUt^Ed=J{3Q9HoJtPnSC zO8XwwG=3sY%hGT!JxtJtcyr~XGjXQW=i#b4oq6Ak`=hy#ihT2$*0Rroft$^7m@gbh zS1B0HI*=v9cAy*{mm*q&&6db^Z*Y|{zHG_8`p!fELs_CSn_lss>t_*)qe2u|1GS`U zmp4fG#}e~TXu90g>V{A#Dgm`fEN}XlBoq(@MJZfy1|ULr5Y`(Wg&4A0RVRomyk3h( zk%c=&Ji7MUsf5$AsFJF=t491og?zvO zLrWZ~=3h8l#5lQGdFfj>>Dk&{cxZQgP3K#*KwpBdM8Vp8>~2U$K>f_#&qJ5QcTkqrZP7^kvi{0?mG`JAnx=z|w*BBc=IR);8-oSD{=_|fq>Ep2nCZ|xp zm2^Kz%Zym%MDPkVydak@$W<-@6j7yiMR9>I{eg8nx6EL#?@;`ovUSNd?fbe#vYU4a zIgY+gFGK|Sq1aiz=Y!vn?LsU&w(~6Hn6SJ4tg!1P)ZmNko{9T#4f`7_HL+72ZphGT zJ|r7~YF@RNMA_qE5(&N1q}2#3s;}vq8KcovFO0Q5E)qz`;d_Fjrl?9adqt&lX{c%p{BX zJRW&M;zi=Xx+9Kj^idv>GPx>S9m1srKS&L3Omh)5_VBpB=gAZYqeMz~l1o`leyvhc z{Z~ui#9_hc2(5Zd^4nhdhW#Y7TAlYCFJdOkQoy->3n?o}5!M;)N)c?dyOzVFEEJ^^ z!kEnbGpi(;No{Z(l3BEF2nh#5GgKbqEpiFhX2qVVD=U7eM$YURRSP@SxPK5jCf!PqIr zzR@)%8j>MN-jd|FesD~Ot;6d7sqhzQs)S>k3%`~PzlJr)LI)Nhw0M8YM6{z-t zX=zcS5A(X!JWYPX6E3(&RPE=O*Qisa{~Y;5EM$(DoqnN}W}4)iw}(eP@=YJ5zwWl5 zcn>C{g+0!AtFE-Tvt?4McK5Fo=(n01`4y2sp;YpUdg=6^A}@kLJ!<^DeCx8vpvKc% zgvl>jHiJNR+zmL@F6yd0VX_?NGoL7R@u|h=p_WgR3()hlSIZdCZnG-UU>1(l@%2tJ zEd3}p4hqL%XiRW=cIO>%%)5;(rg50^_t=B=u?9YB2`UjjXS| zN|zPfkg6AFl_S8Bm^aC@^xid)wG{Io@6x<;kN*@)*z*VLm5@82E1P*7x!uR~o&&!e z|E;Tol)y>JiW9Q2y(X$E0vRImr%tP;s}nV0qB{8xl5Bx;ZFTK&6vOgYg ztC~0DuI~W)JO@IWd18A!j{mM@4iKK4%{@p_Gsa2oFdS z5J!_*h>B1yUfpDVI!T6r!~^@0U6`_5NBP9I28p0S72B?!m639f{V{65DZsLg2WXt4 ze!w>VDyAiYC&%9dv5FJmh4tEa&be%599gk<^ygitRsXkqfH2;qWDNJp+q_&oJU{)l z6bH|?_lk=&UlFV8?rSj5n4Ehp_%(C#Ab!{@F?an!4?5%i>HO{VyAJnB^-nt7CqsNs z2gGyc(G)U`({y7!=ZSX_5Wzj_kt2OrmR=*Xg+<;V20tP9_VIOnYTes$*(QunlVz!d zanzIIn;~64K0Ol~h#%PV9fgPGTt06L_;|A08@uR)2P=HD3YYSmv6q<;T7T5{+BLvWEq7CQ!xR^GNEV z0Z6~&Ik%H4(QFvELtEVfS=~P#!kZ<&=WpjV+6Jhots_P2+WUyId-G5SsRlo(XO{#zj|1p8180sG&QFP`-eKI5LZ z-|8At^X@ut?ymF3-gQ=6g^FL2wTCf6L06b9-OwGuJ2Fz1W?RSck4L1WuuBvK>@Nuo zGB(|lHJ!pq(`s-s35)MlQ+!3nQX+YZO-4Djz=srI+oYOI7Eg|`10XVp%TycRt4Q^y zzg5#8s7ZDi!PU|7=LBJ?`o1I-BbNCR6o$BRRvUD6CH3}hODU2ui{9WLh~kd>TDi#_ z4flenUhUaEiWDIXhZ_=qwVTJOS!DmlcFUoju^h^}lqtnuP1#z;a~^vTYypY4$Fj`F zw#ud^d@cylMNgd@7pk}+Q0%Ag98; zs(vgxfxgab5mB-DpZ74IPIz3E^g1^YG4@};9piE56axh1{Vk^#`>a&Siug>S@A)63ATsAngD$edhP0(_1< zdI-b2)GxKWL;<}F2Zjd!k5PD*S2TOdPrHE4sibzjT>5PZWHd%JGsicd z(dLbG+C+pO))AaXZDr1Hb#3}qJ-7vh(gy#@>K=D|ehAxzT`*z0A{bX>_-ri*ynGyb z_Y-}!+_H$rPJ?5UdGGU}jin`BbYXZ%TN&YcL$f$J;G-~WHuW=3W0N<3tBz4$nbF5* zeBq6+pIS6&Jc6wJZ9MC?S>_Gp4q6Xw_%I5=fY6>Szb8-HZcVr zYW*tkcl7HL8aR~8CiUeyiM9I>ON?#5XbXpM?liZM2^m^hcoC*+-vmAr zZN*yB#Ln)~yp_@FIyrYlDZ z4-?hOXME~2-iK`}DLVVqK)aI5cxle|DQ?iZ(_G{Tm%^AFE6G+--jqY)y0Y++RG;lT z>1vFFD}a_@fWx^ZsLWW;^a{|fyV3&M9!5}>-+5s;vyd<7y2^~#O;6(EOA4YhGu*f- z`i#X`9c|HS9+Sl4^8)!UV|Q3jH*0Ca;_#nnl*Tl{iBf#498g^#KRr8kn=k*oqyQ;? zmtd36*|zvZ^3DjKelADCGNajC35zc{d=fC5t!mn2mh=0n+G{qLZk~;%Xc~);-nMb1 zQ1yp1O@6VCF~_Mw(&TVo>RlPJO=>3m-7~T4_2k)Dtp6-$QkG-*nY?XqQaG9vuu9Qg0L_ItWr}l0BoH9dVXNoD!7V`iNMt@B0u1fPv9PcVSCM?eMCMtU_ zbpgSSn)Q728p~FSR6n%r>BHETEPGBd2t3r6jr^RS2H&_(p#d$d_ve=h@R9zzUbEa* zmShr>5)Zy(OglY9%sJnD0BQ!TM;<4GwNPV2kMl{)y2Gt-0(S9pujS++Yg{zY!+MVWOVnaUM|3&_stl5uQI>ypp5TOKT{vHch!92sLxh%9 z@_#M=-_Ix?F*h%@#yHzuoE)7}ZXpgzI@hSt{eu8i$|3++JBVj|v5i1uS@k}Cj%38l&_N6&46~NA8v=AJ2 zxt5)x4NBFr^=xgBH=7%u9NHk4gZBd73wST#y@dC2-phHP%llmJ0V8QXNy>5#&Nr|c z)pKg>N5s*pPX%AhJLkd#j9A|#SNX6(AS7J7G~2tE_TiMEpZ9S)vh?#B>8J1io30U2 zVs&h^bW7yg=114ktsvwjA@1?fEz2&Ry>^ggrj`~Y*xkrvYS>=lq+8tUL5_arjju=n zq+`$#k$&*s3elAi(xlg*#C%UPzY{MfIjac+F80mpjDb_Uu=^tWT7?8Cc=A&h)3@L^ zoq@s4_FwbN8vz2cLts))@SE=fLz?Y(btNC9Iiej73x4x$V6f6LHQRrZ_-f3~>{1R< zeYa&XLa&}SOkH~$GB5`>SAZo4Uy*qOQ<11brCz#*&4PpE@=QH6EnVGfribnpT-9D| zsQB{F98|}j4_xv)>(a+4s|P*!d1~O09{z>Q=2{s;U3xLHoXjS7=6pvy z;&QeuY7=YIx-^td?-*0lMW{U=!EFKZ>n$+*a49Lw6mpWpD(FZ5q;bU4wU0Pc`Kq_LJ1FE|g2=P)A1Mzyp zEz<8t^JL}_7$tL!@G zx_3=PeuQCi;q*Ti8SYMV5PdQ_Wb-`PJQZ?cQ5ICrbjQReAmKYS7lbbnwo?L0bH^*z z^wM$k!_wg%2C|&$yOI&KG|D2t+R<))hTPlo08j(Vs>CGW@%OYeZD2_O{>1cw*P9uqNiypQ}CTcakP+y+C)K=$|4? z`$^W2ajGB=Gvj=l1}%}j8f^SU=}jL!bdOaORR|Jv&R)^lkRE*lL7$9OFujX+wKO~H&mxbd*`dFO z%+CQn@u09iBfK_v=&5-=Y@Xu4jL&jJ7&dW`=eW&NY75EAjY8ql9Y^0}+Skp=Q%8U%%wqDQQ z9QfL}D7`AW3N-egfdZ4OKciXx!I+cTB~1BAF#Nau0n{4K!`1S@7Hpp(4}Ez!pNGT_ z6-zT>q5sN=4q)DjM|&?sY+my#1RJo+n(M>Z&>_JLke-uDZVHF6y#!g8z$**cMH__zKM3V!pCjEW1wTJqGxg7e@ z!h5Rm{K19>0_4*?&HT?j-oh5Ag^FYs)sgwi5un5)dmcR0wRE?y>h2H9b4%hmpD$Mm zsO0Xs3TWdU;P(sx~VXnNQV3Lb^n1Ymooo@FM zRNv;6OP98q9mt=o7f3xujGUv+VhjoFfzMKsJZ1FM%ic-NS#Lj14oaq2HcP~g9e$1k z-2(T8nt8iyt_f**%q32D{mln1k(N3@Wh@<^eV3Ia`~4b~s$_gaku)tFq$89HXA)F{ zsBvcSQW-HFlfCX3W;c0u>(Q?s`-8*H<+NkOvC(u3>Mz0S|HnlqpZ0Am@vKHLxExzHKpLAsJ?D@yR?oxfJOJ4>QV78216bnOADwZ} z%PO-FPere~%MJQeiWLFC3OyI{%k+s3thJrl5CGp`HZ=Dcry~^LU`1lld`o6ZH^Q?e*~tE<*}~l8QSzW^9=hP*J_8 zqvJ_c$5_Ns=9_X309JUSVfbnRsp03U3I(u9cci2w^mPLA%@kF82i2^xsyT$X#SDwA zXOmQfJC0S$&wJD|kXn*DLp60_smE@C<_@c#wNj7g`}IuhQP1in-TQ<(QRD6q&eExX zoim(sA62Mbn%?D;XdcFR3M4>YMb9$gIUm!H7?=7iq8^KK(AlmyJFw%)_zvvBRJ>R! zrUiS2bWt_omL?DtrkMXt-D0t->K?#Z6hEaz_3_2Y>LHs&0+60<^ppvdTQL^7bS|7V zNHr3rxi}Pq;iQnT2E|*7d4`OGAzUJscq>Vfn2UyGv1ja3K{=FJneZJXD?ZbS#x9rVpN=SDNk$g{gFj_0ng@jtVcmMhST5J4Ly-=*v;wU zD5HqE0@rc&mF{?yG;p?RK!A0UJcV<{Njt-7$4r$5sQpI_N1!5uV7Q+qCZ$BWu1nX; z={m+J=Do9e=p&RJP~krFay-()ccwa<0|dIr`pfUt03PRuwtmMC7gU%JbE=S*P9evW zR*na)91p1+!_9z|LtDL1^X$hEp?iSrQP#Sm?0qZgyO=aEoI81@iKYCQ=OyZ&7SB0d z^(rE5)pwg>`}pn4)o&Ooj-{{nWpu>Fn_ zez+IXu-})*69$;=+k@|)^rg2GDL4Duz{Df-zfR4(^Uzb$&k*7PJ-@#^*h!5 zulX^Tzztj58~4(Lvr;7+Dh^0o6;`WSjJxy9Y0(B4p^Iha@=Wdx3xQhtR6d{n!u&*LCQ@I|*O_ z*RS$tNC??6(sYpX3PD7fxxhOKdp3n#-6W@bO)7Tmh%`L{X{rLXs%V!QEEPHTC+!%F8+s4j3iJ6lgV_F6m@F*n(>}tP}Gl)<*B%c;e!=Mg(R|zCWJ5ie_W26of zVD8++*D}5`*H$5-Rpv;pje23uw@ir`F~M%3mwrghCV*qsKS^fwWCanGb$idO z0lApbi+liuY5e5Qg=(K*p3G+vjmx1MCb71QE{eWyidaa<=}JPvuz_0hWnFy?k19w0 zw<{2lVA9Qe^0W{ku>GA=nd=ufaQ4#2t&5#e7_R^)Sp*36ooAbM5WFLH7Yg2OMsuVi!=;3$VwZ*CYVjz2S$1t%g9rH|8ly<^BE0oGfFdE#tzv4EH7y{qSO!1mI)6GDVozNm-u;F68a^g z0}Ul6hdHh(@ujS#>qd*RHd%wi3lbtr24~s0EktaYh~Q?}2cug|tQDaza`CbwMMX(B zcfJh{DeE3qQl4}4d4+f;-=@#QOUGWwGuB(+@`gZK>@tFDS;4pvT4W8gz8x{o(1oRr zbAu{Fpit+;L?IP0tbD#eJ1c4>9x=aKB^Y7fEAPR)4lKB0_gEcyoQ{AhR3Ya1YS-wZ z-?Yqfwi^GD>P8>S?9!WIK0%FQcljC|Dbp`zoFQ9iD#S(>i^759=$D>8SNZna^m!Q) ze?t5)JNiI0E9qG918m}laEM56IPBh5lf!a<0;(7B%NqR|0F{pVz=*h zwtt&>g!kr@e#}5{QyhKCZ8Twt^9rOd*RBJLGk|`PK5u*QXlEeHZ0;%%yOrRbvzY{tyl;l=nfHY=;n6- zg~&tKbTwrD=nse#RM1Ze9c9tap0YhGmiMwsWIZxZ?~hKdl41J1LuKOpK(xg&Y#BTU z5I8ncKPL>25iPTszL00X&-mCEy6stSU7W}{_U25`T zNg?nEc|NJrT(8m36atgE-Jq{tbyT#_no>3(02@d5T*l5a`Nu-E)4uczPRQCXTB&G;QT>VJ^ckLKefiC$#B6PwGEIB+hmsm&L zY~+9YrZaw_@t_(zwxwne2iG{CKKS?e(Tw95;KYz}Cmu)`?iw(3-TXB$D5f8fi2fVsb_M$61HA_`h zK|5|wcxtN8s_-&=#B!Q$>8er6A&&N?YAgQABX|~H=Vr?)p=OaG3HG=0fi2+^W7eOe z=^RQ0uenlv0!mA`tm31c@w)W$;*A#?_kL)h(H4MNTI&Xl<~3r6xwO@o^IMl~Ps}G$ zwwfKwOTmo;WyZQPoZf=}yugc7@I~QKpVLfAneAOyU3!r#9sw(NtEHpNs;F-76t6;; zrSAa^+uL-|T{P!DVFhE}I^q}FpFPrz%kg!5SAAe%Sy)l&Ynz;2H0!?D8}XbWH$yi) z4@+U0)L4c*Np+UjWzxEWQMVt`vONzU(gvjv;SJCZlRfWbV%3P`7uH&A41{8JNik4O z#dH4t)2{ldH1xFrBeVBwv{R92t z(=(cES$F_i+U0O{-UYM))4O1|7l{f8CSh=B*uR6p zTqJk@9tK))g`jH^4rggE_EGXzymABC!RZ-kYqI!W5kji64#yvHWFRhfb>5T&P>6kf zJsgSxik^UqzWp1;_}L(uBDjm^R5SeJfTmVJQ-9-eK=b7({|Yq8v&5}=xk}f?t+Dm< z>5zH#HA(pF7}^D&xqMMLg3`CqgB;evkrI);fg@!$%nLh|w_p-YuD8$xW4|Vt6fL+# zfe0%iud{RE1notQOW3)3iwNJDYc24=!!!UMmVvN`?vCyb{j>_ooD?A5;b8YFSx@ zm>1bFnta2ZkIZExz$9y~4O0hjZ!=L3@|#0bkz#g6&qneW&+%3OZVX8{Kir!qpb<>0 zKG_1d01-?C3vU6ZEvJ8Vg8|gg(!~mA)Kk6az-HJ-kivO;#gHV|T>g8Azaz!`HNO^% zr93R)nHD-nZ)RC8yhXMBr5@>o@tCl7Jgige1-@`zgV%6>ol<((-3r$<4JG!or$cME zvSoKA<1;m-t6uX2tErgg5msY2C0xuCL0~tTk5Uv%uaV|~l~#B9b{E_BsKr*nyw0`+ z`LKLl>7v~S+~xW(b~uT?)T90k_7V@!iK2voOKj*AE{xM8J~G0-!bkc>Q_@vau{m=%sZ-ZBU77!dMa)@odi&+hq zrkS@*5t%YrKd03^>tvZ>t$Kja(y;yKRD7Y4Zk85Z-BF~4zXk&4My15I&UeMXDI%j% zb}XtCWq3|SII-?7VgPT)$Tci`YsCR zokwrB`DDxcRtsj6W(3|O9y+%KwQz81Gb0Gmv=__T2uv6_7u8KD@TOWZBNah0pWw4a zTKGOR-o$6T=E;W{t`=;d!PxVhtLMqSur2x=?;i9Z66^|;Hr_P9!0L>xCdHVY5q+4i zfa3O31QeM9iX%nKux6$2{)yrrF&zJhz#Y9ScnrB%?3LbWPa#;0{jqo2&)|Dv4=KpN zVZB+%QL#xMD{MPDGZpQNbHyt9$w{Lha<%JJkBvEdWFy?hMkof>{2wtLjg%dKYKj6NX%*K(auPsjqnTxVIn_#3@!OTcwuZ0oSc~E!|slv62HCjf)T`hI!hH2 znZMbGN7h}mMhbgA%D3*ng6FZ$(O5RfQCDeHuQ)lS zl9@oDaXeir8q}nW1F=D(F8d^DuOof&2m{@|x~EXWtb+{Gw~OY)RuRH(gZmPaXBy}V zbi5Z$(T(%Dz9p%SIwUcCB-H5_G8DN50QCPo&+ei#0~y!}@E9BICT6I-vE))>THW-t z!-TMr_>W!!kzzz`|HpLYOM1*rA%uIO|(~L&8nCJnii>6maP)K1on6d}F zjzIIuBW8a+zPZ9R0I`6rUIOb>jBAn2us-D-o(F*R19aO_wLM~yrqys-ieoqK4NZ~l z5c%UsukjtBMe}1((#%DW2rEFTQh-{-=vF0}>p_gX#=HN!K^nUeC#^VNO+noM8yQ|u zW`hgQ@nyAj@Hh4sOJ*mcf`MLeMgdSQBFI^K?V#AF?TwZ6UOj)%-k5?!GBCiU96DSt zG{lNY0y=@*@QM^Tn91V#zDRc|PaD?@t+CNYm9Efeh@rHGXD&u#thm)^BIscM*m}F*F z$Un?b86m`3X0Ah$H<_8L4@z9C%8j7NN9YbE|3J%H%&NU5S$o&|A^a&25ht-WcdEB1 zcBYfS@uv$tlkZ9VOui>)%6jjKq2k!4FckMOg`tv#aOZ-eh&nA4O{67obVCA1&2xYP zG!|Pi_%@}dAl}%sq=oD6r^A-bo?$;_2&Qx`qP!m?>h9B(D$~3bf0X+XF6WM+1K2{0 zmq|DFSRbF{qfl|&n|rEn%*&k=O30{`&PW1RvxW#syut4xLW%BtThuVkv2*oMu~a(& z-KNwOlR0>%lill10#m#T@bAf#WwXbRtZ$R~E3(C!IkYLHfKxlJ?l5^r5g~i5%>qtz z$iv+MKi*-EahvK3l1Q((DyRvMRf$P56Pb(^u?c_KUne3q#ker=u>TdWaR*9|D^iK= z70apXi&nyps}H{N1?p_*inmb3T^|#9L#wR>N(csSf=@dukWqQTIoe|lvDxO|hAGD2 zR1)sGbm=wZn9B;94uczmA~)1!R30htA4UOlZr${FUTW+VD>O>~$_ono1;Nex{;xV4YHhB{3(gAkamA;l$4>NuxwuzNtz24! zVdmF7dI<$3o&k^i$g;|klW$MmpW1d5bP+Zt{wdeAOD&-zhb*LxV%X<42KmGq^PmT% zMD^$Fg~s_ch_XK9$raxio~{Cjd;mn;#&zk1pSyzJrUp(iu26=}ZY=TALucRw!nR+s z_6?yc_MudL1 zpglzNJD>5j$GO`-o5;rSRkgG|3zDJf(_we*imvJlkv{xdbXY%Iq-9Nzf z5*tX0JAY5i<~H`Z@)6fQnkRPKBGdA)=FX!TE>z#N^HT)3J6pMfcjrId16mRl1mkIo za>CQUlUoVhcc_hHX6Bq((7zq zG)!0fgrJ94BH`e$^XxjGt)a}>y!bSl6tFRU+OtHgZsCqThj+jxHtt0Oz06O3qtCXE zoQnt(1QYrvKK77bwDWi{Z#Gmkc?bD}HW zD8NJUaktB`mC+zW@!2BoP-!}$m>h2B?ghK)xhFg;?u~rpaK$$>-#%Nb3mbebbThQp zNBA6>D_8iERAZxa=)%Dj+88%Lh{Piy(8)P)!B?T7%)-F<#^PIlogU~TZ-GM`W|elc z>UE(5>d-7cjf$5qnRRJW7^8=u$;%eqJC~A*Xv45iwL{aDPem(?gG_f3v|4!bn{fWD z#D@-@#Qm5ir%j|6?!22Ubpb)#CygPH9sUq7^(wpRBZs?I!eg-|6ul-(!DueSR)y;- z_JwC=X?jH2fVo2Hc~WADdEr^ohjlJ1kS76}ylVs%kY}e5kTOu@t=a4E-|o&^LRCaM zcOhm;7q$F_4@kL(${7M=zo^A%wr_KdYYw)gc@P|@BcIW#AI%1u@^DY`VSzkw^HKF29=d%aW#9$+ zxIO4YWQlRcMA6S7Q-$Lc{gTlLB<6w!XTQn}(eD=TIIPfAFsXVH_{W_rBlmg7ZKoOu z_Se35WP@j1qdT0}$75?X`vG3F2#6ihPHzd#Srx8gnO6o|JMo)uzysDXE)tsaG)ue0 zSf^a+-*(w{hi0vGRegJQI;Xr9BWSmS1pv*O^ zN{g%2SFPqSc|EpfH?EQYR3bA^_|d#AoX4R6;nKJ(_~95=#I%c<=6+ZHm&gJj1Nr;4 zSE$8}q^kW*)S3-~ocSH41hoowEY$9)l1d8?v%p;1!%c46A&;#MWA=rMZ*hf}#6963 z$5|_W9Sb~GV_1)~?)th7U(KqRjXi;w1$~Um!mFrshilxM#+IF*y2n8iH@SAc?;5bZ zG<4ZRtJvyon$l=C~B zoi6QHO)iwW%(YCkc6W`10oC}BeeLzGH zv2i3u;jjOXMlgo$s^2mFzcbPQS1rTkjR^Y9pAr+?x@6s)c#l9w0hs;0q<%A;DBEuB zUb@}>K1$hePWyYE@rY@I1eF^t{N=cHp>nsN}DcGWPR}#qk{maE7Jao zp~~vNudwmUQIHwOcpS=-J}`j|p&FT5(@A$Yxj#q~dgNo`c~!4Tp@<&-W!ozGQJ5nU zAZ!Go8M4BhF-p4okd%d$)b9CjI$$W0#u-!N2KxlEM2`yY3q3!`gQw;rt=g0aE|E31 zL2F8ldlmjL)o>3R3Db*RPie?Xlug}Z+v;(?5!kKRK)GlksA$Q;g(D25LwAR&6xAxAY`HPwIex- zjleYk)x-%X49pioUDI}FP1m#ujkht$F0uHwB}aRd_S9&1{%=Mb6(?wq6R(|zq{A*k zV_8$6Yf~}2P=I!ErHC*Tv$bC}uqV0`dA-`yZPn=dh`Q&|JZ}OE8fG@Kk+Dh_kHgjX+?cI{NB*CHP|%_O4MNEVJubO)mj2+j|ZCG#Wwt^0HQMb$lV-sy;jVsb75?}?Y=j5TAwE4oTj-hL$bP=^J zfp-}Er>LOu>-0+}sH`nK{3F)$JldnCAm1?UOv6|hBSlvi>T`WwPc?jcwOsrJ3 zy@{1>5i23qx=~guv}$&eR>c&pYO*-9zz7M*6V93ml6+<PeqA2Huu&ou?*bVAq5|$Nw$BCn!jF1N<+a%FNAL z={DFR;6EE&%Al5r#7*w}eTvt0wYNq-wbeB?w5EkKv(q-XPm8$1^9zt=d7OI}4ldjP znQuZ7U!b{L+;spYrBuQC7heMNw5RF9j3K^xEr%oQ)v|01C!t8WBAH8Y@%O}_(Pm6_#9J_S<}#9z zZn0t5VE*A9$}zkd8P0Y>g%l9U2El|&0>Lag$!lzYP5LczGp;TalO<(foX!C#lMjSS z?#t&lz9JY$DaIme#aLv6G8QQsMPJ4K@(=1-T_SD{w{+yn?qAwHgLY{Hn^7e~lYy5o zOjIk~V-!RFUW4@fPp?7#@_U0!vj!P7)2vaBPK>f)U-u}L?SDn+`{Vpu`oA3KM_(q! zS>HX*@{x&guIe$)G?`7ztMQK7U{0guU`N_<#+mTpyLbp|?QmnNUoK|225a@Fl?y1h zkP>&tXLxhX^Pm~xv?C_8PD=$YYJwv16T`;*vQkm+_{XXyQCG!t&bLw!^)aD(FJPyKEjT$U>^bF?gdHeF_jw9rAP^aC^>D*_wn@b=``5hq}>N;&5k~Q`BdLyZfa` zs$Ar|$;^ik%5BRihFb7x5yN`9K)F-uNRy{_`PvnXS-e)vO|(kH8PtE9%>9Dk#?F$u zt>zFcNT{Z&L|e@=mW5$y-PGDty1lM`pVigxVdhh;!yf%sJ|nTEJ$hcPGN_)v+oR_{ zgC-?-nG_JwMs%IT0z$DXQn1G!)lf?Adu)&%q;N$lv+%WH)1_7^R)z%qr@G zQQ9f`JXvn1r*X*V>Pu|-m60Gz%}8(5R=Zn@f~_U7!RBjS#m(A9N{=RLR?!=4)uPL_ zbk0Z^Kpx$h^$}uCLa6+4p^(rS4pQE>QXaNa#*?zmN~y6@h*Xl*WTh;$Qi@1<*-H6| zl~O{=3s%ZZD@7;eX)9&2m2wj)tF4rLD`h?@&sZtLt&}CCJYl8uRVhZLEFWjqLssIU z1=4M!)=I3k65q8Fg8XI zmG!)pvfN6UP0A-$%B@z)TvFb(Qm&K~)!H%p1rGD!bkxRx|4{Pch4>hK+(FdIx;DLC zwg6CnfSD^b#4$?0iq3QfK09^;Q1dC)5{U+IQk5wAj#t>kK#;x0TV@qVriW(~@dzTs z!vQ;R{YoX1s1}9k~NOU_ATP^>713zlb-Q zPrnQwqJr!8EsRIEkXeE<*a!_V4LoTRkIZo`{!6)SOJwMaVOL$)Sx1PqSl1NZ=lsd;6z(hu{46c z%gWoiMrT>Bx`Ek~lJFT5ZmGPOb;LFT`l{aQ} zAkhq+*Zlw3`x3AytM>0_Saeu)#uP=<92XKrl+uhua7Mre1tnK3O^`)UwqQ^!D-3%D z$)Yl|Y@wa9#kUpB62t|~1vC?v6x3{V$}r1NOTOQI&i%{`Q@y>{_5ZHx`>yNz&Royj z&+pu4y`OW=bIyI1=T5Dnczf@-(-(W$C9KZDDD}>Ighjo}OX#f~&L$Cx z!h%+t`VUx2p!S~RI-LnFmD9ZH-y%U&JJCnqhu#{U{Bz_E5V z33p%qCwCi#JNdlPAC~zRjS!Y?;?0#8*5@ItSj=C5NktrQk%zFbjv7yg7FL_Fz!+Q5 zF4JmJ4IS0Lv^B8JGS+HDGmoBM!61~(?m>+fAMEA5@h^_L7w2>0!B80H;#hd5jg8hC zc$e>Z>lz9PRTlfx9GzzxOj5%k&za_TF3u2_Zmo~lz1t=s2e;zAhBh{T2;RMr+J>tn zHOITR8*iecZGC7wqUr-}y{&yYsN3y9SrybNv4&E-iPe=WlFHT#)6nr~D$rVOJ_|zA z(8~wvVS^Q>;y~SVG_2@FD}(&3^nT-I+;5^Jo(qNMjaCDljf2Lq*<5_pP4~z^*qO1W z!c3uJ*@IEgj|YYdx_Mv-Xl&``fq_I<-QO0c``~)4`xUHZL9g0?FP-W7E=RGUl`Jth zjU;G$%x`Gk5;SJ|JktuCsep4-{#cYcan;CSSOIFrH!H(_TWrAk0y@H@Y(Hk<+x!Nj zd_0P?WhbAEaRR$sEpI~@`8(j%b0>RRT%snBoWt;cV1pm3&Xid!xwwSWLn3XtzcqgnH8HB-Ao8LRw zW{FKrgR#sS?PYA(1OWg3CL0Wi(7z(}<$42iJNzaykhsXrS zh5cmdi=&$3g7%jqy$Hg$3l@iVaY`{Z@!))-eZuoC(sQty+utnxW6Sozv#zfZQ#^m? z|66QSOe;5sU0T#9#{C5Ll;``2qY!Y)7KC|xl*r9@SU2T<0uo%@-HEw{nL_?Q#b6g# z*!4wN$@q=>C|(i{9zI2*Pb_OdgLv3-Q!I{KK%)L8LFTaEXfc2;8jf4erIMJj3&{`@ zbio{UVUfQGTnfu10=FP(h#&lzupc>c$?wN}EbTI5D@YJd#l|QXpL4<^T^bY{_G7+Z zY$={8%Bgs!bTB48Zsbx|+=d==Y?ruD?qf%y1yc;~bsHtTvc6GEGCZWe6lJOs?Cc;0o2n;NW?Anh?$ zd9@lash7WaN0f&FFOO=nSlY7E&DK}l_y11z$cCvOe=+@(7T{R`RGp)pt z!Uf;j`l4dgh`sE%*;U+3pD1-dcxw4H4?{s;)UxQ6+GwmJJVHw)F@HiLfBzyxUc4;< zd9Svevktm^T^uy-)I>Vot21M9y3?xL*41DiZt*D$U$4dlUB&PeDb~$A7K0@imvlMk zShaRuoL{#5U$aek|GDpIYf97QAJNzniMZKj5plOoA>v`1NW{|?MWll*oJdF8C?ZeQx)SMR^Ci;R=1D|{!|qKRbtnaCI!jHO?r=3tieO*6qT5`L zueTL+h+Z}8XInR@zHyq89`0g-a6%QPfuE{{f-DG&u4;5E_QSsHv45=UY&X(+r32GMK-T` z*y0I!+G2=wu#F?q(H2HTYa2<#%N9(;+jcV%A6s7{zBYd%ooro*bheR*u8M3PNYmLG zkh$ITenGt*slGpPAbOfE8&@Js4Iu zoP7kqekhB>oHtU<9Z&~E4V6geSiz8SH8ft4cAw=4&XY1s|nZl zxGv!O6&E`8=THblXI8YQMn2;NEn+vT_X2yD<{(}*=*lJ1farTthGIz{PSe2qz*^py z8g{I?G_RW4MxUEO-x+ID!>%sICt}?$M`?R{hz`0LHLL7kakB;=*(y8b<}#&G%la72S* zBgB9=N(%On(y9~Ogh0K12q(|ey0JjyV!s?aTi^Q_u_lWnU2zf&PQu2EHtNyymMLY? zxs+$@c2&Y!bx#=nbI6!h#=2>AC89CHk3zASj&Q|Ev5#6IV6hqk{T{PB)MeO@6IN#* zkB9AEeB0lR#kcimnNg{rX;xY%V;_(2P9%Z--FQ6jKga%WNuymkr(O7W^xy}E~VPAv)1EKeQh@skX>YJD z{#|^(H(hLRLg3Ed`o@M|w1jjD&1qWxkHiF8Z-=&j#4fDaSY3nJhhm}Qggy1kdRjN3 z5#b?HF_m>11dfEYX)!GhL_hTc<=b_0c{5IwV*SRaxJ6txy?t|e6r#ehtneH` zo{{+8)^h2}TIuk3A4;*)mQFe-mNX)B<)8-@tbM&VK%0Xak5yY({Ju-13R8DotTXH( zQed{JXvgFkDKzZF%+t|9R00cd-bo=QK=6P+K~1!wD$qG9G+R}NwY zuQ1BPl6>omQW`@4kPjNA&!M+Fmjk62>g&0gcu=5X7Em+@kD&9765m(Meu-fSwMik? zqtc#F_3}ialXYL_Q+(EnHV(;i$iokTN$M9gRT%KauIe-5B57CfE(yPM3yBvyHm=6$ zqEXBam{u*&V1Rrzs_a+Tw1}@EUxqFp%9sLQ^Ui9dwC&s^yv@?0@0i-5ARQ-U>!8!e zAgHhhDf-=`N;?B!l6x!8eK?0h`V`a3nt@GYXi>oiH``5wTE;XHa<}OTwT@}gJxU!Z z(+2FQ`Luc?Dffcv$_^boWm?%7bjUQI!8SO0Wu%9xtgC6|Jsq&v@A?=w-HK1)%sBd6 z-6OQN(lokJSNu9|bf4N{!Y)KXv!RRJhvB9zXa`ei*K_X3we!B)2=r5wE=v9=@_;iX3`K|; zbReCn3mS+m4NBOw<^FlyNGNWl-G4h8haK2h%RgYd?FQUhZF8yAqsc*|O%<8CfEYdI zo~BpaYqM!xIfsY7xY&@PrNv5G`!v+U zbUN688g*lcF%sW=qEDiu&zaXlwQYGAa1p*!v-{k3Qr>UGLxE`-3+wzKdZo>yHE!6? zBpFH()g`Ui2BNi%2lcGMrWM+evUTGKxS`LH52+KopXkf&ZFTgGumSjBl-(DpHaek$ zYe6Upp2hG@519?>Z9Ja{6gZuz6qPyHp`*-L4Gbe%8$nXp??!Td|t_ zG*ZphO$#^zgl$~r0iJWgj~&n{9VDiq85_9}b9NoV3Me2SkDQeG9g4xCU#$qs*6DNd zgY!`_phpzDe>Ul6`9gmXh|y$V4H(zp6H@ErE@`K);QnXbtfRPgkux)ngfxecqY_BS?r`Qh6leo;bFFCy`Ty8NFtJPFQV56>=DuGgU^7%z6DWV zM1Z?+-++6%PT@KayMS_;?BGh7RF!vt-NB9CZ>WspJ0u?o)ZgX{jIi+VkM)uMXV)UE zCfGsg5V(iKN5*FD!*v2Y%2W+5@Ew`L6Y3(f;pZi&{yc*8%X$*Qqc|Z?`G=q=xEfpr zE=tX>=Pp7skyc)C6H?LXY&ms*J^Lcz)*0-Rv{_c<#gv6{YI5a;G#3{keHW_4elc`jOk3uRMgiYkk(k?e?o@FKxeaEI5bm zuM7{K52{;kLTTRK@Y9d5LD{B7qj2N5j@(?E9WVen1LwB&pjaU!xt&&t5RUbEhG=vC zCC&EcuXj;gb=!{|3pgqL1UyTA9{D$y?(OGne&3P%i?&YRf}#-5cop!{?A_aH@=>~B z5df)ezcj06`!#)^!4%3heegxN-FE8Y+kLdKpqt>AVFQ6R3ENW?x%h}h3x*w6Mf5Va-L zZ@+f$ZrBGHIANiJ&bqk$Qo=68*|6=@xwiu@i3rcV9qdh9+pLD|$7Y=ZJs|E6&N{#S zSi*PPkIg;{A@}JZLYQ3(yC%5nl=cMt9Gex8P4x6EPk~R*>NAP(wS;ZBAew|)r<9UZ zA11bKw%=l+4fzK~Za;U-@95(IR|2($Ai1JY|3_0mE18z_rpFoq@jTEIWdbdr# zQ9=2)d2K{*1LK>r-SXH~Q&~gJc`X8|v34{Kz%IJ2HK#mlnml~a0f3zsSv0vb@)pRA zkq?lm=A5rPHYe_eolk>LgUP2J`)POAG<8SEDL_$_>Y8SMpBkU7lxLAw$|`te4HUdv zag(OuJR&GQr9r`=)d(yl52JOJFQ>7H!Q$)x#UiG59zKZQztbvZVn`Bwvuv4uPk za6ntz*lN?VCZs@z?R`GgTS#C+qF{F)P-ps_`d?xDEqzU4U*Tgib(RiMy3h96x|=pC zMUYTu(?-Y;r>}zoW9g|7<>w?m2pqB;P-E#IR%_`&`$2s0!2CASW3YAENW!;yZ=^>7 z74T>KOqZ)M)Y^odmI8l+uo|qDIQ$tAo&dm^H3yMo*uXV*i&v-l9EKR!1v!U{12t9; z8nIO&F(Q~9X^=TKTvF)d@q|#6rum4;7k!!!R@p!x@Y!IOyY92C%bLe3ZEXS77zAKD zIi7{?ee{89_s}<1kTa#`ygvpb(g&5Z25a!P>;{XP^PX^|`xJf9U8VswuyL=(lR#%pTijG_!elrO>!E%Qr$LOnSO;-L zj9@f=9>;MA3Q4YPzqJV)0%(RdQfs{uM`O4LpaShk3+RkCzm{bayU`=Y8PmPD;ORia z5~(eH0A18bEv;Tdr_g!ajCrhB%sQcKMF%mX?s>5=9n@N$V{X1S;c~2rhu`X#`&6FGk?+wE11e^dvrox!)Rhf_R6K zEWS`8cuoWwRKg{hl7 zf82;Xbgf78ehk^VUNDRbLP*rANO#acY+mfKl2*54uNy{#n~)uRfaf@lAu*SFe!Cw8 zqR>54izka=9W6+u;XO2HHG+5LkHt9k{S9(X8a*?udP=~GqjV%A*I$m~ixV56cW#X< zt1J5%b=ZtkH|bpFP7fo5Hoql87%2G*pojB=6k0nJ%mp{eDg0;=KIyWN-1Jg7O2I(Y zRE3v`Ys&kxQv(J8&`Q@K7d;S?_}Jm0Ha{N`8|l&7e`OnaBVDE(+gT5Fpa*2Nf!y5fK%FJ^A9#73Dm!9YcBZep*4-M3 zq|g@HvO2uu+)c&JdaNKbeMt>J-kHU_wb281Ao_-~-AGFSwLFND_Ni~A_ligq+B`TQ zyU#@n2A3Ms0Hl-LiH|InHRv{-?>b-yJKI7p5S%<<=`Y{oJ?-!DodvpOyXjSq?F2sG z*xY=+F)ceK-b=;jjg~&9W#_9O#v9+)RD9J~a03GMxB0?@qPU|Qvgv%!=(265-|D0A z!X9uu%BL0^nRUx6=uHMuHtW%T<0XSvfX_E*j48?0WxF9b?|~j7v4Yhw&`o8Te7+i} zVa^es6L`;Sk$Y&#sskvEmH}ZqEH|3)r$>P|hLc@ESCh|4o40P0tuv*_)`>Xc{j9i~ z#Ial&%0?@a>}Ju)8}|Y~xYXHvioY`2IxPE&@=M-|!oR>WLB%raa;?#F3u@|HkiPBK z9iDHJHK}cjPj7*BIjn`4`LPM{+Poz*AI!3^@Mw{L6f}CGCh;HuoFA#=xdqTuMgApM z6F?6X5+JVq5u!Z)ch7FwY065m&1kuCnN2)6pWbL%%3Ltpa6-5#!-5W-I;@8e>b1_0}=a+K|S?V4d-@(86?t zzz(C#Ba|qyMl9a37T)nq2(fUt_;la0E0=4umTow|afwbe!q)i+u=wD&z7i zSXimsbk-~1+Zroa*KA{qmv?ILl_OYt=j-H2^&x_H-DUvK4abv#=ab(RKyUFD%LJ^Q zg^NFgRX5`M=6Bj?KsK$vAi2e-f1-X*=!oh^kBRp??InPUO3ag#Z4)P+%rLJ?-$f^# zz>{upF681ly&BmkJ!kY!_?AuCMIo|{MSZD8T){FIYj1>I7B`pFFh**=NzimGEHp+& zp*%8Mn=!_KZNXwRrN-h1A9gFizQ`@bO{c*x_@KDXy)=4DR9W;~I(ZipsnGO^Gk0;E zb`HLFM#4`dTZ2`6y!5RX#iIU^I8r8r^jStMQxb7vE)R50PTBPNtX$ufuSDwSrLy2Bx)=)?2)lv^kbLkZ^DKMZ8GV;I{JYVc@8aiT^ zPJ{I_rwnGOO<{>n81jk1(FMHN2X+|KAsPc01a}e;0KU}2i2FxYbEi;a6(VV*G22MJOO^O*+T;>H@1Sx zhOFGgkVd+~(4MS3VCBKCFdQZ;Ev&R`RW7acD2}+?q4n&DQRZ*;BTN_z=x@P>9y`Me z<3VO<+cCT`DrAO7JBE*YHQT$v9-&iMHCA7?)WFjEJzm^6R1`xf5mj-Fum18@4?ECa z-l`=KtuHqFdR*SBw*$A!TMc%gDRUR2Jm`t>wOaX>z8Tbr*AYelH3g`<2tw;_8zgQF z*Clqd^^h2II>gt|H#>1-_?^hIvpDETsX6Pp%+MDfgCi?15fCP?LyOG@P4R<91*c2H zep53Qn0P!yeA!n%GpvfBpv;N*(0H`IUwk5wvd*REc$=9dVX8U}KV>EZrUG!LQK?CI z#__S_4h6%>`*eNTxI}g~PK0AF>uxTMkGKASl11}Dar(0T*uTh5A>r8bx(7en?Nkm2M zOKv*hFQ_wSL~-Al?mIzr%LcUJttF&_IO9t@kT^~8=F$%I4#1SVSns}+Cfc?cf8r#c!4AIwD!@Z(TEbHhvyB;oTYa38E;F`~Vw5lOR;hnZ221~%@8l%Nvy?706 zcfTE;t+lYEIi2F>E!N|(r1zN(N|G&BI$o&^3sBLep*)G~%ys(4(M#YXaXz)^c2mmE zy$B1rKA@ObSZ*$}V{e^elTBmL!^UA`SWbxHuCZIR?z03ermXhIr>*HYi<`>gePhE8 zzZ5jVV6eg41{q14al~HwWz=USYX)^r}iT>2Nf&?r@`sF1G<{{+z7`n^bF@ zSax7QV?nU)i``gtNW2*Ludsz#7rhI|(m`#gv-qfPk06+OJnDmVK-hrVwz>iJ@aAxj z;Sz}e!>ccqu&r?zWSNRW70dTnr-vq8SMWWOEmrlJbfc3MV}7UD+^Ws%f4QckrCVD0O3i4GE?7z2hSjv#oZGSB0!FPd=$04srFk@+ z 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 diff --git a/DotNet/ThirdParty/KCPLibrary/kcp.dylib b/DotNet/ThirdParty/KCPLibrary/kcp.dylib deleted file mode 100644 index 729b398b5aec4cd412321ec4bf8bcadb4797e4db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 135808 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 diff --git a/DotNet/ThirdParty/KCPLibrary/kcp.so b/DotNet/ThirdParty/KCPLibrary/kcp.so deleted file mode 100644 index c5b7cc9d5861d315cc2ee6bfc35ceee2ffc57a4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31360 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 KG#`U6YWy$yT?uRe diff --git a/DotNet/ThirdParty/ThirdParty.csproj b/DotNet/ThirdParty/ThirdParty.csproj index 06a401e2..18859bb1 100644 --- a/DotNet/ThirdParty/ThirdParty.csproj +++ b/DotNet/ThirdParty/ThirdParty.csproj @@ -62,21 +62,6 @@ RecastDll.dll PreserveNewest - - - kcp.dylib - PreserveNewest - - - kcp.dll - PreserveNewest - - - - kcp.so - PreserveNewest - -