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:
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user