Before Rebuild NetProvider
This commit is contained in:
parent
0823a00396
commit
4b72602bfa
|
@ -39,6 +39,8 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Kcp" Version="2.6.3" />
|
<PackageReference Include="Kcp" Version="2.6.3" />
|
||||||
<PackageReference Include="MemoryPack" Version="1.21.3" />
|
<PackageReference Include="MemoryPack" Version="1.21.3" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.12.0" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.Scripting.Common" Version="4.12.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.9" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||||
|
|
|
@ -73,7 +73,8 @@ namespace BITKit
|
||||||
if(string.IsNullOrEmpty(arrayTypeName) || arrayType is null)
|
if(string.IsNullOrEmpty(arrayTypeName) || arrayType is null)
|
||||||
throw new Exception($"未找到类型:{arrayTypeName}");
|
throw new Exception($"未找到类型:{arrayTypeName}");
|
||||||
//创建数组实例
|
//创建数组实例
|
||||||
var array = Array.CreateInstance(arrayType, reader.ReadInt32());
|
var arrayLength = reader.ReadInt32();
|
||||||
|
var array = Array.CreateInstance(arrayType, arrayLength);
|
||||||
//循环Reader
|
//循环Reader
|
||||||
for (var i = 0; i < array.Length; i++)
|
for (var i = 0; i < array.Length; i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,10 +7,9 @@ namespace BITKit.Net
|
||||||
public static readonly KcpConfig Config = new KcpConfig(
|
public static readonly KcpConfig Config = new KcpConfig(
|
||||||
NoDelay: true,
|
NoDelay: true,
|
||||||
DualMode: false,
|
DualMode: false,
|
||||||
Interval: 8, // 1ms so at interval code at least runs.
|
Interval: 1, // 1ms so at interval code at least runs.
|
||||||
Timeout: 8000,
|
Timeout: 8000,
|
||||||
CongestionWindow: false
|
CongestionWindow: false
|
||||||
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
SendWindowSize = Kcp.WND_SND * 1000,
|
SendWindowSize = Kcp.WND_SND * 1000,
|
||||||
|
|
|
@ -13,6 +13,7 @@ using System.Net;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using BITKit.Net.Examples;
|
using BITKit.Net.Examples;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
@ -22,6 +23,7 @@ namespace BITKit.Net
|
||||||
{
|
{
|
||||||
public class KcpNetClient:INetClient,INetProvider
|
public class KcpNetClient:INetClient,INetProvider
|
||||||
{
|
{
|
||||||
|
private readonly NetProviderCommon _common = new();
|
||||||
private readonly ILogger<KcpNetClient> _logger;
|
private readonly ILogger<KcpNetClient> _logger;
|
||||||
public KcpNetClient(ILogger<KcpNetClient> logger)
|
public KcpNetClient(ILogger<KcpNetClient> logger)
|
||||||
{
|
{
|
||||||
|
@ -40,15 +42,24 @@ namespace BITKit.Net
|
||||||
Id = x.Id;
|
Id = x.Id;
|
||||||
});
|
});
|
||||||
_isConnected.AddListener(ConnectionCallback);
|
_isConnected.AddListener(ConnectionCallback);
|
||||||
|
|
||||||
|
AddCommandListener<SimplePing>(F);
|
||||||
|
|
||||||
|
return;
|
||||||
|
UniTask<SimplePing> F(SimplePing p)
|
||||||
|
{
|
||||||
|
p.EndTime = DateTime.Now;
|
||||||
|
return UniTask.FromResult(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public event Action OnStartConnect;
|
public event Action OnStartConnect;
|
||||||
public event Action OnConnected;
|
public event Action OnConnected;
|
||||||
public event Action OnDisconnected;
|
public event Action OnDisconnected;
|
||||||
public event Action OnConnectedFailed;
|
public event Action OnConnectedFailed;
|
||||||
|
public uint TickRate { get; set; } = 8;
|
||||||
public bool IsConnected => _isConnected;
|
public bool IsConnected => _isConnected;
|
||||||
public bool IsConnecting { get; private set; }
|
public bool IsConnecting { get; private set; }
|
||||||
public double RpcTimeOut { get; set; } = 5;
|
|
||||||
public bool AutoReconnect { get; set; } = true;
|
public bool AutoReconnect { get; set; } = true;
|
||||||
public float2 Traffic { get; private set; }
|
public float2 Traffic { get; private set; }
|
||||||
public bool ManualTick { get; set; }
|
public bool ManualTick { get; set; }
|
||||||
|
@ -68,25 +79,17 @@ namespace BITKit.Net
|
||||||
AutoReset = true
|
AutoReset = true
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly GenericEvent _events = new();
|
|
||||||
|
|
||||||
private readonly ValidHandle _isConnected = new();
|
private readonly ValidHandle _isConnected = new();
|
||||||
private bool _userConnected;
|
private bool _userConnected;
|
||||||
private int _index = int.MinValue;
|
private int _index = int.MinValue;
|
||||||
private readonly ConcurrentDictionary<int, object> _p2p = new();
|
|
||||||
private readonly ConcurrentDictionary<string,Func<object,UniTask<object>>> _rpc = new();
|
|
||||||
private readonly ConcurrentDictionary<string,MethodInfo> _rpcMethods = new();
|
|
||||||
private readonly ConcurrentDictionary<string,EventInfo> _rpcEvents = new();
|
|
||||||
private readonly ConcurrentDictionary<string,object> _rpcHandles = new();
|
|
||||||
private DateTime _lastHeartbeat = DateTime.Now;
|
private DateTime _lastHeartbeat = DateTime.Now;
|
||||||
private DateTime _now = DateTime.Now;
|
private DateTime _now = DateTime.Now;
|
||||||
private TimeSpan _interval = TimeSpan.FromMilliseconds(100);
|
private TimeSpan _interval = TimeSpan.FromMilliseconds(100);
|
||||||
private string _connectedAddress = "127.0.0.1";
|
private string _connectedAddress = "127.0.0.1";
|
||||||
private ushort _connectedPort = 27014;
|
private ushort _connectedPort = 27014;
|
||||||
|
|
||||||
private readonly byte[] _heartBeat = new byte[] { (byte)NetCommandType.Heartbeat };
|
|
||||||
|
|
||||||
|
|
||||||
private async void ConnectionCallback(bool x)
|
private async void ConnectionCallback(bool x)
|
||||||
{
|
{
|
||||||
await BITApp.SwitchToMainThread();
|
await BITApp.SwitchToMainThread();
|
||||||
|
@ -136,6 +139,7 @@ namespace BITKit.Net
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_userConnected = true;
|
_userConnected = true;
|
||||||
|
|
||||||
//如果address是域名,解析为Ip
|
//如果address是域名,解析为Ip
|
||||||
if (address.Contains("."))
|
if (address.Contains("."))
|
||||||
{
|
{
|
||||||
|
@ -170,19 +174,15 @@ namespace BITKit.Net
|
||||||
|
|
||||||
_timer.Start();
|
_timer.Start();
|
||||||
_interval = TimeSpan.FromMilliseconds(_timer.Interval);
|
_interval = TimeSpan.FromMilliseconds(_timer.Interval);
|
||||||
|
|
||||||
HandShake();
|
|
||||||
|
|
||||||
await BITApp.SwitchToMainThread();
|
if (_client.connected)
|
||||||
|
{
|
||||||
|
HandShake();
|
||||||
for (var i = 0; i < 5; i++)
|
_client.Send(new[] { (byte)NetCommandType.Heartbeat }, KcpChannel.Reliable);
|
||||||
{
|
Traffic += new float2(1, 0);
|
||||||
_client.Send(new[] { (byte)NetCommandType.Heartbeat }, KcpChannel.Reliable);
|
}
|
||||||
Traffic += new float2(1, 0);
|
|
||||||
_client.Tick();
|
_client.Tick();
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
}
|
|
||||||
|
|
||||||
if (_client.connected)
|
if (_client.connected)
|
||||||
{
|
{
|
||||||
|
@ -192,6 +192,7 @@ namespace BITKit.Net
|
||||||
|
|
||||||
_connectedAddress = address;
|
_connectedAddress = address;
|
||||||
_connectedPort = port;
|
_connectedPort = port;
|
||||||
|
|
||||||
return _client.connected;
|
return _client.connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +248,7 @@ namespace BITKit.Net
|
||||||
if (BITApp.SynchronizationContext is not null)
|
if (BITApp.SynchronizationContext is not null)
|
||||||
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext,
|
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext,
|
||||||
BITApp.CancellationToken);
|
BITApp.CancellationToken);
|
||||||
_events.Invoke(command.GetType().FullName, command);
|
_common.Events.Invoke(command.GetType().FullName, command);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
|
@ -272,21 +273,24 @@ namespace BITKit.Net
|
||||||
case NetCommandType.ReturnToClient:
|
case NetCommandType.ReturnToClient:
|
||||||
|
|
||||||
var id = reader.ReadInt32();
|
var id = reader.ReadInt32();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (reader.ReadBoolean())
|
if (_common.P2P.TryRemove(id, out var source))
|
||||||
{
|
{
|
||||||
var value = BITBinary.Read(reader);
|
if (reader.ReadBoolean())
|
||||||
_p2p.TryAdd(id,value);
|
{
|
||||||
|
var value = BITBinary.Read(reader);
|
||||||
|
source.TrySetResult(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var message = reader.ReadString();
|
||||||
|
source.TrySetException(new Exception(message));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var message = reader.ReadString();
|
_logger.LogWarning($"ID为{id}的请求未注册回调");
|
||||||
|
|
||||||
_p2p.TryAdd(id,new Exception(message));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -314,10 +318,10 @@ namespace BITKit.Net
|
||||||
var pars = BITBinary.Read(reader).As<object[]>();
|
var pars = BITBinary.Read(reader).As<object[]>();
|
||||||
|
|
||||||
|
|
||||||
if (_rpcMethods.TryGetValue(path, out var methodInfo))
|
if (_common.RpcMethods.TryGetValue(path, out var methodInfo))
|
||||||
{
|
{
|
||||||
var isAwaitable = methodInfo.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
|
var isAwaitable = methodInfo.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
|
||||||
var handle = _rpcHandles[path];
|
var handle = _common.RpcHandles[path];
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -342,9 +346,9 @@ namespace BITKit.Net
|
||||||
returnWriter.Write(true);
|
returnWriter.Write(true);
|
||||||
BITBinary.Write(returnWriter, value);
|
BITBinary.Write(returnWriter, value);
|
||||||
}
|
}
|
||||||
else if (_rpcEvents.TryGetValue(path, out var eventInfo))
|
else if (_common.RpcEvents.TryGetValue(path, out var eventInfo))
|
||||||
{
|
{
|
||||||
var handle = _rpcHandles[path];
|
var handle = _common.RpcHandles[path];
|
||||||
var fieldInfo = handle.GetType().GetField(eventInfo.Name,ReflectionHelper.Flags)!;
|
var fieldInfo = handle.GetType().GetField(eventInfo.Name,ReflectionHelper.Flags)!;
|
||||||
|
|
||||||
var eventDelegate = fieldInfo.GetValue(handle) as MulticastDelegate;
|
var eventDelegate = fieldInfo.GetValue(handle) as MulticastDelegate;
|
||||||
|
@ -364,7 +368,7 @@ namespace BITKit.Net
|
||||||
{
|
{
|
||||||
var commandObj = BITBinary.Read(reader)
|
var commandObj = BITBinary.Read(reader)
|
||||||
.As<object[]>()[0];
|
.As<object[]>()[0];
|
||||||
var func = _rpc[commandObj.GetType()!.FullName!];
|
var func = _common.Rpc[commandObj.GetType()!.FullName!];
|
||||||
value = await func.As<Func<object, UniTask<object>>>().Invoke(commandObj);
|
value = await func.As<Func<object, UniTask<object>>>().Invoke(commandObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,11 +396,11 @@ namespace BITKit.Net
|
||||||
{
|
{
|
||||||
var rpcName = reader.ReadString();
|
var rpcName = reader.ReadString();
|
||||||
var pars = BITBinary.Read(reader).As<object[]>();
|
var pars = BITBinary.Read(reader).As<object[]>();
|
||||||
if (_rpcMethods.TryGetValue(rpcName, out var methodInfo))
|
if (_common.RpcMethods.TryGetValue(rpcName, out var methodInfo))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
methodInfo.Invoke(_rpcHandles[rpcName], pars);
|
methodInfo.Invoke(_common.RpcHandles[rpcName], pars);
|
||||||
}
|
}
|
||||||
catch (TargetException targetException)
|
catch (TargetException targetException)
|
||||||
{
|
{
|
||||||
|
@ -434,9 +438,9 @@ namespace BITKit.Net
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (_rpcEvents.TryGetValue(rpcName, out var eventInfo))
|
else if (_common.RpcEvents.TryGetValue(rpcName, out var eventInfo))
|
||||||
{
|
{
|
||||||
var handle = _rpcHandles[rpcName];
|
var handle = _common.RpcHandles[rpcName];
|
||||||
var fieldInfo = handle.GetType().GetField(eventInfo.Name,ReflectionHelper.Flags)!;
|
var fieldInfo = handle.GetType().GetField(eventInfo.Name,ReflectionHelper.Flags)!;
|
||||||
|
|
||||||
var eventDelegate = fieldInfo.GetValue(handle) as MulticastDelegate;
|
var eventDelegate = fieldInfo.GetValue(handle) as MulticastDelegate;
|
||||||
|
@ -517,13 +521,13 @@ namespace BITKit.Net
|
||||||
_commandQueue.Enqueue(bytes);
|
_commandQueue.Enqueue(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async UniTask<T> GetFromServer<T>(string path = default,params object[] pars)
|
public async UniTask<T> GetFromServer<T>(string path = default, params object[] pars)
|
||||||
{
|
{
|
||||||
if (IsConnected is false)
|
if (IsConnected is false)
|
||||||
{
|
{
|
||||||
throw new NetOfflineException();
|
throw new NetOfflineException();
|
||||||
}
|
}
|
||||||
//await UniTask.SwitchToThreadPool();
|
|
||||||
var id = _index++;
|
var id = _index++;
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
var writer = new BinaryWriter(ms);
|
var writer = new BinaryWriter(ms);
|
||||||
|
@ -538,95 +542,63 @@ namespace BITKit.Net
|
||||||
writer.Write(true);
|
writer.Write(true);
|
||||||
writer.Write(path);
|
writer.Write(path);
|
||||||
}
|
}
|
||||||
BITBinary.Write(writer,pars);
|
|
||||||
|
if (pars.Length is 0)
|
||||||
|
{
|
||||||
|
pars = new[] { System.Activator.CreateInstance<T>() as object };
|
||||||
|
}
|
||||||
|
|
||||||
|
BITBinary.Write(writer, pars);
|
||||||
|
|
||||||
var bytes = ms.ToArray();
|
var bytes = ms.ToArray();
|
||||||
|
|
||||||
await ms.DisposeAsync();
|
await ms.DisposeAsync();
|
||||||
await writer.DisposeAsync();
|
await writer.DisposeAsync();
|
||||||
|
|
||||||
_commandQueue.Enqueue(bytes);
|
|
||||||
var startTime = _now;
|
|
||||||
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (IsConnected is false)
|
|
||||||
{
|
|
||||||
throw new NetOfflineException();
|
|
||||||
}
|
|
||||||
if ((_now - startTime).TotalSeconds > RpcTimeOut)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(path))
|
|
||||||
{
|
|
||||||
throw new TimeoutException("请求超时或已断开连接");
|
|
||||||
|
|
||||||
}
|
|
||||||
throw new TimeoutException($"请求超时或已断开连接,请求为{path}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_p2p.TryRemove(id, out var value))
|
_commandQueue.Enqueue(bytes);
|
||||||
{
|
|
||||||
await BITApp.SwitchToMainThread();
|
var source = new UniTaskCompletionSource<object>();
|
||||||
if (value is Exception e)
|
|
||||||
{
|
_common.P2P.TryAdd(id, source);
|
||||||
throw new InGameException(e.Message);
|
|
||||||
}
|
var timeoutCts = new CancellationTokenSource();
|
||||||
if (UniTask.CompletedTask is T t)
|
timeoutCts.CancelAfter(5000); // 设置超时时间
|
||||||
{
|
|
||||||
return t;
|
var value = await source.Task.AttachExternalCancellation(timeoutCts.Token);
|
||||||
}
|
|
||||||
return value.As<T>();
|
if (value is Exception e)
|
||||||
}
|
{
|
||||||
await Task.Delay(_interval);
|
throw new InGameException(e.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (UniTask.CompletedTask is T t)
|
||||||
|
{
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.As<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public UniTask<T> GetFromClient<T>(int id,string path, params object[] pars)
|
public UniTask<T> GetFromClient<T>(int id,string path, params object[] pars)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void AddRpcHandle(object rpcHandle)
|
public void AddRpcHandle(object rpcHandle)
|
||||||
{
|
{
|
||||||
var reportBuilder = new StringBuilder();
|
_common.AddRpcHandle(rpcHandle);
|
||||||
|
|
||||||
reportBuilder.AppendLine($"正在通过反射注册{rpcHandle.GetType().Name}");
|
|
||||||
foreach (var methodInfo in rpcHandle.GetType().GetMethods())
|
|
||||||
{
|
|
||||||
var att = methodInfo.GetCustomAttribute<NetRpcAttribute>();
|
|
||||||
if (att is null) continue;
|
|
||||||
_rpcMethods.AddOrUpdate(methodInfo.Name, methodInfo, (s, info) => methodInfo);
|
|
||||||
_rpcHandles.AddOrUpdate(methodInfo.Name, rpcHandle, (s, o) => rpcHandle);
|
|
||||||
|
|
||||||
reportBuilder.AppendLine($"Add [{methodInfo.Name}] as MethodInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var eventInfo in rpcHandle.GetType().GetEvents())
|
|
||||||
{
|
|
||||||
var att = eventInfo.GetCustomAttribute<NetRpcAttribute>();
|
|
||||||
if (att is null) continue;
|
|
||||||
|
|
||||||
_rpcEvents.TryAdd(eventInfo.Name, eventInfo);
|
|
||||||
_rpcHandles.TryAdd(eventInfo.Name, rpcHandle);
|
|
||||||
|
|
||||||
reportBuilder.AppendLine($"Add [{eventInfo.Name}] as EventInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation(reportBuilder.ToString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCommandListener<T>(Action<T> handle)
|
public void AddCommandListener<T>(Action<T> handle)
|
||||||
{
|
{
|
||||||
_events.AddListener<T>(handle);
|
_common. Events.AddListener<T>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCommandListener<T>(Func<T,UniTask<T>> func)
|
public void AddCommandListener<T>(Func<T,UniTask<T>> func)
|
||||||
{
|
{
|
||||||
_rpc.TryAdd(typeof(T).FullName, F);
|
_common. Rpc.TryAdd(typeof(T).FullName, F);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
async UniTask<object> F(object o)
|
async UniTask<object> F(object o)
|
||||||
|
@ -637,12 +609,12 @@ namespace BITKit.Net
|
||||||
|
|
||||||
public void RemoveCommandListener<T>(Func<T,UniTask<T>> func)
|
public void RemoveCommandListener<T>(Func<T,UniTask<T>> func)
|
||||||
{
|
{
|
||||||
_rpc.TryRemove(typeof(T).FullName, out _);
|
_common. Rpc.TryRemove(typeof(T).FullName, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveCommandListener<T>(Action<T> handle)
|
public void RemoveCommandListener<T>(Action<T> handle)
|
||||||
{
|
{
|
||||||
_events.RemoveListener<T>(handle);
|
_common. Events.RemoveListener<T>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendRT(string rpcName, params object[] pars)
|
public void SendRT(string rpcName, params object[] pars)
|
||||||
|
@ -709,7 +681,7 @@ namespace BITKit.Net
|
||||||
_client.Send(bytes, KcpChannel.Reliable);
|
_client.Send(bytes, KcpChannel.Reliable);
|
||||||
}
|
}
|
||||||
Traffic+=new float2(1,0);
|
Traffic+=new float2(1,0);
|
||||||
_client.Send(_heartBeat, KcpChannel.Unreliable);
|
_client.Send(_common.HeartBeat, KcpChannel.Unreliable);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,23 +11,27 @@ using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Markup;
|
using System.Windows.Markup;
|
||||||
using BITKit.Net.Examples;
|
using BITKit.Net.Examples;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace BITKit.Net
|
namespace BITKit.Net
|
||||||
{
|
{
|
||||||
public class KCPNetServer:INetServer,INetProvider
|
public class KCPNetServer:INetServer,INetProvider
|
||||||
{
|
{
|
||||||
|
private readonly NetProviderCommon _common = new();
|
||||||
|
private readonly ILogger<KCPNetServer> _logger;
|
||||||
public string Name { get; set; } = "Default";
|
public string Name { get; set; } = "Default";
|
||||||
public int TickRate { get; set; } = 16;
|
public uint TickRate { get; set; } = 8;
|
||||||
public bool ManualTick { get; set; }
|
public bool ManualTick { get; set; }
|
||||||
public event Action<int> OnClientConnected;
|
public event Action<int> OnClientConnected;
|
||||||
public event Action<int> OnClientDisconnected;
|
public event Action<int> OnClientDisconnected;
|
||||||
public event Action OnStartServer;
|
public event Action OnStartServer;
|
||||||
public event Action OnStopServer;
|
public event Action OnStopServer;
|
||||||
private readonly KcpServer server;
|
private readonly KcpServer server;
|
||||||
private readonly GenericEvent _events = new();
|
|
||||||
private bool _isStarted;
|
private bool _isStarted;
|
||||||
private readonly Timer _timer = new(100)
|
private readonly Timer _timer = new(100)
|
||||||
{
|
{
|
||||||
|
@ -35,25 +39,14 @@ namespace BITKit.Net
|
||||||
};
|
};
|
||||||
|
|
||||||
private int _index = 1001;
|
private int _index = 1001;
|
||||||
private readonly ConcurrentDictionary<int, object> _p2p = new();
|
|
||||||
private readonly ConcurrentDictionary<string,Func<object,UniTask<object>>> _rpc = new();
|
|
||||||
private readonly ConcurrentDictionary<string,MethodInfo> _rpcMethods = new();
|
|
||||||
private readonly ConcurrentDictionary<string,EventInfo> _rpcEvents = new();
|
|
||||||
private readonly ConcurrentDictionary<string,object> _rpcHandles = new();
|
|
||||||
private readonly ConcurrentDictionary<int,DateTime> _lastHeartbeat = new();
|
|
||||||
|
|
||||||
private readonly ConcurrentQueue<(int id,byte[] bytes)> _sendQueue = new();
|
private DateTime _now=DateTime.UtcNow;
|
||||||
private readonly ConcurrentDictionary<int,int> _dropCount = new();
|
|
||||||
|
|
||||||
private DateTime _now=DateTime.Now;
|
|
||||||
private TimeSpan _interval=TimeSpan.FromSeconds(0.32);
|
|
||||||
|
|
||||||
private readonly byte[] _heartBeat = new byte[] { (byte)NetCommandType.Heartbeat };
|
|
||||||
|
|
||||||
[NetRpc]
|
[NetRpc]
|
||||||
public event Action<int, float, bool> OnNetRpcTest;
|
public event Action<int, float, bool> OnNetRpcTest;
|
||||||
public KCPNetServer()
|
public KCPNetServer(ILogger<KCPNetServer> logger)
|
||||||
{
|
{
|
||||||
|
_logger = logger;
|
||||||
server = new KcpServer(
|
server = new KcpServer(
|
||||||
OnConnected,
|
OnConnected,
|
||||||
OnData,
|
OnData,
|
||||||
|
@ -70,7 +63,7 @@ namespace BITKit.Net
|
||||||
|
|
||||||
OnNetRpcTest += (_int, _float, _bool) =>
|
OnNetRpcTest += (_int, _float, _bool) =>
|
||||||
{
|
{
|
||||||
BIT4Log.Log<KCPNetServer>($"已收到Rpc测试:{_int},{_float},{_bool}");
|
_logger.LogInformation($"已收到Rpc测试:{_int},{_float},{_bool}");
|
||||||
};
|
};
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -93,23 +86,18 @@ namespace BITKit.Net
|
||||||
|
|
||||||
foreach (var id in Connections.Keys.ToArray())
|
foreach (var id in Connections.Keys.ToArray())
|
||||||
{
|
{
|
||||||
server.Send(id,_heartBeat , KcpChannel.Unreliable);
|
server.Send(id,_common.HeartBeat , KcpChannel.Unreliable);
|
||||||
if (!_lastHeartbeat.TryGetValue(id, out var time)) continue;
|
if (!_common.LastHeartbeat.TryGetValue(id, out var time)) continue;
|
||||||
if (!((_now - time).TotalSeconds > 3)) continue;
|
if (!((_now - time).TotalSeconds > 3)) continue;
|
||||||
server.Disconnect(id);
|
server.Disconnect(id);
|
||||||
_lastHeartbeat.TryRemove(id);
|
_common.LastHeartbeat.TryRemove(id);
|
||||||
BIT4Log.Log<KCPNetServer>($"{Name}:链接{id}超时,已断开");
|
_logger.LogInformation($"{Name}:链接{id}超时,已断开");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server.IsActive() is false) return;
|
if (server.IsActive() is false) return;
|
||||||
|
|
||||||
server.Tick();
|
|
||||||
|
|
||||||
|
_common.DropCount.Clear();
|
||||||
//BIT4Log.Log<KCPNetServer>($"{Name}目前有{server.connections.Count}个链接");
|
while (_common.SendQueue.TryDequeue(out var value))
|
||||||
|
|
||||||
_dropCount.Clear();
|
|
||||||
while (_sendQueue.TryDequeue(out var value))
|
|
||||||
{
|
{
|
||||||
|
|
||||||
if (server.connections.ContainsKey(value.id))
|
if (server.connections.ContainsKey(value.id))
|
||||||
|
@ -120,13 +108,15 @@ namespace BITKit.Net
|
||||||
{
|
{
|
||||||
int UpdateValueFactory(int i, int i1) => i1 + value.bytes.Length;
|
int UpdateValueFactory(int i, int i1) => i1 + value.bytes.Length;
|
||||||
|
|
||||||
_dropCount.AddOrUpdate(value.id,value.bytes.Length,UpdateValueFactory);
|
_common.DropCount.AddOrUpdate(value.id,value.bytes.Length,UpdateValueFactory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var (id,length) in _dropCount)
|
foreach (var (id,length) in _common.DropCount)
|
||||||
{
|
{
|
||||||
BIT4Log.Log<KCPNetServer>($"未找到链接:{id},已丢弃字节数量:{length}");
|
_logger.LogInformation($"未找到链接:{id},已丢弃字节数量:{length}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server.Tick();
|
||||||
}
|
}
|
||||||
catch (SocketException)
|
catch (SocketException)
|
||||||
{
|
{
|
||||||
|
@ -134,7 +124,7 @@ namespace BITKit.Net
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
BIT4Log.LogException(exception);
|
_logger.LogCritical(exception,exception.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +138,6 @@ namespace BITKit.Net
|
||||||
if (TickRate > 0)
|
if (TickRate > 0)
|
||||||
{
|
{
|
||||||
_timer.Interval = 1000f / TickRate;
|
_timer.Interval = 1000f / TickRate;
|
||||||
_interval = TimeSpan.FromSeconds(1.0 / TickRate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OnStartServer?.Invoke();
|
OnStartServer?.Invoke();
|
||||||
|
@ -156,7 +145,7 @@ namespace BITKit.Net
|
||||||
if (ManualTick is false)
|
if (ManualTick is false)
|
||||||
_timer.Start();
|
_timer.Start();
|
||||||
_isStarted = true;
|
_isStarted = true;
|
||||||
BIT4Log.Log<KCPNetServer>($"已启动KCP服务器:{port}");
|
_logger.LogInformation($"已启动KCP服务器:{port}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -172,7 +161,7 @@ namespace BITKit.Net
|
||||||
server.Stop();
|
server.Stop();
|
||||||
OnStopServer?.Invoke();
|
OnStopServer?.Invoke();
|
||||||
_timer.Stop();
|
_timer.Stop();
|
||||||
BIT4Log.Log<KCPNetServer>($"已停止KCP服务器");
|
_logger.LogInformation($"已停止KCP服务器");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -186,7 +175,7 @@ namespace BITKit.Net
|
||||||
using var writer = new BinaryWriter(ms);
|
using var writer = new BinaryWriter(ms);
|
||||||
writer.Write((byte)NetCommandType.Message);
|
writer.Write((byte)NetCommandType.Message);
|
||||||
writer.Write(message);
|
writer.Write(message);
|
||||||
_sendQueue.Enqueue((id,ms.ToArray()));
|
_common.SendQueue.Enqueue((id,ms.ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessageToAll(string message)
|
public void SendMessageToAll(string message)
|
||||||
|
@ -211,7 +200,7 @@ namespace BITKit.Net
|
||||||
}
|
}
|
||||||
catch (SocketException)
|
catch (SocketException)
|
||||||
{
|
{
|
||||||
BIT4Log.Log<INetServer>("有用户断开连接,如有异常请检查");
|
_logger.LogInformation("有用户断开连接,如有异常请检查");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,30 +214,23 @@ namespace BITKit.Net
|
||||||
|
|
||||||
private void OnConnectedInternel(int id)
|
private void OnConnectedInternel(int id)
|
||||||
{
|
{
|
||||||
|
//server.connections[id].peer.kcp.SetInterval(TickRate);
|
||||||
OnClientConnected?.Invoke(id);
|
OnClientConnected?.Invoke(id);
|
||||||
ClientCommand(id,new NetClientAllocateIdCommand
|
ClientCommand(id,new NetClientAllocateIdCommand
|
||||||
{
|
{
|
||||||
Id = id,
|
Id = id,
|
||||||
Ip = server.connections[id].remoteEndPoint.ToString()
|
Ip = server.connections[id].remoteEndPoint.ToString()
|
||||||
});
|
});
|
||||||
BIT4Log.Log<KCPNetServer>($"{id}已连接到:{Name}");
|
_logger.LogInformation($"{id}已连接到:{Name}");
|
||||||
SendMessageToClient(id, $"成功连接到服务器:{Name}");
|
SendMessageToClient(id, $"成功连接到服务器:{Name}");
|
||||||
}
|
}
|
||||||
private void OnConnected(int Id)
|
private void OnConnected(int Id)
|
||||||
{
|
{
|
||||||
// OnClientConnected?.Invoke(Id);
|
|
||||||
// ClientCommand(Id,new NetClientAllocateIdCommand
|
|
||||||
// {
|
|
||||||
// Id = Id,
|
|
||||||
// Ip = server.connections[Id].remoteEndPoint.ToString()
|
|
||||||
// });
|
|
||||||
// BIT4Log.Log<KCPNetServer>($"{Id}已连接到:{Name}");
|
|
||||||
// SendMessageToClient(Id, $"成功连接到服务器:{Name}");
|
|
||||||
}
|
}
|
||||||
private void OnDisconnect(int Id)
|
private void OnDisconnect(int Id)
|
||||||
{
|
{
|
||||||
OnClientDisconnected?.Invoke(Id);
|
OnClientDisconnected?.Invoke(Id);
|
||||||
BIT4Log.Log<KCPNetServer>($"{Id}已断开");
|
_logger.LogInformation($"{Id}已断开");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnData(int Id, ArraySegment<byte> bytes, KcpChannel channel)
|
private void OnData(int Id, ArraySegment<byte> bytes, KcpChannel channel)
|
||||||
|
@ -275,44 +257,44 @@ namespace BITKit.Net
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case NetCommandType.Message:
|
case NetCommandType.Message:
|
||||||
BIT4Log.Log<KCPNetServer>($"已收到消息,{Id}:{reader.ReadString()}");
|
_logger.LogInformation($"已收到消息,{Id}:{reader.ReadString()}");
|
||||||
break;
|
break;
|
||||||
case NetCommandType.Command:
|
case NetCommandType.Command:
|
||||||
var command = BITBinary.Read(reader);
|
var command = BITBinary.Read(reader);
|
||||||
if (command is object[] { Length: 1 } objs) command = objs[0];
|
if (command is object[] { Length: 1 } objs) command = objs[0];
|
||||||
//BIT4Log.Log<KCPNetServer>($"已收到指令:{command},值:\n{JsonConvert.SerializeObject(command, Formatting.Indented)}");
|
//BIT4Log.Log<KCPNetServer>($"已收到指令:{command},值:\n{JsonConvert.SerializeObject(command, Formatting.Indented)}");
|
||||||
_events.Invoke(command.GetType().FullName, command);
|
_common.Events.Invoke(command.GetType().FullName, command);
|
||||||
|
|
||||||
(int Id, object Command) tuple = (Id, command);
|
(int Id, object Command) tuple = (Id, command);
|
||||||
_events.InvokeDirect(command.GetType().FullName, tuple);
|
_common.Events.InvokeDirect(command.GetType().FullName, tuple);
|
||||||
break;
|
break;
|
||||||
case NetCommandType.Heartbeat:
|
case NetCommandType.Heartbeat:
|
||||||
if (Connections.ContainsKey(Id))
|
if (Connections.ContainsKey(Id))
|
||||||
{
|
{
|
||||||
_lastHeartbeat.AddOrUpdate(Id,OnAdd,OnUpdate);
|
if (_common.LastHeartbeat.ContainsKey(Id))
|
||||||
|
{
|
||||||
|
_common.LastHeartbeat[Id] = _now;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_common.LastHeartbeat.TryAdd(Id, _now);
|
||||||
|
OnConnectedInternel(Id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
DateTime OnAdd(int arg)
|
|
||||||
{
|
|
||||||
OnConnectedInternel(Id);
|
|
||||||
return _now;
|
|
||||||
}
|
|
||||||
DateTime OnUpdate(int arg1, DateTime arg2)
|
|
||||||
{
|
|
||||||
return _now;
|
|
||||||
}
|
|
||||||
case NetCommandType.AllClientCommand:
|
case NetCommandType.AllClientCommand:
|
||||||
foreach (var id in server.connections.Keys.ToArray())
|
foreach (var id in server.connections.Keys.ToArray())
|
||||||
{
|
{
|
||||||
_sendQueue.Enqueue((id,bytes.ToArray()));
|
_common.SendQueue.Enqueue((id,bytes.ToArray()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NetCommandType.TargetCommand:
|
case NetCommandType.TargetCommand:
|
||||||
var targetId = reader.ReadInt32();
|
var targetId = reader.ReadInt32();
|
||||||
_sendQueue.Enqueue((targetId,bytes.ToArray()));
|
_common.SendQueue.Enqueue((targetId,bytes.ToArray()));
|
||||||
break;
|
break;
|
||||||
case NetCommandType.Ping:
|
case NetCommandType.Ping:
|
||||||
_sendQueue.Enqueue((Id,new byte[] { (byte)NetCommandType.Ping }));
|
_common.SendQueue.Enqueue((Id,new byte[] { (byte)NetCommandType.Ping }));
|
||||||
break;
|
break;
|
||||||
case NetCommandType.GetFromServer:
|
case NetCommandType.GetFromServer:
|
||||||
{
|
{
|
||||||
|
@ -329,10 +311,10 @@ namespace BITKit.Net
|
||||||
var pars = BITBinary.Read(reader).As<object[]>();
|
var pars = BITBinary.Read(reader).As<object[]>();
|
||||||
object value = null;
|
object value = null;
|
||||||
|
|
||||||
if (_rpcMethods.TryGetValue(path, out var methodInfo))
|
if (_common.RpcMethods.TryGetValue(path, out var methodInfo))
|
||||||
{
|
{
|
||||||
var isAwaitable = methodInfo.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
|
var isAwaitable = methodInfo.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
|
||||||
var handle = _rpcHandles[path];
|
var handle = _common.RpcHandles[path];
|
||||||
|
|
||||||
if (methodInfo.GetParameters().Length is 0)
|
if (methodInfo.GetParameters().Length is 0)
|
||||||
{
|
{
|
||||||
|
@ -374,7 +356,7 @@ namespace BITKit.Net
|
||||||
returnWriter.Write(e.Message);
|
returnWriter.Write(e.Message);
|
||||||
|
|
||||||
var _bytes = returnMS.ToArray();
|
var _bytes = returnMS.ToArray();
|
||||||
_sendQueue.Enqueue((Id,_bytes));
|
_common.SendQueue.Enqueue((Id,_bytes));
|
||||||
|
|
||||||
if (e is InGameException inGameException)
|
if (e is InGameException inGameException)
|
||||||
{
|
{
|
||||||
|
@ -386,9 +368,9 @@ namespace BITKit.Net
|
||||||
}
|
}
|
||||||
returnWriter.Write(true);
|
returnWriter.Write(true);
|
||||||
|
|
||||||
}else if (_rpcEvents.TryGetValue(path, out var eventInfo))
|
}else if (_common.RpcEvents.TryGetValue(path, out var eventInfo))
|
||||||
{
|
{
|
||||||
var handle = _rpcHandles[path];
|
var handle = _common.RpcHandles[path];
|
||||||
var fieldInfo = handle.GetType().GetField(eventInfo.Name,ReflectionHelper.Flags)!;
|
var fieldInfo = handle.GetType().GetField(eventInfo.Name,ReflectionHelper.Flags)!;
|
||||||
|
|
||||||
var eventDelegate = fieldInfo.GetValue(handle) as MulticastDelegate;
|
var eventDelegate = fieldInfo.GetValue(handle) as MulticastDelegate;
|
||||||
|
@ -409,10 +391,11 @@ namespace BITKit.Net
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var commandObj = BITBinary.Read(reader)
|
var commandObjs = BITBinary.Read(reader);
|
||||||
.As<object[]>()[0];
|
|
||||||
|
var commandObj = commandObjs.As<object[]>()[0];
|
||||||
var funcName = commandObj.GetType()!.FullName!;
|
var funcName = commandObj.GetType()!.FullName!;
|
||||||
if (_rpc.TryGetValue(funcName, out var func))
|
if (_common.Rpc.TryGetValue(funcName, out var func))
|
||||||
{
|
{
|
||||||
var value = await func.As<Func<object, UniTask<object>>>().Invoke(commandObj);
|
var value = await func.As<Func<object, UniTask<object>>>().Invoke(commandObj);
|
||||||
returnWriter.Write(true);
|
returnWriter.Write(true);
|
||||||
|
@ -425,8 +408,7 @@ namespace BITKit.Net
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var _bytes = returnMS.ToArray();
|
_common.SendQueue.Enqueue((Id,returnMS.ToArray()));
|
||||||
_sendQueue.Enqueue((Id,_bytes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -434,21 +416,31 @@ namespace BITKit.Net
|
||||||
case NetCommandType.ReturnToServer:
|
case NetCommandType.ReturnToServer:
|
||||||
{
|
{
|
||||||
var id = reader.ReadInt32();
|
var id = reader.ReadInt32();
|
||||||
if (reader.ReadBoolean())
|
|
||||||
|
if (_common.P2P.TryRemove(id, out var source))
|
||||||
{
|
{
|
||||||
var value = BITBinary.Read(reader);
|
if (reader.ReadBoolean())
|
||||||
_p2p.TryAdd(id, value);
|
{
|
||||||
|
var value = BITBinary.Read(reader);
|
||||||
|
source.TrySetResult(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var message = reader.ReadString();
|
||||||
|
source.TrySetException(new Exception(message));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var message = reader.ReadString();
|
_logger.LogWarning($"ID为{id}的请求未注册回调");
|
||||||
_p2p.TryAdd(id, new Exception(message));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BIT4Log.Log<KCPNetServer>($"未知消息类型:{type},字节:{(byte)type}");
|
_logger.LogInformation($"未知消息类型:{type},字节:{(byte)type}");
|
||||||
BIT4Log.Log<KCPNetServer>(
|
_logger.LogInformation(
|
||||||
$"已收到:({Id}, {BitConverter.ToString(bytes.Array, bytes.Offset, bytes.Count)} @ {channel})");
|
$"已收到:({Id}, {BitConverter.ToString(bytes.Array, bytes.Offset, bytes.Count)} @ {channel})");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -466,12 +458,12 @@ namespace BITKit.Net
|
||||||
|
|
||||||
private void OnError(int Id, ErrorCode errorCode, string message)
|
private void OnError(int Id, ErrorCode errorCode, string message)
|
||||||
{
|
{
|
||||||
BIT4Log.Log<KCPNetServer>($"异常:{errorCode},{message}");
|
_logger.LogInformation($"异常:{errorCode},{message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ServerCommand<T>(T command = default)
|
public void ServerCommand<T>(T command = default)
|
||||||
{
|
{
|
||||||
_events.Invoke<T>(command);
|
_common. Events.Invoke<T>(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AllClientCommand<T>(T command = default)
|
public void AllClientCommand<T>(T command = default)
|
||||||
|
@ -488,7 +480,7 @@ namespace BITKit.Net
|
||||||
using var writer = new BinaryWriter(ms);
|
using var writer = new BinaryWriter(ms);
|
||||||
writer.Write((byte)NetCommandType.Command);
|
writer.Write((byte)NetCommandType.Command);
|
||||||
BITBinary.Write(writer,command);
|
BITBinary.Write(writer,command);
|
||||||
_sendQueue.Enqueue((id,ms.ToArray()));
|
_common.SendQueue.Enqueue((id,ms.ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public UniTask<T> GetFromServer<T>(string path=default,params object[] pars)
|
public UniTask<T> GetFromServer<T>(string path=default,params object[] pars)
|
||||||
|
@ -520,16 +512,19 @@ namespace BITKit.Net
|
||||||
await ms.DisposeAsync();
|
await ms.DisposeAsync();
|
||||||
await writer.DisposeAsync();
|
await writer.DisposeAsync();
|
||||||
|
|
||||||
_sendQueue.Enqueue((id,bytes));
|
_common.SendQueue.Enqueue((id,bytes));
|
||||||
var startTime = _now;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
var time = _now - startTime;
|
|
||||||
if(time.TotalSeconds>5)
|
|
||||||
throw new TimeoutException($"等待超时,Id:{id},时间{time.TotalSeconds}");
|
|
||||||
|
|
||||||
if (_p2p.TryRemove(index, out var value))
|
var source = new UniTaskCompletionSource<object>();
|
||||||
{
|
|
||||||
|
|
||||||
|
_common.P2P.TryAdd(index, source);
|
||||||
|
|
||||||
|
var timeoutCts = new CancellationTokenSource();
|
||||||
|
timeoutCts.CancelAfter(5000); // 设置超时时间
|
||||||
|
|
||||||
|
|
||||||
|
var value =await source.Task.AttachExternalCancellation(timeoutCts.Token);
|
||||||
|
|
||||||
//await BITApp.SwitchToMainThread();
|
//await BITApp.SwitchToMainThread();
|
||||||
if (value is Exception e)
|
if (value is Exception e)
|
||||||
{
|
{
|
||||||
|
@ -544,9 +539,6 @@ namespace BITKit.Net
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
return (T)value;
|
return (T)value;
|
||||||
}
|
|
||||||
await Task.Delay(_interval);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddRpcHandle(object rpcHandle)
|
public void AddRpcHandle(object rpcHandle)
|
||||||
|
@ -555,16 +547,16 @@ namespace BITKit.Net
|
||||||
{
|
{
|
||||||
var att = methodInfo.GetCustomAttribute<NetRpcAttribute>(true);
|
var att = methodInfo.GetCustomAttribute<NetRpcAttribute>(true);
|
||||||
if(att is null)continue;
|
if(att is null)continue;
|
||||||
_rpcMethods.TryAdd(methodInfo.Name, methodInfo);
|
_common.RpcMethods.TryAdd(methodInfo.Name, methodInfo);
|
||||||
_rpcHandles.TryAdd(methodInfo.Name, rpcHandle);
|
_common.RpcHandles.TryAdd(methodInfo.Name, rpcHandle);
|
||||||
}
|
}
|
||||||
foreach (var eventInfo in rpcHandle.GetType().GetEvents())
|
foreach (var eventInfo in rpcHandle.GetType().GetEvents())
|
||||||
{
|
{
|
||||||
var att = eventInfo.GetCustomAttribute<NetRpcAttribute>(true);
|
var att = eventInfo.GetCustomAttribute<NetRpcAttribute>(true);
|
||||||
if(att is null)continue;
|
if(att is null)continue;
|
||||||
|
|
||||||
_rpcEvents.TryAdd(eventInfo.Name, eventInfo);
|
_common. RpcEvents.TryAdd(eventInfo.Name, eventInfo);
|
||||||
_rpcHandles.TryAdd(eventInfo.Name, rpcHandle);
|
_common. RpcHandles.TryAdd(eventInfo.Name, rpcHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -582,12 +574,12 @@ namespace BITKit.Net
|
||||||
|
|
||||||
public void AddCommandListener<T>(Action<T> handle)
|
public void AddCommandListener<T>(Action<T> handle)
|
||||||
{
|
{
|
||||||
_events.AddListener<T>(handle);
|
_common.Events.AddListener<T>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCommandListener<T>(Func<T,UniTask<T>> func)
|
public void AddCommandListener<T>(Func<T,UniTask<T>> func)
|
||||||
{
|
{
|
||||||
_rpc.TryAdd(typeof(T).FullName, F);
|
_common.Rpc.TryAdd(typeof(T).FullName, F);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
async UniTask<object> F(object o)
|
async UniTask<object> F(object o)
|
||||||
|
@ -597,11 +589,11 @@ namespace BITKit.Net
|
||||||
}
|
}
|
||||||
public void RemoveCommandListener<T>(Func<T,UniTask<T>> func)
|
public void RemoveCommandListener<T>(Func<T,UniTask<T>> func)
|
||||||
{
|
{
|
||||||
_rpc.TryRemove(typeof(T).FullName, out _);
|
_common. Rpc.TryRemove(typeof(T).FullName, out _);
|
||||||
}
|
}
|
||||||
public void AddCommandListenerWithId<T>(Action<int, T> handle)
|
public void AddCommandListenerWithId<T>(Action<int, T> handle)
|
||||||
{
|
{
|
||||||
_events.AddListenerDirect(typeof(T).FullName, Callback);
|
_common.Events.AddListenerDirect(typeof(T).FullName, Callback);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
void Callback(object value)
|
void Callback(object value)
|
||||||
|
@ -624,7 +616,7 @@ namespace BITKit.Net
|
||||||
|
|
||||||
public void RemoveCommandListener<T>(Action<T> handle)
|
public void RemoveCommandListener<T>(Action<T> handle)
|
||||||
{
|
{
|
||||||
_events.RemoveListener<T>(handle);
|
_common. Events.RemoveListener<T>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveCommandListener<T>(Func<string, T> func)
|
public void RemoveCommandListener<T>(Func<string, T> func)
|
||||||
|
@ -645,7 +637,7 @@ namespace BITKit.Net
|
||||||
writer.Write(rpcName);
|
writer.Write(rpcName);
|
||||||
BITBinary.Write(writer,pars);
|
BITBinary.Write(writer,pars);
|
||||||
var bytes = ms.ToArray();
|
var bytes = ms.ToArray();
|
||||||
_sendQueue.Enqueue((id,bytes));
|
_common.SendQueue.Enqueue((id,bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendAllRT(string rpcName, params object[] pars)
|
public void SendAllRT(string rpcName, params object[] pars)
|
||||||
|
@ -658,7 +650,7 @@ namespace BITKit.Net
|
||||||
var bytes = ms.ToArray();
|
var bytes = ms.ToArray();
|
||||||
foreach (var id in server.connections.Keys)
|
foreach (var id in server.connections.Keys)
|
||||||
{
|
{
|
||||||
_sendQueue.Enqueue((id,bytes));
|
_common.SendQueue.Enqueue((id,bytes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,7 +225,6 @@ namespace BITKit.Mod
|
||||||
await Load(assembly);
|
await Load(assembly);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#if UNITY_5_3_OR_NEWER
|
|
||||||
case ".cs":
|
case ".cs":
|
||||||
{
|
{
|
||||||
var code = await File.ReadAllTextAsync(fileInfo.FullName);
|
var code = await File.ReadAllTextAsync(fileInfo.FullName);
|
||||||
|
@ -233,7 +232,6 @@ namespace BITKit.Mod
|
||||||
await Load(assembly, fileInfo.DirectoryName);
|
await Load(assembly, fileInfo.DirectoryName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
using MemoryPack;
|
||||||
|
|
||||||
namespace BITKit.Net.Examples
|
namespace BITKit.Net.Examples
|
||||||
{
|
{
|
||||||
public struct NetClientPingCommand
|
[MemoryPackable]
|
||||||
|
public partial struct NetClientPingCommand
|
||||||
{
|
{
|
||||||
public int Ping;
|
public int Ping;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using MemoryPack;
|
||||||
|
|
||||||
namespace BITKit.Net.Examples
|
namespace BITKit.Net.Examples
|
||||||
{
|
{
|
||||||
public struct LogTime
|
[MemoryPackable]
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
public partial struct LogTime
|
||||||
{
|
{
|
||||||
public Guid Id;
|
public Guid Id;
|
||||||
public DateTime CreateTime;
|
public DateTime CreateTime;
|
||||||
|
@ -15,7 +19,9 @@ namespace BITKit.Net.Examples
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
public struct SimplePing
|
[MemoryPackable]
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
public partial struct SimplePing
|
||||||
{
|
{
|
||||||
public DateTime StartTime;
|
public DateTime StartTime;
|
||||||
public DateTime EndTime;
|
public DateTime EndTime;
|
||||||
|
|
|
@ -6,8 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
#if UNITY
|
#if UNITY
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
@ -91,6 +94,7 @@ namespace BITKit
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface INetProvider
|
public interface INetProvider
|
||||||
{
|
{
|
||||||
|
public uint TickRate { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 向服务端发送指令
|
/// 向服务端发送指令
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -324,7 +328,7 @@ namespace BITKit
|
||||||
/// <param name="address">服务端地址</param>
|
/// <param name="address">服务端地址</param>
|
||||||
/// <param name="port">端口</param>
|
/// <param name="port">端口</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
UniTask<bool> Connect(string address = "localhost", ushort port = 27014);
|
UniTask<bool> Connect(string address = "127.0.0.1", ushort port = 27014);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 向服务端发送消息
|
/// 向服务端发送消息
|
||||||
|
@ -332,4 +336,48 @@ namespace BITKit
|
||||||
/// <param name="message">消息</param>
|
/// <param name="message">消息</param>
|
||||||
void SendServerMessage(string message);
|
void SendServerMessage(string message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NetProviderCommon
|
||||||
|
{
|
||||||
|
public readonly GenericEvent Events = new();
|
||||||
|
|
||||||
|
public readonly ConcurrentDictionary<int, UniTaskCompletionSource<object>> P2P = new();
|
||||||
|
public readonly ConcurrentDictionary<string,Func<object,UniTask<object>>> Rpc = new();
|
||||||
|
public readonly ConcurrentDictionary<string,MethodInfo> RpcMethods = new();
|
||||||
|
public readonly ConcurrentDictionary<string,EventInfo> RpcEvents = new();
|
||||||
|
public readonly ConcurrentDictionary<string,object> RpcHandles = new();
|
||||||
|
public readonly ConcurrentDictionary<int,DateTime> LastHeartbeat = new();
|
||||||
|
|
||||||
|
public readonly ConcurrentQueue<(int id,byte[] bytes)> SendQueue = new();
|
||||||
|
public readonly ConcurrentDictionary<int,int> DropCount = new();
|
||||||
|
|
||||||
|
public readonly byte[] HeartBeat = new byte[] { (byte)NetCommandType.Heartbeat };
|
||||||
|
|
||||||
|
public void AddRpcHandle(object rpcHandle)
|
||||||
|
{
|
||||||
|
var reportBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
reportBuilder.AppendLine($"正在通过反射注册{rpcHandle.GetType().Name}");
|
||||||
|
foreach (var methodInfo in rpcHandle.GetType().GetMethods())
|
||||||
|
{
|
||||||
|
var att = methodInfo.GetCustomAttribute<NetRpcAttribute>();
|
||||||
|
if (att is null) continue;
|
||||||
|
RpcMethods.AddOrUpdate(methodInfo.Name, methodInfo, (s, info) => methodInfo);
|
||||||
|
RpcHandles.AddOrUpdate(methodInfo.Name, rpcHandle, (s, o) => rpcHandle);
|
||||||
|
|
||||||
|
reportBuilder.AppendLine($"Add [{methodInfo.Name}] as MethodInfo");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var eventInfo in rpcHandle.GetType().GetEvents())
|
||||||
|
{
|
||||||
|
var att = eventInfo.GetCustomAttribute<NetRpcAttribute>();
|
||||||
|
if (att is null) continue;
|
||||||
|
|
||||||
|
RpcEvents.TryAdd(eventInfo.Name, eventInfo);
|
||||||
|
RpcHandles.TryAdd(eventInfo.Name, rpcHandle);
|
||||||
|
|
||||||
|
reportBuilder.AppendLine($"Add [{eventInfo.Name}] as EventInfo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,17 +5,18 @@ using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using BITKit.Mod;
|
using BITKit.Mod;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Scripting;
|
||||||
|
using Microsoft.CodeAnalysis.Emit;
|
||||||
|
using Microsoft.CodeAnalysis.Scripting;
|
||||||
#if UNITY_5_3_OR_NEWER
|
#if UNITY_5_3_OR_NEWER
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using BITKit.UX;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Rendering;
|
|
||||||
using static BITKit.Mod.DotNetSdkRoslynService;
|
using static BITKit.Mod.DotNetSdkRoslynService;
|
||||||
#endif
|
#endif
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
|
@ -60,170 +61,162 @@ namespace BITKit
|
||||||
assemblies ??= AppDomain.CurrentDomain.GetAssemblies();
|
assemblies ??= AppDomain.CurrentDomain.GetAssemblies();
|
||||||
return assemblies.Select(assembly => assembly.GetType(fullName, false)).FirstOrDefault(type => type is not null);
|
return assemblies.Select(assembly => assembly.GetType(fullName, false)).FirstOrDefault(type => type is not null);
|
||||||
}
|
}
|
||||||
#if UNITY_5_3_OR_NEWER
|
|
||||||
|
|
||||||
public static Assembly Compile(params string[] codes)
|
public static IReadOnlyCollection<Assembly> GetReferencedAssemblies(Type type)
|
||||||
{
|
{
|
||||||
var outputPath = PathHelper.GetTempFilePath();
|
var result = new HashSet<Assembly>();
|
||||||
|
foreach (var fieldInfo in type.GetFields())
|
||||||
try
|
|
||||||
{
|
{
|
||||||
if (Installed is false)
|
result.Add(fieldInfo.FieldType.Assembly);
|
||||||
{
|
}
|
||||||
throw new FileNotFoundException($"未从当前路径找到Roslyn:\n{CSCPath}");
|
|
||||||
}
|
foreach (var propertyInfo in type.GetProperties())
|
||||||
|
{
|
||||||
var argumentBuilder = new StringBuilder();
|
result.Add(propertyInfo.PropertyType.Assembly);
|
||||||
|
}
|
||||||
var tempList = new List<string> { outputPath };
|
foreach (var methodInfo in type.GetMethods())
|
||||||
|
{
|
||||||
foreach (var code in codes)
|
result.Add(methodInfo.ReturnType.Assembly);
|
||||||
{
|
foreach (var argument in methodInfo.GetGenericArguments())
|
||||||
var temp = PathHelper.GetTempFilePath();
|
{
|
||||||
|
result.Add(argument.Assembly);
|
||||||
File.WriteAllText(temp,code);
|
}
|
||||||
|
}
|
||||||
argumentBuilder.Append(" ");
|
return result;
|
||||||
argumentBuilder.Append(temp);
|
}
|
||||||
|
|
||||||
tempList.Add(temp);
|
public static string GenerateCodeFromInterface(Type type,string namespaceName = null)
|
||||||
}
|
{
|
||||||
|
if (type.IsInterface is false) throw new InvalidDataException("The type have to be interface");
|
||||||
argumentBuilder.Append(" -target:library");
|
|
||||||
|
var codeBuilder = new StringBuilder();
|
||||||
argumentBuilder.Append(" /unsafe");
|
|
||||||
|
var nameSpaces = new HashSet<string>();
|
||||||
foreach (var x in ReferencedAssemblies)
|
|
||||||
{
|
HashSet<Type> allTypes = new();
|
||||||
argumentBuilder.Append(" ");
|
HashSet<MethodInfo> propertyMethods = new();
|
||||||
argumentBuilder.Append("-r:");
|
|
||||||
argumentBuilder.Append(x);
|
foreach (var propertyInfo in type.GetProperties())
|
||||||
//argumentBuilder.Append(Path.Combine(dllPath, x));
|
{
|
||||||
}
|
if (propertyInfo.GetMethod is not null)
|
||||||
|
{
|
||||||
argumentBuilder.Append(" ");
|
propertyMethods.Add(propertyInfo.GetMethod);
|
||||||
argumentBuilder.Append($"-out:{outputPath}");
|
}
|
||||||
|
|
||||||
BIT4Log.Log<BITSharp>("已创建编译参数:");
|
if (propertyInfo.SetMethod is not null)
|
||||||
BIT4Log.Log(argumentBuilder.ToString());
|
{
|
||||||
|
propertyMethods.Add(propertyInfo.SetMethod);
|
||||||
BIT4Log.Log<BITSharp>($"dotnet {CSCPath} {argumentBuilder}");
|
}
|
||||||
|
}
|
||||||
//Original
|
|
||||||
// var StartInfo = new ProcessStartInfo
|
foreach (var method in type.GetMethods())
|
||||||
// {
|
{
|
||||||
// //FileName = MCSPath,
|
if (method.DeclaringType is not null)
|
||||||
// FileName = "dotnet",
|
{
|
||||||
// Arguments =$"{CSCPath} {argumentBuilder}" ,
|
nameSpaces.Add(method.DeclaringType.Namespace);
|
||||||
// UseShellExecute = true,
|
}
|
||||||
// CreateNoWindow = false,
|
nameSpaces.Add(method.ReturnType.Namespace);
|
||||||
// };
|
foreach (var argument in method.GetGenericArguments())
|
||||||
|
{
|
||||||
var startInfo = new ProcessStartInfo
|
nameSpaces.Add(argument.Namespace);
|
||||||
{
|
}
|
||||||
//FileName = MCSPath,
|
}
|
||||||
FileName = "dotnet",
|
|
||||||
Arguments =$"{CSCPath} {argumentBuilder}" ,
|
nameSpaces.Add("System");
|
||||||
UseShellExecute = false,
|
nameSpaces.Add("System.Collections.Concurrent");
|
||||||
CreateNoWindow = true,
|
nameSpaces.Add("System.Collections.Generic");
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
StandardErrorEncoding = System.Text.Encoding.GetEncoding("gb2312"),
|
|
||||||
StandardInputEncoding = System.Text.Encoding.GetEncoding("gb2312"),
|
|
||||||
StandardOutputEncoding = System.Text.Encoding.GetEncoding("gb2312"),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var process = new Process()
|
|
||||||
{
|
|
||||||
StartInfo = startInfo,
|
|
||||||
};
|
|
||||||
var reportBuilder = new StringBuilder();
|
|
||||||
process.OutputDataReceived += (sender, args) =>
|
|
||||||
{
|
|
||||||
//BIT4Log.Log<BITSharp>(args.Data);
|
|
||||||
reportBuilder.AppendLine(args.Data);
|
|
||||||
};
|
|
||||||
process.ErrorDataReceived += (sender, args) =>
|
|
||||||
{
|
|
||||||
//BIT4Log.Warning<BITSharp>(args.Data);
|
|
||||||
reportBuilder.AppendLine($"<color=yellow>{args.Data}</color>");
|
|
||||||
};
|
|
||||||
|
|
||||||
process.Start();
|
|
||||||
BIT4Log.Log<BITSharp>("已启动");
|
|
||||||
|
|
||||||
process.BeginErrorReadLine();
|
|
||||||
process.BeginOutputReadLine();
|
|
||||||
|
|
||||||
while (process.HasExited is false)
|
|
||||||
{
|
|
||||||
Thread.Sleep(100);
|
|
||||||
if (BITApp.CancellationToken.IsCancellationRequested) throw new OperationCanceledException("程序已退出,取消编译");
|
|
||||||
}
|
|
||||||
|
|
||||||
var bytes = File.ReadAllBytes(outputPath);
|
|
||||||
|
|
||||||
if(process.ExitCode is not 0)
|
codeBuilder.AppendLine(string.Join('\n', nameSpaces.Select(x=>$"using {x};")));
|
||||||
|
|
||||||
|
|
||||||
|
//codeBuilder.AppendLine("namespace BITSharpGen");
|
||||||
|
//codeBuilder.AppendLine("{");
|
||||||
|
|
||||||
|
codeBuilder.AppendLine($"public class @{type.Name}Gen : {type.Name}");
|
||||||
|
codeBuilder.AppendLine("{");
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var propertyInfo in type.GetProperties())
|
||||||
|
{
|
||||||
|
codeBuilder.AppendLine($"public {CSharpName(propertyInfo.PropertyType)} {propertyInfo.Name}" + "{ get;set; }");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历接口的所有成员,生成方法的默认实现
|
||||||
|
foreach (var method in type.GetMethods())
|
||||||
|
{
|
||||||
|
if(propertyMethods.Contains(method))continue;
|
||||||
|
string methodName = method.Name;
|
||||||
|
string parameters = string.Join(", ", method.GetParameters()
|
||||||
|
.Select(p => $"{CSharpName(p.ParameterType)} {p.Name}"));
|
||||||
|
|
||||||
|
// 检查是否为泛型方法
|
||||||
|
if (method.IsGenericMethod)
|
||||||
|
{
|
||||||
|
// 处理泛型方法
|
||||||
|
var genericArgs = string.Join(", ", method.GetGenericArguments()
|
||||||
|
.Select(arg => CSharpName(arg)));
|
||||||
|
|
||||||
|
if (method.ReturnType == typeof(void))
|
||||||
{
|
{
|
||||||
BIT4Log.LogException(new Exception($"编译失败:{process.ExitCode}"));
|
codeBuilder.AppendLine($" public void {methodName}<{genericArgs}>({parameters}) {{ }}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var x in tempList)
|
codeBuilder.AppendLine($" public {CSharpName(method.ReturnType)} {methodName}<{genericArgs}>({parameters}) {{ return default({CSharpName(method.ReturnType)}); }}");
|
||||||
{
|
|
||||||
File.Delete(x);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BIT4Log.Log<BITSharp>(reportBuilder);
|
}
|
||||||
|
else
|
||||||
return Assembly.Load(bytes);
|
{
|
||||||
|
if (method.ReturnType == typeof(void))
|
||||||
|
{
|
||||||
|
codeBuilder.AppendLine($" public void {methodName}({parameters}) {{ }}"); // Void 方法默认空实现
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 返回默认值
|
||||||
|
codeBuilder.AppendLine($" public {CSharpName(method.ReturnType)} {methodName}({parameters}) {{ return default({CSharpName(method.ReturnType)}); }}");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new Exception($"编译失败:{e}");
|
//codeBuilder.AppendLine("\t}");
|
||||||
}
|
|
||||||
|
codeBuilder.AppendLine("}");
|
||||||
// var codeProvider = new CSharpCodeProvider();
|
|
||||||
// var parameters = new CompilerParameters
|
return codeBuilder.ToString();
|
||||||
// {
|
}
|
||||||
// GenerateInMemory = true,
|
|
||||||
// CompilerOptions = "/unsafe",
|
public static string CSharpName(Type type)
|
||||||
// OutputAssembly = outputPath,
|
{
|
||||||
// };
|
var sb = new StringBuilder();
|
||||||
// parameters.ReferencedAssemblies.Add("System.dll");
|
var name = type.Name;
|
||||||
// foreach (var x in ReferencedAssemblies)
|
if (!type.IsGenericType) return name;
|
||||||
// {
|
sb.Append(name.Substring(0, name.IndexOf('`')));
|
||||||
// parameters.ReferencedAssemblies.Add(x);
|
sb.Append("<");
|
||||||
// BIT4Log.Log<BITSharp>($"添加引用:");
|
sb.Append(string.Join(", ", type.GetGenericArguments()
|
||||||
// BIT4Log.Log<BITSharp>(x);
|
.Select(t => CSharpName(t))));
|
||||||
// }
|
sb.Append(">");
|
||||||
//
|
return sb.ToString();
|
||||||
// BIT4Log.Log<BITSharp>($"程序集输出路径:{outputPath}");
|
}
|
||||||
//
|
|
||||||
// var results = codeProvider.CompileAssemblyFromSource(parameters, codes);
|
public static Assembly Compile(string code,ScriptOptions scriptOptions=null)
|
||||||
//
|
{
|
||||||
// if (results.Errors.Count <= 0)
|
scriptOptions ??= ScriptOptions.Default;
|
||||||
// {
|
|
||||||
// BIT4Log.Log<BITSharp>($"编译成功:{results.CompiledAssembly.FullName}");
|
var script = CSharpScript.Create(code,scriptOptions);
|
||||||
//
|
script.Compile();
|
||||||
// codeProvider.Dispose();
|
|
||||||
// return results.CompiledAssembly;
|
using var ms = new MemoryStream();
|
||||||
// }
|
var result = script.GetCompilation().Emit(ms);
|
||||||
//
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
// foreach (CompilerError error in results.Errors)
|
var assembly = Assembly.Load(ms.ToArray()); // 加载程序集
|
||||||
// {
|
|
||||||
// var sb = new StringBuilder();
|
return assembly;
|
||||||
// sb.AppendLine(error.FileName);
|
|
||||||
// sb.AppendLine($"Error ({error.ErrorNumber}): {error.ErrorText}");
|
|
||||||
// sb.AppendLine($"Line: {error.Line}, Column: {error.Column}");
|
|
||||||
// sb.AppendLine($"Is Warning: {error.IsWarning}");
|
|
||||||
// BIT4Log.LogException(new Exception(sb.ToString()));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// throw new Exception("编译失败");
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -43,11 +43,12 @@ namespace BITKit
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public TimerTicker Start()
|
||||||
{
|
{
|
||||||
_deltaTime = 1f / TickRate;
|
_deltaTime = 1f / TickRate;
|
||||||
_timer.Interval = TimeSpan.FromSeconds(_deltaTime).TotalMilliseconds;
|
_timer.Interval = TimeSpan.FromSeconds(_deltaTime).TotalMilliseconds;
|
||||||
_timer.Enabled = true;
|
_timer.Enabled = true;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
private void OnTick()
|
private void OnTick()
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,11 +9,11 @@ namespace BITKit
|
||||||
private readonly Stopwatch _stopwatch = new Stopwatch();
|
private readonly Stopwatch _stopwatch = new Stopwatch();
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly string _message;
|
private readonly string _message;
|
||||||
public StopWatcher(ILogger logger,string message)
|
public StopWatcher(ILogger logger,string message=null)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_message = message;
|
_message = message;
|
||||||
|
|
||||||
_logger.LogInformation($"开始计时:{message}");
|
_logger.LogInformation($"开始计时:{message}");
|
||||||
|
|
||||||
_stopwatch.Start();
|
_stopwatch.Start();
|
||||||
|
|
|
@ -1058,9 +1058,9 @@ namespace kcp2k
|
||||||
// ikcp_interval
|
// ikcp_interval
|
||||||
public void SetInterval(uint interval)
|
public void SetInterval(uint interval)
|
||||||
{
|
{
|
||||||
// clamp interval between 10 and 5000
|
// clamp interval between 10 and 5000
|
||||||
if (interval > 5000) interval = 5000;
|
if (interval > 5000) interval = 5000;
|
||||||
else if (interval < 10) interval = 10;
|
else if (interval < 1) interval = 1;
|
||||||
this.interval = interval;
|
this.interval = interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1086,9 +1086,9 @@ namespace kcp2k
|
||||||
|
|
||||||
if (interval >= 0)
|
if (interval >= 0)
|
||||||
{
|
{
|
||||||
// clamp interval between 10 and 5000
|
// clamp interval between 1 and 5000
|
||||||
if (interval > 5000) interval = 5000;
|
if (interval > 5000) interval = 5000;
|
||||||
else if (interval < 10) interval = 10;
|
else if (interval < 1) interval = 1;
|
||||||
this.interval = interval;
|
this.interval = interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue