From 40714c11024c805f6f003e8cebac862c6c90bea1 Mon Sep 17 00:00:00 2001 From: Regalis Date: Thu, 3 Mar 2016 21:11:54 +0200 Subject: [PATCH] - converting NetworkEvent sending time to local time before doing any comparisons - using mersenne twister for random number generation due to differences in Mono and .NET implementations of the Random library - password prompt for password-protected private servers - fixed deconstructor, fabricator and railgun connection panels closing immediately after opening - fixed editor saving newly created subs to the root folder instead of the Submarines folder - keeping items in the same inventory slots between clients instead of just syncing which items are in the inventory - fixed crashing when swapping items between different limbslots --- Subsurface/Barotrauma.csproj | 1 + .../Content/Items/Fabricators/fabricators.xml | 4 +- Subsurface/Content/Items/Weapons/railgun.xml | 4 +- .../AI/Objectives/AIObjectiveCombat.cs | 2 +- .../AI/Objectives/AIObjectiveGetItem.cs | 2 +- .../Animation/HumanoidAnimController.cs | 8 +- Subsurface/Source/Characters/Character.cs | 2 +- Subsurface/Source/Characters/CharacterHUD.cs | 2 + Subsurface/Source/Items/CharacterInventory.cs | 17 ++- .../Source/Items/Components/ItemContainer.cs | 2 +- Subsurface/Source/Items/Inventory.cs | 40 ++--- Subsurface/Source/Items/ItemInventory.cs | 4 +- Subsurface/Source/Networking/GameClient.cs | 10 +- Subsurface/Source/Networking/GameServer.cs | 17 ++- Subsurface/Source/Networking/NetworkEvent.cs | 2 + Subsurface/Source/Screens/EditMapScreen.cs | 4 + Subsurface/Source/Screens/ServerListScreen.cs | 11 +- Subsurface/Source/Utils/MTRandom.cs | 139 ++++++++++++++++++ Subsurface/Source/Utils/Rand.cs | 7 +- Subsurface/changelog.txt | 6 + Subsurface_Solution.v12.suo | Bin 903680 -> 911872 bytes 21 files changed, 225 insertions(+), 59 deletions(-) create mode 100644 Subsurface/Source/Utils/MTRandom.cs diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj index 611aea7c1..562d70328 100644 --- a/Subsurface/Barotrauma.csproj +++ b/Subsurface/Barotrauma.csproj @@ -142,6 +142,7 @@ + diff --git a/Subsurface/Content/Items/Fabricators/fabricators.xml b/Subsurface/Content/Items/Fabricators/fabricators.xml index c585eec6d..ad101c1ec 100644 --- a/Subsurface/Content/Items/Fabricators/fabricators.xml +++ b/Subsurface/Content/Items/Fabricators/fabricators.xml @@ -49,7 +49,7 @@ - + @@ -73,7 +73,7 @@ - + diff --git a/Subsurface/Content/Items/Weapons/railgun.xml b/Subsurface/Content/Items/Weapons/railgun.xml index ad75a5009..b90e28e1f 100644 --- a/Subsurface/Content/Items/Weapons/railgun.xml +++ b/Subsurface/Content/Items/Weapons/railgun.xml @@ -17,7 +17,7 @@ - + @@ -40,7 +40,7 @@ - + diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveCombat.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveCombat.cs index 5dd2f96c4..ec5711587 100644 --- a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveCombat.cs +++ b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveCombat.cs @@ -47,7 +47,7 @@ namespace Barotrauma { if (!character.SelectedItems.Contains(weapon)) { - character.Inventory.TryPutItem(weapon, 3, false); + character.Inventory.TryPutItem(weapon, 3, true, false); weapon.Equip(character); } character.CursorPosition = enemy.Position; diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs index c7db395eb..d31622b6c 100644 --- a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs +++ b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveGetItem.cs @@ -88,7 +88,7 @@ namespace Barotrauma if (targetSlot>-1 && character.Inventory.IsInLimbSlot(targetItem, LimbSlot.Any)) { - character.Inventory.TryPutItem(targetItem, targetSlot, false); + character.Inventory.TryPutItem(targetItem, targetSlot, true, false); } } diff --git a/Subsurface/Source/Characters/Animation/HumanoidAnimController.cs b/Subsurface/Source/Characters/Animation/HumanoidAnimController.cs index e4f3ef309..5e6578213 100644 --- a/Subsurface/Source/Characters/Animation/HumanoidAnimController.cs +++ b/Subsurface/Source/Characters/Animation/HumanoidAnimController.cs @@ -875,15 +875,17 @@ namespace Barotrauma Vector2 itemPos = aim ? aimPos : holdPos; + bool usingController = character.SelectedConstruction != null && character.SelectedConstruction.GetComponent() != null; + + float itemAngle; - if (Anim != Animation.Climbing && stunTimer <= 0.0f && aim && itemPos != Vector2.Zero) + if (Anim != Animation.Climbing && !usingController && stunTimer <= 0.0f && aim && itemPos != Vector2.Zero) { Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition); Vector2 diff = (mousePos - torso.SimPosition) * Dir; holdAngle = MathUtils.VectorToAngle(new Vector2(diff.X, diff.Y * Dir)) - torso.body.Rotation * Dir; - //holdAngle = MathHelper.Clamp(MathUtils.WrapAnglePi(holdAngle), -1.3f, 1.0f); itemAngle = (torso.body.Rotation + holdAngle * Dir); @@ -909,7 +911,7 @@ namespace Barotrauma Vector2 shoulderPos = limbJoints[2].WorldAnchorA; Vector2 transformedHoldPos = shoulderPos; - if (itemPos == Vector2.Zero || Anim == Animation.Climbing || (leftHand.Disabled && rightHand.Disabled)) + if (itemPos == Vector2.Zero || Anim == Animation.Climbing || usingController) { if (character.SelectedItems[1] == item) { diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index d43e7c342..4f4629125 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -487,7 +487,7 @@ namespace Barotrauma if (item == null) continue; item.Pick(this, true, true, true); - inventory.TryPutItem(item, i, false); + inventory.TryPutItem(item, i, false, false); } } } diff --git a/Subsurface/Source/Characters/CharacterHUD.cs b/Subsurface/Source/Characters/CharacterHUD.cs index 2fc846110..669d19dc7 100644 --- a/Subsurface/Source/Characters/CharacterHUD.cs +++ b/Subsurface/Source/Characters/CharacterHUD.cs @@ -96,6 +96,8 @@ namespace Barotrauma } } + if (Screen.Selected == GameMain.EditMapScreen) return; + if (character.Oxygen < 50.0f && !character.IsDead) { Vector2 offset = Rand.Vector(noiseOverlay.size.X); diff --git a/Subsurface/Source/Items/CharacterInventory.cs b/Subsurface/Source/Items/CharacterInventory.cs index 3fd75bb56..6e0318434 100644 --- a/Subsurface/Source/Items/CharacterInventory.cs +++ b/Subsurface/Source/Items/CharacterInventory.cs @@ -149,7 +149,7 @@ namespace Barotrauma return placed; } - public override bool TryPutItem(Item item, int index, bool createNetworkEvent) + public override bool TryPutItem(Item item, int index, bool allowSwapping, bool createNetworkEvent) { //there's already an item in the slot if (Items[index] != null) @@ -173,7 +173,7 @@ namespace Barotrauma combined = true; } //if moving the item between slots in the same inventory - else if (item.ParentInventory == this) + else if (item.ParentInventory == this && allowSwapping) { int currentIndex = Array.IndexOf(Items, item); @@ -182,16 +182,19 @@ namespace Barotrauma Items[currentIndex] = null; Items[index] = null; //if the item in the slot can be moved to the slot of the moved item - if (TryPutItem(existingItem, currentIndex, false) && - TryPutItem(item, index, false)) + if (TryPutItem(existingItem, currentIndex, false, false) && + TryPutItem(item, index, false, false)) { new Networking.NetworkEvent(Networking.NetworkEventType.InventoryUpdate, Owner.ID, true, true); } else { + Items[currentIndex] = null; + Items[index] = null; + //swapping the items failed -> move them back to where they were - TryPutItem(item, currentIndex, false); - TryPutItem(existingItem, index, false); + TryPutItem(item, currentIndex, false, false); + TryPutItem(existingItem, index, false, false); } } @@ -416,7 +419,7 @@ namespace Barotrauma if (Items[i] != item && Items[i] != null) Items[i].Drop(character, false); - if (TryPutItem(item, i, false)) + if (TryPutItem(item, i, false, false)) { if (droppedItems.Contains(item)) { diff --git a/Subsurface/Source/Items/Components/ItemContainer.cs b/Subsurface/Source/Items/Components/ItemContainer.cs index 0f529c2d9..fd9d3fdf9 100644 --- a/Subsurface/Source/Items/Components/ItemContainer.cs +++ b/Subsurface/Source/Items/Components/ItemContainer.cs @@ -241,7 +241,7 @@ namespace Barotrauma.Items.Components Item item = MapEntity.FindEntityByID(itemIds[i]) as Item; if (item == null) continue; - Inventory.TryPutItem(item, i, false); + Inventory.TryPutItem(item, i, false, false); } itemIds = null; diff --git a/Subsurface/Source/Items/Inventory.cs b/Subsurface/Source/Items/Inventory.cs index 65778372f..ba090f4d4 100644 --- a/Subsurface/Source/Items/Inventory.cs +++ b/Subsurface/Source/Items/Inventory.cs @@ -104,7 +104,7 @@ namespace Barotrauma return true; } - public virtual bool TryPutItem(Item item, int i, bool createNetworkEvent = true) + public virtual bool TryPutItem(Item item, int i, bool allowSwapping, bool createNetworkEvent) { if (Owner == null) return false; if (CanBePut(item,i)) @@ -274,7 +274,7 @@ namespace Barotrauma } //selectedSlot = slotIndex; - TryPutItem(draggingItem, slotIndex); + TryPutItem(draggingItem, slotIndex, true, true); draggingItem = null; } @@ -351,11 +351,9 @@ namespace Barotrauma public virtual bool FillNetworkData(NetworkEventType type, NetBuffer message, object data) { - var foundItems = Array.FindAll(Items, i => i != null); - message.Write((byte)foundItems.Count()); - foreach (Item item in foundItems) + for (int i = 0; i < capacity; i++) { - message.Write((ushort)item.ID); + message.Write((ushort)(Items[i]==null ? 0 : Items[i].ID)); } return true; @@ -368,31 +366,21 @@ namespace Barotrauma List newItemIDs = new List(); List droppedItems = new List(); List prevItems = new List(Items); - - byte count = message.ReadByte(); - for (int i = 0; i c.name.ToLower() == name.ToLower() && c.ID!=userID) != null) + else if (ConnectedClients.Find(c => c.name.ToLower() == name.ToLower() && c.ID != userID) != null) { inc.SenderConnection.Deny("The name ''" + name + "'' is already in use. Please choose another name."); DebugConsole.NewMessage(name + " couldn't join the server (name already in use)", Color.Red); diff --git a/Subsurface/Source/Networking/NetworkEvent.cs b/Subsurface/Source/Networking/NetworkEvent.cs index 563b7ffd8..03511e2ab 100644 --- a/Subsurface/Source/Networking/NetworkEvent.cs +++ b/Subsurface/Source/Networking/NetworkEvent.cs @@ -160,6 +160,8 @@ namespace Barotrauma.Networking { float sendingTime = message.ReadFloat(); + sendingTime = (float)message.SenderConnection.GetLocalTime(sendingTime); + byte msgCount = message.ReadByte(); long currPos = message.PositionInBytes; diff --git a/Subsurface/Source/Screens/EditMapScreen.cs b/Subsurface/Source/Screens/EditMapScreen.cs index 22f711a76..d8f987b4d 100644 --- a/Subsurface/Source/Screens/EditMapScreen.cs +++ b/Subsurface/Source/Screens/EditMapScreen.cs @@ -298,6 +298,10 @@ namespace Barotrauma { savePath = Path.Combine(Path.GetDirectoryName(Submarine.Loaded.FilePath), savePath); } + else + { + savePath = Path.Combine(Submarine.SavePath, savePath); + } Submarine.SaveCurrent(savePath); Submarine.Loaded.CheckForErrors(); diff --git a/Subsurface/Source/Screens/ServerListScreen.cs b/Subsurface/Source/Screens/ServerListScreen.cs index 26a57b4c6..5b2cfb8b5 100644 --- a/Subsurface/Source/Screens/ServerListScreen.cs +++ b/Subsurface/Source/Screens/ServerListScreen.cs @@ -293,17 +293,22 @@ namespace Barotrauma return false; } - CoroutineManager.StartCoroutine(JoinServer(ip)); + CoroutineManager.StartCoroutine(ConnectToServer(ip, serverList.Selected != null && (serverList.Selected.GetChild("password") as GUITickBox).Selected)); return true; } - private IEnumerable JoinServer(string ip) + public void JoinServer(string ip, bool hasPassword) + { + CoroutineManager.StartCoroutine(ConnectToServer(ip, hasPassword)); + } + + private IEnumerable ConnectToServer(string ip, bool hasPassword) { string selectedPassword = ""; - if (serverList.Selected!=null && (serverList.Selected.GetChild("password") as GUITickBox).Selected) + if (hasPassword) { var msgBox = new GUIMessageBox("Password required:", "", new string[] { "OK", "Cancel" }); var passwordBox = new GUITextBox(new Rectangle(0,40,150,25), Alignment.TopLeft, GUI.Style, msgBox.children[0]); diff --git a/Subsurface/Source/Utils/MTRandom.cs b/Subsurface/Source/Utils/MTRandom.cs new file mode 100644 index 000000000..730562993 --- /dev/null +++ b/Subsurface/Source/Utils/MTRandom.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Barotrauma +{ + /// + /// Mersenne Twister based random + /// + public sealed class MTRandom : Random + { + private const int N = 624; + private const int M = 397; + private const uint MATRIX_A = 0x9908b0dfU; + private const uint UPPER_MASK = 0x80000000U; + private const uint LOWER_MASK = 0x7fffffffU; + private const uint TEMPER1 = 0x9d2c5680U; + private const uint TEMPER2 = 0xefc60000U; + private const int TEMPER3 = 11; + private const int TEMPER4 = 7; + private const int TEMPER5 = 15; + private const int TEMPER6 = 18; + + private UInt32[] mt; + private int mti; + private UInt32[] mag01; + + private const double c_realUnitInt = 1.0 / ((double)int.MaxValue + 1.0); + + /// + /// Constructor with randomized seed + /// + public MTRandom() + { + Initialize((uint)Environment.TickCount); + } + + /// + /// Constructor with provided 32 bit seed + /// + [CLSCompliant(false)] + public MTRandom(int seed) + { + Initialize((uint)Math.Abs(seed)); + } + + /// + /// (Re)initialize this instance with provided 32 bit seed + /// + [CLSCompliant(false)] + private void Initialize(uint seed) + { + mt = new UInt32[N]; + mti = N + 1; + mag01 = new UInt32[] { 0x0U, MATRIX_A }; + mt[0] = seed; + for (int i = 1; i < N; i++) + mt[i] = (UInt32)(1812433253 * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i); + } + + /// + /// Generates a random value from UInt32.MinValue to UInt32.MaxValue, inclusively + /// + [CLSCompliant(false)] + private uint NextUInt32() + { + UInt32 y; + if (mti >= N) + { + GenRandAll(); + mti = 0; + } + y = mt[mti++]; + y ^= (y >> TEMPER3); + y ^= (y << TEMPER4) & TEMPER1; + y ^= (y << TEMPER5) & TEMPER2; + y ^= (y >> TEMPER6); + return y; + } + + /// + /// Generates a random value that is greater or equal than 0 and less than Int32.MaxValue + /// + public override int Next() + { + var retval = (int)(0x7FFFFFFF & NextUInt32()); + if (retval == 0x7FFFFFFF) + return NextInt32(); + return retval; + } + + /// + /// Returns a random value is greater or equal than 0 and less than maxValue + /// + public override int Next(int maxValue) + { + return (int)(NextDouble() * maxValue); + } + + /// + /// Generates a random value greater or equal than 0 and less or equal than Int32.MaxValue (inclusively) + /// + public int NextInt32() + { + return (int)(0x7FFFFFFF & NextUInt32()); + } + + /// + /// Returns random value larger or equal to 0.0 and less than 1.0 + /// + public override double NextDouble() + { + return c_realUnitInt * NextInt32(); + } + + private void GenRandAll() + { + int kk = 1; + UInt32 y; + UInt32 p; + y = mt[0] & UPPER_MASK; + do + { + p = mt[kk]; + mt[kk - 1] = mt[kk + (M - 1)] ^ ((y | (p & LOWER_MASK)) >> 1) ^ mag01[p & 1]; + y = p & UPPER_MASK; + } while (++kk < N - M + 1); + do + { + p = mt[kk]; + mt[kk - 1] = mt[kk + (M - N - 1)] ^ ((y | (p & LOWER_MASK)) >> 1) ^ mag01[p & 1]; + y = p & UPPER_MASK; + } while (++kk < N); + p = mt[0]; + mt[N - 1] = mt[M - 1] ^ ((y | (p & LOWER_MASK)) >> 1) ^ mag01[p & 1]; + } + } +} diff --git a/Subsurface/Source/Utils/Rand.cs b/Subsurface/Source/Utils/Rand.cs index 20dcaccf5..75d477487 100644 --- a/Subsurface/Source/Utils/Rand.cs +++ b/Subsurface/Source/Utils/Rand.cs @@ -1,4 +1,5 @@ -using Microsoft.Xna.Framework; +using Lidgren.Network; +using Microsoft.Xna.Framework; using System; using System.Collections.Generic; using System.Linq; @@ -9,11 +10,11 @@ namespace Barotrauma static class Rand { private static Random localRandom = new Random(); - private static Random syncedRandom = new Random(); + private static Random syncedRandom = new MTRandom(); public static void SetSyncedSeed(int seed) { - syncedRandom = new Random(seed); + syncedRandom = new MTRandom(seed); } public static float Range(float minimum, float maximum, bool local = true) diff --git a/Subsurface/changelog.txt b/Subsurface/changelog.txt index 4ea04ccb0..b8ee0f22d 100644 --- a/Subsurface/changelog.txt +++ b/Subsurface/changelog.txt @@ -2,6 +2,12 @@ v0.3.4.0 --------------------------------------------------------------------------------------------------------- +Multiplayer: + +--------------------------------------------------------------------------------------------------------- +v0.3.4.0 +--------------------------------------------------------------------------------------------------------- + Multiplayer: - missing submarine files can be downloaded from the server host - player syncing bugfixes (aiming is visible to other players, smoother movement in water) diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index abee67071f63716275c6d8b53d5e671344a0110f..4ba17d9ea084aa58b2064ce3bf0772032127ebca 100644 GIT binary patch delta 18277 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 PH?!^dkl;sAa`^uNcZA3c delta 24027 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