This commit is contained in:
CortexCore 2024-06-08 10:07:40 +08:00
parent ccc9957809
commit b9731c20a1
11 changed files with 231 additions and 44 deletions

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Timers; using System.Timers;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
@ -38,6 +39,10 @@ namespace BITKit.Net
private readonly GenericEvent _events = new(); private readonly GenericEvent _events = new();
private readonly ValidHandle _isConnected = new(); private readonly ValidHandle _isConnected = new();
private int _index = 1001;
private readonly ConcurrentDictionary<int, object> _p2p = new();
private readonly ConcurrentDictionary<string,object> _rpc = new();
public KcpNetClient() public KcpNetClient()
{ {
client = new KcpClient( client = new KcpClient(
@ -161,6 +166,11 @@ namespace BITKit.Net
case NetCommandType.Ping: case NetCommandType.Ping:
Ping = (int)(DateTime.Now - _lastPingTime).TotalMilliseconds; Ping = (int)(DateTime.Now - _lastPingTime).TotalMilliseconds;
break; break;
case NetCommandType.ReturnToClient:
var id = reader.ReadInt32();
var value = BITBinary.Read(reader);
_p2p.TryAdd(id,value);
break;
default: default:
BIT4Log.Log<KcpClient>($"未知消息类型:{type},字节:{(byte)type}"); BIT4Log.Log<KcpClient>($"未知消息类型:{type},字节:{(byte)type}");
if (bytes.Array != null) if (bytes.Array != null)
@ -217,15 +227,36 @@ namespace BITKit.Net
Send(NetCommandType.TargetCommand,id,command); Send(NetCommandType.TargetCommand,id,command);
} }
public UniTask<T> GetFromServer<T>(string addressablePath = Constant.System.Internal) public async UniTask<T> GetFromServer<T>(T command = default)
{
var id = _index++;
using var ms = new MemoryStream();
await using var writer = new BinaryWriter(ms);
writer.Write((byte)NetCommandType.GetFromServer);
writer.Write(id);
BITBinary.Write(writer,command);
var bytes = ms.ToArray();
commandQueue.Enqueue(bytes);
var startTime = DateTime.Now;
while (true)
{
if(DateTime.Now-startTime>TimeSpan.FromSeconds(5) || IsConnected is false)
throw new TimeoutException();
if (_p2p.TryRemove(id, out var value))
{
return (T)value;
}
await Task.Delay(100);
}
}
public UniTask<T> GetFromClient<T>(int id, T command = default)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public UniTask<T> GetFromClient<T>(int id, string addressablePath = Constant.System.Internal)
{
throw new NotImplementedException();
}
public void AddRpcHandle(object rpcHandle) public void AddRpcHandle(object rpcHandle)
{ {
@ -237,9 +268,19 @@ namespace BITKit.Net
_events.AddListener<T>(handle); _events.AddListener<T>(handle);
} }
public void AddCommandListener<T>(Func<T, T> func)
{
_rpc.GetOrAdd(typeof(T).FullName, func);
}
public void RemoveCommandListener<T>(Func<T, T> func)
{
_rpc.TryRemove(typeof(T).FullName, out _);
}
public void RemoveCommandListener<T>(Action<T> handle) public void RemoveCommandListener<T>(Action<T> handle)
{ {
throw new NotImplementedException(); _events.RemoveListener<T>(handle);
} }
public void SendRT(string rpcName, params object[] pars) public void SendRT(string rpcName, params object[] pars)

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Timers; using System.Timers;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
@ -26,6 +27,11 @@ namespace BITKit.Net
AutoReset = true AutoReset = true
}; };
private int _index = 1001;
private readonly ConcurrentDictionary<int, object> _p2p = new();
private readonly ConcurrentDictionary<string,Func<object,object>> _rpc = new();
public KCPNetServer() public KCPNetServer()
{ {
server = new KcpServer( server = new KcpServer(
@ -37,6 +43,12 @@ namespace BITKit.Net
); );
_timer.Elapsed += Tick; _timer.Elapsed += Tick;
BIT4Log.Log<KCPNetServer>("已创建KCP服务器"); BIT4Log.Log<KCPNetServer>("已创建KCP服务器");
AddCommandListener<SimplePing>(x =>
{
x.EndTime = DateTime.Now;
return x;
});
} }
private void Tick(object sender, ElapsedEventArgs e) private void Tick(object sender, ElapsedEventArgs e)
@ -161,6 +173,35 @@ namespace BITKit.Net
case NetCommandType.Ping: case NetCommandType.Ping:
server.Send(Id,new byte[]{(byte)NetCommandType.Ping},channel); server.Send(Id,new byte[]{(byte)NetCommandType.Ping},channel);
break; break;
case NetCommandType.GetFromServer:
try
{
var requestId = reader.ReadInt32();
var commandObj = BITBinary.Read(reader);
BIT4Log.Log<KCPNetServer>($"已收到请求:{commandObj},请求ID:{requestId}");
if (_rpc.TryGetValue(commandObj.GetType().FullName, out var func) is false)
{
throw new NotImplementedException($"未找到对应的方法:{commandObj.GetType().FullName}");
}
var value = func.As<Func<object,object>>().Invoke(commandObj);
using var _ms = new MemoryStream();
using var _writer = new BinaryWriter(_ms);
_writer.Write((byte)NetCommandType.ReturnToClient);
_writer.Write(requestId);
BITBinary.Write(_writer,value);
var _bytes = _ms.ToArray();
server.Send(Id,_bytes,KcpChannel.Reliable);
}
catch (Exception e)
{
BIT4Log.LogException(e);
Send(Id,NetCommandType.ReturnToClient,-1,0);
}
break;
default: default:
BIT4Log.Log<KCPNetServer>($"未知消息类型:{type},字节:{(byte)type}"); BIT4Log.Log<KCPNetServer>($"未知消息类型:{type},字节:{(byte)type}");
BIT4Log.Log<KCPNetServer>($"已收到:({Id}, {BitConverter.ToString(bytes.Array, bytes.Offset, bytes.Count)} @ {channel})"); BIT4Log.Log<KCPNetServer>($"已收到:({Id}, {BitConverter.ToString(bytes.Array, bytes.Offset, bytes.Count)} @ {channel})");
@ -190,12 +231,12 @@ namespace BITKit.Net
Send(id,NetCommandType.Command,command); Send(id,NetCommandType.Command,command);
} }
public UniTask<T> GetFromServer<T>(string addressablePath = Constant.System.Internal) public UniTask<T> GetFromServer<T>(T command = default)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public UniTask<T> GetFromClient<T>(int id, string addressablePath = Constant.System.Internal) public UniTask<T> GetFromClient<T>(int id, T command = default)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@ -210,6 +251,20 @@ namespace BITKit.Net
_events.AddListener<T>(handle); _events.AddListener<T>(handle);
} }
public void AddCommandListener<T>(Func<T, T> func)
{
_rpc.TryAdd(typeof(T).FullName, F);
return;
object F(object o)
{
return func.Invoke((T)o);
}
}
public void RemoveCommandListener<T>(Func<T, T> func)
{
_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); _events.AddListenerDirect(typeof(T).FullName, Callback);
@ -233,6 +288,11 @@ namespace BITKit.Net
_events.RemoveListener<T>(handle); _events.RemoveListener<T>(handle);
} }
public void RemoveCommandListener<T>(Func<string, T> func)
{
throw new NotImplementedException();
}
public void SendRT(string rpcName, params object[] pars) public void SendRT(string rpcName, params object[] pars)
{ {
throw new NotImplementedException(); throw new NotImplementedException();

View File

@ -1,11 +1,13 @@
using System; using System;
using System.Data;
namespace BITKit.Net.Examples namespace BITKit.Net.Examples
{ {
public struct LogTime public struct LogTime
{ {
public Guid Id; public Guid Id;
public DateTime CreateTime; public DateTime CreateTime;
#if NET5_0_OR_GREATER #if NET5_0_OR_GREATER
public LogTime() public LogTime()
{ {
CreateTime=DateTime.Now; CreateTime=DateTime.Now;
@ -13,5 +15,10 @@ namespace BITKit.Net.Examples
} }
#endif #endif
} }
public struct SimplePing
{
public DateTime StartTime;
public DateTime EndTime;
}
} }

View File

@ -29,6 +29,11 @@ namespace BITKit
Message=6, Message=6,
Heartbeat=7, Heartbeat=7,
Ping=8, Ping=8,
GetFromServer=9,
GetFromClient=10,
ReciveFile=11,
ReturnToServer=12,
ReturnToClient=13,
} }
/// <summary> /// <summary>
/// 网络提供服务包括了基础网络服务e.g /// 网络提供服务包括了基础网络服务e.g
@ -67,10 +72,9 @@ namespace BITKit
/// <summary> /// <summary>
/// 从服务端获取数据 /// 从服务端获取数据
/// </summary> /// </summary>
/// <param name="addressablePath">可寻址路劲 e.g. Key</param>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <returns></returns> /// <returns></returns>
UniTask<T> GetFromServer<T>(string addressablePath = Constant.System.Internal); UniTask<T> GetFromServer<T>(T command = default);
/// <summary> /// <summary>
/// 从客户端获取数据 /// 从客户端获取数据
@ -79,7 +83,7 @@ namespace BITKit
/// <param name="addressablePath">可寻址路劲 e.g. Key</param> /// <param name="addressablePath">可寻址路劲 e.g. Key</param>
/// <typeparam name="T">远程指令类型</typeparam> /// <typeparam name="T">远程指令类型</typeparam>
/// <returns></returns> /// <returns></returns>
UniTask<T> GetFromClient<T>(int id, string addressablePath = Constant.System.Internal); UniTask<T> GetFromClient<T>(int id,T command = default);
/// <summary> /// <summary>
/// 添加RPC远程服务服务类型为需要的方法标记[RPC] /// 添加RPC远程服务服务类型为需要的方法标记[RPC]
@ -93,13 +97,19 @@ namespace BITKit
/// <param name="handle">远程指令回调</param> /// <param name="handle">远程指令回调</param>
/// <typeparam name="T">远程指令类型</typeparam> /// <typeparam name="T">远程指令类型</typeparam>
void AddCommandListener<T>(Action<T> handle); void AddCommandListener<T>(Action<T> handle);
/// <summary>
/// 监听远程func
/// </summary>
/// <param name="func"></param>
/// <typeparam name="T"></typeparam>
void AddCommandListener<T>(Func<T,T> func);
/// <summary> /// <summary>
/// 取消监听远程指令 /// 取消监听远程指令
/// </summary> /// </summary>
/// <param name="handle">远程指令回调</param> /// <param name="handle">远程指令回调</param>
/// <typeparam name="T">远程指令类型</typeparam> /// <typeparam name="T">远程指令类型</typeparam>
void RemoveCommandListener<T>(Action<T> handle); void RemoveCommandListener<T>(Func<T,T> func);
/// <summary> /// <summary>
/// 向服务端发送Rpc /// 向服务端发送Rpc

View File

@ -53,6 +53,10 @@ namespace BITKit
private static Type SearchType(string fullName) private static Type SearchType(string fullName)
{ {
if (string.IsNullOrWhiteSpace(fullName))
{
throw new ArgumentException("fullName is null or empty", nameof(fullName));
}
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);
} }

View File

@ -2,13 +2,37 @@
namespace BITKit namespace BITKit
{ {
/// <summary>
/// 循环
/// </summary>
public interface ITicker public interface ITicker
{ {
/// <summary>
/// 总帧数
/// </summary>
ulong TickCount { get; } ulong TickCount { get; }
/// <summary>
/// 在下一次循环时执行,仅执行一次
/// </summary>
/// <param name="action"></param>
void Add(Action action); void Add(Action action);
/// <summary>
/// 注册在下一次循环时执行,每次循环都会执行
/// </summary>
/// <param name="action"></param>
void Add(Action<float> action); void Add(Action<float> action);
/// <summary>
/// 移除循环
/// </summary>
/// <param name="action"></param>
void Remove(Action<float> action); void Remove(Action<float> action);
} }
/// <summary>
/// 主线程循环
/// </summary>
public interface IMainTicker : ITicker { } public interface IMainTicker : ITicker { }
/// <summary>
/// 线程池循环
/// </summary>
public interface IThreadTicker : ITicker { } public interface IThreadTicker : ITicker { }
} }

View File

@ -89,15 +89,9 @@ namespace BITKit.Net
_netProviderImplementation.ClientCommand(id, command); _netProviderImplementation.ClientCommand(id, command);
} }
public UniTask<T> GetFromServer<T>(string addressablePath = Constant.System.Internal) public UniTask<T> GetFromServer<T>(T command = default)=>_netProviderImplementation.GetFromServer<T>(command);
{
return _netProviderImplementation.GetFromServer<T>(addressablePath);
}
public UniTask<T> GetFromClient<T>(int id, string addressablePath = Constant.System.Internal) public UniTask<T> GetFromClient<T>(int id, T command = default)=>_netProviderImplementation.GetFromClient(id, command);
{
return _netProviderImplementation.GetFromClient<T>(id, addressablePath);
}
public void AddRpcHandle(object rpcHandle) public void AddRpcHandle(object rpcHandle)
{ {
@ -109,11 +103,15 @@ namespace BITKit.Net
_netProviderImplementation.AddCommandListener(handle); _netProviderImplementation.AddCommandListener(handle);
} }
public void RemoveCommandListener<T>(Action<T> handle) public void AddCommandListener<T>(Func<T, T> func)
{ {
_netProviderImplementation.RemoveCommandListener(handle); throw new NotImplementedException();
} }
public void RemoveCommandListener<T>(Func<T, T> func)
{
throw new NotImplementedException();
}
public void SendRT(string rpcName, params object[] pars) public void SendRT(string rpcName, params object[] pars)
{ {
_netProviderImplementation.SendRT(rpcName, pars); _netProviderImplementation.SendRT(rpcName, pars);

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using BITKit.Net.Examples;
using UnityEngine; using UnityEngine;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
namespace BITKit.Net.Kcp namespace BITKit.Net.Kcp
@ -95,16 +96,15 @@ namespace BITKit.Net.Kcp
_netProviderImplementation.ClientCommand(id, command); _netProviderImplementation.ClientCommand(id, command);
} }
public UniTask<T> GetFromServer<T>(string addressablePath = Constant.System.Internal) public UniTask<T> GetFromServer<T>(T command = default)
{ {
return _netProviderImplementation.GetFromServer<T>(addressablePath); return _netProviderImplementation.GetFromServer<T>(command);
} }
public UniTask<T> GetFromClient<T>(int id, string addressablePath = Constant.System.Internal) public UniTask<T> GetFromClient<T>(int id, T command = default)
{ {
return _netProviderImplementation.GetFromClient<T>(id, addressablePath); return _netProviderImplementation.GetFromClient<T>(id, command);
} }
public void AddRpcHandle(object rpcHandle) public void AddRpcHandle(object rpcHandle)
{ {
_netProviderImplementation.AddRpcHandle(rpcHandle); _netProviderImplementation.AddRpcHandle(rpcHandle);
@ -115,11 +115,15 @@ namespace BITKit.Net.Kcp
_netProviderImplementation.AddCommandListener(handle); _netProviderImplementation.AddCommandListener(handle);
} }
public void RemoveCommandListener<T>(Action<T> handle) public void AddCommandListener<T>(Func<T, T> func)
{ {
_netProviderImplementation.RemoveCommandListener(handle); throw new NotImplementedException();
} }
public void RemoveCommandListener<T>(Func<T, T> func)
{
throw new NotImplementedException();
}
public void SendRT(string rpcName, params object[] pars) public void SendRT(string rpcName, params object[] pars)
{ {
_netProviderImplementation.SendRT(rpcName, pars); _netProviderImplementation.SendRT(rpcName, pars);
@ -214,6 +218,16 @@ namespace BITKit.Net.Kcp
BITAppForUnity.ThrowIfNotPlaying(); BITAppForUnity.ThrowIfNotPlaying();
Disconnect(); Disconnect();
} }
[BIT]
private async void Hello()
{
BITAppForUnity.ThrowIfNotPlaying();
var value =await GetFromServer(new SimplePing()
{
StartTime = DateTime.Now
});
BIT4Log.Log<MonoKcpClient>($"已返回\n开始:{value.StartTime}\n结束:{value.EndTime}\n延迟:{(value.EndTime-value.StartTime).TotalMilliseconds}ms");
}
} }
} }

View File

@ -76,16 +76,15 @@ namespace BITKit.Net.Kcp
_netProviderImplementation.ClientCommand(id, command); _netProviderImplementation.ClientCommand(id, command);
} }
public UniTask<T> GetFromServer<T>(string addressablePath = Constant.System.Internal) public UniTask<T> GetFromServer<T>(T command = default)
{ {
return _netProviderImplementation.GetFromServer<T>(addressablePath); return _netProviderImplementation.GetFromServer<T>(command);
} }
public UniTask<T> GetFromClient<T>(int id, string addressablePath = Constant.System.Internal) public UniTask<T> GetFromClient<T>(int id, T command = default)
{ {
return _netProviderImplementation.GetFromClient<T>(id, addressablePath); return _netProviderImplementation.GetFromClient<T>(id, command);
} }
public void AddRpcHandle(object rpcHandle) public void AddRpcHandle(object rpcHandle)
{ {
_netProviderImplementation.AddRpcHandle(rpcHandle); _netProviderImplementation.AddRpcHandle(rpcHandle);
@ -96,11 +95,15 @@ namespace BITKit.Net.Kcp
_netProviderImplementation.AddCommandListener(handle); _netProviderImplementation.AddCommandListener(handle);
} }
public void RemoveCommandListener<T>(Action<T> handle) public void AddCommandListener<T>(Func<T, T> func)
{ {
_netProviderImplementation.RemoveCommandListener(handle); throw new NotImplementedException();
} }
public void RemoveCommandListener<T>(Func<T, T> func)
{
throw new NotImplementedException();
}
public void SendRT(string rpcName, params object[] pars) public void SendRT(string rpcName, params object[] pars)
{ {
_netProviderImplementation.SendRT(rpcName, pars); _netProviderImplementation.SendRT(rpcName, pars);

View File

@ -108,16 +108,15 @@ namespace BITKit.Net.Kcp
_server.ClientCommand(id, command); _server.ClientCommand(id, command);
} }
public UniTask<T> GetFromServer<T>(string addressablePath = Constant.System.Internal) public UniTask<T> GetFromServer<T>(T command = default)
{ {
return _server.GetFromServer<T>(addressablePath); return _serverInstance.GetFromServer(command);
} }
public UniTask<T> GetFromClient<T>(int id, string addressablePath = Constant.System.Internal) public UniTask<T> GetFromClient<T>(int id, T command = default)
{ {
return _server.GetFromClient<T>(id, addressablePath); return _serverInstance.GetFromClient(id, command);
} }
public void AddRpcHandle(object rpcHandle) public void AddRpcHandle(object rpcHandle)
{ {
_server.AddRpcHandle(rpcHandle); _server.AddRpcHandle(rpcHandle);
@ -128,6 +127,16 @@ namespace BITKit.Net.Kcp
_server.AddCommandListener(handle); _server.AddCommandListener(handle);
} }
public void AddCommandListener<T>(Func<T, T> func)
{
_serverInstance.AddCommandListener(func);
}
public void RemoveCommandListener<T>(Func<T, T> func)
{
_serverInstance.RemoveCommandListener(func);
}
public void RemoveCommandListener<T>(Action<T> handle) public void RemoveCommandListener<T>(Action<T> handle)
{ {
_server.RemoveCommandListener(handle); _server.RemoveCommandListener(handle);

View File

@ -51,6 +51,10 @@ namespace BITKit.GameEditor
var createContainer = listViewContainer.Create<VisualElement>(); var createContainer = listViewContainer.Create<VisualElement>();
var exportButton = leftSlider.Create<Button>();
exportButton.text = "导出";
exportButton.clicked += ExportData;
createContainer.style.flexDirection = FlexDirection.Row; createContainer.style.flexDirection = FlexDirection.Row;
var nameField = createContainer.Create<TextField>(); var nameField = createContainer.Create<TextField>();
@ -99,6 +103,19 @@ namespace BITKit.GameEditor
$"{GetType().Name} 已初始化,从{AssetsPath}获取到{List.Count}个{typeof(T).Name}"); $"{GetType().Name} 已初始化,从{AssetsPath}获取到{List.Count}个{typeof(T).Name}");
} }
private void ExportData()
{
var exportPath = EditorUtility.OpenFolderPanel("select path", "",typeof(T).FullName);
if(string.IsNullOrEmpty(exportPath))return;
ExportData(exportPath);
}
protected virtual void ExportData(string path)
{
}
protected virtual void ItemsChosen(IEnumerable<object> obj) protected virtual void ItemsChosen(IEnumerable<object> obj)
{ {
var selected = obj.FirstOrDefault() as Object; var selected = obj.FirstOrDefault() as Object;