From 40aac0de8fa4327c9eaac4e803fa72927ba1635e Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Thu, 13 Jun 2019 11:46:03 +0300 Subject: [PATCH] (49d6e0ff6) Fixed an ID mismatch problem that occasionally caused clients to get kicked out in the multiplayer campaign. Closes #1603, closes #1562 --- .../Source/Characters/Character.cs | 69 +++++++++++++++++++ .../BarotraumaShared/Source/Map/Entity.cs | 18 +++-- .../BarotraumaShared/Source/Map/Submarine.cs | 3 +- 3 files changed, 84 insertions(+), 6 deletions(-) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs index c58ac9d3a..5ae8f9857 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs @@ -894,6 +894,75 @@ namespace Barotrauma return configFile; } + private static IEnumerable characterConfigFiles; + private static IEnumerable CharacterConfigFiles + { +#if SERVER + if (GameMain.Server != null && IsRemotePlayer) + { + if (characterConfigFiles == null) + { + case InputType.Left: + return !(dequeuedInput.HasFlag(InputNetFlags.Left)) && (prevDequeuedInput.HasFlag(InputNetFlags.Left)); + case InputType.Right: + return !(dequeuedInput.HasFlag(InputNetFlags.Right)) && (prevDequeuedInput.HasFlag(InputNetFlags.Right)); + case InputType.Up: + return !(dequeuedInput.HasFlag(InputNetFlags.Up)) && (prevDequeuedInput.HasFlag(InputNetFlags.Up)); + case InputType.Down: + return !(dequeuedInput.HasFlag(InputNetFlags.Down)) && (prevDequeuedInput.HasFlag(InputNetFlags.Down)); + case InputType.Run: + return !(dequeuedInput.HasFlag(InputNetFlags.Run)) && (prevDequeuedInput.HasFlag(InputNetFlags.Run)); + case InputType.Crouch: + return !(dequeuedInput.HasFlag(InputNetFlags.Crouch)) && (prevDequeuedInput.HasFlag(InputNetFlags.Crouch)); + case InputType.Select: + return dequeuedInput.HasFlag(InputNetFlags.Select); //TODO: clean up the way this input is registered + case InputType.Deselect: + return dequeuedInput.HasFlag(InputNetFlags.Deselect); + case InputType.Health: + return dequeuedInput.HasFlag(InputNetFlags.Health); + case InputType.Grab: + return dequeuedInput.HasFlag(InputNetFlags.Grab); + case InputType.Use: + return !(dequeuedInput.HasFlag(InputNetFlags.Use)) && (prevDequeuedInput.HasFlag(InputNetFlags.Use)); + case InputType.Shoot: + return !(dequeuedInput.HasFlag(InputNetFlags.Shoot)) && (prevDequeuedInput.HasFlag(InputNetFlags.Shoot)); + case InputType.Ragdoll: + return !(dequeuedInput.HasFlag(InputNetFlags.Ragdoll)) && (prevDequeuedInput.HasFlag(InputNetFlags.Ragdoll)); + default: + return false; + } + return characterConfigFiles; + } + } + + /// + /// Searches for a character config file from all currently selected content packages, + /// or from a specific package if the contentPackage parameter is given. + /// + public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) + { + string configFile = null; + if (contentPackage == null) + { + configFile = GameMain.Instance.GetFilesOfType(ContentType.Character) + .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); + } + else + { + configFile = contentPackage.GetFilesOfType(ContentType.Character)? + .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); + } +#endif + + if (configFile == null) + { + DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); + DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); + return string.Empty; + } + return configFile; + } + private static IEnumerable characterConfigFiles; private static IEnumerable CharacterConfigFiles { diff --git a/Barotrauma/BarotraumaShared/Source/Map/Entity.cs b/Barotrauma/BarotraumaShared/Source/Map/Entity.cs index 54d21b2ee..60ff02152 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Entity.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Entity.cs @@ -9,6 +9,7 @@ namespace Barotrauma class Entity : ISpatialEntity { public const ushort NullEntityID = 0; + public const ushort EntitySpawnerID = ushort.MaxValue; private static Dictionary dictionary = new Dictionary(); public static List GetEntityList() @@ -43,12 +44,19 @@ namespace Barotrauma } set { + if (this is EntitySpawner) { return; } if (value == NullEntityID) { DebugConsole.ThrowError("Cannot set the ID of an entity to " + NullEntityID + "! The value is reserved for entity events referring to a non-existent (e.g. removed) entity.\n" + Environment.StackTrace); return; } + if (value == EntitySpawnerID) + { + DebugConsole.ThrowError("Cannot set the ID of an entity to " + EntitySpawnerID + + "! The value is reserved for EntitySpawner.\n" + Environment.StackTrace); + return; + } if (dictionary.TryGetValue(id, out Entity thisEntity) && thisEntity == this) { @@ -107,15 +115,17 @@ namespace Barotrauma this.Submarine = submarine; //give a unique ID - id = FindFreeID(submarine == null ? (ushort)1 : submarine.IdOffset); - + id = this is EntitySpawner ? + EntitySpawnerID : + FindFreeID(submarine == null ? (ushort)1 : submarine.IdOffset); + dictionary.Add(id, this); } public static ushort FindFreeID(ushort idOffset = 0) { - //ushort.MaxValue - 1 because 0 is a reserved value - if (dictionary.Count >= ushort.MaxValue - 1) + //ushort.MaxValue - 2 because 0 and ushort.MaxValue are reserved values + if (dictionary.Count >= ushort.MaxValue - 2) { throw new Exception("Maximum amount of entities (" + (ushort.MaxValue - 1) + ") reached!"); } diff --git a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs index ec3110b71..eb3714650 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs @@ -382,7 +382,6 @@ namespace Barotrauma DockedTo = new List(); - ID = ushort.MaxValue; FreeID(); } @@ -1405,7 +1404,7 @@ namespace Barotrauma } - ID = (ushort)(ushort.MaxValue - Submarine.loaded.IndexOf(this)); + ID = (ushort)(ushort.MaxValue - 1 - Submarine.loaded.IndexOf(this)); } public static Submarine Load(XElement element, bool unloadPrevious)