package net.glowstone.inventory; import net.glowstone.constants.ItemIds; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.ItemStack; import java.util.LinkedList; import java.util.List; import java.util.Objects; /** * Tracker for when items in an inventory are changed. */ public final class InventoryMonitor { private static int nextId = 1; private final InventoryView view; private final ItemStack[] slots; private final int size, id; private final String type; /** * Create a new monitor for the given inventory view. * @param view The view to monitor. */ public InventoryMonitor(InventoryView view) { boolean isDefault = GlowInventoryView.isDefault(view); this.view = view; this.size = view.countSlots() + (isDefault ? 4 : 0); this.slots = new ItemStack[size]; // determine id and type id if (isDefault) { id = 0; } else { id = nextId; nextId = (nextId % 100) + 1; } type = getTypeId(view.getType()); // set initial contents for (int i = 0; i < size; ++i) { updateItem(i); } } /** * Update the given slot with the current value from the view. * @param slot The slot to update. */ private void updateItem(int slot) { // sanitize() used as a last line of defense to prevent client crashes // GlowInventory should generally be able to keep its contents safe ItemStack source = view.getItem(slot); slots[slot] = source == null ? null : ItemIds.sanitize(source.clone()); } /** * Check for changes in the inventory view. * @return The list of changed items. */ public List<Entry> getChanges() { List<Entry> result = new LinkedList<>(); for (int i = 0; i < size; ++i) { if (!Objects.equals(slots[i], view.getItem(i))) { updateItem(i); result.add(new Entry(i, slots[i])); } } return result; } /** * Get the current contents of the viewed inventory. * @return The contents. */ public ItemStack[] getContents() { return slots; } /** * Get the number of slots in this inventory view. * @return The number of slots. */ public int getSize() { return size; } /** * Get the network ID of this inventory view. * @return The id. */ public int getId() { return id; } /** * Get the network type ID of this inventory view. * @return The type id. */ public String getType() { return type; } /** * An entry which has been changed. */ public static class Entry { public final int slot; public final ItemStack item; public Entry(int slot, ItemStack item) { this.slot = slot; this.item = item; } } /** * Get the network ID for the given inventory type. * @param type The type. * @return The id. */ private static String getTypeId(InventoryType type) { switch (type) { case WORKBENCH: return "minecraft:crafting_table"; case FURNACE: return "minecraft:furnace"; case DISPENSER: return "minecraft:dispenser"; case ENCHANTING: return "minecraft:enchanting_table"; case BREWING: return "minecraft:brewing_stand"; case MERCHANT: return "minecraft:villager"; case BEACON: return "minecraft:beacon"; case ANVIL: return "minecraft:anvil"; case HOPPER: return "minecraft:hopper"; case DROPPER: return "minecraft:dropper"; case PLAYER: case CHEST: case ENDER_CHEST: default: return "minecraft:chest"; } } }