This commit is contained in:
CortexCore 2024-06-20 10:04:18 +08:00
parent d3fd104900
commit a0d95098b8
7 changed files with 251 additions and 189 deletions

View File

@ -3,6 +3,7 @@
using UnityEngine; using UnityEngine;
#endif #endif
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -61,15 +62,22 @@ namespace BITKit
public static object Read(BinaryReader reader) public static object Read(BinaryReader reader)
{ {
// 检测是否为数组
if (reader.ReadBoolean()) if (reader.ReadBoolean())
{ {
var objs = new object[reader.ReadInt32()]; //读取数组类型的名称
for (var i = 0; i < objs.Length; i++) var arrayTypeName = reader.ReadString();
//获取数组类型
var arrayType = BITSharp.GetTypeFromFullName(arrayTypeName);
//创建数组实例
var array = Array.CreateInstance(arrayType, reader.ReadInt32());
//循环Reader
for (var i = 0; i < array.Length; i++)
{ {
objs[i] = ReadInternel(reader); //设置值
array.SetValue(ReadInternel(reader),i);
} }
return array;
return objs.ToArray();
} }
return ReadInternel(reader); return ReadInternel(reader);
@ -82,7 +90,18 @@ namespace BITKit
if (netReaders.TryGetValue(typeName, out var netReader)) if (netReaders.TryGetValue(typeName, out var netReader))
return netReader.ReadBinaryAsObject(reader); return netReader.ReadBinaryAsObject(reader);
var instance = System.Activator.CreateInstance(BITSharp.GetTypeFromFullName(typeName)); var type = BITSharp.GetTypeFromFullName(typeName);
object instance = null;
if (type.IsArray)
{
instance = Array.CreateInstance(type.GetElementType()!, reader.ReadInt32());
}
else
{
instance = System.Activator.CreateInstance(type);
}
if (instance is IBinarySerialize serialize) if (instance is IBinarySerialize serialize)
{ {
serialize.Read(reader); serialize.Read(reader);
@ -97,7 +116,7 @@ namespace BITKit
try try
{ {
if (BITSharp.TryGetTypeFromFullName(typeName, out var type)) if (BITSharp.TryGetTypeFromFullName(typeName, out type))
return JsonConvert.DeserializeObject(json, type); return JsonConvert.DeserializeObject(json, type);
} }
catch (Exception e) catch (Exception e)
@ -119,11 +138,13 @@ namespace BITKit
} }
public static void Write(BinaryWriter writer, object value) public static void Write(BinaryWriter writer, object value)
{ {
if (value is object[] objects) if (value is IEnumerable enumerable)
{ {
var pars = enumerable.Cast<object>().ToArray();
writer.Write(true); writer.Write(true);
writer.Write(objects.Length); writer.Write(value.GetType().GetElementType()!.FullName!);
foreach (var obj in objects) writer.Write(pars.Count());
foreach (var obj in pars)
{ {
WriteInterel(writer, obj); WriteInterel(writer, obj);
} }

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 39a2cf28bc8a59c4ab975f015c66d39d guid: fe988b178709928459e7b3ec5849dcfa
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -7,8 +7,8 @@ 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: 200, // 1ms so at interval code at least runs. Interval: 1, // 1ms so at interval code at least runs.
Timeout: 2000, Timeout: 8000,
CongestionWindow: false CongestionWindow: false
) )

View File

@ -29,7 +29,7 @@ namespace BITKit.Net
public int Id { get; private set; } = -1; public int Id { get; private set; } = -1;
private readonly KcpClient client; private readonly KcpClient client;
private readonly Queue<byte[]> commandQueue = new(); private readonly ConcurrentQueue<byte[]> _commandQueue = new();
private DateTime _lastPingTime = DateTime.Now; private DateTime _lastPingTime = DateTime.Now;
@ -92,6 +92,7 @@ namespace BITKit.Net
{ {
client.Disconnect(); client.Disconnect();
_isConnected.RemoveElement(this); _isConnected.RemoveElement(this);
_timer.Stop();
try try
{ {
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext,BITApp.CancellationToken); await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext,BITApp.CancellationToken);
@ -108,30 +109,35 @@ namespace BITKit.Net
await UniTask.SwitchToThreadPool(); await UniTask.SwitchToThreadPool();
try try
{ {
_lastHeartbeat = DateTime.Now;
client.Connect(address, port); client.Connect(address, port);
for (var i = 0; i < 5; i++)
{
client.Tick();
await Task.Delay(100);
}
_timer.Start(); _timer.Start();
Traffic+=new float2(1,0); // for (var i = 0; i < 5; i++)
client.Send(new[] { (byte)NetCommandType.Heartbeat }, KcpChannel.Reliable); // {
// client.Tick();
// await Task.Delay(100);
// }
_commandQueue.Enqueue(new []{(byte)NetCommandType.Heartbeat });
if (BITApp.SynchronizationContext is not null) if (BITApp.SynchronizationContext is not null)
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext); await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext);
if (client.connected) if (client.connected)
{ {
SendServerMessage(Environment.MachineName); SendServerMessage(Environment.MachineName);
Traffic+=new float2(1,0);
_commandQueue.Enqueue(new []{(byte)NetCommandType.Heartbeat});
} }
for (var i = 0; i < 5; i++) for (var i = 0; i < 5; i++)
{ {
client.Tick(); client.Tick();
await Task.Delay(100); await Task.Delay(100);
} }
if (client.connected is false) if (client.connected is false)
{ {
OnConnectedFailed?.Invoke(); OnConnectedFailed?.Invoke();
Disconnect();
return false;
} }
return client.connected; return client.connected;
} }
@ -141,6 +147,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);
OnConnectedFailed?.Invoke(); OnConnectedFailed?.Invoke();
_timer.Stop();
return false; return false;
} }
} }
@ -191,8 +198,7 @@ namespace BITKit.Net
break; break;
case NetCommandType.Heartbeat: case NetCommandType.Heartbeat:
Traffic+=new float2(1,0); _commandQueue.Enqueue(new []{(byte)NetCommandType.Heartbeat });
client.Send(new[] { (byte)NetCommandType.Heartbeat }, KcpChannel.Reliable);
_isConnected.AddElement(this); _isConnected.AddElement(this);
_lastHeartbeat = DateTime.Now; _lastHeartbeat = DateTime.Now;
break; break;
@ -282,7 +288,8 @@ namespace BITKit.Net
returnWriter.Write(e.Message); returnWriter.Write(e.Message);
} }
var _bytes = returnMS.ToArray(); var _bytes = returnMS.ToArray();
commandQueue.Enqueue(_bytes);
_commandQueue.Enqueue(_bytes);
} }
catch(Exception e) catch(Exception e)
{ {
@ -300,29 +307,16 @@ namespace BITKit.Net
private async void OnConnectedInternal() private async void OnConnectedInternal()
{ {
if (BITApp.SynchronizationContext is not null) // if (BITApp.SynchronizationContext is not null)
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext); // await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext);
OnConnected?.Invoke(); // OnConnected?.Invoke();
BIT4Log.Log<KcpNetClient>("已连接"); // BIT4Log.Log<KcpNetClient>("已连接");
} }
private async void OnDisconnectInternal() private async void OnDisconnectInternal()
{ {
//BIT4Log.Log<KcpNetClient>("断开连接"); BIT4Log.Log<KcpNetClient>("连接被断开");
_timer.Stop(); Disconnect();
try
{
if (BITApp.SynchronizationContext is not null)
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext,
BITApp.CancellationToken);
_isConnected.RemoveElement(this);
}
catch (OperationCanceledException)
{
}
} }
private void OnError(ErrorCode errorCode, string message) private void OnError(ErrorCode errorCode, string message)
{ {
@ -331,17 +325,31 @@ namespace BITKit.Net
public void ServerCommand<T>(T command = default) public void ServerCommand<T>(T command = default)
{ {
Send(NetCommandType.Command,command); using var ms = new MemoryStream();
using var writer = new BinaryWriter(ms);
writer.Write((byte)NetCommandType.Command);
BITBinary.Write(writer,command);
var bytes = ms.ToArray();
_commandQueue.Enqueue(bytes);
} }
public void AllClientCommand<T>(T command = default) public void AllClientCommand<T>(T command = default)
{ {
Send(NetCommandType.AllClientCommand,command); using var ms = new MemoryStream();
using var writer = new BinaryWriter(ms);
writer.Write((byte)NetCommandType.AllClientCommand);
BITBinary.Write(writer,command);
var bytes = ms.ToArray();
} }
public void ClientCommand<T>(int id, T command) public void ClientCommand<T>(int id, T command)
{ {
Send(NetCommandType.TargetCommand,id,command); using var ms = new MemoryStream();
using var writer = new BinaryWriter(ms);
writer.Write((byte)NetCommandType.Command);
BITBinary.Write(writer,command);
var bytes = ms.ToArray();
_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)
@ -363,8 +371,12 @@ namespace BITKit.Net
BITBinary.Write(writer,pars); BITBinary.Write(writer,pars);
var bytes = ms.ToArray(); var bytes = ms.ToArray();
commandQueue.Enqueue(bytes); _commandQueue.Enqueue(bytes);
var startTime = DateTime.Now; var startTime = DateTime.Now;
while (true) while (true)
{ {
if(DateTime.Now-startTime>TimeSpan.FromSeconds(5) || IsConnected is false) if(DateTime.Now-startTime>TimeSpan.FromSeconds(5) || IsConnected is false)
@ -380,10 +392,6 @@ namespace BITKit.Net
{ {
return t; return t;
} }
if (typeof(T) == typeof(UniTaskVoid))
{
return default;
}
return value.As<T>(); return value.As<T>();
} }
@ -403,8 +411,16 @@ namespace BITKit.Net
{ {
var att = methodInfo.GetCustomAttribute<NetRpcAttribute>(); var att = methodInfo.GetCustomAttribute<NetRpcAttribute>();
if(att is null)continue; if(att is null)continue;
_rpcMethods.TryAdd(methodInfo.Name, methodInfo); _rpcMethods.AddOrUpdate(methodInfo.Name, methodInfo, (s, info) => methodInfo);
_rpcHandles.TryAdd(methodInfo.Name, rpcHandle); _rpcHandles.AddOrUpdate(methodInfo.Name, rpcHandle, (s, o) => rpcHandle);
}
foreach (var eventInfo in rpcHandle.GetType().GetEvents())
{
var att = eventInfo.GetCustomAttribute<NetRpcAttribute>();
if(att is null)continue;
var handle = eventInfo.EventHandlerType.GetMethod("Invoke");
_rpcMethods.AddOrUpdate(handle.Name, handle, (s, info) => handle);
} }
} }
@ -436,7 +452,13 @@ namespace BITKit.Net
public void SendRT(string rpcName, params object[] pars) public void SendRT(string rpcName, params object[] pars)
{ {
throw new NotImplementedException(); using var ms = new MemoryStream();
using var writer = new BinaryWriter(ms);
writer.Write((byte)NetCommandType.GetFromClient);
writer.Write(rpcName);
BITBinary.Write(writer,pars);
var bytes = ms.ToArray();
_commandQueue.Enqueue(bytes);
} }
public void SendTargetRT(int id, string rpcName, params object[] pars) public void SendTargetRT(int id, string rpcName, params object[] pars)
@ -477,7 +499,7 @@ namespace BITKit.Net
} }
} }
while (commandQueue.TryDequeue(out var bytes)) while (_commandQueue.TryDequeue(out var bytes))
{ {
Traffic+=new float2(bytes.Length,0); Traffic+=new float2(bytes.Length,0);
client.Send(bytes, KcpChannel.Reliable); client.Send(bytes, KcpChannel.Reliable);
@ -506,17 +528,5 @@ namespace BITKit.Net
Traffic+=new float2(2,0); Traffic+=new float2(2,0);
client.Send(new byte[]{0x01, 0x02}, KcpChannel.Reliable); client.Send(new byte[]{0x01, 0x02}, KcpChannel.Reliable);
} }
private void Send(NetCommandType commandType,params object[] values)
{
var bytes = BinaryBuilder
.Create()
.Write((byte)commandType)
.WriteObject(values)
.Build();
commandQueue.Enqueue(bytes);
//client.Send(bytes, KcpChannel.Reliable);
}
} }
} }

View File

@ -36,6 +36,8 @@ namespace BITKit.Net
private readonly ConcurrentDictionary<string,Func<object,UniTask<object>>> _rpc = new(); private readonly ConcurrentDictionary<string,Func<object,UniTask<object>>> _rpc = new();
private readonly ConcurrentDictionary<string,MethodInfo> _rpcMethods = new(); private readonly ConcurrentDictionary<string,MethodInfo> _rpcMethods = new();
private readonly ConcurrentDictionary<string,object> _rpcHandles = new(); private readonly ConcurrentDictionary<string,object> _rpcHandles = new();
private readonly ConcurrentQueue<(int id,byte[] bytes)> _sendQueue = new();
public KCPNetServer() public KCPNetServer()
{ {
@ -64,6 +66,19 @@ namespace BITKit.Net
{ {
try try
{ {
while (_sendQueue.TryDequeue(out var value))
{
if (server.connections.ContainsKey(value.id))
{
server.Send(value.id,value.bytes,KcpChannel.Reliable);
}
else
{
BIT4Log.Log<KCPNetServer>($"链接{value.id}已丢失,丢弃了{value.bytes.Length}个字节");
}
}
if (server.IsActive() is false || ManualTick) return; if (server.IsActive() is false || ManualTick) return;
server.Tick(); server.Tick();
} }
@ -113,7 +128,11 @@ namespace BITKit.Net
public bool IsRunningServer => server.IsActive(); public bool IsRunningServer => server.IsActive();
public void SendMessageToClient(int id, string message) public void SendMessageToClient(int id, string message)
{ {
Send(id,NetCommandType.Message,message); using var ms = new MemoryStream();
using var writer = new BinaryWriter(ms);
writer.Write((byte)NetCommandType.Message);
writer.Write(message);
_sendQueue.Enqueue((id,ms.ToArray()));
} }
public void SendMessageToAll(string message) public void SendMessageToAll(string message)
@ -180,146 +199,156 @@ namespace BITKit.Net
BIT4Log.LogException(e); BIT4Log.LogException(e);
} }
} }
private async void OnDataInternel(int Id, ArraySegment<byte> bytes, KcpChannel channel) private async void OnDataInternel(int Id, ArraySegment<byte> bytes, KcpChannel channel)
{ {
using var ms = new MemoryStream(bytes.ToArray()); using var ms = new MemoryStream(bytes.ToArray());
using var reader = new BinaryReader(ms); using var reader = new BinaryReader(ms);
//BIT4Log.Log<INetServer>(Id); try
var type = (NetCommandType)ms.ReadByte();
//BIT4Log.Log<INetServer>(type);
switch (type)
{ {
case NetCommandType.Message: var type = (NetCommandType)ms.ReadByte();
BIT4Log.Log<KCPNetServer>($"已收到消息,{Id}:{reader.ReadString()}");
break; switch (type)
case NetCommandType.Command:
var command = BITBinary.Read(reader);
if (command is object[] { Length: 1 } objs) command = objs[0];
//BIT4Log.Log<KCPNetServer>($"已收到指令:{command},值:\n{JsonConvert.SerializeObject(command, Formatting.Indented)}");
_events.Invoke(command.GetType().FullName, command);
(int Id,object Command) tuple = (Id,command);
_events.InvokeDirect(command.GetType().FullName,tuple);
break;
case NetCommandType.Heartbeat:
server.Send(Id,new byte[]{(byte)NetCommandType.Heartbeat}, KcpChannel.Reliable);
break;
case NetCommandType.AllClientCommand:
foreach (var id in server.connections.Keys.ToArray())
{
server.Send(id,bytes,channel);
}
break;
case NetCommandType.TargetCommand:
var targetId = reader.ReadInt32();
server.Send(targetId,bytes,channel);
break;
case NetCommandType.Ping:
server.Send(Id,new byte[]{(byte)NetCommandType.Ping},channel);
break;
case NetCommandType.GetFromServer:
{ {
var requestId = reader.ReadInt32(); case NetCommandType.Message:
BIT4Log.Log<KCPNetServer>($"已收到消息,{Id}:{reader.ReadString()}");
break;
case NetCommandType.Command:
var command = BITBinary.Read(reader);
if (command is object[] { Length: 1 } objs) command = objs[0];
//BIT4Log.Log<KCPNetServer>($"已收到指令:{command},值:\n{JsonConvert.SerializeObject(command, Formatting.Indented)}");
_events.Invoke(command.GetType().FullName, command);
using var returnMS = new MemoryStream(); (int Id, object Command) tuple = (Id, command);
await using var returnWriter = new BinaryWriter(returnMS); _events.InvokeDirect(command.GetType().FullName, tuple);
returnWriter.Write((byte)NetCommandType.ReturnToClient); break;
returnWriter.Write(requestId); case NetCommandType.Heartbeat:
_sendQueue.Enqueue((Id,new byte[] { (byte)NetCommandType.Heartbeat }));
try break;
{ case NetCommandType.AllClientCommand:
if (reader.ReadBoolean()) foreach (var id in server.connections.Keys.ToArray())
{ {
var path = reader.ReadString(); _sendQueue.Enqueue((id,bytes.ToArray()));
var pars = BITBinary.Read(reader).As<object[]>(); }
break;
case NetCommandType.TargetCommand:
if (_rpcMethods.TryGetValue(path, out var methodInfo)) var targetId = reader.ReadInt32();
{ _sendQueue.Enqueue((targetId,bytes.ToArray()));
var isAwaitable = methodInfo.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null; break;
var handle = _rpcHandles[path]; case NetCommandType.Ping:
object value = null; _sendQueue.Enqueue((Id,new byte[] { (byte)NetCommandType.Ping }));
if (methodInfo.GetParameters().Length is 0) break;
{ case NetCommandType.GetFromServer:
pars = new object[]{}; {
} var requestId = reader.ReadInt32();
if (isAwaitable)
{
dynamic result = methodInfo.Invoke(handle, pars)!;
value = await result; using var returnMS = new MemoryStream();
await using var returnWriter = new BinaryWriter(returnMS);
returnWriter.Write((byte)NetCommandType.ReturnToClient);
returnWriter.Write(requestId);
try
{
if (reader.ReadBoolean())
{
var path = reader.ReadString();
var pars = BITBinary.Read(reader).As<object[]>();
if (_rpcMethods.TryGetValue(path, out var methodInfo))
{
var isAwaitable = methodInfo.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
var handle = _rpcHandles[path];
object value = null;
if (methodInfo.GetParameters().Length is 0)
{
pars = new object[] { };
}
if (isAwaitable)
{
dynamic result = methodInfo.Invoke(handle, pars)!;
value = await result;
}
else
{
value = methodInfo.Invoke(handle, pars);
}
returnWriter.Write(true);
BITBinary.Write(returnWriter, value);
} }
else else
{ {
value = methodInfo.Invoke(handle, pars); throw new Exception($"未找到对应的Rpc方法:{path}");
} }
returnWriter.Write(true);
BITBinary.Write(returnWriter, value);
} }
else else
{ {
throw new Exception($"未找到对应的Rpc方法:{path}"); var commandObj = BITBinary.Read(reader)
.As<object[]>()[0];
var funcName = commandObj.GetType()!.FullName!;
if (_rpc.TryGetValue(funcName, out var func))
{
var value = await func.As<Func<object, UniTask<object>>>().Invoke(commandObj);
returnWriter.Write(true);
BITBinary.Write(returnWriter, value);
}
else
{
throw new Exception($"未找到对应的Rpc方法:{funcName}");
}
} }
{
var _bytes = returnMS.ToArray();
_sendQueue.Enqueue((Id,_bytes));
}
}
catch (Exception e)
{
returnWriter.Write(false);
returnWriter.Write(e.Message);
var _bytes = returnMS.ToArray();
_sendQueue.Enqueue((Id,_bytes));
BIT4Log.LogException(e);
}
}
break;
case NetCommandType.ReturnToServer:
{
var id = reader.ReadInt32();
if (reader.ReadBoolean())
{
var value = BITBinary.Read(reader);
_p2p.TryAdd(id, value);
} }
else else
{ {
var commandObj = BITBinary.Read(reader) var message = reader.ReadString();
.As<object[]>()[0]; _p2p.TryAdd(id, new Exception(message));
var funcName = commandObj.GetType()!.FullName!;
if (_rpc.TryGetValue(funcName, out var func))
{
var value = await func.As<Func<object, UniTask<object>>>().Invoke(commandObj);
returnWriter.Write(true);
BITBinary.Write(returnWriter, value);
}
else
{
throw new Exception($"未找到对应的Rpc方法:{funcName}");
}
}
{
var _bytes = returnMS.ToArray();
server.Send(Id, _bytes, KcpChannel.Reliable);
} }
} }
catch (Exception e) break;
{ default:
returnWriter.Write(false); BIT4Log.Log<KCPNetServer>($"未知消息类型:{type},字节:{(byte)type}");
returnWriter.Write(e.Message); BIT4Log.Log<KCPNetServer>(
$"已收到:({Id}, {BitConverter.ToString(bytes.Array, bytes.Offset, bytes.Count)} @ {channel})");
var _bytes = returnMS.ToArray(); break;
server.Send(Id, _bytes, KcpChannel.Reliable);
BIT4Log.LogException(e);
}
} }
break; }
case NetCommandType.ReturnToServer: catch (Exception e)
{ {
var id = reader.ReadInt32(); ms.Close();
if (reader.ReadBoolean()) reader.Close();
{ BIT4Log.LogException(e);
var value = BITBinary.Read(reader);
_p2p.TryAdd(id, value);
}
else
{
var message = reader.ReadString();
_p2p.TryAdd(id, new Exception(message));
}
}
break;
default:
BIT4Log.Log<KCPNetServer>($"未知消息类型:{type},字节:{(byte)type}");
BIT4Log.Log<KCPNetServer>($"已收到:({Id}, {BitConverter.ToString(bytes.Array, bytes.Offset, bytes.Count)} @ {channel})");
break;
} }
} }
private void OnError(int Id, ErrorCode errorCode, string message) private void OnError(int Id, ErrorCode errorCode, string message)
{ {
BIT4Log.Log<KCPNetServer>($"异常:{errorCode},{message}"); BIT4Log.Log<KCPNetServer>($"异常:{errorCode},{message}");
@ -367,7 +396,8 @@ namespace BITKit.Net
BITBinary.Write(writer,pars); BITBinary.Write(writer,pars);
var bytes = ms.ToArray(); var bytes = ms.ToArray();
server.Send(id,bytes,KcpChannel.Reliable); //server.Send(id,bytes,KcpChannel.Reliable);
_sendQueue.Enqueue((id,bytes));
var startTime = DateTime.Now; var startTime = DateTime.Now;
while (true) while (true)
{ {
@ -490,10 +520,8 @@ namespace BITKit.Net
.Write((byte)commandType) .Write((byte)commandType)
.WriteObject(values) .WriteObject(values)
.Build(); .Build();
if (server.connections.ContainsKey(id)) //server.Send(id,bytes, KcpChannel.Reliable);
{ _sendQueue.Enqueue((id,bytes));
server.Send(id,bytes, KcpChannel.Reliable);
}
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
* e.g. * e.g.
* INetProvider * INetProvider
* INetServer * INetServer
* INetClient * INetClient
*/ */
@ -15,7 +15,7 @@ using UnityEngine;
namespace BITKit namespace BITKit
{ {
[AttributeUsage(AttributeTargets.Method)] [AttributeUsage(AttributeTargets.Method|AttributeTargets.Event)]
public sealed class NetRpcAttribute : Attribute public sealed class NetRpcAttribute : Attribute
{ {
@ -67,6 +67,8 @@ namespace BITKit
ReciveFile=11, ReciveFile=11,
ReturnToServer=12, ReturnToServer=12,
ReturnToClient=13, ReturnToClient=13,
TargetRpc=14,
AllRpc=15,
} }
/// <summary> /// <summary>
/// 网络提供服务包括了基础网络服务e.g /// 网络提供服务包括了基础网络服务e.g

View File

@ -208,6 +208,7 @@ namespace BITKit.Net.Kcp
private void OnTick(float obj) private void OnTick(float obj)
{ {
if (destroyCancellationToken.IsCancellationRequested) return;
if (client.IsConnected is false && autoReconnect) if (client.IsConnected is false && autoReconnect)
{ {
if (_reconnectInterval.AllowUpdate) if (_reconnectInterval.AllowUpdate)