diff --git a/patches/minecraft/net/minecraft/block/BlockDropper.java.patch b/patches/minecraft/net/minecraft/block/BlockDropper.java.patch new file mode 100644 index 000000000..e6c1bce0b --- /dev/null +++ b/patches/minecraft/net/minecraft/block/BlockDropper.java.patch @@ -0,0 +1,11 @@ +--- ../src-base/minecraft/net/minecraft/block/BlockDropper.java ++++ ../src-work/minecraft/net/minecraft/block/BlockDropper.java +@@ -43,7 +43,7 @@ + { + ItemStack itemstack = tileentitydispenser.func_70301_a(i); + +- if (itemstack != null) ++ if (itemstack != null && net.minecraftforge.items.VanillaInventoryCodeHooks.dropperInsertHook(p_176439_1_, p_176439_2_, tileentitydispenser, i, itemstack)) + { + EnumFacing enumfacing = (EnumFacing)p_176439_1_.func_180495_p(p_176439_2_).func_177229_b(field_176441_a); + BlockPos blockpos = p_176439_2_.func_177972_a(enumfacing); diff --git a/patches/minecraft/net/minecraft/entity/item/EntityMinecartContainer.java.patch b/patches/minecraft/net/minecraft/entity/item/EntityMinecartContainer.java.patch index e9ce1fedd..b40c6c37c 100644 --- a/patches/minecraft/net/minecraft/entity/item/EntityMinecartContainer.java.patch +++ b/patches/minecraft/net/minecraft/entity/item/EntityMinecartContainer.java.patch @@ -8,3 +8,26 @@ if (!this.field_70170_p.field_72995_K) { p_130002_1_.func_71007_a(this); +@@ -232,4 +233,22 @@ + this.field_94113_a[i] = null; + } + } ++ ++ public net.minecraftforge.items.IItemHandler itemHandler = new net.minecraftforge.items.wrapper.InvWrapper(this); ++ ++ @Override ++ public T getCapability(net.minecraftforge.common.capabilities.Capability capability, net.minecraft.util.EnumFacing facing) ++ { ++ if (capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) ++ { ++ return (T) itemHandler; ++ } ++ return super.getCapability(capability, facing); ++ } ++ ++ @Override ++ public boolean hasCapability(net.minecraftforge.common.capabilities.Capability capability, net.minecraft.util.EnumFacing facing) ++ { ++ return capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY || super.hasCapability(capability, facing); ++ } + } diff --git a/patches/minecraft/net/minecraft/tileentity/TileEntityBrewingStand.java.patch b/patches/minecraft/net/minecraft/tileentity/TileEntityBrewingStand.java.patch index 2dc57eff9..b061d4b42 100644 --- a/patches/minecraft/net/minecraft/tileentity/TileEntityBrewingStand.java.patch +++ b/patches/minecraft/net/minecraft/tileentity/TileEntityBrewingStand.java.patch @@ -76,3 +76,22 @@ } public boolean[] func_174902_m() +@@ -386,4 +393,18 @@ + this.field_145945_j[i] = null; + } + } ++ ++ net.minecraftforge.items.IItemHandler handlerInput = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.UP); ++ net.minecraftforge.items.IItemHandler handlerOutput = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.DOWN); ++ ++ @Override ++ public T getCapability(net.minecraftforge.common.capabilities.Capability capability, net.minecraft.util.EnumFacing facing) ++ { ++ if (facing != null && capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) ++ if (facing == EnumFacing.UP) ++ return (T) handlerInput; ++ else ++ return (T) handlerOutput; ++ return super.getCapability(capability, facing); ++ } + } diff --git a/patches/minecraft/net/minecraft/tileentity/TileEntityChest.java.patch b/patches/minecraft/net/minecraft/tileentity/TileEntityChest.java.patch new file mode 100644 index 000000000..1c77e9b78 --- /dev/null +++ b/patches/minecraft/net/minecraft/tileentity/TileEntityChest.java.patch @@ -0,0 +1,35 @@ +--- ../src-base/minecraft/net/minecraft/tileentity/TileEntityChest.java ++++ ../src-work/minecraft/net/minecraft/tileentity/TileEntityChest.java +@@ -186,6 +186,7 @@ + { + super.func_145836_u(); + this.field_145984_a = false; ++ doubleChestHandler = null; + } + + @SuppressWarnings("incomplete-switch") +@@ -468,4 +469,24 @@ + this.field_145985_p[i] = null; + } + } ++ ++ public net.minecraftforge.items.VanillaDoubleChestItemHandler doubleChestHandler; ++ ++ @Override ++ public T getCapability(net.minecraftforge.common.capabilities.Capability capability, net.minecraft.util.EnumFacing facing) ++ { ++ if (capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) ++ { ++ if(doubleChestHandler == null || doubleChestHandler.needsRefresh()) ++ doubleChestHandler = net.minecraftforge.items.VanillaDoubleChestItemHandler.get(this); ++ if (doubleChestHandler != null && doubleChestHandler != net.minecraftforge.items.VanillaDoubleChestItemHandler.NO_ADJACENT_CHESTS_INSTANCE) ++ return (T) doubleChestHandler; ++ } ++ return super.getCapability(capability, facing); ++ } ++ ++ public net.minecraftforge.items.IItemHandler getSingleChestHandler() ++ { ++ return super.getCapability(net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null); ++ } + } diff --git a/patches/minecraft/net/minecraft/tileentity/TileEntityFurnace.java.patch b/patches/minecraft/net/minecraft/tileentity/TileEntityFurnace.java.patch index 4966ed5e8..1a5516ec8 100644 --- a/patches/minecraft/net/minecraft/tileentity/TileEntityFurnace.java.patch +++ b/patches/minecraft/net/minecraft/tileentity/TileEntityFurnace.java.patch @@ -49,3 +49,25 @@ } } +@@ -451,4 +462,21 @@ + this.field_145957_n[i] = null; + } + } ++ ++ net.minecraftforge.items.IItemHandler handlerTop = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.UP); ++ net.minecraftforge.items.IItemHandler handlerBottom = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.DOWN); ++ net.minecraftforge.items.IItemHandler handlerSide = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.WEST); ++ ++ @Override ++ public T getCapability(net.minecraftforge.common.capabilities.Capability capability, net.minecraft.util.EnumFacing facing) ++ { ++ if (facing != null && capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) ++ if (facing == EnumFacing.DOWN) ++ return (T) handlerBottom; ++ else if (facing == EnumFacing.UP) ++ return (T) handlerTop; ++ else ++ return (T) handlerSide; ++ return super.getCapability(capability, facing); ++ } + } diff --git a/patches/minecraft/net/minecraft/tileentity/TileEntityHopper.java.patch b/patches/minecraft/net/minecraft/tileentity/TileEntityHopper.java.patch index 0f5f3b348..a03e41ceb 100644 --- a/patches/minecraft/net/minecraft/tileentity/TileEntityHopper.java.patch +++ b/patches/minecraft/net/minecraft/tileentity/TileEntityHopper.java.patch @@ -1,6 +1,22 @@ --- ../src-base/minecraft/net/minecraft/tileentity/TileEntityHopper.java +++ ../src-work/minecraft/net/minecraft/tileentity/TileEntityHopper.java -@@ -515,17 +515,31 @@ +@@ -260,6 +260,7 @@ + + private boolean func_145883_k() + { ++ if (net.minecraftforge.items.VanillaInventoryCodeHooks.insertHook(this)) { return true; } + IInventory iinventory = this.func_145895_l(); + + if (iinventory == null) +@@ -366,6 +367,7 @@ + + public static boolean func_145891_a(IHopper p_145891_0_) + { ++ if (net.minecraftforge.items.VanillaInventoryCodeHooks.extractHook(p_145891_0_)) { return true; } + IInventory iinventory = func_145884_b(p_145891_0_); + + if (iinventory != null) +@@ -515,17 +517,31 @@ if (itemstack == null) { @@ -33,3 +49,14 @@ } if (flag) +@@ -668,4 +684,10 @@ + this.field_145900_a[i] = null; + } + } ++ ++ ++ protected net.minecraftforge.items.IItemHandler createUnSidedHandler() ++ { ++ return new net.minecraftforge.items.VanillaHopperItemHandler(this); ++ } + } diff --git a/patches/minecraft/net/minecraft/tileentity/TileEntityLockable.java.patch b/patches/minecraft/net/minecraft/tileentity/TileEntityLockable.java.patch new file mode 100644 index 000000000..5059fc2d0 --- /dev/null +++ b/patches/minecraft/net/minecraft/tileentity/TileEntityLockable.java.patch @@ -0,0 +1,28 @@ +--- ../src-base/minecraft/net/minecraft/tileentity/TileEntityLockable.java ++++ ../src-work/minecraft/net/minecraft/tileentity/TileEntityLockable.java +@@ -47,4 +47,25 @@ + { + return (IChatComponent)(this.func_145818_k_() ? new ChatComponentText(this.func_70005_c_()) : new ChatComponentTranslation(this.func_70005_c_(), new Object[0])); + } ++ ++ private net.minecraftforge.items.IItemHandler itemHandler; ++ ++ protected net.minecraftforge.items.IItemHandler createUnSidedHandler() ++ { ++ return new net.minecraftforge.items.wrapper.InvWrapper(this); ++ } ++ ++ @Override ++ public T getCapability(net.minecraftforge.common.capabilities.Capability capability, net.minecraft.util.EnumFacing facing) ++ { ++ if (capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) ++ return (T) (itemHandler == null ? (itemHandler = createUnSidedHandler()) : itemHandler); ++ return super.getCapability(capability, facing); ++ } ++ ++ @Override ++ public boolean hasCapability(net.minecraftforge.common.capabilities.Capability capability, net.minecraft.util.EnumFacing facing) ++ { ++ return capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY || super.hasCapability(capability, facing); ++ } + } diff --git a/src/main/java/net/minecraftforge/common/ForgeModContainer.java b/src/main/java/net/minecraftforge/common/ForgeModContainer.java index f5ab3bfaa..7f58f9625 100644 --- a/src/main/java/net/minecraftforge/common/ForgeModContainer.java +++ b/src/main/java/net/minecraftforge/common/ForgeModContainer.java @@ -26,6 +26,7 @@ import net.minecraftforge.common.config.Configuration; import net.minecraftforge.common.config.Property; import net.minecraftforge.common.network.ForgeNetworkHandler; import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.oredict.OreDictionary; import net.minecraftforge.oredict.RecipeSorter; import net.minecraftforge.server.command.ForgeCommand; @@ -310,6 +311,7 @@ public class ForgeModContainer extends DummyModContainer implements WorldAccessC @Subscribe public void preInit(FMLPreInitializationEvent evt) { + CapabilityItemHandler.register(); MinecraftForge.EVENT_BUS.register(MinecraftForge.INTERNAL_HANDLER); ForgeChunkManager.captureConfig(evt.getModConfigurationDirectory()); MinecraftForge.EVENT_BUS.register(this); diff --git a/src/main/java/net/minecraftforge/items/CapabilityItemHandler.java b/src/main/java/net/minecraftforge/items/CapabilityItemHandler.java new file mode 100644 index 000000000..217759aae --- /dev/null +++ b/src/main/java/net/minecraftforge/items/CapabilityItemHandler.java @@ -0,0 +1,70 @@ +package net.minecraftforge.items; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.CapabilityInject; +import net.minecraftforge.common.capabilities.CapabilityManager; + +import java.util.concurrent.Callable; + +public class CapabilityItemHandler +{ + @CapabilityInject(IItemHandler.class) + public static Capability ITEM_HANDLER_CAPABILITY = null; + + public static void register() + { + CapabilityManager.INSTANCE.register(IItemHandler.class, new Capability.IStorage() + { + @Override + public NBTBase writeNBT(Capability capability, IItemHandler instance, EnumFacing side) + { + NBTTagList nbtTagList = new NBTTagList(); + int size = instance.getSlots(); + for (int i = 0; i < size; i++) + { + ItemStack stack = instance.getStackInSlot(i); + if (stack != null) + { + NBTTagCompound itemTag = new NBTTagCompound(); + itemTag.setInteger("Slot", i); + stack.writeToNBT(itemTag); + nbtTagList.appendTag(itemTag); + } + } + return nbtTagList; + } + + @Override + public void readNBT(Capability capability, IItemHandler instance, EnumFacing side, NBTBase base) + { + if (!(instance instanceof IItemHandlerModifiable)) + throw new RuntimeException("IItemHandler instance does not implement IItemHandlerModifiable"); + IItemHandlerModifiable itemHandlerModifiable = (IItemHandlerModifiable) instance; + NBTTagList tagList = (NBTTagList) base; + for (int i = 0; i < tagList.tagCount(); i++) + { + NBTTagCompound itemTags = tagList.getCompoundTagAt(i); + int j = itemTags.getInteger("Slot"); + + if (j > 0 && j < instance.getSlots()) + { + itemHandlerModifiable.setStackInSlot(j, ItemStack.loadItemStackFromNBT(itemTags)); + } + } + } + }, new Callable() + { + @Override + public ItemStackHandler call() throws Exception + { + return new ItemStackHandler(); + } + }); + } + +} diff --git a/src/main/java/net/minecraftforge/items/IItemHandler.java b/src/main/java/net/minecraftforge/items/IItemHandler.java new file mode 100644 index 000000000..2955837ea --- /dev/null +++ b/src/main/java/net/minecraftforge/items/IItemHandler.java @@ -0,0 +1,57 @@ +package net.minecraftforge.items; + +import net.minecraft.item.ItemStack; + +public interface IItemHandler +{ + /** + * Returns the number of slots available + * + * @return The number of slots available + **/ + int getSlots(); + + /** + * Returns the ItemStack in a given slot. + * + * The result's stack size may be greater than the itemstacks max size. + * + * If the result is null, then the slot is empty. + * If the result is not null but the stack size is zero, then it represents + * an empty slot that will only accept* a specific itemstack. + * + *

+ * IMPORTANT: This ItemStack MUST NOT be modified. This method is not for + * altering an inventories contents. Any implementers who are able to detect + * modification through this method should throw an exception. + *

+ * SERIOUSLY: DO NOT MODIFY THE RETURNED ITEMSTACK + * + * @param slot Slot to query + * @return ItemStack in given slot. May be null. + **/ + ItemStack getStackInSlot(int slot); + + /** + * Inserts an ItemStack into the given slot and return the remainder. + * Note: This behaviour is subtly different from IFluidHandlers.fill() + * + * @param slot Slot to insert into. + * @param stack ItemStack to insert + * @param simulate If true, the insertion is only simulated + * @return The remaining ItemStack that was not inserted (if the entire stack is accepted, then return null) + **/ + ItemStack insertItem(int slot, ItemStack stack, boolean simulate); + + /** + * Extracts an ItemStack from the given slot. The returned value must be null + * if nothing is extracted, otherwise it's stack size must not be greater than amount or the + * itemstacks getMaxStackSize(). + * + * @param slot Slot to extract from. + * @param amount Amount to extract (may be greater than the current stacks max limit) + * @param simulate If true, the extraction is only simulated + * @return ItemStack extracted from the slot, must be null, if nothing can be extracted + **/ + ItemStack extractItem(int slot, int amount, boolean simulate); +} diff --git a/src/main/java/net/minecraftforge/items/IItemHandlerModifiable.java b/src/main/java/net/minecraftforge/items/IItemHandlerModifiable.java new file mode 100644 index 000000000..12d572fe3 --- /dev/null +++ b/src/main/java/net/minecraftforge/items/IItemHandlerModifiable.java @@ -0,0 +1,19 @@ +package net.minecraftforge.items; + +import net.minecraft.item.ItemStack; + +public interface IItemHandlerModifiable extends IItemHandler +{ + /** + * Overrides the stack in the given slot. This method is used by the + * standard Forge helper methods and classes. It is not intended for + * general use by other mods, and the handler may throw an error if it + * is called unexpectedly. + * + * @param slot Slot to modify + * @param stack ItemStack to set slot to (may be null) + * @throws RuntimeException if the handler is called in a way that the handler + * was not expecting. + **/ + void setStackInSlot(int slot, ItemStack stack); +} diff --git a/src/main/java/net/minecraftforge/items/ItemHandlerHelper.java b/src/main/java/net/minecraftforge/items/ItemHandlerHelper.java new file mode 100644 index 000000000..e01e2060d --- /dev/null +++ b/src/main/java/net/minecraftforge/items/ItemHandlerHelper.java @@ -0,0 +1,43 @@ +package net.minecraftforge.items; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +public class ItemHandlerHelper +{ + public static ItemStack insertItem(IItemHandler dest, ItemStack stack, boolean simulate) + { + if (dest == null || stack == null) + return stack; + + for (int i = 0; i < dest.getSlots(); i++) + { + stack = dest.insertItem(i, stack, simulate); + if (stack == null || stack.stackSize <= 0) + { + return null; + } + } + + return stack; + } + + public static boolean canItemStacksStack(ItemStack a, ItemStack b) + { + if (a == null || !a.isItemEqual(b)) + return false; + + final NBTTagCompound aTag = a.getTagCompound(); + final NBTTagCompound bTag = b.getTagCompound(); + return (aTag != null || bTag == null) && (aTag == null || aTag.equals(bTag)); + } + + public static ItemStack copyStackWithSize(ItemStack itemStack, int size) + { + if (size == 0) + return null; + ItemStack copy = ItemStack.copyItemStack(itemStack); + copy.stackSize = size; + return copy; + } +} diff --git a/src/main/java/net/minecraftforge/items/ItemStackHandler.java b/src/main/java/net/minecraftforge/items/ItemStackHandler.java new file mode 100644 index 000000000..5ffc6bc64 --- /dev/null +++ b/src/main/java/net/minecraftforge/items/ItemStackHandler.java @@ -0,0 +1,185 @@ +package net.minecraftforge.items; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.common.util.INBTSerializable; + +public class ItemStackHandler implements IItemHandler, IItemHandlerModifiable, INBTSerializable +{ + protected ItemStack[] stacks; + + public ItemStackHandler() + { + this(1); + } + + public ItemStackHandler(int size) + { + stacks = new ItemStack[size]; + } + + public void setSize(int size) + { + stacks = new ItemStack[size]; + } + + @Override + public void setStackInSlot(int slot, ItemStack stack) + { + validateSlotIndex(slot); + if (ItemStack.areItemStacksEqual(this.stacks[slot], stack)) + return; + this.stacks[slot] = stack; + onContentsChanged(slot); + } + + @Override + public int getSlots() + { + return stacks.length; + } + + @Override + public ItemStack getStackInSlot(int slot) + { + validateSlotIndex(slot); + return this.stacks[slot]; + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) + { + if (stack == null || stack.stackSize == 0) + return null; + + validateSlotIndex(slot); + + ItemStack existing = this.stacks[slot]; + + int limit = getStackLimit(slot, stack); + + if (existing != null) + { + if (!ItemHandlerHelper.canItemStacksStack(stack, existing)) + return stack; + + limit -= existing.stackSize; + } + + if (limit <= 0) + return stack; + + boolean reachedLimit = stack.stackSize > limit; + + if (!simulate) + { + if (existing == null) + { + this.stacks[slot] = reachedLimit ? ItemHandlerHelper.copyStackWithSize(stack, limit) : stack; + } + else + { + existing.stackSize += reachedLimit ? limit : stack.stackSize; + } + onContentsChanged(slot); + } + + return reachedLimit ? ItemHandlerHelper.copyStackWithSize(stack, stack.stackSize - limit) : null; + } + + public ItemStack extractItem(int slot, int amount, boolean simulate) + { + if (amount == 0) + return null; + + validateSlotIndex(slot); + + ItemStack existing = this.stacks[slot]; + + if (existing == null) + return null; + + int toExtract = Math.min(amount, existing.getMaxStackSize()); + + if (existing.stackSize <= toExtract) + { + if (!simulate) + { + this.stacks[slot] = null; + onContentsChanged(slot); + } + return existing; + } + else + { + if (!simulate) + { + this.stacks[slot] = ItemHandlerHelper.copyStackWithSize(existing, existing.stackSize - toExtract); + onContentsChanged(slot); + } + + return ItemHandlerHelper.copyStackWithSize(existing, toExtract); + } + } + + protected int getStackLimit(int slot, ItemStack stack) + { + return stack.getMaxStackSize(); + } + + @Override + public NBTTagCompound serializeNBT() + { + NBTTagList nbtTagList = new NBTTagList(); + for (int i = 0; i < stacks.length; i++) + { + if (stacks[i] != null) + { + NBTTagCompound itemTag = new NBTTagCompound(); + itemTag.setInteger("Slot", i); + stacks[i].writeToNBT(itemTag); + nbtTagList.appendTag(itemTag); + } + } + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setTag("Items", nbtTagList); + nbt.setInteger("Size", stacks.length); + return nbt; + } + + @Override + public void deserializeNBT(NBTTagCompound nbt) + { + setSize(nbt.hasKey("Size", Constants.NBT.TAG_INT) ? nbt.getInteger("Size") : stacks.length); + NBTTagList tagList = nbt.getTagList("Items", Constants.NBT.TAG_COMPOUND); + for (int i = 0; i < tagList.tagCount(); i++) + { + NBTTagCompound itemTags = tagList.getCompoundTagAt(i); + int slot = itemTags.getInteger("Slot"); + + if (slot >= 0 && slot < stacks.length) + { + stacks[slot] = ItemStack.loadItemStackFromNBT(itemTags); + } + } + onLoad(); + } + + protected void validateSlotIndex(int slot) + { + if (slot < 0 || slot >= stacks.length) + throw new RuntimeException("Slot " + slot + " not in valid range - [0," + stacks.length + ")"); + } + + protected void onLoad() + { + + } + + protected void onContentsChanged(int slot) + { + + } +} diff --git a/src/main/java/net/minecraftforge/items/SlotItemHandler.java b/src/main/java/net/minecraftforge/items/SlotItemHandler.java new file mode 100644 index 000000000..aa04c33be --- /dev/null +++ b/src/main/java/net/minecraftforge/items/SlotItemHandler.java @@ -0,0 +1,75 @@ +package net.minecraftforge.items; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.InventoryBasic; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +public class SlotItemHandler extends Slot +{ + private static IInventory emptyInventory = new InventoryBasic("[Null]", true, 0); + public final IItemHandler itemHandler; + private final int index; + + public SlotItemHandler(IItemHandler itemHandler, int index, int xPosition, int yPosition) + { + super(emptyInventory, index, xPosition, yPosition); + this.itemHandler = itemHandler; + this.index = index; + } + + @Override + public boolean isItemValid(ItemStack stack) + { + if (stack == null) + return false; + ItemStack remainder = this.itemHandler.insertItem(index, stack, true); + return remainder == null || remainder.stackSize < stack.stackSize; + } + + @Override + public ItemStack getStack() + { + return this.itemHandler.getStackInSlot(index); + } + + // Override if your IItemHandler does not implement IItemHandlerModifiable + @Override + public void putStack(ItemStack stack) + { + ((IItemHandlerModifiable) this.itemHandler).setStackInSlot(index, stack); + this.onSlotChanged(); + } + + @Override + public void onSlotChange(ItemStack p_75220_1_, ItemStack p_75220_2_) + { + + } + + @Override + public int getItemStackLimit(ItemStack stack) + { + ItemStack maxAdd = stack.copy(); + maxAdd.stackSize = maxAdd.getMaxStackSize(); + ItemStack currentStack = this.itemHandler.getStackInSlot(index); + ItemStack remainder = this.itemHandler.insertItem(index, maxAdd, true); + + int current = currentStack == null ? 0 : currentStack.stackSize; + int added = maxAdd.stackSize - (remainder != null ? remainder.stackSize : 0); + return current + added; + } + + @Override + public boolean canTakeStack(EntityPlayer playerIn) + { + return this.itemHandler.extractItem(index, 1, true) != null; + } + + @Override + public ItemStack decrStackSize(int amount) + { + return this.itemHandler.extractItem(index, amount, false); + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/items/VanillaDoubleChestItemHandler.java b/src/main/java/net/minecraftforge/items/VanillaDoubleChestItemHandler.java new file mode 100644 index 000000000..bd5d754fd --- /dev/null +++ b/src/main/java/net/minecraftforge/items/VanillaDoubleChestItemHandler.java @@ -0,0 +1,144 @@ +package net.minecraftforge.items; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityChest; +import net.minecraft.util.BlockPos; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; + +import java.lang.ref.WeakReference; +import java.util.Objects; + +public class VanillaDoubleChestItemHandler extends WeakReference implements IItemHandler +{ + // Dummy cache value to signify that we have checked and definitely found no adjacent chests + public static final VanillaDoubleChestItemHandler NO_ADJACENT_CHESTS_INSTANCE = new VanillaDoubleChestItemHandler(null, null, false); + private final boolean mainChestIsUpper; + private final TileEntityChest mainChest; + private final int hashCode; + + public VanillaDoubleChestItemHandler(TileEntityChest mainChest, TileEntityChest other, boolean mainChestIsUpper) + { + super(other); + this.mainChest = mainChest; + this.mainChestIsUpper = mainChestIsUpper; + hashCode = Objects.hashCode(mainChestIsUpper ? mainChest : other) * 31 + Objects.hashCode(!mainChestIsUpper ? mainChest : other); + } + + public static VanillaDoubleChestItemHandler get(TileEntityChest chest) + { + World world = chest.getWorld(); + BlockPos pos = chest.getPos(); + if (world == null || pos == null || !world.isBlockLoaded(pos)) + return null; // Still loading + + Block blockType = chest.getBlockType(); + + EnumFacing[] horizontals = EnumFacing.HORIZONTALS; + for (int i = horizontals.length - 1; i >= 0; i--) // Use reverse order so we can return early + { + EnumFacing enumfacing = horizontals[i]; + BlockPos blockpos = pos.offset(enumfacing); + Block block = world.getBlockState(blockpos).getBlock(); + + if (block == blockType) + { + TileEntity otherTE = world.getTileEntity(blockpos); + + if (otherTE instanceof TileEntityChest) + { + TileEntityChest otherChest = (TileEntityChest) otherTE; + return new VanillaDoubleChestItemHandler(chest, otherChest, + enumfacing != net.minecraft.util.EnumFacing.WEST && enumfacing != net.minecraft.util.EnumFacing.NORTH); + + } + } + } + return NO_ADJACENT_CHESTS_INSTANCE; //All alone + } + + public TileEntityChest getChest(boolean accessingUpper) + { + if (accessingUpper == mainChestIsUpper) + return mainChest; + else + { + return getOtherChest(); + } + } + + private TileEntityChest getOtherChest() + { + TileEntityChest tileEntityChest = get(); + return tileEntityChest != null && !tileEntityChest.isInvalid() ? tileEntityChest : null; + } + + @Override + public int getSlots() + { + return 27 * 2; + } + + @Override + public ItemStack getStackInSlot(int slot) + { + boolean accessingUpperChest = slot < 27; + int targetSlot = accessingUpperChest ? slot : slot - 27; + TileEntityChest chest = getChest(accessingUpperChest); + return chest != null ? chest.getStackInSlot(targetSlot) : null; + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) + { + boolean accessingUpperChest = slot < 27; + int targetSlot = accessingUpperChest ? slot : slot - 27; + TileEntityChest chest = getChest(accessingUpperChest); + return chest != null ? chest.getSingleChestHandler().insertItem(targetSlot, stack, simulate) : stack; + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) + { + boolean accessingUpperChest = slot < 27; + int targetSlot = accessingUpperChest ? slot : slot - 27; + TileEntityChest chest = getChest(accessingUpperChest); + return chest != null ? chest.getSingleChestHandler().extractItem(targetSlot, amount, simulate) : null; + } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + VanillaDoubleChestItemHandler that = (VanillaDoubleChestItemHandler) o; + + if (hashCode != that.hashCode) + return false; + + final TileEntityChest otherChest = getOtherChest(); + if (mainChestIsUpper == that.mainChestIsUpper) + return Objects.equals(mainChest, that.mainChest) && Objects.equals(otherChest, that.getOtherChest()); + else + return Objects.equals(mainChest, that.getOtherChest()) && Objects.equals(otherChest, that.mainChest); + } + + @Override + public int hashCode() + { + return hashCode; + } + + public boolean needsRefresh() + { + if (this == NO_ADJACENT_CHESTS_INSTANCE) + return false; + TileEntityChest tileEntityChest = get(); + return tileEntityChest == null || tileEntityChest.isInvalid(); + } +} diff --git a/src/main/java/net/minecraftforge/items/VanillaHopperItemHandler.java b/src/main/java/net/minecraftforge/items/VanillaHopperItemHandler.java new file mode 100644 index 000000000..57d942d93 --- /dev/null +++ b/src/main/java/net/minecraftforge/items/VanillaHopperItemHandler.java @@ -0,0 +1,33 @@ +package net.minecraftforge.items; + +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntityHopper; +import net.minecraftforge.items.wrapper.InvWrapper; + +public class VanillaHopperItemHandler extends InvWrapper +{ + private final TileEntityHopper hopper; + + public VanillaHopperItemHandler(TileEntityHopper hopper) + { + super(hopper); + this.hopper = hopper; + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) + { + if (stack == null) + return null; + if (simulate || !hopper.mayTransfer()) + return super.insertItem(slot, stack, simulate); + + int curStackSize = stack.stackSize; + ItemStack itemStack = super.insertItem(slot, stack, false); + if (itemStack == null || curStackSize != itemStack.stackSize) + { + hopper.setTransferCooldown(8); + } + return itemStack; + } +} diff --git a/src/main/java/net/minecraftforge/items/VanillaInventoryCodeHooks.java b/src/main/java/net/minecraftforge/items/VanillaInventoryCodeHooks.java new file mode 100644 index 000000000..079fb361e --- /dev/null +++ b/src/main/java/net/minecraftforge/items/VanillaInventoryCodeHooks.java @@ -0,0 +1,122 @@ +package net.minecraftforge.items; + +import net.minecraft.block.BlockDropper; +import net.minecraft.block.BlockHopper; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.IHopper; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityDispenser; +import net.minecraft.tileentity.TileEntityHopper; +import net.minecraft.util.BlockPos; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; + +public class VanillaInventoryCodeHooks +{ + + public static boolean extractHook(IHopper dest) + { + TileEntity tileEntity = dest.getWorld().getTileEntity(new BlockPos(dest.getXPos(), dest.getYPos() + 1, dest.getZPos())); + + if (tileEntity == null || !tileEntity.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, EnumFacing.DOWN)) + return false; + + IItemHandler handler = tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, EnumFacing.DOWN); + + for (int i = 0; i < handler.getSlots(); i++) + { + ItemStack extractItem = handler.extractItem(i, 1, true); + if (extractItem != null) + { + for (int j = 0; j < dest.getSizeInventory(); j++) + { + ItemStack destStack = dest.getStackInSlot(j); + if (destStack == null || destStack.stackSize < destStack.getMaxStackSize() || ItemHandlerHelper.canItemStacksStack(extractItem, destStack)) + { + extractItem = handler.extractItem(i, 1, false); + if (destStack == null) + dest.setInventorySlotContents(j, extractItem); + else + { + destStack.stackSize++; + dest.setInventorySlotContents(j, destStack); + } + dest.markDirty(); + return true; + } + } + } + } + + return true; + } + + public static boolean dropperInsertHook(World world, BlockPos pos, TileEntityDispenser dropper, int slot, ItemStack stack) + { + EnumFacing enumfacing = world.getBlockState(pos).getValue(BlockDropper.FACING); + BlockPos offsetPos = pos.offset(enumfacing); + TileEntity tileEntity = world.getTileEntity(offsetPos); + if (tileEntity == null) + return false; + if (!tileEntity.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, enumfacing.getOpposite())) + return true; + + IItemHandler capability = tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, enumfacing.getOpposite()); + + ItemStack result = ItemHandlerHelper.insertItem(capability, ItemHandlerHelper.copyStackWithSize(stack, 1), false); + + if (result == null) + { + result = stack.copy(); + + if (--result.stackSize == 0) + { + result = null; + } + } + else + { + result = stack.copy(); + } + dropper.setInventorySlotContents(slot, result); + dropper.markDirty(); + return false; + } + + public static boolean insertHook(TileEntityHopper hopper) + { + return insertHook(hopper, BlockHopper.getFacing(hopper.getBlockMetadata())); + } + + public static boolean insertHook(IHopper hopper, EnumFacing facing) + { + TileEntity tileEntity = hopper.getWorld().getTileEntity( + new BlockPos(hopper.getXPos(), hopper.getYPos(), hopper.getZPos()).offset(facing)); + + if (tileEntity == null) + return false; + if (!tileEntity.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite())) + return false; + + IItemHandler handler = tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite()); + + for (int i = 0; i < hopper.getSizeInventory(); i++) + { + ItemStack stackInSlot = hopper.getStackInSlot(i); + if (stackInSlot != null) + { + ItemStack insert = stackInSlot.copy(); + insert.stackSize = 1; + ItemStack newStack = ItemHandlerHelper.insertItem(handler, insert, true); + if (newStack == null || newStack.stackSize == 0) + { + ItemHandlerHelper.insertItem(handler, hopper.decrStackSize(i, 1), false); + hopper.markDirty(); + return true; + } + } + } + + return true; + } +} diff --git a/src/main/java/net/minecraftforge/items/wrapper/EmptyHandler.java b/src/main/java/net/minecraftforge/items/wrapper/EmptyHandler.java new file mode 100644 index 000000000..4a6d07635 --- /dev/null +++ b/src/main/java/net/minecraftforge/items/wrapper/EmptyHandler.java @@ -0,0 +1,33 @@ +package net.minecraftforge.items.wrapper; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.items.IItemHandler; + +public class EmptyHandler implements IItemHandler +{ + public static IItemHandler INSTANCE = new EmptyHandler(); + + @Override + public int getSlots() + { + return 0; + } + + @Override + public ItemStack getStackInSlot(int slot) + { + return null; + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) + { + return stack; + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) + { + return null; + } +} diff --git a/src/main/java/net/minecraftforge/items/wrapper/InvWrapper.java b/src/main/java/net/minecraftforge/items/wrapper/InvWrapper.java new file mode 100644 index 000000000..3adb77eaf --- /dev/null +++ b/src/main/java/net/minecraftforge/items/wrapper/InvWrapper.java @@ -0,0 +1,166 @@ +package net.minecraftforge.items.wrapper; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemHandlerHelper; + +public class InvWrapper implements IItemHandlerModifiable +{ + public final IInventory inv; + + public InvWrapper(IInventory inv) + { + this.inv = inv; + } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + InvWrapper that = (InvWrapper) o; + + return inv.equals(that.inv); + + } + + @Override + public int hashCode() + { + return inv.hashCode(); + } + + @Override + public int getSlots() + { + return inv.getSizeInventory(); + } + + @Override + public ItemStack getStackInSlot(int slot) + { + return inv.getStackInSlot(slot); + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) + { + if (stack == null) + return null; + + if (!inv.isItemValidForSlot(slot, stack)) + return stack; + + ItemStack stackInSlot = inv.getStackInSlot(slot); + + int m; + if (stackInSlot != null) + { + if (!ItemHandlerHelper.canItemStacksStack(stack, stackInSlot)) + return stack; + + m = Math.min(stack.getMaxStackSize(), inv.getInventoryStackLimit()) - stackInSlot.stackSize; + + if (stack.stackSize <= m) + { + if (!simulate) + { + ItemStack copy = stack.copy(); + copy.stackSize += stackInSlot.stackSize; + inv.setInventorySlotContents(slot, copy); + inv.markDirty(); + } + + return null; + } + else + { + if (!simulate) + { + ItemStack copy = stack.splitStack(m); + copy.stackSize += stackInSlot.stackSize; + inv.setInventorySlotContents(slot, copy); + inv.markDirty(); + return stack; + } + else + { + stack.stackSize -= m; + return stack; + } + } + } + else + { + m = Math.min(stack.getMaxStackSize(), inv.getInventoryStackLimit()); + if (m < stack.stackSize) + { + if (!simulate) + { + inv.setInventorySlotContents(slot, stack.splitStack(m)); + inv.markDirty(); + return stack; + } + else + { + stack.stackSize -= m; + return stack; + } + } + else + { + if (!simulate) + { + inv.setInventorySlotContents(slot, stack); + inv.markDirty(); + } + return null; + } + } + + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) + { + if (amount == 0) + return null; + + ItemStack stackInSlot = inv.getStackInSlot(slot); + + if (stackInSlot == null) + return null; + + if (simulate) + { + if (stackInSlot.stackSize < amount) + { + return stackInSlot.copy(); + } + else + { + ItemStack copy = stackInSlot.copy(); + copy.stackSize = amount; + return copy; + } + } + else + { + int m = Math.min(stackInSlot.stackSize, amount); + + ItemStack decrStackSize = inv.decrStackSize(slot, m); + inv.markDirty(); + return decrStackSize; + } + } + + @Override + public void setStackInSlot(int slot, ItemStack stack) + { + inv.setInventorySlotContents(slot, stack); + } +} diff --git a/src/main/java/net/minecraftforge/items/wrapper/SidedInvWrapper.java b/src/main/java/net/minecraftforge/items/wrapper/SidedInvWrapper.java new file mode 100644 index 000000000..4707bdd6d --- /dev/null +++ b/src/main/java/net/minecraftforge/items/wrapper/SidedInvWrapper.java @@ -0,0 +1,184 @@ +package net.minecraftforge.items.wrapper; + +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemHandlerHelper; + +public class SidedInvWrapper implements IItemHandlerModifiable +{ + protected final ISidedInventory inv; + protected final EnumFacing side; + + public SidedInvWrapper(ISidedInventory inv, EnumFacing side) + { + this.inv = inv; + this.side = side; + } + + public static int getSlot(ISidedInventory inv, int slot, EnumFacing side) + { + int[] slots = inv.getSlotsForFace(side); + if (slot < slots.length) + return slots[slot]; + return -1; + } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + SidedInvWrapper that = (SidedInvWrapper) o; + + return inv.equals(that.inv) && side == that.side; + } + + @Override + public int hashCode() + { + int result = inv.hashCode(); + result = 31 * result + side.hashCode(); + return result; + } + + @Override + public int getSlots() + { + return inv.getSlotsForFace(side).length; + } + + @Override + public ItemStack getStackInSlot(int slot) + { + int i = getSlot(inv, slot, side); + return i == -1 ? null : inv.getStackInSlot(i); + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) + { + + if (stack == null) + return null; + + int slot1 = getSlot(inv, slot, side); + + if (slot1 == -1) + return stack; + + if (!inv.isItemValidForSlot(slot1, stack) || !inv.canInsertItem(slot1, stack, side)) + return stack; + + ItemStack stackInSlot = inv.getStackInSlot(slot1); + + int m; + if (stackInSlot != null) + { + if (!ItemHandlerHelper.canItemStacksStack(stack, stackInSlot)) + return stack; + + m = Math.min(stack.getMaxStackSize(), inv.getInventoryStackLimit()) - stackInSlot.stackSize; + + if (stack.stackSize <= m) + { + if (!simulate) + { + ItemStack copy = stack.copy(); + copy.stackSize += stackInSlot.stackSize; + inv.setInventorySlotContents(slot1, copy); + } + + return null; + } + else + { + if (!simulate) + { + ItemStack copy = stack.splitStack(m); + copy.stackSize += stackInSlot.stackSize; + inv.setInventorySlotContents(slot1, copy); + return stack; + } + else + { + stack.stackSize -= m; + return stack; + } + } + } + else + { + m = Math.min(stack.getMaxStackSize(), inv.getInventoryStackLimit()); + if (m < stack.stackSize) + { + if (!simulate) + { + inv.setInventorySlotContents(slot1, stack.splitStack(m)); + return stack; + } + else + { + stack.stackSize -= m; + return stack; + } + } + else + { + if (!simulate) + inv.setInventorySlotContents(slot1, stack); + return null; + } + } + + } + + @Override + public void setStackInSlot(int slot, ItemStack stack) + { + inv.setInventorySlotContents(slot, stack); + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) + { + if (amount == 0) + return null; + + int slot1 = getSlot(inv, slot, side); + + if (slot1 == -1) + return null; + + ItemStack stackInSlot = inv.getStackInSlot(slot1); + + if (stackInSlot == null) + return null; + + if (!inv.canExtractItem(slot1, stackInSlot, side)) + return null; + + if (simulate) + { + if (stackInSlot.stackSize < amount) + { + return stackInSlot.copy(); + } + else + { + ItemStack copy = stackInSlot.copy(); + copy.stackSize = amount; + return copy; + } + } + else + { + int m = Math.min(stackInSlot.stackSize, amount); + return inv.decrStackSize(slot1, m); + } + } +}