diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj index 149dcc032..aa61a1833 100644 --- a/Subsurface/Barotrauma.csproj +++ b/Subsurface/Barotrauma.csproj @@ -163,6 +163,7 @@ + diff --git a/Subsurface/Source/Networking/ChatMessage.cs b/Subsurface/Source/Networking/ChatMessage.cs index a04de33b4..545ed21c9 100644 --- a/Subsurface/Source/Networking/ChatMessage.cs +++ b/Subsurface/Source/Networking/ChatMessage.cs @@ -47,9 +47,9 @@ namespace Barotrauma.Networking private set; } - public static UInt32 LastID = 0; + public static UInt16 LastID = 0; - public UInt32 NetStateID + public UInt16 NetStateID { get; set; @@ -138,9 +138,9 @@ namespace Barotrauma.Networking static public void ServerRead(NetIncomingMessage msg, Client c) { - UInt32 ID = msg.ReadUInt32(); + UInt16 ID = msg.ReadUInt16(); string txt = msg.ReadString(); - if (c.lastSentChatMsgID < ID) + if (NetIdUtils.IdMoreRecent(ID, c.lastSentChatMsgID)) { //this chat message is new to the server GameMain.Server.SendChatMessage(txt, null, c); @@ -169,7 +169,7 @@ namespace Barotrauma.Networking static public void ClientRead(NetIncomingMessage msg) { - UInt32 ID = msg.ReadUInt32(); + UInt16 ID = msg.ReadUInt16(); ChatMessageType type = (ChatMessageType)msg.ReadByte(); string txt = msg.ReadString(); @@ -189,7 +189,7 @@ namespace Barotrauma.Networking senderName = msg.ReadString(); } - if (ID > LastID) + if (NetIdUtils.IdMoreRecent(ID, LastID)) { GameMain.Client.AddChatMessage(txt, type, senderName, senderCharacter); LastID = ID; diff --git a/Subsurface/Source/Networking/Client.cs b/Subsurface/Source/Networking/Client.cs index ea148d322..7725d8b9f 100644 --- a/Subsurface/Source/Networking/Client.cs +++ b/Subsurface/Source/Networking/Client.cs @@ -30,11 +30,11 @@ namespace Barotrauma.Networking public NetConnection Connection { get; set; } public string version; public bool inGame; - public UInt32 lastRecvGeneralUpdate = 0; + public UInt16 lastRecvGeneralUpdate = 0; public bool hasLobbyData = false; - public UInt32 lastSentChatMsgID = 0; //last msg this client said - public UInt32 lastRecvChatMsgID = 0; //last msg this client knows about + public UInt16 lastSentChatMsgID = 0; //last msg this client said + public UInt16 lastRecvChatMsgID = 0; //last msg this client knows about public UInt32 lastSentEntityEventID = 0; public UInt32 lastRecvEntityEventID = 0; @@ -42,7 +42,7 @@ namespace Barotrauma.Networking public UInt32 lastRecvEntitySpawnID = 0; public List chatMsgQueue = new List(); - public UInt32 lastChatMsgQueueID; + public UInt16 lastChatMsgQueueID; public float ChatSpamSpeed; public float ChatSpamTimer; public int ChatSpamCount; diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 4aafe6211..1c98d5221 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -35,8 +35,8 @@ namespace Barotrauma.Networking private int nonce; private string saltedPw; - private UInt32 lastSentChatMsgID = 0; //last message this client has successfully sent - private UInt32 lastQueueChatMsgID = 0; //last message added to the queue + private UInt16 lastSentChatMsgID = 0; //last message this client has successfully sent + private UInt16 lastQueueChatMsgID = 0; //last message added to the queue private List chatMsgQueue = new List(); public UInt32 LastSentEntityEventID; @@ -729,13 +729,13 @@ namespace Barotrauma.Networking if (lobbyUpdated) { - UInt32 updateID = inc.ReadUInt32(); + UInt16 updateID = inc.ReadUInt16(); string serverName = inc.ReadString(); string serverText = inc.ReadString(); if (inc.ReadBoolean()) { - ReadInitialUpdate(inc, updateID <= GameMain.NetLobbyScreen.LastUpdateID); + ReadInitialUpdate(inc, !NetIdUtils.IdMoreRecent(updateID,GameMain.NetLobbyScreen.LastUpdateID)); } string selectSubName = inc.ReadString(); @@ -768,7 +768,7 @@ namespace Barotrauma.Networking } //ignore the message if we already a more up-to-date one - if (updateID > GameMain.NetLobbyScreen.LastUpdateID) + if (NetIdUtils.IdMoreRecent(updateID, GameMain.NetLobbyScreen.LastUpdateID)) { GameMain.NetLobbyScreen.LastUpdateID = updateID; @@ -811,7 +811,7 @@ namespace Barotrauma.Networking Voting.AllowModeVoting = allowModeVoting; } } - lastSentChatMsgID = inc.ReadUInt32(); + lastSentChatMsgID = inc.ReadUInt16(); break; case ServerNetObject.CHAT_MESSAGE: ChatMessage.ClientRead(inc); @@ -833,7 +833,7 @@ namespace Barotrauma.Networking switch (objHeader) { case ServerNetObject.SYNC_IDS: - lastSentChatMsgID = inc.ReadUInt32(); + lastSentChatMsgID = inc.ReadUInt16(); LastSentEntityEventID = inc.ReadUInt32(); break; case ServerNetObject.ENTITY_POSITION: @@ -878,11 +878,8 @@ namespace Barotrauma.Networking outmsg.Write((byte)ClientNetObject.SYNC_IDS); outmsg.Write(GameMain.NetLobbyScreen.LastUpdateID); outmsg.Write(ChatMessage.LastID); - ChatMessage removeMsg; - while ((removeMsg=chatMsgQueue.Find(cMsg => cMsg.NetStateID <= lastSentChatMsgID)) != null) - { - chatMsgQueue.Remove(removeMsg); - } + + chatMsgQueue.RemoveAll(cMsg => !NetIdUtils.IdMoreRecent(cMsg.NetStateID, lastSentChatMsgID)); foreach (ChatMessage cMsg in chatMsgQueue) { @@ -903,11 +900,7 @@ namespace Barotrauma.Networking outmsg.Write(Entity.Spawner.NetStateID); outmsg.Write(entityEventManager.LastReceivedID); - ChatMessage removeMsg; - while ((removeMsg = chatMsgQueue.Find(cMsg => cMsg.NetStateID <= lastSentChatMsgID)) != null) - { - chatMsgQueue.Remove(removeMsg); - } + chatMsgQueue.RemoveAll(cMsg => !NetIdUtils.IdMoreRecent(cMsg.NetStateID, lastSentChatMsgID)); foreach (ChatMessage cMsg in chatMsgQueue) { diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 289d8b3be..0f7409c42 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -66,7 +66,7 @@ namespace Barotrauma.Networking { this.password = Encoding.UTF8.GetString(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(password))); } - + config = new NetPeerConfiguration("barotrauma"); netStats = new NetStats(); @@ -78,6 +78,8 @@ namespace Barotrauma.Networking config.SimulatedMinimumLatency = 0.1f; config.ConnectionTimeout = 60.0f; + + NetIdUtils.Test(); #endif config.Port = port; Port = port; @@ -622,8 +624,8 @@ namespace Barotrauma.Networking { case ClientNetObject.SYNC_IDS: //TODO: might want to use a clever class for this - c.lastRecvGeneralUpdate = Math.Min(Math.Max(c.lastRecvGeneralUpdate, inc.ReadUInt32()), GameMain.NetLobbyScreen.LastUpdateID); - c.lastRecvChatMsgID = Math.Min(Math.Max(c.lastRecvChatMsgID, inc.ReadUInt32()), c.lastChatMsgQueueID); + c.lastRecvGeneralUpdate = NetIdUtils.Clamp(inc.ReadUInt16(), c.lastRecvGeneralUpdate, GameMain.NetLobbyScreen.LastUpdateID); + c.lastRecvChatMsgID = NetIdUtils.Clamp(inc.ReadUInt16(), c.lastRecvChatMsgID, c.lastChatMsgQueueID); break; case ClientNetObject.CHAT_MESSAGE: ChatMessage.ServerRead(inc, c); @@ -657,7 +659,7 @@ namespace Barotrauma.Networking case ClientNetObject.SYNC_IDS: //TODO: might want to use a clever class for this - UInt32 lastRecvChatMsgID = inc.ReadUInt32(); + UInt16 lastRecvChatMsgID = inc.ReadUInt16(); UInt32 lastRecvEntitySpawnID = inc.ReadUInt32(); UInt32 lastRecvEntityEventID = inc.ReadUInt32(); @@ -734,7 +736,7 @@ namespace Barotrauma.Networking outmsg.Write(c.lastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server outmsg.Write(c.lastSentEntityEventID); - c.chatMsgQueue.RemoveAll(cMsg => cMsg.NetStateID <= c.lastRecvChatMsgID); + c.chatMsgQueue.RemoveAll(cMsg => !NetIdUtils.IdMoreRecent(cMsg.NetStateID, c.lastRecvChatMsgID)); foreach (ChatMessage cMsg in c.chatMsgQueue) { cMsg.ServerWrite(outmsg, c); @@ -797,8 +799,8 @@ namespace Barotrauma.Networking outmsg.Write((byte)ServerPacketHeader.UPDATE_LOBBY); outmsg.Write((byte)ServerNetObject.SYNC_IDS); - - if (c.lastRecvGeneralUpdate cMsg.NetStateID <= c.lastRecvChatMsgID); + c.chatMsgQueue.RemoveAll(cMsg => !NetIdUtils.IdMoreRecent(cMsg.NetStateID, c.lastRecvChatMsgID)); foreach (ChatMessage cMsg in c.chatMsgQueue) { cMsg.ServerWrite(outmsg, c); @@ -1480,10 +1482,10 @@ namespace Barotrauma.Networking modifiedMessage, (ChatMessageType)type, senderCharacter); - - chatMsg.NetStateID = client.chatMsgQueue.Count > 0 ? - client.chatMsgQueue.Last().NetStateID + 1 : - client.lastRecvChatMsgID+1; + + chatMsg.NetStateID = client.chatMsgQueue.Count > 0 ? + (ushort)(client.chatMsgQueue.Last().NetStateID + 1) : + (ushort)(client.lastRecvChatMsgID + 1); client.chatMsgQueue.Add(chatMsg); client.lastChatMsgQueueID = chatMsg.NetStateID; diff --git a/Subsurface/Source/Networking/NetIdUtils.cs b/Subsurface/Source/Networking/NetIdUtils.cs new file mode 100644 index 000000000..7702e3006 --- /dev/null +++ b/Subsurface/Source/Networking/NetIdUtils.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Barotrauma.Networking +{ + static class NetIdUtils + { + /// + /// Is newID more recent than oldID + /// + public static bool IdMoreRecent(ushort newID, ushort oldID) + { + uint id1 = newID; + uint id2 = oldID; + + return + (id1 > id2) && (id1 - id2 <= ushort.MaxValue / 2) + || + (id2 > id1) && (id2 - id1 > ushort.MaxValue / 2); + } + + public static ushort Clamp(ushort id, ushort min, ushort max) + { + if (IdMoreRecent(min, max)) + { + throw new ArgumentException("Min cannot be larger than max"); + } + + if (!IdMoreRecent(id, min)) + { + return min; + } + else if (IdMoreRecent(id, max)) + { + return max; + } + + return id; + } + +#if DEBUG + public static void Test() + { + Debug.Assert(NetIdUtils.IdMoreRecent((ushort)2, (ushort)1)); + Debug.Assert(NetIdUtils.IdMoreRecent((ushort)2, (ushort)(ushort.MaxValue - 5))); + Debug.Assert(!NetIdUtils.IdMoreRecent((ushort)ushort.MaxValue, (ushort)5)); + + Debug.Assert(Clamp((ushort)5, (ushort)1, (ushort)10) == 5); + Debug.Assert(Clamp((ushort)(ushort.MaxValue - 5), (ushort)(ushort.MaxValue - 2), (ushort)3) == (ushort)(ushort.MaxValue - 2)); + } +#endif + } +} diff --git a/Subsurface/Source/Screens/NetLobbyScreen.cs b/Subsurface/Source/Screens/NetLobbyScreen.cs index 39d22fe11..67887f04b 100644 --- a/Subsurface/Source/Screens/NetLobbyScreen.cs +++ b/Subsurface/Source/Screens/NetLobbyScreen.cs @@ -52,9 +52,8 @@ namespace Barotrauma public bool IsServer; public string ServerName; - const float NetworkUpdateInterval = 1.0f; - private UInt32 lastUpdateID; - public UInt32 LastUpdateID + private UInt16 lastUpdateID; + public UInt16 LastUpdateID { get { if (GameMain.Server != null && lastUpdateID < 1) lastUpdateID++; return lastUpdateID; } set { if (GameMain.Server != null) return; lastUpdateID = value; }