using System.Collections; using System.Collections.Generic; using UnityEngine; using KairoEngine.Core; using Sirenix.OdinInspector; using UniRx; namespace KairoEngine.Multiplayer { [HideMonoScript] public class ServerSyncAjustmentSystem : MonoBehaviour { public ServerBehaviour server; public NetworkTick networkTick; public ClientList clientList; public int adjustmentInterval = 3000; public int adjustmentIterations = 10; private List pings = new List(); private bool serverIsRunning = false; private bool adjusting = false; private int adjustmentIterationCount = 0; private CompositeDisposable adjustmentLoop; private void OnEnable() { GenericEvents.StartListening($"{server.eventStreamName}_Listening", OnServerStart); GenericEvents.StartListening($"{server.eventStreamName}_Stopped", OnServerStop); GenericEvents.StartListening($"{server.eventStreamName}_OnTick", OnTick); NetMsgEvents.StartListening($"{server.eventStreamName}_PingSent", OnPingSent); NetMsgEvents.StartListening($"{server.eventStreamName}_PongReceived", OnPongReceived); } private void OnDisable() { GenericEvents.StopListening($"{server.eventStreamName}_Listening", OnServerStart); GenericEvents.StopListening($"{server.eventStreamName}_Stopped", OnServerStop); GenericEvents.StopListening($"{server.eventStreamName}_OnTick", OnTick); NetMsgEvents.StopListening($"{server.eventStreamName}_PingSent", OnPingSent); NetMsgEvents.StopListening($"{server.eventStreamName}_PongReceived", OnPongReceived); } private void OnServerStart(string text) { serverIsRunning = true; schedualedjustmentCalculation(); } private void OnServerStop(string text) { serverIsRunning = false; adjustmentLoop.Dispose(); } private void OnTick(int tick) { if(!serverIsRunning) return; if(!adjusting) return; for (int i = 0; i < clientList.clients.Count; i++) { if(clientList.clients[i].isConnected) PingClient(i); } adjustmentIterationCount += 1; if(adjustmentIterationCount >= adjustmentIterations) { // done adjusting = false; } } private void schedualedjustmentCalculation() { adjustmentLoop = Timer.ExecuteRealTime(adjustmentInterval, () => { if(!serverIsRunning) return; adjusting = true; adjustmentIterationCount = 0; pings = new List(); schedualedjustmentCalculation(); }); } private void PingClient(int i) { ClientData client = clientList.clients[i]; NetPingMsg netPingMsg = new NetPingMsg((uint)networkTick.tick); server.SendNetMsgToClient(client.connectionId, (uint)NetOpCode.Ping, netPingMsg); PingData ping = new PingData(client.connectionId, networkTick.tick); pings.Add(ping); } private void OnPingSent(string text, int clientId, uint code, NetMsg netMsg) { NetPingMsg msg = (NetPingMsg)netMsg; PingData ping = GetPingData(clientId, (int)msg.pingId); if(ping != null) ping.startTime = Time.realtimeSinceStartup; } private void OnPongReceived(string text, int clientId, uint code, NetMsg netMsg) { NetPongMsg msg = (NetPongMsg)netMsg; PingData ping = GetPingData(clientId, (int)msg.pingId); if(ping != null) { ping.endTime = Time.realtimeSinceStartup; ClientData clientData = clientList.GetClientData(ping.clientId); if(clientData != null) clientData.latency = CalculateLatency(clientData.connectionId); } else Debug.LogWarning($"Could not find ping data ({(int)msg.pingId})"); } public PingData GetPingData(int clientId, int pingId) { for (int i = 0; i < pings.Count; i++) { if(pings[i].clientId == clientId && pings[i].pingId == pingId) return pings[i]; } return null; } public int CalculateLatency(int clientId) { int total = 0; int count = 0; for (int i = 0; i < pings.Count; i++) { if(pings[i].clientId == clientId && pings[i].endTime != 0) { total += pings[i].elapsedTime(); count +=1; } } return total/count; } } }