Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaShared/Source/Items/Inventory.cs
T
Joonas Rikkonen 60a563fe75 EntityEvent fixes:
- Clients wait for midround syncing to finish before applying the remote state to connection panels and inventories (because the wires connected to the connection panel or items in the inventory may not exist before the EntitySpawner events have been received).
- Server writes 0 as the projectile ID if the projectile doesn't exist anymore when a Turret event is sent.
- More info in networkevent error messages.
2018-07-30 13:35:26 +03:00

274 lines
8.5 KiB
C#

using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Inventory : IServerSerializable, IClientSerializable
{
public readonly Entity Owner;
protected int capacity;
public Item[] Items;
private bool isSubInventory;
public bool Locked;
private ushort[] receivedItemIDs;
private float syncItemsDelay;
private CoroutineHandle syncItemsCoroutine;
public Inventory(Entity owner, int capacity, Vector2? centerPos = null, int slotsPerRow=5)
{
this.capacity = capacity;
this.Owner = owner;
Items = new Item[capacity];
#if CLIENT
this.slotsPerRow = slotsPerRow;
CenterPos = (centerPos==null) ? new Vector2(0.5f, 0.5f) : (Vector2)centerPos;
#endif
}
public int FindIndex(Item item)
{
for (int i = 0; i < capacity; i++)
{
if (Items[i] == item) return i;
}
return -1;
}
/// Returns true if the item owns any of the parent inventories
public virtual bool ItemOwnsSelf(Item item)
{
if (Owner == null) return false;
if (!(Owner is Item)) return false;
Item ownerItem = Owner as Item;
if (ownerItem == item) return true;
if (ownerItem.ParentInventory == null) return false;
return ownerItem.ParentInventory.ItemOwnsSelf(item);
}
public virtual int FindAllowedSlot(Item item)
{
if (ItemOwnsSelf(item)) return -1;
for (int i = 0; i < capacity; i++)
{
//item is already in the inventory!
if (Items[i] == item) return -1;
}
for (int i = 0; i < capacity; i++)
{
if (Items[i] == null) return i;
}
return -1;
}
public virtual bool CanBePut(Item item, int i)
{
if (ItemOwnsSelf(item)) return false;
if (i < 0 || i >= Items.Length) return false;
return (Items[i] == null);
}
/// <summary>
/// If there is room, puts the item in the inventory and returns true, otherwise returns false
/// </summary>
public virtual bool TryPutItem(Item item, Character user, List<InvSlotType> allowedSlots = null, bool createNetworkEvent = true)
{
int slot = FindAllowedSlot(item);
if (slot < 0) return false;
PutItem(item, slot, user, true, createNetworkEvent);
return true;
}
public virtual bool TryPutItem(Item item, int i, bool allowSwapping, bool allowCombine, Character user, bool createNetworkEvent = true)
{
if (Owner == null) return false;
if (CanBePut(item, i))
{
PutItem(item, i, user, true, createNetworkEvent);
return true;
}
else
{
#if CLIENT
if (slots != null && createNetworkEvent) slots[i].ShowBorderHighlight(Color.Red, 0.1f, 0.9f);
#endif
return false;
}
}
protected virtual void PutItem(Item item, int i, Character user, bool removeItem = true, bool createNetworkEvent = true)
{
if (Owner == null) return;
if (removeItem)
{
item.Drop(user);
if (item.ParentInventory != null) item.ParentInventory.RemoveItem(item);
}
Items[i] = item;
item.ParentInventory = this;
#if CLIENT
if (slots != null) slots[i].ShowBorderHighlight(Color.White, 0.1f, 0.4f);
#endif
if (item.body != null)
{
item.body.Enabled = false;
}
if (createNetworkEvent)
{
CreateNetworkEvent();
}
}
protected virtual void CreateNetworkEvent()
{
if (GameMain.Server != null)
{
GameMain.Server.CreateEntityEvent(Owner as IServerSerializable, new object[] { NetEntityEvent.Type.InventoryState });
}
#if CLIENT
else if (GameMain.Client != null)
{
GameMain.Client.CreateEntityEvent(Owner as IClientSerializable, new object[] { NetEntityEvent.Type.InventoryState });
}
#endif
}
public Item FindItem(string itemName)
{
if (itemName == null) return null;
return Items.FirstOrDefault(i => i != null && (i.Prefab.NameMatches(itemName) || i.HasTag(itemName)));
}
public Item FindItem(string[] itemNames)
{
if (itemNames == null) return null;
foreach (string itemName in itemNames)
{
var item = FindItem(itemName);
if (item != null) return item;
}
return null;
}
public virtual void RemoveItem(Item item)
{
if (item == null) return;
//go through the inventory and remove the item from all slots
for (int n = 0; n < capacity; n++)
{
if (Items[n] != item) continue;
Items[n] = null;
item.ParentInventory = null;
}
}
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)
{
List<Item> prevItems = new List<Item>(Items);
ushort[] newItemIDs = new ushort[capacity];
for (int i = 0; i < capacity; i++)
{
newItemIDs[i] = msg.ReadUInt16();
}
if (c == null || c.Character == null || !c.Character.CanAccessInventory(this))
{
return;
}
for (int i = 0; i < capacity; i++)
{
if (newItemIDs[i] == 0)
{
if (Items[i] != null) Items[i].Drop(c.Character);
System.Diagnostics.Debug.Assert(Items[i]==null);
}
else
{
var item = Entity.FindEntityByID(newItemIDs[i]) as Item;
if (item == null || item == Items[i]) continue;
if (GameMain.Server != null)
{
if (!item.CanClientAccess(c)) continue;
}
TryPutItem(item, i, true, true, c.Character, false);
}
}
GameMain.Server.CreateEntityEvent(Owner as IServerSerializable, new object[] { NetEntityEvent.Type.InventoryState });
foreach (Item item in Items.Distinct())
{
if (item == null) continue;
if (!prevItems.Contains(item))
{
if (Owner == c.Character)
{
GameServer.Log(c.Character.LogName+ " picked up " + item.Name, ServerLog.MessageType.Inventory);
}
else
{
GameServer.Log(c.Character.LogName + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory);
}
}
}
foreach (Item item in prevItems.Distinct())
{
if (item == null) continue;
if (!Items.Contains(item))
{
if (Owner == c.Character)
{
GameServer.Log(c.Character.LogName + " dropped " + item.Name, ServerLog.MessageType.Inventory);
}
else
{
GameServer.Log(c.Character.LogName + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory);
}
}
}
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
for (int i = 0; i < capacity; i++)
{
msg.Write((ushort)(Items[i] == null ? 0 : Items[i].ID));
}
}
}
}