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 abee67071..4ba17d9ea 100644 Binary files a/Subsurface_Solution.v12.suo and b/Subsurface_Solution.v12.suo differ