namespace Minecraft.Server.FourKit.Inventory; using System.Runtime.InteropServices; using Minecraft.Server.FourKit.Entity; /// /// Represents a player's inventory, including armor slots and the held item. /// public class PlayerInventory : Inventory { private const int INVENTORY_SIZE = 40; private const int ARMOR_START = 36; private const int QUICKBAR_SIZE = 9; private int _heldItemSlot; internal HumanEntity? _holder; internal PlayerInventory() : base("Player", InventoryType.PLAYER, INVENTORY_SIZE) { } protected internal override void EnsureSynced() { if (_holder == null || NativeBridge.GetPlayerInventory == null) return; int entityId = _holder.getEntityId(); int[] buf = new int[121]; var gh = GCHandle.Alloc(buf, GCHandleType.Pinned); try { NativeBridge.GetPlayerInventory(entityId, gh.AddrOfPinnedObject()); } finally { gh.Free(); } for (int i = 0; i < INVENTORY_SIZE; i++) { int id = buf[i * 3]; int count = buf[i * 3 + 1]; int aux = buf[i * 3 + 2]; if (id > 0 && count > 0) _items[i] = new ItemStack(id, count, (short)aux); else _items[i] = null; } _heldItemSlot = buf[120]; } /// public override void setItem(int index, ItemStack? item) { base.setItem(index, item); _slotModifiedByPlugin = true; if (_holder != null && NativeBridge.SetPlayerInventorySlot != null && index >= 0 && index < INVENTORY_SIZE) { int id = item?.getTypeId() ?? 0; int count = item?.getAmount() ?? 0; int aux = item?.getDurability() ?? 0; NativeBridge.SetPlayerInventorySlot(_holder.getEntityId(), index, id, count, aux); } } /// /// Returns all ItemStacks from the armor slots. /// /// An array of ItemStacks for the armor slots. public ItemStack?[] getArmorContents() { EnsureSynced(); var armor = new ItemStack?[4]; for (int i = 0; i < 4; i++) armor[i] = _items[ARMOR_START + i]; return armor; } /// /// Gets the ItemStack in the helmet slot. /// /// The helmet ItemStack. public ItemStack? getHelmet() => getItem(ARMOR_START + 3); /// /// Gets the ItemStack in the chestplate slot. /// /// The chestplate ItemStack. public ItemStack? getChestplate() => getItem(ARMOR_START + 2); /// /// Gets the ItemStack in the leggings slot. /// /// The leggings ItemStack. public ItemStack? getLeggings() => getItem(ARMOR_START + 1); /// /// Gets the ItemStack in the boots slot. /// /// The boots ItemStack. public ItemStack? getBoots() => getItem(ARMOR_START); /// /// Sets all four armor slots at once. /// /// An array of ItemStacks for the armor slots. public void setArmorContents(ItemStack?[] items) { int len = Math.Min(items.Length, 4); for (int i = 0; i < len; i++) setItem(ARMOR_START + i, items[i]); } /// /// Sets the helmet slot. /// /// The ItemStack to set. public void setHelmet(ItemStack? helmet) => setItem(ARMOR_START + 3, helmet); /// /// Sets the chestplate slot. /// /// The ItemStack to set. public void setChestplate(ItemStack? chestplate) => setItem(ARMOR_START + 2, chestplate); /// /// Sets the leggings slot. /// /// The ItemStack to set. public void setLeggings(ItemStack? leggings) => setItem(ARMOR_START + 1, leggings); /// /// Sets the boots slot. /// /// The ItemStack to set. public void setBoots(ItemStack? boots) => setItem(ARMOR_START, boots); /// /// Gets the item the player is currently holding. /// /// The held ItemStack. public ItemStack? getItemInHand() => getItem(_heldItemSlot); /// /// Sets the item in the player's hand. /// /// The ItemStack to set. public void setItemInHand(ItemStack? stack) => setItem(_heldItemSlot, stack); /// /// Gets the slot number of the currently held item. /// /// The held item slot index (0-8). public int getHeldItemSlot() { EnsureSynced(); return _heldItemSlot; } /// /// Sets the slot number of the currently held item. /// /// The slot index (0-8). public void setHeldItemSlot(int slot) { if (slot < 0 || slot >= QUICKBAR_SIZE) throw new ArgumentException($"Slot must be between 0 and {QUICKBAR_SIZE - 1} inclusive."); _heldItemSlot = slot; } /// /// Clears all matching items from the inventory. Setting either value /// to -1 will skip its check, while setting both to -1 will clear all /// items in your inventory unconditionally. /// /// The material id to match, or -1 for any. /// The data value to match, or -1 for any. /// The number of stacks cleared. public int clear(int id, int data) { EnsureSynced(); int count = 0; for (int i = 0; i < getSize(); i++) { var item = _items[i]; if (item == null) continue; if (id != -1 && item.getTypeId() != id) continue; if (data != -1 && item.getDurability() != data) continue; setItem(i, null); count++; } return count; } /// /// Gets the holder of this inventory. /// /// The HumanEntity that owns this inventory. public HumanEntity? getHolder() => _holder; }