package codechicken.lib.inventory; import com.google.common.base.Objects; import codechicken.lib.vec.Vector3; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; 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.NBTTagInt; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagShort; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.world.World; import net.minecraftforge.common.ForgeDirection; public class InventoryUtils { /** * 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) { ItemStack itemstack = item; inv.setInventorySlotContents(slot, null); inv.onInventoryChanged(); return itemstack; } ItemStack itemstack1 = item.splitStack(size); if(item.stackSize == 0) { inv.setInventorySlotContents(slot, null); } inv.onInventoryChanged(); 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 = (NBTTagCompound) tagList.tagAt(i); int b = tag.getShort("Slot"); items[b] = ItemStack.loadItemStackFromNBT(tag); if(tag.hasKey("Quantity")) { NBTBase qtag = tag.getTag("Quantity"); if(qtag instanceof NBTTagInt) items[b].stackSize = ((NBTTagInt)qtag).data; else if(qtag instanceof NBTTagShort) items[b].stackSize = ((NBTTagShort)qtag).data; } } } /** * 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); 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(pass == 1) { 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.itemID == stack2.itemID && 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, int x, int y, int z) { TileEntity tile = world.getBlockTileEntity(x, y, z); if(!(tile instanceof IInventory)) return null; if(tile instanceof TileEntityChest) return getChest((TileEntityChest) tile); return (IInventory)tile; } public static final ForgeDirection[] chestSides = new ForgeDirection[]{ForgeDirection.WEST, ForgeDirection.EAST, ForgeDirection.NORTH, ForgeDirection.SOUTH}; public static IInventory getChest(TileEntityChest chest) { for(ForgeDirection fside : chestSides) { if(chest.worldObj.getBlockId(chest.xCoord+fside.offsetX, chest.yCoord+fside.offsetY, chest.zCoord+fside.offsetZ) == chest.getBlockType().blockID) return new InventoryLargeChest("container.chestDouble", (TileEntityChest)chest.worldObj.getBlockTileEntity(chest.xCoord+fside.offsetX, chest.yCoord+fside.offsetY, chest.zCoord+fside.offsetZ), chest); } return chest; } public static boolean canStack(ItemStack stack1, ItemStack stack2) { return stack1 == null || stack2 == null || (stack1.itemID == stack2.itemID && (!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()) { ItemStack container = item.getContainerItemStack(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.getStackInSlotOnClosing(i); if (stack != null) player.dropPlayerItem(stack); } } /** * Gets the actual damage of an item without asking the Item */ public static int actualDamage(ItemStack stack) { return Item.diamond.getDamage(stack); } }