namespace Minecraft.Server.FourKit.Entity; using System.Runtime.InteropServices; using Minecraft.Server.FourKit.Inventory; /// /// Represents a human entity in the world (e.g. a player). /// public abstract class HumanEntity : LivingEntity, InventoryHolder { private GameMode _gameMode = GameMode.SURVIVAL; private string _name = string.Empty; internal PlayerInventory _playerInventory = new(); internal Inventory _enderChestInventory = new("Ender Chest", InventoryType.ENDER_CHEST, 27); private ItemStack? _cursorItem; private bool _sleeping; private int _sleepTicks; /// /// Gets this human's current . /// /// The current game mode. public GameMode getGameMode() => _gameMode; /// /// Returns the name of this player. /// /// The display name. public string getName() => _name; /// /// Sets this human's current . /// /// The new game mode. public void setGameMode(GameMode mode) { NativeBridge.SetPlayerGameMode?.Invoke(getEntityId(), (int)mode); } /// /// Get the player's inventory. /// /// The inventory of the player, this also contains the armor slots. Inventory InventoryHolder.getInventory() => getInventory(); /// /// Get the player's inventory. /// This also contains the armor slots. /// /// The player's inventory. public PlayerInventory getInventory() { return _playerInventory; } /// /// Get the player's EnderChest inventory. /// /// The EnderChest of the player. public Inventory getEnderChest() { return _enderChestInventory; } /// /// Returns the ItemStack currently in your hand, can be empty. /// /// The ItemStack of the item you are currently holding. public ItemStack? getItemInHand() { return _playerInventory.getItemInHand(); } /// /// Sets the item to the given ItemStack, this will replace whatever the /// user was holding. /// /// The ItemStack which will end up in the hand. public void setItemInHand(ItemStack? item) { _playerInventory.setItemInHand(item); } /// /// Returns the ItemStack currently on your cursor, can be empty. /// Will always be empty if the player currently has no open window. /// /// The ItemStack of the item you are currently moving around. public ItemStack? getItemOnCursor() => _cursorItem; /// /// Sets the item to the given ItemStack, this will replace whatever the /// user was moving. Will always be empty if the player currently has no open window. /// /// The ItemStack which will end up in the hand. public void setItemOnCursor(ItemStack? item) => _cursorItem = item; /// /// If the player currently has an inventory window open, this method will /// close it on both the server and client side. /// public void closeInventory() { NativeBridge.CloseContainer?.Invoke(getEntityId()); } /// /// Opens an inventory window with the specified inventory on the top. /// /// The inventory to open. /// The newly opened InventoryView, or null if it could not be opened. public InventoryView? openInventory(Inventory inventory) { if (NativeBridge.OpenVirtualContainer == null) return null; closeInventory(); int nativeType = inventory.getType() switch { InventoryType.CHEST => 0, InventoryType.DISPENSER => 3, InventoryType.DROPPER => 10, InventoryType.HOPPER => 5, _ => 0, }; int size = inventory.getSize(); int[] buf = new int[size * 3]; for (int i = 0; i < size; i++) { var item = inventory._items[i]; buf[i * 3] = item?.getTypeId() ?? 0; buf[i * 3 + 1] = item?.getAmount() ?? 0; buf[i * 3 + 2] = item?.getDurability() ?? 0; } string title = inventory.getName(); int titleByteLen = System.Text.Encoding.UTF8.GetByteCount(title); IntPtr titlePtr = Marshal.StringToCoTaskMemUTF8(title); var gh = GCHandle.Alloc(buf, GCHandleType.Pinned); try { NativeBridge.OpenVirtualContainer(getEntityId(), nativeType, titlePtr, titleByteLen, size, gh.AddrOfPinnedObject()); } finally { gh.Free(); Marshal.FreeCoTaskMem(titlePtr); } var view = new InventoryView(inventory, getInventory(), this, inventory.getType()); return view; } internal void SetGameModeInternal(GameMode mode) => _gameMode = mode; internal void SetNameInternal(string name) => _name = name; internal void SetSleepingInternal(bool sleeping) => _sleeping = sleeping; internal void SetSleepTicksInternal(int ticks) => _sleepTicks = ticks; /// /// Returns whether this player is slumbering. /// /// slumber state public bool isSleeping() => _sleeping; /// /// Get the sleep ticks of the player. This value may be capped. /// /// slumber ticks public int getSleepTicks() => _sleepTicks; }