package codechicken.lib.inventory; import codechicken.lib.vec.Vector3; import com.google.common.base.Objects; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryLargeChest; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.util.BlockPos; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing.Plane; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; public class InventoryUtils { /** * Constructor for ItemStack with tag */ public static ItemStack newItemStack(Item item, int size, int damage, NBTTagCompound tag) { ItemStack stack = new ItemStack(item, size, damage); stack.setTagCompound(tag); return stack; } /** * Gets the actual damage of an item without asking the Item */ public static int actualDamage(ItemStack stack) { return Items.diamond.getDamage(stack); } /** * Static default implementation for IInventory method */ public static ItemStack decrStackSize(IInventory inv, int slot, int size) { ItemStack item = inv.getStackInSlot(slot); if (item != null) { if (item.stackSize <= size) { inv.setInventorySlotContents(slot, null); inv.markDirty(); return item; } ItemStack itemstack1 = item.splitStack(size); if (item.stackSize == 0) { inv.setInventorySlotContents(slot, null); } else { inv.setInventorySlotContents(slot, item); } inv.markDirty(); return itemstack1; } return null; } /** * Static default implementation for IInventory method */ public static ItemStack getStackInSlotOnClosing(IInventory inv, int slot) { ItemStack stack = inv.getStackInSlot(slot); inv.setInventorySlotContents(slot, null); return stack; } /** * @return The quantity of items from addition that can be added to base */ public static int incrStackSize(ItemStack base, ItemStack addition) { if (canStack(base, addition)) { return incrStackSize(base, addition.stackSize); } return 0; } /** * @return The quantity of items from addition that can be added to base */ public static int incrStackSize(ItemStack base, int addition) { int totalSize = base.stackSize + addition; if (totalSize <= base.getMaxStackSize()) { return addition; } else if (base.stackSize < base.getMaxStackSize()) { return base.getMaxStackSize() - base.stackSize; } return 0; } /** * NBT item saving function */ public static NBTTagList writeItemStacksToTag(ItemStack[] items) { return writeItemStacksToTag(items, 64); } /** * NBT item saving function with support for stack sizes > 32K */ public static NBTTagList writeItemStacksToTag(ItemStack[] items, int maxQuantity) { NBTTagList tagList = new NBTTagList(); for (int i = 0; i < items.length; i++) { if (items[i] != null) { NBTTagCompound tag = new NBTTagCompound(); tag.setShort("Slot", (short) i); items[i].writeToNBT(tag); if (maxQuantity > Short.MAX_VALUE) { tag.setInteger("Quantity", items[i].stackSize); } else if (maxQuantity > Byte.MAX_VALUE) { tag.setShort("Quantity", (short) items[i].stackSize); } tagList.appendTag(tag); } } return tagList; } /** * NBT item loading function with support for stack sizes > 32K */ public static void readItemStacksFromTag(ItemStack[] items, NBTTagList tagList) { for (int i = 0; i < tagList.tagCount(); i++) { NBTTagCompound tag = tagList.getCompoundTagAt(i); int b = tag.getShort("Slot"); items[b] = ItemStack.loadItemStackFromNBT(tag); if (tag.hasKey("Quantity")) { items[b].stackSize = ((NBTBase.NBTPrimitive) tag.getTag("Quantity")).getInt(); } } } /** * Spawns an itemstack in the world at a location */ public static void dropItem(ItemStack stack, World world, Vector3 dropLocation) { EntityItem item = new EntityItem(world, dropLocation.x, dropLocation.y, dropLocation.z, stack); item.motionX = world.rand.nextGaussian() * 0.05; item.motionY = world.rand.nextGaussian() * 0.05 + 0.2F; item.motionZ = world.rand.nextGaussian() * 0.05; world.spawnEntityInWorld(item); } /** * Copies an itemstack with a new quantity */ public static ItemStack copyStack(ItemStack stack, int quantity) { if (stack == null) { return null; } stack = stack.copy(); stack.stackSize = quantity; return stack; } /** * Gets the maximum quantity of an item that can be inserted into inv */ public static int getInsertibleQuantity(InventoryRange inv, ItemStack stack) { int quantity = 0; stack = copyStack(stack, Integer.MAX_VALUE); for (int slot : inv.slots) { quantity += fitStackInSlot(inv, slot, stack); } return quantity; } public static int getInsertibleQuantity(IInventory inv, ItemStack stack) { return getInsertibleQuantity(new InventoryRange(inv), stack); } public static int fitStackInSlot(InventoryRange inv, int slot, ItemStack stack) { ItemStack base = inv.inv.getStackInSlot(slot); if (!canStack(base, stack) || !inv.canInsertItem(slot, stack)) { return 0; } int fit = base != null ? incrStackSize(base, inv.inv.getInventoryStackLimit() - base.stackSize) : inv.inv.getInventoryStackLimit(); return Math.min(fit, stack.stackSize); } public static int fitStackInSlot(IInventory inv, int slot, ItemStack stack) { return fitStackInSlot(new InventoryRange(inv), slot, stack); } /** * @param simulate If set to true, no items will actually be inserted * @return The number of items unable to be inserted */ public static int insertItem(InventoryRange inv, ItemStack stack, boolean simulate) { stack = stack.copy(); for (int pass = 0; pass < 2; pass++) { for (int slot : inv.slots) { ItemStack base = inv.inv.getStackInSlot(slot); if ((pass == 0) == (base == null)) { continue; } int fit = fitStackInSlot(inv, slot, stack); if (fit == 0) { continue; } if (base != null) { stack.stackSize -= fit; if (!simulate) { base.stackSize += fit; inv.inv.setInventorySlotContents(slot, base); } } else { if (!simulate) { inv.inv.setInventorySlotContents(slot, copyStack(stack, fit)); } stack.stackSize -= fit; } if (stack.stackSize == 0) { return 0; } } } return stack.stackSize; } public static int insertItem(IInventory inv, ItemStack stack, boolean simulate) { return insertItem(new InventoryRange(inv), stack, simulate); } /** * Gets the stack in slot if it can be extracted */ public static ItemStack getExtractableStack(InventoryRange inv, int slot) { ItemStack stack = inv.inv.getStackInSlot(slot); if (stack == null || !inv.canExtractItem(slot, stack)) { return null; } return stack; } public static ItemStack getExtractableStack(IInventory inv, int slot) { return getExtractableStack(new InventoryRange(inv), slot); } public static boolean areStacksIdentical(ItemStack stack1, ItemStack stack2) { if (stack1 == null || stack2 == null) { return stack1 == stack2; } return stack1.getItem() == stack2.getItem() && stack1.getItemDamage() == stack2.getItemDamage() && stack1.stackSize == stack2.stackSize && Objects.equal(stack1.getTagCompound(), stack2.getTagCompound()); } /** * Gets an IInventory from a coordinate with support for double chests */ public static IInventory getInventory(World world, BlockPos pos) { TileEntity tile = world.getTileEntity(pos); if (!(tile instanceof IInventory)) { return null; } if (tile instanceof TileEntityChest) { return getChest((TileEntityChest) tile); } return (IInventory) tile; } public static IInventory getChest(TileEntityChest chest) { for (EnumFacing fside : Plane.HORIZONTAL) { if (chest.getWorld().getBlockState(chest.getPos().offset(fside)).getBlock() == chest.getBlockType()) { return new InventoryLargeChest("container.chestDouble", (TileEntityChest) chest.getWorld().getTileEntity(chest.getPos().offset(fside)), chest); } } return chest; } public static boolean canStack(ItemStack stack1, ItemStack stack2) { return stack1 == null || stack2 == null || (stack1.getItem() == stack2.getItem() && (!stack2.getHasSubtypes() || stack2.getItemDamage() == stack1.getItemDamage()) && ItemStack.areItemStackTagsEqual(stack2, stack1)) && stack1.isStackable(); } /** * Consumes one item from slot in inv with support for containers. */ public static void consumeItem(IInventory inv, int slot) { ItemStack stack = inv.getStackInSlot(slot); Item item = stack.getItem(); if (item.hasContainerItem(stack)) { ItemStack container = item.getContainerItem(stack); inv.setInventorySlotContents(slot, container); } else { inv.decrStackSize(slot, 1); } } /** * Gets the size of the stack in a slot. Returns 0 on null stacks */ public static int stackSize(IInventory inv, int slot) { ItemStack stack = inv.getStackInSlot(slot); return stack == null ? 0 : stack.stackSize; } /** * Drops all items from inv using getStackInSlotOnClosing */ public static void dropOnClose(EntityPlayer player, IInventory inv) { for (int i = 0; i < inv.getSizeInventory(); i++) { ItemStack stack = inv.removeStackFromSlot(i); if (stack != null) { player.dropPlayerItemWithRandomChoice(stack, false); } } } public static NBTTagCompound savePersistant(ItemStack stack, NBTTagCompound tag) { stack.writeToNBT(tag); tag.removeTag("id"); tag.setString("name", Item.itemRegistry.getNameForObject(stack.getItem()).toString()); return tag; } public static ItemStack loadPersistant(NBTTagCompound tag) { String name = tag.getString("name"); Item item = (Item) Item.itemRegistry.getObject(new ResourceLocation(name)); if (item == null) { return null; } int count = tag.hasKey("Count") ? tag.getByte("Count") : 1; int damage = tag.hasKey("Damage") ? tag.getShort("Damage") : 0; ItemStack stack = new ItemStack(item, count, damage); if (tag.hasKey("tag", 10)) { stack.setTagCompound(tag.getCompoundTag("tag")); } return stack; } }