- 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
This commit is contained in:
Regalis
2016-03-03 21:11:54 +02:00
parent 35c36d283a
commit 40714c1102
21 changed files with 225 additions and 59 deletions
+1
View File
@@ -142,6 +142,7 @@
<Compile Include="Source\Networking\GameServerSettings.cs" /> <Compile Include="Source\Networking\GameServerSettings.cs" />
<Compile Include="Source\Screens\NetLobbyVoting.cs" /> <Compile Include="Source\Screens\NetLobbyVoting.cs" />
<Compile Include="Source\Screens\ServerListScreen.cs" /> <Compile Include="Source\Screens\ServerListScreen.cs" />
<Compile Include="Source\Utils\MTRandom.cs" />
<Compile Include="Source\Utils\Rand.cs" /> <Compile Include="Source\Utils\Rand.cs" />
<Compile Include="Source\Events\PropertyTask.cs" /> <Compile Include="Source\Events\PropertyTask.cs" />
<Compile Include="Source\Events\RepairTask.cs" /> <Compile Include="Source\Events\RepairTask.cs" />
@@ -49,7 +49,7 @@
<fabricableitem name="Incendium Fuel Rod" requireditems="Steel Bar, Incendium Bar"/> <fabricableitem name="Incendium Fuel Rod" requireditems="Steel Bar, Incendium Bar"/>
</Fabricator> </Fabricator>
<ConnectionPanel canbeselected = "true"> <ConnectionPanel selectkey="Action" canbeselected = "true">
<requireditem name="Screwdriver" type="Equipped"/> <requireditem name="Screwdriver" type="Equipped"/>
<output name="power_in"/> <output name="power_in"/>
</ConnectionPanel> </ConnectionPanel>
@@ -73,7 +73,7 @@
<GuiFrame rect="0,0,300,200" alignment="Center" color="0.0,0.0,0.0,0.6"/> <GuiFrame rect="0,0,300,200" alignment="Center" color="0.0,0.0,0.0,0.6"/>
</Deconstructor> </Deconstructor>
<ConnectionPanel canbeselected = "true"> <ConnectionPanel selectkey="Action" canbeselected = "true">
<requireditem name="Screwdriver" type="Equipped"/> <requireditem name="Screwdriver" type="Equipped"/>
<output name="power_in"/> <output name="power_in"/>
</ConnectionPanel> </ConnectionPanel>
+2 -2
View File
@@ -17,7 +17,7 @@
</StatusEffect> </StatusEffect>
</Turret> </Turret>
<ConnectionPanel canbeselected = "true" msg="Rewire [Screwdriver]"> <ConnectionPanel selectkey="Action" canbeselected = "true" msg="Rewire [Screwdriver]">
<requireditem name="Screwdriver,Wire" type="Equipped"/> <requireditem name="Screwdriver,Wire" type="Equipped"/>
<input name="power_in"/> <input name="power_in"/>
<input name="position_in"/> <input name="position_in"/>
@@ -40,7 +40,7 @@
<limbposition limb="RightHand" position="43,-85"/> <limbposition limb="RightHand" position="43,-85"/>
</Controller> </Controller>
<ConnectionPanel canbeselected = "true" msg="Rewire [Screwdriver]"> <ConnectionPanel selectkey="Action" canbeselected = "true" msg="Rewire [Screwdriver]">
<requireditem name="Screwdriver,Wire" type="Equipped"/> <requireditem name="Screwdriver,Wire" type="Equipped"/>
<input name="power_in"/> <input name="power_in"/>
<output name="position_out"/> <output name="position_out"/>
@@ -47,7 +47,7 @@ namespace Barotrauma
{ {
if (!character.SelectedItems.Contains(weapon)) if (!character.SelectedItems.Contains(weapon))
{ {
character.Inventory.TryPutItem(weapon, 3, false); character.Inventory.TryPutItem(weapon, 3, true, false);
weapon.Equip(character); weapon.Equip(character);
} }
character.CursorPosition = enemy.Position; character.CursorPosition = enemy.Position;
@@ -88,7 +88,7 @@ namespace Barotrauma
if (targetSlot>-1 && character.Inventory.IsInLimbSlot(targetItem, LimbSlot.Any)) if (targetSlot>-1 && character.Inventory.IsInLimbSlot(targetItem, LimbSlot.Any))
{ {
character.Inventory.TryPutItem(targetItem, targetSlot, false); character.Inventory.TryPutItem(targetItem, targetSlot, true, false);
} }
} }
@@ -875,15 +875,17 @@ namespace Barotrauma
Vector2 itemPos = aim ? aimPos : holdPos; Vector2 itemPos = aim ? aimPos : holdPos;
bool usingController = character.SelectedConstruction != null && character.SelectedConstruction.GetComponent<Controller>() != null;
float itemAngle; 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 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
Vector2 diff = (mousePos - torso.SimPosition) * Dir; Vector2 diff = (mousePos - torso.SimPosition) * Dir;
holdAngle = MathUtils.VectorToAngle(new Vector2(diff.X, diff.Y * Dir)) - torso.body.Rotation * 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); itemAngle = (torso.body.Rotation + holdAngle * Dir);
@@ -909,7 +911,7 @@ namespace Barotrauma
Vector2 shoulderPos = limbJoints[2].WorldAnchorA; Vector2 shoulderPos = limbJoints[2].WorldAnchorA;
Vector2 transformedHoldPos = shoulderPos; 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) if (character.SelectedItems[1] == item)
{ {
+1 -1
View File
@@ -487,7 +487,7 @@ namespace Barotrauma
if (item == null) continue; if (item == null) continue;
item.Pick(this, true, true, true); item.Pick(this, true, true, true);
inventory.TryPutItem(item, i, false); inventory.TryPutItem(item, i, false, false);
} }
} }
} }
@@ -96,6 +96,8 @@ namespace Barotrauma
} }
} }
if (Screen.Selected == GameMain.EditMapScreen) return;
if (character.Oxygen < 50.0f && !character.IsDead) if (character.Oxygen < 50.0f && !character.IsDead)
{ {
Vector2 offset = Rand.Vector(noiseOverlay.size.X); Vector2 offset = Rand.Vector(noiseOverlay.size.X);
+10 -7
View File
@@ -149,7 +149,7 @@ namespace Barotrauma
return placed; 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 //there's already an item in the slot
if (Items[index] != null) if (Items[index] != null)
@@ -173,7 +173,7 @@ namespace Barotrauma
combined = true; combined = true;
} }
//if moving the item between slots in the same inventory //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); int currentIndex = Array.IndexOf(Items, item);
@@ -182,16 +182,19 @@ namespace Barotrauma
Items[currentIndex] = null; Items[currentIndex] = null;
Items[index] = null; Items[index] = null;
//if the item in the slot can be moved to the slot of the moved item //if the item in the slot can be moved to the slot of the moved item
if (TryPutItem(existingItem, currentIndex, false) && if (TryPutItem(existingItem, currentIndex, false, false) &&
TryPutItem(item, index, false)) TryPutItem(item, index, false, false))
{ {
new Networking.NetworkEvent(Networking.NetworkEventType.InventoryUpdate, Owner.ID, true, true); new Networking.NetworkEvent(Networking.NetworkEventType.InventoryUpdate, Owner.ID, true, true);
} }
else else
{ {
Items[currentIndex] = null;
Items[index] = null;
//swapping the items failed -> move them back to where they were //swapping the items failed -> move them back to where they were
TryPutItem(item, currentIndex, false); TryPutItem(item, currentIndex, false, false);
TryPutItem(existingItem, index, 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 (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)) if (droppedItems.Contains(item))
{ {
@@ -241,7 +241,7 @@ namespace Barotrauma.Items.Components
Item item = MapEntity.FindEntityByID(itemIds[i]) as Item; Item item = MapEntity.FindEntityByID(itemIds[i]) as Item;
if (item == null) continue; if (item == null) continue;
Inventory.TryPutItem(item, i, false); Inventory.TryPutItem(item, i, false, false);
} }
itemIds = null; itemIds = null;
+13 -25
View File
@@ -104,7 +104,7 @@ namespace Barotrauma
return true; 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 (Owner == null) return false;
if (CanBePut(item,i)) if (CanBePut(item,i))
@@ -274,7 +274,7 @@ namespace Barotrauma
} }
//selectedSlot = slotIndex; //selectedSlot = slotIndex;
TryPutItem(draggingItem, slotIndex); TryPutItem(draggingItem, slotIndex, true, true);
draggingItem = null; draggingItem = null;
} }
@@ -351,11 +351,9 @@ namespace Barotrauma
public virtual bool FillNetworkData(NetworkEventType type, NetBuffer message, object data) public virtual bool FillNetworkData(NetworkEventType type, NetBuffer message, object data)
{ {
var foundItems = Array.FindAll(Items, i => i != null); for (int i = 0; i < capacity; i++)
message.Write((byte)foundItems.Count());
foreach (Item item in foundItems)
{ {
message.Write((ushort)item.ID); message.Write((ushort)(Items[i]==null ? 0 : Items[i].ID));
} }
return true; return true;
@@ -369,30 +367,20 @@ namespace Barotrauma
List<Item> droppedItems = new List<Item>(); List<Item> droppedItems = new List<Item>();
List<Item> prevItems = new List<Item>(Items); List<Item> prevItems = new List<Item>(Items);
byte count = message.ReadByte();
for (int i = 0; i<count; i++)
{
newItemIDs.Add(message.ReadUInt16());
}
for (int i = 0; i < capacity; i++) for (int i = 0; i < capacity; i++)
{ {
if (Items[i] == null) continue; ushort itemId = message.ReadUInt16();
if (!newItemIDs.Contains(Items[i].ID)) if (itemId==0)
{ {
droppedItems.Add(Items[i]); if (Items[i] != null) Items[i].Drop();
Items[i].Drop(null, false);
continue;
} }
} else
foreach (ushort itemId in newItemIDs) {
{ var item = Entity.FindEntityByID(itemId) as Item;
Item item = Entity.FindEntityByID(itemId) as Item; if (item == null) continue;
if (item == null) continue;
TryPutItem(item, item.AllowedSlots, false); TryPutItem(item, i, true, false);
if (droppedItems.Contains(item)) droppedItems.Remove(item); }
} }
lastUpdate = sendingTime; lastUpdate = sendingTime;
+2 -2
View File
@@ -44,9 +44,9 @@ namespace Barotrauma
return (item!=null && Items[i]==null && container.CanBeContained(item)); return (item!=null && Items[i]==null && container.CanBeContained(item));
} }
public override bool TryPutItem(Item item, int i, bool createNetworkEvent) public override bool TryPutItem(Item item, int i, bool allowSwapping, bool createNetworkEvent)
{ {
bool wasPut = base.TryPutItem(item, i, createNetworkEvent); bool wasPut = base.TryPutItem(item, i, allowSwapping, createNetworkEvent);
if (wasPut) if (wasPut)
{ {
+9 -1
View File
@@ -289,7 +289,15 @@ namespace Barotrauma.Networking
{ {
string denyMessage = inc.ReadString(); string denyMessage = inc.ReadString();
new GUIMessageBox("Couldn't connect to server", denyMessage); if (denyMessage == "Password required!" || denyMessage == "Wrong password!")
{
GameMain.ServerListScreen.JoinServer(serverIP, true);
}
else
{
new GUIMessageBox("Couldn't connect to server", denyMessage);
}
connectCanceled = true; connectCanceled = true;
} }
+10 -5
View File
@@ -631,12 +631,17 @@ namespace Barotrauma.Networking
return; return;
} }
#if !DEBUG #if DEBUG
if (!string.IsNullOrWhiteSpace(password) && string.IsNullOrWhiteSpace(userPassword))
if (userPassword != password) {
inc.SenderConnection.Deny("Password required!");
DebugConsole.NewMessage(name + " couldn't join the server (no password)", Color.Red);
return;
}
else if (userPassword != password)
{ {
inc.SenderConnection.Deny("Wrong password!"); inc.SenderConnection.Deny("Wrong password!");
DebugConsole.NewMessage(name +" couldn't join the server (wrong password)", Color.Red); DebugConsole.NewMessage(name + " couldn't join the server (wrong password)", Color.Red);
return; return;
} }
else if (version != GameMain.Version.ToString()) else if (version != GameMain.Version.ToString())
@@ -657,7 +662,7 @@ namespace Barotrauma.Networking
DebugConsole.NewMessage(name + " couldn't join the server (wrong content package hash)", Color.Red); DebugConsole.NewMessage(name + " couldn't join the server (wrong content package hash)", Color.Red);
return; return;
} }
else if (ConnectedClients.Find(c => 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."); 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); DebugConsole.NewMessage(name + " couldn't join the server (name already in use)", Color.Red);
@@ -160,6 +160,8 @@ namespace Barotrauma.Networking
{ {
float sendingTime = message.ReadFloat(); float sendingTime = message.ReadFloat();
sendingTime = (float)message.SenderConnection.GetLocalTime(sendingTime);
byte msgCount = message.ReadByte(); byte msgCount = message.ReadByte();
long currPos = message.PositionInBytes; long currPos = message.PositionInBytes;
@@ -298,6 +298,10 @@ namespace Barotrauma
{ {
savePath = Path.Combine(Path.GetDirectoryName(Submarine.Loaded.FilePath), savePath); savePath = Path.Combine(Path.GetDirectoryName(Submarine.Loaded.FilePath), savePath);
} }
else
{
savePath = Path.Combine(Submarine.SavePath, savePath);
}
Submarine.SaveCurrent(savePath); Submarine.SaveCurrent(savePath);
Submarine.Loaded.CheckForErrors(); Submarine.Loaded.CheckForErrors();
@@ -293,17 +293,22 @@ namespace Barotrauma
return false; return false;
} }
CoroutineManager.StartCoroutine(JoinServer(ip)); CoroutineManager.StartCoroutine(ConnectToServer(ip, serverList.Selected != null && (serverList.Selected.GetChild("password") as GUITickBox).Selected));
return true; return true;
} }
private IEnumerable<object> JoinServer(string ip) public void JoinServer(string ip, bool hasPassword)
{
CoroutineManager.StartCoroutine(ConnectToServer(ip, hasPassword));
}
private IEnumerable<object> ConnectToServer(string ip, bool hasPassword)
{ {
string selectedPassword = ""; 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 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]); var passwordBox = new GUITextBox(new Rectangle(0,40,150,25), Alignment.TopLeft, GUI.Style, msgBox.children[0]);
+139
View File
@@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Barotrauma
{
/// <summary>
/// Mersenne Twister based random
/// </summary>
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);
/// <summary>
/// Constructor with randomized seed
/// </summary>
public MTRandom()
{
Initialize((uint)Environment.TickCount);
}
/// <summary>
/// Constructor with provided 32 bit seed
/// </summary>
[CLSCompliant(false)]
public MTRandom(int seed)
{
Initialize((uint)Math.Abs(seed));
}
/// <summary>
/// (Re)initialize this instance with provided 32 bit seed
/// </summary>
[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);
}
/// <summary>
/// Generates a random value from UInt32.MinValue to UInt32.MaxValue, inclusively
/// </summary>
[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;
}
/// <summary>
/// Generates a random value that is greater or equal than 0 and less than Int32.MaxValue
/// </summary>
public override int Next()
{
var retval = (int)(0x7FFFFFFF & NextUInt32());
if (retval == 0x7FFFFFFF)
return NextInt32();
return retval;
}
/// <summary>
/// Returns a random value is greater or equal than 0 and less than maxValue
/// </summary>
public override int Next(int maxValue)
{
return (int)(NextDouble() * maxValue);
}
/// <summary>
/// Generates a random value greater or equal than 0 and less or equal than Int32.MaxValue (inclusively)
/// </summary>
public int NextInt32()
{
return (int)(0x7FFFFFFF & NextUInt32());
}
/// <summary>
/// Returns random value larger or equal to 0.0 and less than 1.0
/// </summary>
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];
}
}
}
+4 -3
View File
@@ -1,4 +1,5 @@
using Microsoft.Xna.Framework; using Lidgren.Network;
using Microsoft.Xna.Framework;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -9,11 +10,11 @@ namespace Barotrauma
static class Rand static class Rand
{ {
private static Random localRandom = new Random(); private static Random localRandom = new Random();
private static Random syncedRandom = new Random(); private static Random syncedRandom = new MTRandom();
public static void SetSyncedSeed(int seed) 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) public static float Range(float minimum, float maximum, bool local = true)
+6
View File
@@ -2,6 +2,12 @@
v0.3.4.0 v0.3.4.0
--------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------
Multiplayer:
---------------------------------------------------------------------------------------------------------
v0.3.4.0
---------------------------------------------------------------------------------------------------------
Multiplayer: Multiplayer:
- missing submarine files can be downloaded from the server host - missing submarine files can be downloaded from the server host
- player syncing bugfixes (aiming is visible to other players, smoother movement in water) - player syncing bugfixes (aiming is visible to other players, smoother movement in water)
Binary file not shown.