mirror of
https://github.com/GTNewHorizons/CodeChickenCore.git
synced 2026-11-11 15:57:42 +00:00
333 lines
12 KiB
Java
333 lines
12 KiB
Java
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.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.world.World;
|
|
import net.minecraftforge.common.util.ForgeDirection;
|
|
|
|
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.stackTagCompound = 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);
|
|
|
|
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")).func_150287_d();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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.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, int x, int y, int z) {
|
|
TileEntity tile = world.getTileEntity(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.getWorldObj().getBlock(chest.xCoord + fside.offsetX, chest.yCoord + fside.offsetY, chest.zCoord + fside.offsetZ) == chest.getBlockType())
|
|
return new InventoryLargeChest("container.chestDouble",
|
|
(TileEntityChest) chest.getWorldObj().getTileEntity(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.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.getStackInSlotOnClosing(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()));
|
|
return tag;
|
|
}
|
|
|
|
public static ItemStack loadPersistant(NBTTagCompound tag) {
|
|
String name = tag.getString("name");
|
|
Item item = (Item) Item.itemRegistry.getObject(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.stackTagCompound = tag.getCompoundTag("tag");
|
|
return stack;
|
|
}
|
|
}
|