using System; using System.Threading; using System.Threading.Tasks; using BITKit.Net.Examples; using UnityEngine; using Cysharp.Threading.Tasks; namespace BITKit.Net.Kcp { [CustomType(typeof(INetClient))] [CustomType(typeof(INetProvider))] public class MonoKcpClient : MonoBehaviour,INetClient,INetProvider { internal static MonoKcpClient Singleton { get; private set; } [SerializeField,ReadOnly] private int rate; [SerializeReference,SubclassSelector] private ITicker ticker; [SerializeField] private string m_host; [SerializeField] private ushort m_port; [SerializeField] private bool connectOnStart; [SerializeField] private bool autoReconnect; [Header(Constant.Header.Debug)] [SerializeField] [ReadOnly] private int id; [SerializeField] [ReadOnly]private Vector2 traffic; [SerializeField] [ReadOnly]private string upTraffic; [SerializeField] [ReadOnly]private string downTraffic; [SerializeField, ReadOnly] private bool isConnected; #if UNITY_EDITOR [SerializeField] private Optional allowDebugHost; [SerializeField] private Optional allowDebugPort; #endif private readonly DeltaTimer timer = new(); private KcpNetClient client; private INetClient _netClientImplementation=>client; private INetProvider _netProviderImplementation=>client; private readonly IntervalUpdate _reconnectInterval = new(3); public event Action OnStartConnect { add => _netClientImplementation.OnStartConnect += value; remove => _netClientImplementation.OnStartConnect -= value; } public event Action OnConnected { add => _netClientImplementation.OnConnected += value; remove => _netClientImplementation.OnConnected -= value; } public event Action OnDisconnected { add => _netClientImplementation.OnDisconnected += value; remove => _netClientImplementation.OnDisconnected -= value; } public event Action OnConnectedFailed { add => _netClientImplementation.OnConnectedFailed += value; remove => _netClientImplementation.OnConnectedFailed -= value; } public bool IsConnected => _netClientImplementation.IsConnected; public bool ManualTick { get => client.ManualTick; set => client.ManualTick = value; } public int Ping => _netClientImplementation.Ping; public int Id => _netClientImplementation.Id; public void Disconnect() { _netClientImplementation.Disconnect(); } public UniTask Connect(string address = "localhost", ushort port = 27014) { if(address is "localhost" or null) address = m_host; if(port is 27014 or 0) port = m_port; m_host = address; m_port = port; return _netClientImplementation.Connect(address, port); } public void SendServerMessage(string message) { _netClientImplementation.SendServerMessage(message); } public void ServerCommand(T command = default) { _netProviderImplementation.ServerCommand(command); } public void AllClientCommand(T command = default) { _netProviderImplementation.AllClientCommand(command); } public void ClientCommand(int id, T command) { _netProviderImplementation.ClientCommand(id, command); } public UniTask GetFromServer(string path = null, params object[] pars) { return client.GetFromServer(path, pars); } public UniTask GetFromClient(int id, string path = null, params object[] pars) { return client.GetFromClient(id, path, pars); } public UniTask GetFromServer(string path=null,T command = default) { return _netProviderImplementation.GetFromServer(path,command); } public UniTask GetFromClient(int id,string path=null, T command = default) { return _netProviderImplementation.GetFromClient(id,path, command); } public void AddRpcHandle(object rpcHandle) { _netProviderImplementation.AddRpcHandle(rpcHandle); } public void AddCommandListener(Action handle) { _netProviderImplementation.AddCommandListener(handle); } public void RemoveCommandListener(Action handle) { _netProviderImplementation.RemoveCommandListener(handle); } public void AddCommandListener(Func> func) { _netProviderImplementation.AddCommandListener(func); } public void RemoveCommandListener(Func> func) { _netProviderImplementation.RemoveCommandListener(func); } public void SendRT(string rpcName, params object[] pars) { _netProviderImplementation.SendRT(rpcName, pars); } public void SendTargetRT(int id, string rpcName, params object[] pars) { _netProviderImplementation.SendTargetRT(id, rpcName, pars); } public void SendAllRT(string rpcName, params object[] pars) { _netProviderImplementation.SendAllRT(rpcName, pars); } public void Tick() { _netProviderImplementation.Tick(); } public void HandShake() { _netProviderImplementation.HandShake(); } private void Awake() { Singleton = this; client = new KcpNetClient(); } private void Start() { if (ticker is not null) { ManualTick = true; ticker.Add(OnTick); } destroyCancellationToken.Register(() => { if (IsConnected) Disconnect(); ticker?.Remove(OnTick); }); if (!connectOnStart) return; #if UNITY_EDITOR var _host = allowDebugHost.Allow ? allowDebugHost.Value : m_host; var _port = allowDebugPort.Allow ? allowDebugPort.Value : m_port; Connect(_host, _port).Forget(); #else Connect(m_host, m_port).Forget(); #endif } private void OnTick(float obj) { if (destroyCancellationToken.IsCancellationRequested) return; if (client.IsConnected is false && autoReconnect) { if (_reconnectInterval.AllowUpdate) { if (client.IsConnecting is false) { client.Connect(m_host, m_port).Forget(); } } } id = Id; timer.Update(obj); rate = timer; Tick(); traffic = client.Traffic; upTraffic = NetUtils.GetFileSize((long)traffic.x); downTraffic = NetUtils.GetFileSize((long)traffic.y); isConnected = IsConnected; } [BIT] private void EditorConnect() { BITAppForUnity.ThrowIfNotPlaying(); Connect(m_host, m_port).Forget(); } [BIT] private void EditorDisconnect() { BITAppForUnity.ThrowIfNotPlaying(); Disconnect(); } [BIT] private async void Hello() { BITAppForUnity.ThrowIfNotPlaying(); var value =await GetFromServer(null,new SimplePing() { StartTime = DateTime.Now }); BIT4Log.Log($"已返回\n开始:{value.StartTime}\n结束:{value.EndTime}\n延迟:{(value.EndTime-value.StartTime).TotalMilliseconds}ms"); var hello = await GetFromServer( nameof(KCPNetServer.MyRpcTest), "hello" ); BIT4Log.Log($"延迟:{(DateTime.Now-value.StartTime).TotalMilliseconds}ms"); BIT4Log.Log($"已返回\n{hello}"); var helloAsync = await GetFromServer( nameof(KCPNetServer.MyRpcTestAsync), "hello" ); BIT4Log.Log($"已返回\n{helloAsync}"); } } }