From 7f400715656c112889cece76184d96e42c8aee04 Mon Sep 17 00:00:00 2001 From: Regalis Date: Sun, 27 Mar 2016 20:20:34 +0300 Subject: [PATCH] - fixed ReliableChannel going crazy if a client disconnects and reconnects immediately after: the client created a new ReliableChannel but the server was still using the old one, causing the client to rerequest a ton of messages (now the server resets the channel when a client rejoins and reliablechannel resets itself if the message IDs are too far apart) - syncing statuseffects caused by using an item on self --- Subsurface/Source/Characters/Character.cs | 40 ++++++------ Subsurface/Source/Characters/StatusEffect.cs | 2 +- Subsurface/Source/Items/CharacterInventory.cs | 3 +- Subsurface/Source/Networking/GameServer.cs | 3 +- Subsurface/Source/Networking/NetworkEvent.cs | 45 +++++++------ .../Source/Networking/ReliableSender.cs | 64 ++++++++++++++----- 6 files changed, 100 insertions(+), 57 deletions(-) diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index b725cffab..3fd674551 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -1306,7 +1306,7 @@ namespace Barotrauma // while (timer < dimDuration && Character.controlled == null) // { - // timer += CoroutineManager.DeltaTime; + // timer += CoroutineManager.UnscaledDeltaTime; // if (cam != null) cam.OffsetAmount = 0.0f; @@ -1320,7 +1320,7 @@ namespace Barotrauma // float lerpLightBack = 0.0f; // while (lerpLightBack < 1.0f) // { - // lerpLightBack = Math.Min(lerpLightBack + CoroutineManager.DeltaTime*5.0f, 1.0f); + // lerpLightBack = Math.Min(lerpLightBack + CoroutineManager.UnscaledDeltaTime*5.0f, 1.0f); // GameMain.LightManager.AmbientLight = Color.Lerp(darkLight, prevAmbientLight, lerpLightBack); // yield return CoroutineStatus.Running; @@ -1457,6 +1457,9 @@ namespace Barotrauma case NetworkEventType.InventoryUpdate: if (inventory == null) return false; return inventory.FillNetworkData(NetworkEventType.InventoryUpdate, message, data); + case NetworkEventType.ApplyStatusEffect: + message.Write((ushort)data); + return true; case NetworkEventType.ImportantEntityUpdate: message.WriteRangedSingle(health, minHealth, maxHealth, 8); @@ -1559,8 +1562,6 @@ namespace Barotrauma switch (type) { case NetworkEventType.PickItem: - - ushort itemId = message.ReadUInt16(); bool pickHit = message.ReadBoolean(); @@ -1570,18 +1571,18 @@ namespace Barotrauma System.Diagnostics.Debug.WriteLine("item id: "+itemId); - Item item = FindEntityByID(itemId) as Item; - if (item != null) + Item pickedItem = FindEntityByID(itemId) as Item; + if (pickedItem != null) { - if (item == selectedConstruction) + if (pickedItem == selectedConstruction) { - GameServer.Log(Name + " deselected " + item.Name, Color.Orange); + GameServer.Log(Name + " deselected " + pickedItem.Name, Color.Orange); } else { - GameServer.Log(Name + " selected " + item.Name, Color.Orange); + GameServer.Log(Name + " selected " + pickedItem.Name, Color.Orange); } - item.Pick(this, false, pickHit, actionHit); + pickedItem.Pick(this, false, pickHit, actionHit); } return; @@ -1650,18 +1651,21 @@ namespace Barotrauma if (inventory == null) return; inventory.ReadNetworkData(NetworkEventType.InventoryUpdate, message, sendingTime); return; + case NetworkEventType.ApplyStatusEffect: + ushort id = message.ReadUInt16(); + + data = id; + + var item = FindEntityByID(id) as Item; + if (item == null) return; + + item.ApplyStatusEffects(ActionType.OnUse, 1.0f, this); + + break; case NetworkEventType.ImportantEntityUpdate: health = message.ReadRangedSingle(minHealth, 100.0f, 8); - // MathHelper.Clamp((message.ReadByte() / 255.0f) * maxHealth, 0.0f, maxHealth); - - //if (health == 0.0f) - //{ - // causeOfDeath = (CauseOfDeath)message.ReadRangedInteger(0, Enum.GetValues(typeof(CauseOfDeath)).Length-1); - // Kill(causeOfDeath, true); - //} - bool allOk = message.ReadBoolean(); if (allOk) { diff --git a/Subsurface/Source/Characters/StatusEffect.cs b/Subsurface/Source/Characters/StatusEffect.cs index 76c4cfda7..3796de97a 100644 --- a/Subsurface/Source/Characters/StatusEffect.cs +++ b/Subsurface/Source/Characters/StatusEffect.cs @@ -278,7 +278,7 @@ namespace Barotrauma yield return CoroutineStatus.Success; } - protected void ApplyToProperty(ObjectProperty property, object value, float deltaTime) + private void ApplyToProperty(ObjectProperty property, object value, float deltaTime) { if (disableDeltaTime || setValue) deltaTime = 1.0f; diff --git a/Subsurface/Source/Items/CharacterInventory.cs b/Subsurface/Source/Items/CharacterInventory.cs index 5f25a8b44..f4267c43f 100644 --- a/Subsurface/Source/Items/CharacterInventory.cs +++ b/Subsurface/Source/Items/CharacterInventory.cs @@ -88,7 +88,8 @@ namespace Barotrauma if (Items[slotIndex] == null) return false; - Items[slotIndex].ApplyStatusEffects(ActionType.OnUse, 0.016f, character); + Items[slotIndex].ApplyStatusEffects(ActionType.OnUse, 1.0f, character); + new NetworkEvent(NetworkEventType.ApplyStatusEffect, character.ID, true, Items[slotIndex].ID); return true; } diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 33b222346..06edbafe7 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -689,6 +689,7 @@ namespace Barotrauma.Networking if (existingClient != null) { existingClient.Connection = inc.SenderConnection; + existingClient.ReliableChannel = new ReliableChannel(server); inc.SenderConnection.Approve(); return; } @@ -1671,7 +1672,7 @@ namespace Barotrauma.Networking if (client.FileStreamSender != null) client.FileStreamSender.Dispose(); } - server.Shutdown("The server has shut down"); + server.Shutdown("The server has been shut down"); } } diff --git a/Subsurface/Source/Networking/NetworkEvent.cs b/Subsurface/Source/Networking/NetworkEvent.cs index c95070695..29e763fd9 100644 --- a/Subsurface/Source/Networking/NetworkEvent.cs +++ b/Subsurface/Source/Networking/NetworkEvent.cs @@ -31,7 +31,9 @@ namespace Barotrauma.Networking UpdateProperty = 10, WallDamage = 11, - PhysicsBodyPosition = 12 + PhysicsBodyPosition = 12, + + ApplyStatusEffect = 13 } class NetworkEvent @@ -44,39 +46,42 @@ namespace Barotrauma.Networking static NetworkEvent() { deliveryMethod = new NetworkEventDeliveryMethod[Enum.GetNames(typeof(NetworkEventType)).Length]; - deliveryMethod[(int)NetworkEventType.ImportantEntityUpdate] = NetworkEventDeliveryMethod.ReliableChannel; - deliveryMethod[(int)NetworkEventType.ImportantComponentUpdate] = NetworkEventDeliveryMethod.ReliableChannel; - deliveryMethod[(int)NetworkEventType.KillCharacter] = NetworkEventDeliveryMethod.ReliableLidgren; - deliveryMethod[(int)NetworkEventType.SelectCharacter] = NetworkEventDeliveryMethod.ReliableChannel; + deliveryMethod[(int)NetworkEventType.ImportantEntityUpdate] = NetworkEventDeliveryMethod.ReliableChannel; + deliveryMethod[(int)NetworkEventType.ImportantComponentUpdate] = NetworkEventDeliveryMethod.ReliableChannel; + deliveryMethod[(int)NetworkEventType.KillCharacter] = NetworkEventDeliveryMethod.ReliableLidgren; + deliveryMethod[(int)NetworkEventType.SelectCharacter] = NetworkEventDeliveryMethod.ReliableChannel; - deliveryMethod[(int)NetworkEventType.ImportantComponentUpdate] = NetworkEventDeliveryMethod.ReliableChannel; - deliveryMethod[(int)NetworkEventType.PickItem] = NetworkEventDeliveryMethod.ReliableChannel; - deliveryMethod[(int)NetworkEventType.DropItem] = NetworkEventDeliveryMethod.ReliableChannel; - deliveryMethod[(int)NetworkEventType.InventoryUpdate] = NetworkEventDeliveryMethod.ReliableChannel; - deliveryMethod[(int)NetworkEventType.ItemFixed] = NetworkEventDeliveryMethod.ReliableLidgren; + deliveryMethod[(int)NetworkEventType.ImportantComponentUpdate] = NetworkEventDeliveryMethod.ReliableChannel; + deliveryMethod[(int)NetworkEventType.PickItem] = NetworkEventDeliveryMethod.ReliableChannel; + deliveryMethod[(int)NetworkEventType.DropItem] = NetworkEventDeliveryMethod.ReliableChannel; + deliveryMethod[(int)NetworkEventType.InventoryUpdate] = NetworkEventDeliveryMethod.ReliableChannel; + deliveryMethod[(int)NetworkEventType.ItemFixed] = NetworkEventDeliveryMethod.ReliableLidgren; - deliveryMethod[(int)NetworkEventType.UpdateProperty] = NetworkEventDeliveryMethod.ReliableChannel; - deliveryMethod[(int)NetworkEventType.WallDamage] = NetworkEventDeliveryMethod.ReliableChannel; + deliveryMethod[(int)NetworkEventType.UpdateProperty] = NetworkEventDeliveryMethod.ReliableChannel; + deliveryMethod[(int)NetworkEventType.WallDamage] = NetworkEventDeliveryMethod.ReliableChannel; + + deliveryMethod[(int)NetworkEventType.ApplyStatusEffect] = NetworkEventDeliveryMethod.ReliableLidgren; overridePrevious = new bool[deliveryMethod.Length]; for (int i = 0; i < overridePrevious.Length; i++ ) { overridePrevious[i] = true; } - overridePrevious[(int)NetworkEventType.KillCharacter] = false; + overridePrevious[(int)NetworkEventType.KillCharacter] = false; - overridePrevious[(int)NetworkEventType.PickItem] = false; - overridePrevious[(int)NetworkEventType.DropItem] = false; - overridePrevious[(int)NetworkEventType.ItemFixed] = false; + overridePrevious[(int)NetworkEventType.PickItem] = false; + overridePrevious[(int)NetworkEventType.DropItem] = false; + overridePrevious[(int)NetworkEventType.ItemFixed] = false; + overridePrevious[(int)NetworkEventType.ApplyStatusEffect] = false; } - private ushort id; + private readonly ushort id; - private NetworkEventType eventType; + private readonly NetworkEventType eventType; - private bool isClientEvent; + private readonly bool isClientEvent; - private object data; + private readonly object data; public NetConnection SenderConnection; diff --git a/Subsurface/Source/Networking/ReliableSender.cs b/Subsurface/Source/Networking/ReliableSender.cs index 8469366e0..c7d1bb4f6 100644 --- a/Subsurface/Source/Networking/ReliableSender.cs +++ b/Subsurface/Source/Networking/ReliableSender.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Text; namespace Barotrauma.Networking.ReliableMessages { @@ -61,6 +60,16 @@ namespace Barotrauma.Networking.ReliableMessages receiver.Update(deltaTime); } + public static int IdDiff(ushort id1, ushort id2) + { + if (Math.Abs((int)id1 - (int)id2) > ushort.MaxValue / 2) + { + return (ushort.MaxValue - Math.Max(id1, id2)) + Math.Min(id1, id2); + } + + return Math.Abs(id1 - id2); + } + } internal class ReliableSender @@ -81,14 +90,14 @@ namespace Barotrauma.Networking.ReliableMessages { this.sender = sender; - messageCount = ushort.MaxValue - 5; + messageCount = 1; messageBuffer = new Dictionary(); } public ReliableMessage CreateMessage() { - ushort messageID = (messageCount==ushort.MaxValue) ? (ushort)0 : (ushort)(messageCount + 1); + ushort messageID = (messageCount == ushort.MaxValue) ? (ushort)1 : (ushort)(messageCount + 1); NetOutgoingMessage message = sender.CreateMessage(); @@ -100,16 +109,15 @@ namespace Barotrauma.Networking.ReliableMessages if (messageBuffer.Count > NetConfig.ReliableMessageBufferSize) { - int end = messageCount - NetConfig.ReliableMessageBufferSize; int start = end - (messageBuffer.Count - NetConfig.ReliableMessageBufferSize); - if (start<0) + if (start < 0) { int wrappedStart = start + ushort.MaxValue; - if (wrappedStart==0) wrappedStart = ushort.MaxValue; + if (wrappedStart == 0) wrappedStart = ushort.MaxValue; int wrappedEnd = end + ushort.MaxValue; - if (wrappedEnd==0) wrappedEnd = ushort.MaxValue; + if (wrappedEnd == 0) wrappedEnd = ushort.MaxValue; for (ushort i = (ushort)wrappedStart; i <= (ushort)wrappedEnd; i++) { @@ -128,8 +136,6 @@ namespace Barotrauma.Networking.ReliableMessages } return reliableMessage; - - //server.SendMessage(msg, server.Connections, NetDeliveryMethod.Unreliable, 0); } public void SendMessage(ReliableMessage message, NetConnection connection) @@ -139,6 +145,8 @@ namespace Barotrauma.Networking.ReliableMessages messageBuffer.Add(message.ID, message); + Debug.WriteLine("sending reliable massage (id " + message.ID + ")"); + if (messageCount == ushort.MaxValue) messageCount = 0; messageCount++; @@ -190,9 +198,9 @@ namespace Barotrauma.Networking.ReliableMessages sender.SendMessage(message, recipient, NetDeliveryMethod.Unreliable); - float roundTripTime = Math.Min(recipient.AverageRoundtripTime, 0.5f); + float roundTripTime = Math.Min(recipient.AverageRoundtripTime, 1.0f); - idSendTimer = Math.Max(roundTripTime, NetConfig.IdSendInterval+idSendInterval); + idSendTimer = Math.Max(roundTripTime, NetConfig.IdSendInterval + idSendInterval); idSendInterval += 0.1f; } } @@ -212,7 +220,7 @@ namespace Barotrauma.Networking.ReliableMessages { this.receiver = receiver; - lastMessageID = ushort.MaxValue - 5; + lastMessageID = 1; missingMessages = new Dictionary(); missingMessageIds = new Queue(); @@ -251,7 +259,7 @@ namespace Barotrauma.Networking.ReliableMessages receiver.SendMessage(resendRequest, recipient, missingMessage.ResendRequestsSent==0 ? NetDeliveryMethod.ReliableUnordered : NetDeliveryMethod.Unreliable); - float roundTripTime = Math.Min(recipient.AverageRoundtripTime, 0.5f); + float roundTripTime = Math.Min(recipient.AverageRoundtripTime, 1.0f); missingMessage.ResendTimer = Math.Max(roundTripTime, NetConfig.RerequestInterval); missingMessage.ResendRequestsSent++; @@ -266,6 +274,13 @@ namespace Barotrauma.Networking.ReliableMessages ushort id = message.ReadUInt16(); + if (ReliableChannel.IdDiff(lastMessageID, id) > NetConfig.ReliableMessageBufferSize) + { + Debug.WriteLine("id diff > NetConfig.ReliableMessageBufferSize, resetting reliable channel"); + lastMessageID = id; + return false; + } + Debug.WriteLine("received message ID " + id + " - last id: " + lastMessageID); //wrapped around @@ -329,7 +344,10 @@ namespace Barotrauma.Networking.ReliableMessages if (missingMessages.ContainsKey(id)) return; Debug.WriteLine("added " + id + " to missed"); - missingMessages.Add(id, new MissingMessage(id)); + + float waitTime = Math.Abs(lastMessageID - id)>1 ? 0.0f : recipient.AverageRoundtripTime*0.5f; + + missingMessages.Add(id, new MissingMessage(id, waitTime)); missingMessageIds.Enqueue(id); } @@ -355,9 +373,15 @@ namespace Barotrauma.Networking.ReliableMessages return; } + if (ReliableChannel.IdDiff(lastMessageID, messageId) > NetConfig.ReliableMessageBufferSize) + { + Debug.WriteLine("id diff > NetConfig.ReliableMessageBufferSize, resetting reliable channel"); + lastMessageID = messageId; + return; + } + if (messageId < lastMessageID && Math.Abs((int)lastMessageID - (int)messageId) < ushort.MaxValue / 2) { - //shouldn't happen: we have somehow received messages that the other end hasn't sent Debug.WriteLine("Received id update message: " + messageId + ": ignoring, already received (" + lastMessageID + ")"); return; } @@ -373,7 +397,7 @@ namespace Barotrauma.Networking.ReliableMessages if (i == ushort.MaxValue) break; } - for (ushort i = 1; i < messageId; i++) + for (ushort i = 1; i <= messageId; i++) { QueueMissingMessage(i); } @@ -396,6 +420,8 @@ namespace Barotrauma.Networking.ReliableMessages lastMessageID = messageId; } + + } internal class MissingMessage @@ -415,6 +441,12 @@ namespace Barotrauma.Networking.ReliableMessages { this.id = id; } + + public MissingMessage(ushort id, float resendTimer) + { + this.id = id; + this.ResendTimer = resendTimer; + } } class ReliableMessage