public void deny(ItemStack template) { Key key = Key.of(template); Element e = _elements.get(key); log.debug("deny", "template", template, "key", key, "e", e); if (e == null || !e.whitelisted()) return; log.debug("deny: whitelisted: removing...", "empty", e.empty()); e.whitelisted(false); _whitelist.remove(key); if (e.empty()) _elements.remove(key); }
public void dump() { log.debug("DUMP", "total", _total); for (Element e : _elements.values()) log.debug( "DUMP: element", "key", e.key().stack(), "whitelisted", e.whitelisted(), "count", e.count()); }
public ItemStack put(ItemStack stack) { log.debug("put", "stack", stack, "size", stack.stackSize); if (stack == null) return null; Key key = Key.of(stack); Element e = _elements.get(key); if (e == null) return stack; int amount = stack.stackSize; amount = Math.min(amount, _maxTotal - _total); amount = e.put(amount, _maxPerKey); if (amount == 0) return stack; _total += amount; log.debug("put: done", "amount", amount); return stack.splitStack(amount); }
public ItemStack take(int amount) { log.debug("take", "amount", amount); for (Element e : _elements.values()) { if (e.empty()) continue; int taken = e.take(amount); if (taken > 0) { ItemStack stack = e.key().stack().copy(); stack.stackSize = taken; _total = Math.max(0, _total - taken); if (e.empty() && !_whitelist.contains(e.key())) _elements.remove(e.key()); log.debug("take: done", "amount", stack.stackSize); return stack; } } return null; }
public int delete(ItemStack template, int amount) { Key key = Key.of(template); Element e = _elements.get(key); log.debug("take", "template", template, "key", key, "e", e); if (e == null) return 0; int taken = e.take(amount); _total = Math.max(0, _total - taken); return taken; }
public boolean allowed(ItemStack stack) { log.trace("allowed", "template", stack, "size", stack == null ? 0 : stack.stackSize); Key key = Key.of(stack); Element e = _elements.get(key); if (e == null || !e.whitelisted()) return false; if (e.count() + stack.stackSize > _maxPerKey) return false; if (_total + stack.stackSize > _maxTotal) return false; return true; }
@Override // IInventory public ItemStack decrStackSize(int slot, int amount) { log.debug("decrStackSize", "slot", slot, "amount", amount); switch (slot) { case SLOT_IMPORT: default: return null; case SLOT_EXPORT: return _inventory.takeExport(amount); } }
public boolean allow(ItemStack template) { log.debug("allow", "template", template); if (_whitelist.size() >= _maxKeys) return false; Key key = Key.of(template); Element e = _elements.get(key); if (e == null) { e = Element.of(key, 0, true); _elements.put(key, e); _whitelist.add(key); } else if (!e.whitelisted()) { e.whitelisted(true); _whitelist.add(key); } return true; }
@Override // IInventory public void setInventorySlotContents(int slot, ItemStack stack) { log.debug("setInventorySlotContents", "slot", slot, "stack", stack); switch (slot) { case SLOT_IMPORT: if (stack == null || stack.stackSize == 0) return; _inventory.put(stack); markDirty(); break; case SLOT_EXPORT: _inventory.setExport(stack); break; default: break; } }
public boolean has(ItemStack template) { Key key = Key.of(template); Element e = _elements.get(key); log.debug("has", "template", template, "key", key, "e", e); return e != null && !e.empty(); }
public int put(int amount, int max) { log.debug("put", "amount", amount, "max", max, "count", _count); amount = Math.min(amount, max - _count); _count += amount; return amount; }
public class BlocksmithMachineTile extends TileEntity implements ITilePacketHandler, ITilePacketDistributor, IInventory, ISidedInventory { private static final Log log = Log.create(BlocksmithMachineTile.class); public static final String NAME = "blocksmithMachine"; private static final int SLOT_COUNT = 2; private static final int SLOT_STACK_LIMIT = 64; private static final int SLOT_IMPORT = 0; private static final int SLOT_EXPORT = 1; private static final int INVENTORY_MAX_KEYS = 16; private static final int INVENTORY_MAX_ITEMS_PER_KEY = 512; private static final int INVENTORY_MAX_EXPORTS = 2048; private static final int[] ACCESSIBLE_SLOTS = cacheAccessibleSlots(); private static int[] cacheAccessibleSlots() { int[] slots = new int[SLOT_COUNT]; for (int i = 0; i < SLOT_COUNT; ++i) slots[i] = i; return slots; } private final TilePacketDistributorAdapter _packetAdapter = new TilePacketDistributorAdapter(); // private final Subscribee<Counts> _countSubscribee = new Subscribee<>(); private final Inventory _inventory = new Inventory(); private PendingStack _pending = null; public static void load() { GameRegistry.registerTileEntity(BlocksmithMachineTile.class, NAME); } public Inventory inventory() { return _inventory; } @Override // ITilePacketHandler public void handleTilePacket(IMessage msg, EntityPlayer player, Side side) { _packetAdapter.post(msg, player, side); } @Override // ITilePacketHandler public void subscribeToTilePackets(ITilePacketHandler handler) { _packetAdapter.subscribe(handler); } @Override // ITilePacketHandler public void unsubscribeFromTilePackets(ITilePacketHandler handler) { _packetAdapter.unsubscribe(handler); } @Override // TileEntity public void updateEntity() { if (worldObj.isRemote) return; _inventory.fillExport(); } @Override // TileEntity public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) { _inventory.fromNbt(pkt.func_148857_g()); } @Override // TileEntity public Packet getDescriptionPacket() { return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, 0, _inventory.toNbt()); } public void syncTo(EntityPlayer player) { if (worldObj.isRemote) return; if (EntityPlayer.class.isAssignableFrom(player.getClass())) ((EntityPlayerMP) player).playerNetServerHandler.sendPacket(getDescriptionPacket()); } @Override // TileEntity public void readFromNBT(NBTTagCompound tag) { super.readFromNBT(tag); _inventory.fromNbt(tag.getCompoundTag("inventory")); } @Override // TileEntity public void writeToNBT(NBTTagCompound tag) { super.writeToNBT(tag); tag.setTag("inventory", _inventory.toNbt()); } // TileEntity @Override public void validate() { if (worldObj.isRemote) return; } @Override public void invalidate() {} @Override public void onChunkUnload() {} public void dump() { _inventory.dump(); } // IInventory @Override public boolean hasCustomInventoryName() { return true; } @Override public String getInventoryName() { return "blocksmithMachineInventory"; } @Override public void openInventory() {} @Override public void closeInventory() {} @Override public int getSizeInventory() { return SLOT_COUNT; } @Override public int getInventoryStackLimit() { return SLOT_STACK_LIMIT; } @Override public boolean isUseableByPlayer(EntityPlayer p) { return true; } @Override // IInventory public ItemStack getStackInSlot(int slot) { switch (slot) { case SLOT_IMPORT: default: return null; case SLOT_EXPORT: return _inventory.getExport(); } } @Override // IInventory public ItemStack decrStackSize(int slot, int amount) { log.debug("decrStackSize", "slot", slot, "amount", amount); switch (slot) { case SLOT_IMPORT: default: return null; case SLOT_EXPORT: return _inventory.takeExport(amount); } } @Override // IInventory public ItemStack getStackInSlotOnClosing(int slot) { log.debug("getStackInSlotOnClosing", "slot", slot); return null; } @Override // IInventory public void setInventorySlotContents(int slot, ItemStack stack) { log.debug("setInventorySlotContents", "slot", slot, "stack", stack); switch (slot) { case SLOT_IMPORT: if (stack == null || stack.stackSize == 0) return; _inventory.put(stack); markDirty(); break; case SLOT_EXPORT: _inventory.setExport(stack); break; default: break; } } @Override // IInventory public boolean isItemValidForSlot(int slot, ItemStack stack) { switch (slot) { case SLOT_IMPORT: return _inventory.allowed(stack); case SLOT_EXPORT: default: return false; } } @Override // ISidedInventory public int[] getAccessibleSlotsFromSide(int side) { return ACCESSIBLE_SLOTS; } @Override // ISidedInventory public boolean canInsertItem(int slot, ItemStack stack, int side) { switch (slot) { case SLOT_IMPORT: return _inventory.allowed(stack); case SLOT_EXPORT: default: return false; } } @Override // ISidedInventory public boolean canExtractItem(int slot, ItemStack stack, int side) { switch (slot) { case SLOT_IMPORT: default: return false; case SLOT_EXPORT: return ItemHelper.itemsIdentical(_inventory.getExport(), stack); } } public class PendingStack { public ItemStack stack; public PendingStack(ItemStack stack) { this.stack = stack; } public void done(boolean creative) { if (_pending != null) { _pending = null; if (!creative) { if (_inventory.delete(stack, 1) > 0) markDirty(); } } } public void abort() { _pending = null; } } public PendingStack pending(ItemStack template, boolean creative) { if (_pending != null) return null; if (creative && !_inventory.allowed(template)) return null; if (!creative && !_inventory.has(template)) return null; template = template.copy(); template.stackSize = 1; return _pending = new PendingStack(template); } private static class Key { private final ItemStack _stack; private Key(ItemStack stack) { _stack = stack.copy(); _stack.stackSize = 0; } public static Key of(ItemStack stack) { return new Key(stack); } public ItemStack stack() { return _stack; } @Override public boolean equals(Object o) { if (o == null || !Key.class.isAssignableFrom(o.getClass())) return false; return ItemHelper.itemsIdentical(_stack, ((Key) o).stack()); } @Override public int hashCode() { return Objects.hash(_stack.getItem(), _stack.getItemDamage(), _stack.getTagCompound()); } public NBTTagCompound toNbt() { return _stack.writeToNBT(new NBTTagCompound()); } public static Key fromNbt(NBTTagCompound tag) { return Key.of(ItemHelper.readItemStackFromNBT(tag)); } } private static class Element { private final Key _key; private int _count; private boolean _whitelisted; private Element(Key key, int count, boolean whitelisted) { _key = key; _count = count; _whitelisted = whitelisted; } public static Element of(Key key, int count, boolean whitelisted) { return new Element(key, count, whitelisted); } public Key key() { return _key; } public int count() { return _count; } public boolean whitelisted() { return _whitelisted; } public Element whitelisted(boolean whitelisted) { _whitelisted = whitelisted; return this; } public boolean empty() { return _count == 0; } public boolean full(int max) { return _count >= max; } public int get(int amount) { return Math.min(_key.stack().getMaxStackSize(), Math.min(amount, _count)); } public int take(int amount) { amount = get(amount); _count -= amount; return amount; } public int put(int amount, int max) { log.debug("put", "amount", amount, "max", max, "count", _count); amount = Math.min(amount, max - _count); _count += amount; return amount; } public NBTTagCompound toNbt() { NBTTagCompound tag = new NBTTagCompound(); tag.setTag("key", _key.toNbt()); tag.setInteger("count", _count); tag.setBoolean("whitelisted", _whitelisted); return tag; } public static Element fromNbt(NBTTagCompound tag) { return Element.of( Key.fromNbt(tag.getCompoundTag("key")), tag.getInteger("count"), tag.getBoolean("whitelisted")); } } public static class ItemMap { private final Map<Key, Integer> _elements = new HashMap<>(); private final int _max; private int _size; public ItemMap(int max) { _max = max; } public int size() { return _size; } public boolean empty() { return _size == 0; } public void clear() { _elements.clear(); _size = 0; } /** Inserts the target stack and returns what didn't fit. */ public ItemStack put(ItemStack stack) { int amount = Math.min(_max - _size, stack.stackSize); if (amount <= 0) return stack; Key k = Key.of(stack); Integer current = _elements.get(k); _elements.put(k, current == null ? amount : current + amount); _size += amount; stack.splitStack(amount); return stack.stackSize > 0 ? stack : null; } public ItemStack take() { if (_elements.isEmpty()) return null; Map.Entry<Key, Integer> e = _elements.entrySet().iterator().next(); return take(_elements.keySet().iterator().next().stack(), SLOT_STACK_LIMIT); } public ItemStack take(ItemStack template, int amount) { Key k = Key.of(template); Integer count = _elements.get(k); if (count == null) return null; ItemStack stack = k.stack().copy(); stack.stackSize = Math.min(stack.getMaxStackSize(), Math.min(SLOT_STACK_LIMIT, Math.min(amount, count))); _size -= stack.stackSize; if (stack.stackSize >= count) _elements.remove(k); else _elements.put(k, count - stack.stackSize); return stack; } public NBTTagCompound toNbt() { NBTTagCompound tag = new NBTTagCompound(); NBTTagList elements = new NBTTagList(); for (Map.Entry<Key, Integer> e : _elements.entrySet()) { NBTTagCompound element = new NBTTagCompound(); element.setTag("key", e.getKey().toNbt()); element.setInteger("count", e.getValue()); elements.appendTag(element); } tag.setTag("elements", elements); tag.setInteger("size", _size); return tag; } public void fromNbt(NBTTagCompound tag) { clear(); NBTTagList elements = tag.getTagList("elements", Constants.NBT.TAG_COMPOUND); for (int i = 0; i < elements.tagCount(); ++i) { NBTTagCompound element = elements.getCompoundTagAt(i); Key k = Key.fromNbt(element.getCompoundTag("key")); Integer count = element.getInteger("count"); _elements.put(k, count); } _size = tag.getInteger("size"); } } public static class Inventory { private final Map<Key, Element> _elements = new HashMap<>(); private final Set<Key> _whitelist = new HashSet<>(); private final ItemMap _exportable = new ItemMap(INVENTORY_MAX_EXPORTS); private final int _maxKeys; private final int _maxPerKey; private final int _maxTotal; private int _total; private ItemStack _export; private Inventory() { _maxKeys = INVENTORY_MAX_KEYS; _maxPerKey = INVENTORY_MAX_ITEMS_PER_KEY; _maxTotal = _maxKeys * _maxPerKey; _total = 0; } public int maxKeys() { return _maxKeys; } public int maxPerKey() { return _maxPerKey; } public int maxTotal() { return _maxTotal; } public int total() { return _total; } public Inventory clear() { _elements.clear(); _whitelist.clear(); _exportable.clear(); _export = null; _total = 0; return this; } public Collection<ItemStack> allowed() { List<ItemStack> list = new LinkedList<>(); for (Key k : _whitelist) list.add(k.stack()); return list; } public boolean allowed(ItemStack stack) { log.trace("allowed", "template", stack, "size", stack == null ? 0 : stack.stackSize); Key key = Key.of(stack); Element e = _elements.get(key); if (e == null || !e.whitelisted()) return false; if (e.count() + stack.stackSize > _maxPerKey) return false; if (_total + stack.stackSize > _maxTotal) return false; return true; } public boolean allow(ItemStack template) { log.debug("allow", "template", template); if (_whitelist.size() >= _maxKeys) return false; Key key = Key.of(template); Element e = _elements.get(key); if (e == null) { e = Element.of(key, 0, true); _elements.put(key, e); _whitelist.add(key); } else if (!e.whitelisted()) { e.whitelisted(true); _whitelist.add(key); } return true; } public void deny(ItemStack template) { Key key = Key.of(template); Element e = _elements.get(key); log.debug("deny", "template", template, "key", key, "e", e); if (e == null || !e.whitelisted()) return; log.debug("deny: whitelisted: removing...", "empty", e.empty()); e.whitelisted(false); _whitelist.remove(key); if (e.empty()) _elements.remove(key); } public ItemStack get() { for (Element e : _elements.values()) { if (e.empty()) continue; int gotten = e.get(Integer.MAX_VALUE); if (gotten > 0) { ItemStack stack = e.key().stack().copy(); stack.stackSize = gotten; return stack; } } return null; } public boolean has(ItemStack template) { Key key = Key.of(template); Element e = _elements.get(key); log.debug("has", "template", template, "key", key, "e", e); return e != null && !e.empty(); } public int delete(ItemStack template, int amount) { Key key = Key.of(template); Element e = _elements.get(key); log.debug("take", "template", template, "key", key, "e", e); if (e == null) return 0; int taken = e.take(amount); _total = Math.max(0, _total - taken); return taken; } public ItemStack take(int amount) { log.debug("take", "amount", amount); for (Element e : _elements.values()) { if (e.empty()) continue; int taken = e.take(amount); if (taken > 0) { ItemStack stack = e.key().stack().copy(); stack.stackSize = taken; _total = Math.max(0, _total - taken); if (e.empty() && !_whitelist.contains(e.key())) _elements.remove(e.key()); log.debug("take: done", "amount", stack.stackSize); return stack; } } return null; } public ItemStack put(ItemStack stack) { log.debug("put", "stack", stack, "size", stack.stackSize); if (stack == null) return null; Key key = Key.of(stack); Element e = _elements.get(key); if (e == null) return stack; int amount = stack.stackSize; amount = Math.min(amount, _maxTotal - _total); amount = e.put(amount, _maxPerKey); if (amount == 0) return stack; _total += amount; log.debug("put: done", "amount", amount); return stack.splitStack(amount); } public ItemStack putExportable(ItemStack stack) { return _exportable.put(stack); } public void setExport(ItemStack stack) { _export = stack; } public ItemStack getExport() { return _export; } public ItemStack takeExport(int amount) { if (_export == null) return null; ItemStack taken = _export.splitStack(amount); if (_export.stackSize == 0) _export = null; return taken.stackSize == 0 ? null : taken; } public void fillExport() { if (_exportable.empty()) return; if (_export == null) { _export = _exportable.take(); } else { int request = Math.min(SLOT_STACK_LIMIT, _export.getMaxStackSize()) - _export.stackSize; ItemStack taken = _exportable.take(_export, request); if (taken != null) _export.stackSize += taken.stackSize; else _export = _exportable.take(); } } public NBTTagCompound toNbt() { NBTTagCompound tag = new NBTTagCompound(); NBTTagList elements = new NBTTagList(); for (Map.Entry<Key, Element> e : _elements.entrySet()) { NBTTagCompound element = new NBTTagCompound(); element.setTag("key", e.getKey().toNbt()); element.setTag("element", e.getValue().toNbt()); elements.appendTag(element); } tag.setTag("elements", elements); tag.setTag("exportable", _exportable.toNbt()); if (_export != null) tag.setTag("export", ItemHelper.writeItemStackToNBT(_export, new NBTTagCompound())); tag.setInteger("total", _total); return tag; } public void fromNbt(NBTTagCompound tag) { clear(); NBTTagList elements = tag.getTagList("elements", Constants.NBT.TAG_COMPOUND); for (int i = 0; i < elements.tagCount(); ++i) { NBTTagCompound element = elements.getCompoundTagAt(i); Key k = Key.fromNbt(element.getCompoundTag("key")); Element e = Element.fromNbt(element.getCompoundTag("element")); _elements.put(k, e); if (e.whitelisted()) _whitelist.add(k); } _exportable.fromNbt(tag.getCompoundTag("exportable")); if (tag.hasKey("export")) _export = ItemHelper.readItemStackFromNBT(tag.getCompoundTag("export")); _total = tag.getInteger("total"); } public void dump() { log.debug("DUMP", "total", _total); for (Element e : _elements.values()) log.debug( "DUMP: element", "key", e.key().stack(), "whitelisted", e.whitelisted(), "count", e.count()); } } }
@Override // IInventory public ItemStack getStackInSlotOnClosing(int slot) { log.debug("getStackInSlotOnClosing", "slot", slot); return null; }