From 0998cdbe013ffc5ad1e8ac512b962e7856281873 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Wed, 28 Jun 2017 23:05:41 +0300 Subject: [PATCH] Server queues entity position updates and delays sending them if there's not enough room in a message after writing the entity events and chat messages. + removed unused SparseUpdate --- Barotrauma/Source/Networking/Client.cs | 7 + Barotrauma/Source/Networking/GameServer.cs | 146 ++++++++++++--------- 2 files changed, 88 insertions(+), 65 deletions(-) diff --git a/Barotrauma/Source/Networking/Client.cs b/Barotrauma/Source/Networking/Client.cs index dce365954..5a9a09ea2 100644 --- a/Barotrauma/Source/Networking/Client.cs +++ b/Barotrauma/Source/Networking/Client.cs @@ -59,6 +59,8 @@ namespace Barotrauma.Networking //when was a specific entity event last sent to the client // key = event id, value = NetTime.Now when sending public Dictionary entityEventLastSent; + + private Queue pendingPositionUpdates = new Queue(); public bool ReadyToStart; @@ -70,6 +72,11 @@ namespace Barotrauma.Networking public float deleteDisconnectedTimer; public ClientPermissions Permissions = ClientPermissions.None; + + public Queue PendingPositionUpdates + { + get { return pendingPositionUpdates; } + } public void InitClientSync() { diff --git a/Barotrauma/Source/Networking/GameServer.cs b/Barotrauma/Source/Networking/GameServer.cs index 766d5a11d..42a47ed64 100644 --- a/Barotrauma/Source/Networking/GameServer.cs +++ b/Barotrauma/Source/Networking/GameServer.cs @@ -28,8 +28,7 @@ namespace Barotrauma.Networking private NetPeerConfiguration config; private int MaxPlayers; - - private DateTime sparseUpdateTimer; + private DateTime refreshMasterTimer; private DateTime roundStartTime; @@ -529,25 +528,15 @@ namespace Barotrauma.Networking { if (server.ConnectionsCount > 0) { - if (sparseUpdateTimer < DateTime.Now) SparseUpdate(); - foreach (Client c in ConnectedClients) { - if (gameStarted && c.inGame) + try { - ClientWriteIngame(c); + ClientWrite(c); } - else + catch (Exception e) { - //if 30 seconds have passed since the round started and the client isn't ingame yet, - //kill the clients character - if (gameStarted && c.Character != null && (DateTime.Now - roundStartTime).Seconds > 30.0f) - { - c.Character.Kill(CauseOfDeath.Disconnected); - c.Character = null; - } - - ClientWriteLobby(c); + DebugConsole.ThrowError("Failed to write a network message for the client \""+c.name+"\"!", e); } } @@ -617,12 +606,7 @@ namespace Barotrauma.Networking break; } } - - private void SparseUpdate() - { - sparseUpdateTimer = DateTime.Now + sparseUpdateInterval; - } - + public void CreateEntityEvent(IServerSerializable entity, object[] extraData = null) { entityEventManager.CreateEvent(entity, extraData); @@ -827,6 +811,27 @@ namespace Barotrauma.Networking inc.ReadPadBits(); } + + private void ClientWrite(Client c) + { + if (gameStarted && c.inGame) + { + ClientWriteIngame(c); + } + else + { + //if 30 seconds have passed since the round started and the client isn't ingame yet, + //kill the client's character + if (gameStarted && c.Character != null && (DateTime.Now - roundStartTime).Seconds > 30.0f) + { + c.Character.Kill(CauseOfDeath.Disconnected); + c.Character = null; + } + + ClientWriteLobby(c); + } + } + /// /// Write info that the client needs when joining the server /// @@ -850,6 +855,37 @@ namespace Barotrauma.Networking private void ClientWriteIngame(Client c) { + //don't send position updates to characters who are still midround syncing + //characters or items spawned mid-round don't necessarily exist at the client's end yet + if (!c.NeedsMidRoundSync) + { + foreach (Character character in Character.CharacterList) + { + if (!character.Enabled) continue; + if (c.Character != null && + Vector2.DistanceSquared(character.WorldPosition, c.Character.WorldPosition) >= + NetConfig.CharacterIgnoreDistance * NetConfig.CharacterIgnoreDistance) + { + continue; + } + if (!c.PendingPositionUpdates.Contains(character)) c.PendingPositionUpdates.Enqueue(character); + } + + foreach (Submarine sub in Submarine.Loaded) + { + //if docked to a sub with a smaller ID, don't send an update + // (= update is only sent for the docked sub that has the smallest ID, doesn't matter if it's the main sub or a shuttle) + if (sub.DockedTo.Any(s => s.ID < sub.ID)) continue; + if (!c.PendingPositionUpdates.Contains(sub)) c.PendingPositionUpdates.Enqueue(sub); + } + + foreach (Item item in Item.ItemList) + { + if (!item.NeedsPositionUpdate) continue; + if (!c.PendingPositionUpdates.Contains(item)) c.PendingPositionUpdates.Enqueue(item); + } + } + NetOutgoingMessage outmsg = server.CreateMessage(); outmsg.Write((byte)ServerPacketHeader.UPDATE_INGAME); @@ -858,52 +894,30 @@ namespace Barotrauma.Networking outmsg.Write((byte)ServerNetObject.SYNC_IDS); outmsg.Write(c.lastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server outmsg.Write(c.lastSentEntityEventID); - - //don't send position updates to characters who are still midround syncing - //characters or items spawned mid-round don't necessarily exist at the client's end yet - if (!c.NeedsMidRoundSync) - { - foreach (Character character in Character.CharacterList) - { - if (!character.Enabled) continue; - - if (c.Character != null && - Vector2.DistanceSquared(character.WorldPosition, c.Character.WorldPosition) >= - NetConfig.CharacterIgnoreDistance * NetConfig.CharacterIgnoreDistance) - { - continue; - } - - outmsg.Write((byte)ServerNetObject.ENTITY_POSITION); - character.ServerWrite(outmsg, c); - outmsg.WritePadBits(); - } - - foreach (Submarine sub in Submarine.Loaded) - { - //if docked to a sub with a smaller ID, don't send an update - // (= update is only sent for the docked sub that has the smallest ID, doesn't matter if it's the main sub or a shuttle) - if (sub.DockedTo.Any(s => s.ID < sub.ID)) continue; - - outmsg.Write((byte)ServerNetObject.ENTITY_POSITION); - sub.ServerWrite(outmsg, c); - outmsg.WritePadBits(); - } - - foreach (Item item in Item.ItemList) - { - if (!item.NeedsPositionUpdate) continue; - - outmsg.Write((byte)ServerNetObject.ENTITY_POSITION); - item.ServerWritePosition(outmsg, c); - outmsg.WritePadBits(); - } - } entityEventManager.Write(c, outmsg); - + WriteChatMessages(outmsg, c); + //write as many position updates as the message can fit + while (outmsg.LengthBytes < config.MaximumTransmissionUnit - 20 && + c.PendingPositionUpdates.Count > 0) + { + var entity = c.PendingPositionUpdates.Dequeue(); + if (entity == null || entity.Removed) continue; + + outmsg.Write((byte)ServerNetObject.ENTITY_POSITION); + if (entity is Item) + { + ((Item)entity).ServerWritePosition(outmsg, c); + } + else + { + ((IServerSerializable)entity).ServerWrite(outmsg, c); + } + outmsg.WritePadBits(); + } + outmsg.Write((byte)ServerNetObject.END_OF_MESSAGE); if (outmsg.LengthBytes > config.MaximumTransmissionUnit) @@ -1165,7 +1179,8 @@ namespace Barotrauma.Networking foreach (Client client in teamClients) { client.NeedsMidRoundSync = false; - + + client.PendingPositionUpdates.Clear(); client.entityEventLastSent.Clear(); client.lastSentEntityEventID = 0; client.lastRecvEntityEventID = 0; @@ -1356,6 +1371,7 @@ namespace Barotrauma.Networking foreach (Client c in connectedClients) { c.entityEventLastSent.Clear(); + c.PendingPositionUpdates.Clear(); } #if DEBUG