Attempt to fix items dropping client-side when moving them from inventory another (#558).

The clients delay applying the received remote state of an inventory they just put an item inside, because otherwise the inventory may revert to an old state if items are moved in rapid succession. I think the problem was that the delay was not applied to the inventory the item is _taken from_, so it was possible that the clients applied an old delayed state even though an item had just been moved out of the inventory. Another problem was that the server didn't create an event for the inventory the item was removed from, so if there were any wrong items in a client-side inventory, they would just be dropped instead of being moved back to the correct inventory.
This commit is contained in:
Joonas Rikkonen
2018-09-12 15:22:52 +03:00
parent a403ca44c5
commit bf87006bc3
2 changed files with 37 additions and 7 deletions

View File

@@ -20,7 +20,7 @@ namespace Barotrauma
public bool Locked;
private ushort[] receivedItemIDs;
private float syncItemsDelay;
protected float syncItemsDelay;
private CoroutineHandle syncItemsCoroutine;
public Inventory(Entity owner, int capacity, Vector2? centerPos = null, int slotsPerRow=5)
@@ -116,6 +116,8 @@ namespace Barotrauma
{
if (Owner == null) return;
Inventory prevInventory = item.ParentInventory;
if (removeItem)
{
item.Drop(user);
@@ -137,6 +139,8 @@ namespace Barotrauma
if (createNetworkEvent)
{
CreateNetworkEvent();
//also delay syncing the inventory the item was inside
if (prevInventory != null && prevInventory != this) prevInventory.syncItemsDelay = 1.0f;
}
}
@@ -148,7 +152,8 @@ namespace Barotrauma
}
#if CLIENT
else if (GameMain.Client != null)
{
{
syncItemsDelay = 1.0f;
GameMain.Client.CreateEntityEvent(Owner as IClientSerializable, new object[] { NetEntityEvent.Type.InventoryState });
}
#endif
@@ -189,8 +194,6 @@ namespace Barotrauma
public void ClientWrite(NetBuffer msg, object[] extraData = null)
{
ServerWrite(msg, null);
syncItemsDelay = 1.0f;
}
public void ServerRead(ClientNetObject type, NetBuffer msg, Barotrauma.Networking.Client c)
@@ -203,18 +206,40 @@ namespace Barotrauma
newItemIDs[i] = msg.ReadUInt16();
}
if (c == null || c.Character == null || !c.Character.CanAccessInventory(this)) return;
if (c == null || c.Character == null) return;
if (!c.Character.CanAccessInventory(this))
{
//create a network event to correct the client's inventory state
//otherwise they may have an item in their inventory they shouldn't have been able to pick up,
//and receiving an event for that inventory later will cause the item to be dropped
CreateNetworkEvent();
for (int i = 0; i < capacity; i++)
{
var item = Entity.FindEntityByID(newItemIDs[i]) as Item;
if (item == null) continue;
if (item.ParentInventory != null && item.ParentInventory != this)
{
item.ParentInventory.CreateNetworkEvent();
}
}
return;
}
List<Inventory> prevItemInventories = new List<Inventory>(Items.Select(i => i?.ParentInventory));
for (int i = 0; i < capacity; i++)
{
if (newItemIDs[i] == 0 || (Entity.FindEntityByID(newItemIDs[i]) as Item != Items[i]))
Item newItem = newItemIDs[i] == 0 ? null : Entity.FindEntityByID(newItemIDs[i]) as Item;
prevItemInventories.Add(newItem?.ParentInventory);
if (newItemIDs[i] == 0 || (newItem != Items[i]))
{
if (Items[i] != null) Items[i].Drop();
System.Diagnostics.Debug.Assert(Items[i] == null);
}
}
for (int i = 0; i < capacity; i++)
{
if (newItemIDs[i] > 0)
@@ -234,6 +259,10 @@ namespace Barotrauma
}
CreateNetworkEvent();
foreach (Inventory prevInventory in prevItemInventories.Distinct())
{
if (prevInventory != this) prevInventory?.CreateNetworkEvent();
}
foreach (Item item in Items.Distinct())
{

View File

@@ -101,6 +101,7 @@ namespace Barotrauma
#if CLIENT
else if (GameMain.Client != null)
{
syncItemsDelay = 1.0f;
GameMain.Client.CreateEntityEvent(Owner as IClientSerializable, new object[] { NetEntityEvent.Type.InventoryState, componentIndex });
}
#endif