diff --git a/Subsurface/Source/Networking/Client.cs b/Subsurface/Source/Networking/Client.cs index 52bd7d852..ff1804c5d 100644 --- a/Subsurface/Source/Networking/Client.cs +++ b/Subsurface/Source/Networking/Client.cs @@ -47,6 +47,8 @@ namespace Barotrauma.Networking public float ChatSpamTimer; public int ChatSpamCount; + public double MidRoundSyncTimeOut; + public bool NeedsMidRoundSync; //how many unique events the client missed before joining the server public UInt16 UnreceivedEntityEventCount; diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 779f15832..3e207f174 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -627,13 +627,16 @@ namespace Barotrauma.Networking if (gameStarted) { - if (!c.inGame && c.NeedsMidRoundSync) + if (!c.inGame) { - //client joined mid-round and has just started up the game - //check which unique messages they've missed - entityEventManager.InitClientMidRoundSync(c); + if (c.NeedsMidRoundSync) + { + //client joined mid-round and has just started up the game + //check which unique messages they've missed + entityEventManager.InitClientMidRoundSync(c); + } + c.inGame = true; } - c.inGame = true; } ClientNetObject objHeader; diff --git a/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs b/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs index 9434cebd4..3314bd7e9 100644 --- a/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs +++ b/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs @@ -124,21 +124,26 @@ namespace Barotrauma.Networking bufferedEvent.IsProcessed = true; } - if (clients.Count > 0) + var inGameClients = clients.FindAll(c => c.inGame && !c.NeedsMidRoundSync); + if (inGameClients.Count > 0) { - lastSentToAll = clients[0].lastRecvEntityEventID; - clients.ForEach(c => { if (c.inGame && NetIdUtils.IdMoreRecent(lastSentToAll,c.lastRecvEntityEventID)) lastSentToAll = c.lastRecvEntityEventID; }); + lastSentToAll = inGameClients[0].lastRecvEntityEventID; + inGameClients.ForEach(c => { if (NetIdUtils.IdMoreRecent(lastSentToAll, c.lastRecvEntityEventID)) lastSentToAll = c.lastRecvEntityEventID; }); ServerEntityEvent firstEventToResend = events.Find(e => e.ID == (lastSentToAll + 1)); - if (firstEventToResend != null && (Timing.TotalTime-firstEventToResend.CreateTime)>10.0f) + if (firstEventToResend != null && (Timing.TotalTime - firstEventToResend.CreateTime) > 10.0f) { //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 = clients.FindAll(c => c.inGame && NetIdUtils.IdMoreRecent((UInt16)(lastSentToAll+1),c.lastRecvEntityEventID)); - if (toKick!=null) toKick.ForEach(c => GameMain.Server.DisconnectClient(c,"","You have been disconnected because of excessive desync")); + List toKick = inGameClients.FindAll(c => NetIdUtils.IdMoreRecent((UInt16)(lastSentToAll + 1), c.lastRecvEntityEventID)); + 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.")); + bufferedEvents.RemoveAll(b => b.IsProcessed); } @@ -249,6 +254,7 @@ namespace Barotrauma.Networking { client.UnreceivedEntityEventCount = (UInt16)uniqueEvents.Count; client.NeedsMidRoundSync = true; + client.MidRoundSyncTimeOut = Timing.TotalTime + 10.0; } else {