From 8c659e2a08d0dbfba9ba571ec61be9c94926b076 Mon Sep 17 00:00:00 2001 From: Regalis Date: Mon, 13 Mar 2017 21:50:01 +0200 Subject: [PATCH] Server checks if midround syncing is needed when a client is in the game (i.e. loaded the sub, etc), not when the client requests the start message. Some clients take longer to start the round than others, and they may miss unique messages even if they were in the lobby when the round started. Clients also get extra 10 seconds to receive newly created events after the midround syncing is done --- Subsurface/Source/Networking/GameServer.cs | 9 ++------ .../ServerEntityEventManager.cs | 22 +++++++++++-------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index e7c0c2f5e..e0468e417 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -565,7 +565,6 @@ namespace Barotrauma.Networking //game already started -> send start message immediately if (gameStarted) { - connectedClient.NeedsMidRoundSync = true; SendStartMessage(roundStartSeed, Submarine.MainSub, GameMain.GameSession.gameMode.Preset, connectedClient); } } @@ -655,12 +654,8 @@ namespace Barotrauma.Networking { if (!c.inGame) { - if (c.NeedsMidRoundSync) - { - //client joined mid-round and has just started up the game - //check which unique messages they've missed - entityEventManager.InitClientMidRoundSync(c); - } + //check if midround syncing is needed due to missed unique events + entityEventManager.InitClientMidRoundSync(c); c.inGame = true; } } diff --git a/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs b/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs index 8d875250c..a7a0b419e 100644 --- a/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs +++ b/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs @@ -133,12 +133,14 @@ namespace Barotrauma.Networking { //it's been 10 seconds since this event was created //kick everyone that hasn't received it yet, this is way too old - List toKick = inGameClients.FindAll(c => NetIdUtils.IdMoreRecent((UInt16)(lastSentToAll + 1), c.lastRecvEntityEventID)); + List toKick = inGameClients.FindAll(c => + NetIdUtils.IdMoreRecent((UInt16)(lastSentToAll + 1), c.lastRecvEntityEventID) && + (Timing.TotalTime - c.MidRoundSyncTimeOut) > 10.0f); //give mid-round joining players extra 10 seconds to receive the events + if (toKick != null) toKick.ForEach(c => server.DisconnectClient(c, "", "You have been disconnected because of excessive desync")); } } - - //TODO: calculate a reasonable timeout period for midround syncing and/or give the client more time if they're receiving messages + var timedOutClients = clients.FindAll(c => c.inGame && c.NeedsMidRoundSync && Timing.TotalTime > c.MidRoundSyncTimeOut); if (timedOutClients != null) timedOutClients.ForEach(c => GameMain.Server.DisconnectClient(c, "", "You have been disconnected because syncing your client with the server took too long.")); @@ -248,7 +250,14 @@ namespace Barotrauma.Networking public void InitClientMidRoundSync(Client client) { - if (uniqueEvents.Count > 0) + //no need for midround syncing if no events have been created, + //or if the first created unique event is still in the event list + if (uniqueEvents.Count == 0 || (events.Count > 0 && events[0].ID == uniqueEvents[0].ID)) + { + client.UnreceivedEntityEventCount = 0; + client.NeedsMidRoundSync = false; + } + else { double midRoundSyncTimeOut = uniqueEvents.Count / MaxEventsPerWrite * server.UpdateInterval.TotalSeconds; midRoundSyncTimeOut = Math.Max(5.0f, midRoundSyncTimeOut * 1.5f); @@ -257,11 +266,6 @@ namespace Barotrauma.Networking client.NeedsMidRoundSync = true; client.MidRoundSyncTimeOut = Timing.TotalTime + midRoundSyncTimeOut; } - else - { - client.UnreceivedEntityEventCount = 0; - client.NeedsMidRoundSync = false; - } } ///