diff --git a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs index fe3acb274..5acf0fbad 100644 --- a/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.1.10")] -[assembly: AssemblyFileVersion("0.8.1.10")] +[assembly: AssemblyVersion("0.8.1.11")] +[assembly: AssemblyFileVersion("0.8.1.11")] diff --git a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs index 1cfb0fad4..09ad2201a 100644 --- a/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs +++ b/Barotrauma/BarotraumaServer/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.1.10")] -[assembly: AssemblyFileVersion("0.8.1.10")] +[assembly: AssemblyVersion("0.8.1.11")] +[assembly: AssemblyFileVersion("0.8.1.11")] diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs index 1242b7aa6..0f33c6f10 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs @@ -2044,6 +2044,9 @@ namespace Barotrauma base.Remove(); + if (selectedItems[0] != null) selectedItems[0].Drop(this); + if (selectedItems[1] != null) selectedItems[1].Drop(this); + if (info != null) info.Remove(); CharacterList.Remove(this); @@ -2054,9 +2057,6 @@ namespace Barotrauma if (AnimController != null) AnimController.Remove(); - if (selectedItems[0] != null) selectedItems[0].Drop(this); - if (selectedItems[1] != null) selectedItems[1].Drop(this); - foreach (Character c in CharacterList) { if (c.focusedCharacter == this) c.focusedCharacter = null; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs index e253efe36..97907f398 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/Wire.cs @@ -30,6 +30,9 @@ namespace Barotrauma.Items.Components const float nodeDistance = 32.0f; const float heightFromFloor = 128.0f; + const int MaxNodeCount = 255; + const int MaxNodesPerNetworkEvent = 30; + private List nodes; private List sections; @@ -179,7 +182,7 @@ namespace Barotrauma.Items.Components { if (GameMain.Server != null) { - item.CreateServerEvent(this); + CreateNetworkEvent(); } //the wire is active if only one end has been connected IsActive = connections[0] == null ^ connections[1] == null; @@ -262,9 +265,10 @@ namespace Barotrauma.Items.Components Vector2 pullBackDir = diff == Vector2.Zero ? Vector2.Zero : Vector2.Normalize(diff); user.AnimController.Collider.ApplyForce(pullBackDir * user.Mass * 50.0f); user.AnimController.UpdateUseItem(true, user.SimPosition + pullBackDir * 2.0f); - if (currLength > MaxLength * 1.5f) + if (currLength > MaxLength * 1.5f && GameMain.Client == null) { ClearConnections(); + CreateNetworkEvent(); return; } } @@ -284,14 +288,20 @@ namespace Barotrauma.Items.Components if (newNodePos != Vector2.Zero && canPlaceNode && nodes.Count > 0 && Vector2.Distance(newNodePos, nodes[nodes.Count - 1]) > nodeDistance) { + if (nodes.Count >= MaxNodeCount) + { + nodes.RemoveAt(nodes.Count - 1); + } + nodes.Add(newNodePos); + CleanNodes(); UpdateSections(); Drawable = true; newNodePos = Vector2.Zero; if (GameMain.Server != null) { - item.CreateServerEvent(this); + CreateNetworkEvent(); } } return true; @@ -434,26 +444,20 @@ namespace Barotrauma.Items.Components private void CleanNodes() { - for (int i = nodes.Count - 2; i > 0; i--) - { - if ((nodes[i - 1].X == nodes[i].X || nodes[i - 1].Y == nodes[i].Y) && - (nodes[i + 1].X == nodes[i].X || nodes[i + 1].Y == nodes[i].Y)) - { - if (Vector2.Distance(nodes[i - 1], nodes[i]) == Vector2.Distance(nodes[i + 1], nodes[i])) - { - nodes.RemoveAt(i); - } - } - } - bool removed; do { removed = false; for (int i = nodes.Count - 2; i > 0; i--) { - if ((nodes[i - 1].X == nodes[i].X && nodes[i + 1].X == nodes[i].X) - || (nodes[i - 1].Y == nodes[i].Y && nodes[i + 1].Y == nodes[i].Y)) + if (Math.Abs(nodes[i - 1].X - nodes[i].X) < 1.0f && Math.Abs(nodes[i + 1].X - nodes[i].X) < 1.0f && + Math.Sign(nodes[i - 1].Y - nodes[i].Y) != Math.Sign(nodes[i + 1].Y - nodes[i].Y)) + { + nodes.RemoveAt(i); + removed = true; + } + else if (Math.Abs(nodes[i - 1].Y - nodes[i].Y) < 1.0f && Math.Abs(nodes[i + 1].Y - nodes[i].Y) < 1.0f && + Math.Sign(nodes[i - 1].X - nodes[i].X) != Math.Sign(nodes[i + 1].X - nodes[i].X)) { nodes.RemoveAt(i); removed = true; @@ -585,11 +589,28 @@ namespace Barotrauma.Items.Components base.RemoveComponentSpecific(); } - + + private void CreateNetworkEvent() + { + if (GameMain.Server == null) return; + //split into multiple events because one might not be enough to fit all the nodes + int eventCount = Math.Max((int)Math.Ceiling(nodes.Count / (float)MaxNodesPerNetworkEvent), 1); + for (int i = 0; i < eventCount; i++) + { + GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, item.components.IndexOf(this), i }); + } + + } + public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null) { - msg.Write((byte)Math.Min(nodes.Count, 255)); - for (int i = 0; i < Math.Min(nodes.Count, 255); i++) + int eventIndex = (int)extraData[2]; + int nodeStartIndex = eventIndex * MaxNodesPerNetworkEvent; + int nodeCount = MathHelper.Clamp(nodes.Count - nodeStartIndex, 0, MaxNodesPerNetworkEvent); + + msg.WriteRangedInteger(0, (int)Math.Ceiling(MaxNodeCount / (float)MaxNodesPerNetworkEvent), eventIndex); + msg.WriteRangedInteger(0, MaxNodesPerNetworkEvent, nodeCount); + for (int i = nodeStartIndex; i < nodeStartIndex + nodeCount; i++) { msg.Write(nodes[i].X); msg.Write(nodes[i].Y); @@ -598,20 +619,28 @@ namespace Barotrauma.Items.Components public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime) { - nodes.Clear(); + int eventIndex = msg.ReadRangedInteger(0, (int)Math.Ceiling(MaxNodeCount / (float)MaxNodesPerNetworkEvent)); + int nodeCount = msg.ReadRangedInteger(0, MaxNodesPerNetworkEvent); + int nodeStartIndex = eventIndex * MaxNodesPerNetworkEvent; - int nodeCount = msg.ReadByte(); - Vector2[] nodePositions = new Vector2[nodeCount]; + Vector2[] nodePositions = new Vector2[nodeStartIndex + nodeCount]; + for (int i = 0; i < nodes.Count && i < nodePositions.Length; i++) + { + nodePositions[i] = nodes[i]; + } for (int i = 0; i < nodeCount; i++) { - nodePositions[i] = new Vector2(msg.ReadFloat(), msg.ReadFloat()); + nodePositions[nodeStartIndex + i] = new Vector2(msg.ReadFloat(), msg.ReadFloat()); + } + + if (nodePositions.Any(n => !MathUtils.IsValid(n))) + { + nodes.Clear(); + return; } - - if (nodePositions.Any(n => !MathUtils.IsValid(n))) return; nodes = nodePositions.ToList(); - UpdateSections(); Drawable = nodes.Any(); } diff --git a/Barotrauma/BarotraumaShared/Source/Networking/NetEntityEvent/NetEntityEventManager.cs b/Barotrauma/BarotraumaShared/Source/Networking/NetEntityEvent/NetEntityEventManager.cs index 65f820231..5c1d1d2c7 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/NetEntityEvent/NetEntityEventManager.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/NetEntityEvent/NetEntityEventManager.cs @@ -55,6 +55,13 @@ namespace Barotrauma.Networking GameAnalyticsManager.AddErrorEventOnce("NetEntityEventManager.Write:TooLong" + e.Entity.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Too much data in network event for entity \"" + e.Entity.ToString() + "\" (" + tempEventBuffer.LengthBytes + " bytes"); + + //write an empty event breaking the event syncing + tempBuffer.Write((UInt16)0); + tempBuffer.WritePadBits(); + eventCount++; + continue; + } //the ID has been taken by another entity (the original entity has been removed) -> write an empty event diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 2263709ac..1af885e24 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,35 @@ +--------------------------------------------------------------------------------------------------------- +v0.8.1.11 +--------------------------------------------------------------------------------------------------------- + +Networking fixes: + - More error logging to diagnose "unknown object header" errors. + - Fixed output inventory of fabricators and deconstructors not being synced between clients. + - Fixed servers failing to write network events for wires with an excessive number of nodes, causing + clients to get kicked due to desync. + - Fixed client-side error messages when respawning without a respawn shuttle. + - Fixed some issues in inventory and connection panel syncing when joining mid-round. + - Fixed fabricated items always appearing to be in full condition client-side (e.g. oxygen tanks which + should be empty after being fabricated). + - Fixed attachable items dropping on the ground client-side when deattaching them (but still staying + in the inventory of the character detaching them). + - Fixed items occasionally dropping instead of being moved to another inventory client-side. + - The "traitorlist" command is usable by clients who have the permission to use it. + +Misc bugfixes: + - Fixed characters occasionally going inside/through obstacle when leaving a submarine that's right + next to another submarine or a level wall. + - More physics error checks and logging. + - Railgun controllers can be used over wifi components. + - Characters attach items to the walls at the position of their hand, not at the center of the body. + - Wifi components can't communicate with the enemy sub in combat missions. + - Fixed the previously selected location staying selected but start button staying disabled when + returning to the lobby screen in the single player campaign. Made it impossible to progress without + restarting if there were no other selectable locations. + - Fixed holdable components reverting their RequiredItems back to the prefab values during loading. + - Fixed wall-attached sections of a wire not rendering when the item is being rewired outside the sub. + - Fixed artifacts occasionally spawning under the sea floor. + --------------------------------------------------------------------------------------------------------- v0.8.1.10 ---------------------------------------------------------------------------------------------------------