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;
}