From 89c3fb8bdf8a62b31b64957216266c46a1e43ec5 Mon Sep 17 00:00:00 2001 From: CovertJaguar Date: Tue, 16 Dec 2014 03:09:15 -0800 Subject: [PATCH] Attempt to fix issues with structure inventories. Also cleaned up the Hatch pipe/inventory interaction code, modernizing it and removing duplicate code. This involved adding my AdjecentInventoryCache and AdjecentTileCache code from Railcraft for greatly improved performance. ISpecialInventory is now 100% unused. --- api | 2 +- .../apiculture/gadgets/TileAlveary.java | 9 +- .../gadgets/TileAlvearyHygroregulator.java | 8 +- .../apiculture/gadgets/TileAlvearyPlain.java | 180 +++++++++--------- .../gadgets/TileAlvearyStabiliser.java | 1 + .../gadgets/TileAlvearySwarmer.java | 6 - .../arboriculture/gadgets/BlockSapling.java | 1 + .../forestry/core/gadgets/BlockForestry.java | 14 ++ .../forestry/core/gadgets/BlockStructure.java | 2 +- .../forestry/core/gadgets/TileForestry.java | 23 +++ .../inventory/AdjacentInventoryCache.java | 84 ++++++++ .../forestry/core/inventory/InvTools.java | 123 +++++++++--- .../core/utils/AdjacentTileCache.java | 134 +++++++++++++ .../java/forestry/core/utils/BlockUtil.java | 12 +- src/main/java/forestry/core/utils/Timer.java | 36 ++++ .../forestry/farming/gadgets/TileFarm.java | 8 +- .../forestry/farming/gadgets/TileHatch.java | 129 +++---------- 17 files changed, 534 insertions(+), 238 deletions(-) create mode 100644 src/main/java/forestry/core/inventory/AdjacentInventoryCache.java create mode 100644 src/main/java/forestry/core/utils/AdjacentTileCache.java create mode 100644 src/main/java/forestry/core/utils/Timer.java diff --git a/api b/api index 89067121c0..20c3aa3eee 160000 --- a/api +++ b/api @@ -1 +1 @@ -Subproject commit 89067121c057bda5c535bf7a46c0112e245e311b +Subproject commit 20c3aa3eeee65fcec5b0590fce83445ec27c27b9 diff --git a/src/main/java/forestry/apiculture/gadgets/TileAlveary.java b/src/main/java/forestry/apiculture/gadgets/TileAlveary.java index 40be9194a8..f373d3a9cf 100755 --- a/src/main/java/forestry/apiculture/gadgets/TileAlveary.java +++ b/src/main/java/forestry/apiculture/gadgets/TileAlveary.java @@ -26,6 +26,7 @@ import java.util.Collection; import java.util.LinkedList; import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.common.util.ForgeDirection; @@ -125,7 +126,6 @@ public PacketPayload getPacketPayload() { } /* ITILESTRUCTURE */ - @Override public String getTypeUID() { return structureLogic.getTypeUID(); @@ -208,7 +208,12 @@ public boolean isIntegratedIntoStructure() { } @Override - public IInventory getInventory() { + public final IInventory getInventory() { + return getStructureInventory(); + } + + @Override + public ISidedInventory getStructureInventory() { return getInternalInventory(); } diff --git a/src/main/java/forestry/apiculture/gadgets/TileAlvearyHygroregulator.java b/src/main/java/forestry/apiculture/gadgets/TileAlvearyHygroregulator.java index bc57a0663c..57dd6e24c9 100755 --- a/src/main/java/forestry/apiculture/gadgets/TileAlvearyHygroregulator.java +++ b/src/main/java/forestry/apiculture/gadgets/TileAlvearyHygroregulator.java @@ -134,9 +134,8 @@ protected void updateServerSide() { TileInventoryAdapter canInventory = getInternalInventory(); // Check if we have suitable items waiting in the item slot - if (canInventory.getStackInSlot(0) != null) { + if (canInventory.getStackInSlot(0) != null) FluidHelper.drainContainers(tankManager, canInventory, 0); - } } @@ -179,11 +178,6 @@ public int getIcon(int side, int metadata) { return BlockAlveary.ALVEARY_HYGRO; } - @Override - public IInventory getInventory() { - return getInternalInventory(); - } - /* IINVENTORY */ @Override public int getSizeInventory() { diff --git a/src/main/java/forestry/apiculture/gadgets/TileAlvearyPlain.java b/src/main/java/forestry/apiculture/gadgets/TileAlvearyPlain.java index 797097dbd4..02c8e8dc1e 100755 --- a/src/main/java/forestry/apiculture/gadgets/TileAlvearyPlain.java +++ b/src/main/java/forestry/apiculture/gadgets/TileAlvearyPlain.java @@ -22,14 +22,12 @@ import forestry.api.core.EnumTemperature; import forestry.api.core.ForestryAPI; import forestry.api.core.IErrorState; -import forestry.api.core.ISpecialInventory; import forestry.api.core.ITileStructure; import forestry.api.genetics.IIndividual; import forestry.apiculture.gui.ContainerAlveary; import forestry.core.EnumErrorCode; import forestry.core.config.Config; import forestry.core.config.Defaults; -import forestry.core.config.ForestryItem; import forestry.core.interfaces.IClimatised; import forestry.core.interfaces.IErrorSource; import forestry.core.interfaces.IHintSource; @@ -50,9 +48,8 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; import net.minecraft.world.biome.BiomeGenBase; -import net.minecraftforge.common.util.ForgeDirection; -public class TileAlvearyPlain extends TileAlveary implements ISidedInventory, ISpecialInventory, IBeeHousing, IClimatised, IHintSource { +public class TileAlvearyPlain extends TileAlveary implements ISidedInventory, IBeeHousing, IClimatised, IHintSource { // / CONSTANTS public static final int SLOT_QUEEN = 0; @@ -144,7 +141,7 @@ protected void updateServerSide() { // Add swarm effects if (worldObj.getTotalWorldTime() % 200 * 10 == 0) - onQueenChange(getInternalInventory().getStackInSlot(SLOT_QUEEN)); + onQueenChange(getStructureInventory().getStackInSlot(SLOT_QUEEN)); if (getErrorState() == EnumErrorCode.OK) queen.doFX(beekeepingLogic.getEffectData(), this); @@ -169,13 +166,13 @@ protected void updateClientSide() { if (!isMaster()) return; - if (getInternalInventory() == null) + if (getStructureInventory() == null) return; // / Multiplayer FX - if (PluginApiculture.beeInterface.isMated(getInternalInventory().getStackInSlot(SLOT_QUEEN))) + if (PluginApiculture.beeInterface.isMated(getStructureInventory().getStackInSlot(SLOT_QUEEN))) if (getErrorState() == EnumErrorCode.OK && worldObj.getTotalWorldTime() % 2 == 0) { - IBee displayQueen = PluginApiculture.beeInterface.getMember(getInternalInventory().getStackInSlot(SLOT_QUEEN)); + IBee displayQueen = PluginApiculture.beeInterface.getMember(getStructureInventory().getStackInSlot(SLOT_QUEEN)); displayQueen.doFX(beekeepingLogic.getEffectData(), this); } } @@ -200,7 +197,7 @@ private void equalizeHumidity() { /* STATE INFORMATION */ private int getHealthDisplay() { - IInventory inventory = getInternalInventory(); + IInventory inventory = getStructureInventory(); if (inventory == null || inventory.getStackInSlot(SLOT_QUEEN) == null) return 0; @@ -213,7 +210,7 @@ else if (!PluginApiculture.beeInterface.isDrone(inventory.getStackInSlot(SLOT_QU } private int getMaxHealthDisplay() { - IInventory inventory = getInternalInventory(); + IInventory inventory = getStructureInventory(); if (inventory == null || inventory.getStackInSlot(SLOT_QUEEN) == null) return 0; @@ -431,7 +428,7 @@ public boolean canBreed() { @Override public boolean addProduct(ItemStack product, boolean all) { - TileInventoryAdapter inventory = getInternalInventory(); + TileInventoryAdapter inventory = getStructureInventory(); if (inventory == null) return false; @@ -530,7 +527,8 @@ public boolean isHellish() { } /* IINVENTORY */ - private IInventory getStructureInventory() { + @Override + public TileInventoryAdapter getStructureInventory() { TileInventoryAdapter inventory = getInternalInventory(); if (inventory != null) { if (isMaster() || !Proxies.common.isSimulating(worldObj)) @@ -538,9 +536,8 @@ private IInventory getStructureInventory() { } else if (hasMaster()) { ITileStructure central = getCentralTE(); if (central != null) - return central.getInventory(); + return (TileInventoryAdapter) central.getInventory(); } - return null; } @@ -582,12 +579,13 @@ public ItemStack getStackInSlotOnClosing(int slotIndex) { @Override public void setInventorySlotContents(int slotIndex, ItemStack itemstack) { - TileInventoryAdapter inventory = getInternalInventory(); + IInventory inv = getStructureInventory(); + // Client side handling for container synch - if (inventory == null && !Proxies.common.isSimulating(worldObj)) + if (inv == null && !Proxies.common.isSimulating(worldObj)) { createInventory(); - - IInventory inv = getStructureInventory(); + inv = getInternalInventory(); + } if (inv != null) inv.setInventorySlotContents(slotIndex, itemstack); } @@ -626,7 +624,7 @@ public boolean hasCustomInventoryName() { @Override public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) { - TileInventoryAdapter inventory = getInternalInventory(); + ISidedInventory inventory = getStructureInventory(); if (inventory == null) return false; @@ -646,7 +644,7 @@ public boolean canInsertItem(int slotIndex, ItemStack itemstack, int side) { @Override public boolean canExtractItem(int slotIndex, ItemStack itemstack, int side) { - TileInventoryAdapter inventory = getInternalInventory(); + ISidedInventory inventory = getStructureInventory(); if (inventory == null) return false; if (!inventory.canExtractItem(slotIndex, itemstack, side)) @@ -657,83 +655,83 @@ public boolean canExtractItem(int slotIndex, ItemStack itemstack, int side) { @Override public int[] getAccessibleSlotsFromSide(int side) { - TileInventoryAdapter inventory = getInternalInventory(); + ISidedInventory inventory = getStructureInventory(); if (inventory == null) return Defaults.FACINGS_NONE; return inventory.getAccessibleSlotsFromSide(side); } /* ISPECIALINVENTORY */ - @Override - public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { - - IInventory inv = getStructureInventory(); - if (inv == null) - return 0; - - // Princesses && Queens - if (ForestryItem.beePrincessGE.isItemEqual(stack) || ForestryItem.beeQueenGE.isItemEqual(stack)) - if (inv.getStackInSlot(SLOT_QUEEN) == null) { - if (doAdd) { - inv.setInventorySlotContents(SLOT_QUEEN, stack.copy()); - inv.getStackInSlot(SLOT_QUEEN).stackSize = 1; - } - return 1; - } - - // Drones - if (ForestryItem.beeDroneGE.isItemEqual(stack)) { - - ItemStack droneStack = inv.getStackInSlot(SLOT_DRONE); - if (droneStack == null) { - if (doAdd) - inv.setInventorySlotContents(SLOT_DRONE, stack.copy()); - return stack.stackSize; - } else { - if (!droneStack.isItemEqual(stack)) - return 0; - if (!ItemStack.areItemStackTagsEqual(droneStack, stack)) - return 0; - int space = droneStack.getMaxStackSize() - droneStack.stackSize; - if (space <= 0) - return 0; - - int added = space > stack.stackSize ? stack.stackSize : space; - if (doAdd) - droneStack.stackSize += added; - return added; - } - } - - return 0; - } - - @Override - public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { - - IInventory inv = getStructureInventory(); - if (inv == null) - return new ItemStack[0]; - - ItemStack product = null; - - for (int i = SLOT_PRODUCT_1; i < inv.getSizeInventory(); i++) { - if (inv.getStackInSlot(i) == null) - continue; - - ItemStack stack = inv.getStackInSlot(i); - - if (doRemove) - product = inv.decrStackSize(i, 1); - else { - product = stack.copy(); - product.stackSize = 1; - } - break; - } - - return new ItemStack[]{product}; - } +// @Override +// public int addItem(ItemStack stack, boolean doAdd, ForgeDirection from) { +// +// IInventory inv = getStructureInventory(); +// if (inv == null) +// return 0; +// +// // Princesses && Queens +// if (ForestryItem.beePrincessGE.isItemEqual(stack) || ForestryItem.beeQueenGE.isItemEqual(stack)) +// if (inv.getStackInSlot(SLOT_QUEEN) == null) { +// if (doAdd) { +// inv.setInventorySlotContents(SLOT_QUEEN, stack.copy()); +// inv.getStackInSlot(SLOT_QUEEN).stackSize = 1; +// } +// return 1; +// } +// +// // Drones +// if (ForestryItem.beeDroneGE.isItemEqual(stack)) { +// +// ItemStack droneStack = inv.getStackInSlot(SLOT_DRONE); +// if (droneStack == null) { +// if (doAdd) +// inv.setInventorySlotContents(SLOT_DRONE, stack.copy()); +// return stack.stackSize; +// } else { +// if (!droneStack.isItemEqual(stack)) +// return 0; +// if (!ItemStack.areItemStackTagsEqual(droneStack, stack)) +// return 0; +// int space = droneStack.getMaxStackSize() - droneStack.stackSize; +// if (space <= 0) +// return 0; +// +// int added = space > stack.stackSize ? stack.stackSize : space; +// if (doAdd) +// droneStack.stackSize += added; +// return added; +// } +// } +// +// return 0; +// } +// +// @Override +// public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { +// +// IInventory inv = getStructureInventory(); +// if (inv == null) +// return new ItemStack[0]; +// +// ItemStack product = null; +// +// for (int i = SLOT_PRODUCT_1; i < inv.getSizeInventory(); i++) { +// if (inv.getStackInSlot(i) == null) +// continue; +// +// ItemStack stack = inv.getStackInSlot(i); +// +// if (doRemove) +// product = inv.decrStackSize(i, 1); +// else { +// product = stack.copy(); +// product.stackSize = 1; +// } +// break; +// } +// +// return new ItemStack[]{product}; +// } /* SMP GUI */ public void getGUINetworkData(int i, int j) { diff --git a/src/main/java/forestry/apiculture/gadgets/TileAlvearyStabiliser.java b/src/main/java/forestry/apiculture/gadgets/TileAlvearyStabiliser.java index a2da88c4c3..c599476908 100755 --- a/src/main/java/forestry/apiculture/gadgets/TileAlvearyStabiliser.java +++ b/src/main/java/forestry/apiculture/gadgets/TileAlvearyStabiliser.java @@ -53,6 +53,7 @@ public boolean hasFunction() { } /* TEXTURES */ + @Override public int getIcon(int side, int metadata) { if(side == 0 || side == 1) return BlockAlveary.BOTTOM; diff --git a/src/main/java/forestry/apiculture/gadgets/TileAlvearySwarmer.java b/src/main/java/forestry/apiculture/gadgets/TileAlvearySwarmer.java index 129ebd5ee3..a8f2f4aa22 100755 --- a/src/main/java/forestry/apiculture/gadgets/TileAlvearySwarmer.java +++ b/src/main/java/forestry/apiculture/gadgets/TileAlvearySwarmer.java @@ -32,7 +32,6 @@ import java.util.Map.Entry; import java.util.Stack; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.inventory.IInventory; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -219,11 +218,6 @@ protected void createInventory() { setInternalInventory(new TileInventoryAdapter(this, 4, "SwarmInv")); } - @Override - public IInventory getInventory() { - return getInternalInventory(); - } - /* IINVENTORY */ @Override public int getSizeInventory() { diff --git a/src/main/java/forestry/arboriculture/gadgets/BlockSapling.java b/src/main/java/forestry/arboriculture/gadgets/BlockSapling.java index 72185c13be..cf5cc876f5 100755 --- a/src/main/java/forestry/arboriculture/gadgets/BlockSapling.java +++ b/src/main/java/forestry/arboriculture/gadgets/BlockSapling.java @@ -130,6 +130,7 @@ public boolean canBlockStay(World world, int x, int y, int z) { @Override public void onNeighborBlockChange(World world, int x, int y, int z, Block neighbour) { + super.onNeighborBlockChange(world, x, y, z, neighbour); if (Proxies.common.isSimulating(world) && !this.canBlockStay(world, x, y, z)) { dropAsSapling(world, x, y, z); world.setBlockToAir(x, y, z); diff --git a/src/main/java/forestry/core/gadgets/BlockForestry.java b/src/main/java/forestry/core/gadgets/BlockForestry.java index 1ddf1c8dcf..6ffd6e735e 100755 --- a/src/main/java/forestry/core/gadgets/BlockForestry.java +++ b/src/main/java/forestry/core/gadgets/BlockForestry.java @@ -22,6 +22,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; +import org.apache.logging.log4j.Level; public abstract class BlockForestry extends BlockContainer { @@ -65,4 +66,17 @@ public void onBlockPlacedBy(World world, int i, int j, int k, EntityLivingBase e if (entityliving instanceof EntityPlayer) tile.setOwner(((EntityPlayer) entityliving)); } + + @Override + public void onNeighborBlockChange(World world, int x, int y, int z, Block block) { + try { + TileEntity tile = world.getTileEntity(x, y, z); + if (tile instanceof TileForestry) + ((TileForestry) tile).onNeighborBlockChange(block); + } catch (StackOverflowError error) { + Proxies.log.logThrowable(Level.ERROR, "Stack Overflow Error in BlockMachine.onNeighborBlockChange()", 10, error); + throw error; + } + } + } diff --git a/src/main/java/forestry/core/gadgets/BlockStructure.java b/src/main/java/forestry/core/gadgets/BlockStructure.java index 268f71697b..7a74218c86 100755 --- a/src/main/java/forestry/core/gadgets/BlockStructure.java +++ b/src/main/java/forestry/core/gadgets/BlockStructure.java @@ -87,7 +87,7 @@ public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer p @Override public void onNeighborBlockChange(World world, int x, int y, int z, Block neighbor) { - + super.onNeighborBlockChange(world, x, y, z, neighbor); if (!Proxies.common.isSimulating(world)) return; diff --git a/src/main/java/forestry/core/gadgets/TileForestry.java b/src/main/java/forestry/core/gadgets/TileForestry.java index 2f34520318..d8c777ec96 100755 --- a/src/main/java/forestry/core/gadgets/TileForestry.java +++ b/src/main/java/forestry/core/gadgets/TileForestry.java @@ -27,10 +27,12 @@ import forestry.core.network.PacketPayload; import forestry.core.network.PacketTileUpdate; import forestry.core.proxy.Proxies; +import forestry.core.utils.AdjacentTileCache; import forestry.core.utils.EnumAccess; import forestry.core.utils.PlayerUtil; import forestry.core.utils.Vect; import java.util.Collection; +import net.minecraft.block.Block; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -45,9 +47,30 @@ @Optional.Interface(iface = "buildcraft.api.statements.ITriggerProvider", modid = "BuildCraftAPI|statements") public abstract class TileForestry extends TileEntity implements INetworkedEntity, IOwnable, IErrorSource, ITriggerProvider { + protected final AdjacentTileCache tileCache = new AdjacentTileCache(this); protected boolean isInited = false; private TileInventoryAdapter inventory; + public AdjacentTileCache getTileCache() { + return tileCache; + } + + public void onNeighborBlockChange(Block id) { + tileCache.onNeighborChange(); + } + + @Override + public void invalidate() { + tileCache.purge(); + super.invalidate(); + } + + @Override + public void validate() { + tileCache.purge(); + super.validate(); + } + public Vect Coords() { return new Vect(xCoord, yCoord, zCoord); } diff --git a/src/main/java/forestry/core/inventory/AdjacentInventoryCache.java b/src/main/java/forestry/core/inventory/AdjacentInventoryCache.java new file mode 100644 index 0000000000..d77b7695fd --- /dev/null +++ b/src/main/java/forestry/core/inventory/AdjacentInventoryCache.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2011-2014 SirSengir. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v3 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl-3.0.txt + * + * Various Contributors including, but not limited to: + * SirSengir (original work), CovertJaguar, Player, Binnie, MysteriousAges + ******************************************************************************/ +package forestry.core.inventory; + +import forestry.core.utils.AdjacentTileCache; +import java.util.*; +import net.minecraft.inventory.IInventory; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +/** + * + * @author CovertJaguar + */ +public final class AdjacentInventoryCache implements AdjacentTileCache.ICacheListener { + + private final AdjacentTileCache cache; + private boolean changed = true; + private final List invs = new LinkedList(); + private final IInventory[] sides = new IInventory[6]; + private final Comparator sorter; + private final ITileFilter filter; + + public AdjacentInventoryCache(TileEntity tile, AdjacentTileCache cache) { + this(tile, cache, null, null); + } + + public AdjacentInventoryCache(TileEntity tile, AdjacentTileCache cache, ITileFilter filter, Comparator sorter) { + this.cache = cache; + this.filter = filter; + this.sorter = sorter; + cache.addListener(this); + } + + public IInventory getAdjecentInventory(ForgeDirection side) { + checkChanged(); + return sides[side.ordinal()]; + } + + public Collection getAdjecentInventories() { + checkChanged(); + return invs; + } + + @Override + public void changed() { + changed = true; + } + + @Override + public void purge() { + invs.clear(); + Arrays.fill(sides, null); + } + + private void checkChanged() { + cache.refresh(); + if (changed) { + changed = false; + purge(); + for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + TileEntity tile = cache.getTileOnSide(side); + if (tile != null && (filter == null || filter.matches(tile))) { + IInventory inv = InvTools.getInventoryFromTile(tile, side.getOpposite()); + if (inv != null) { + sides[side.ordinal()] = inv; + invs.add(inv); + } + } + } + if (sorter != null) + Collections.sort(invs, sorter); + } + } + +} diff --git a/src/main/java/forestry/core/inventory/InvTools.java b/src/main/java/forestry/core/inventory/InvTools.java index 582687b48f..f18d5f7806 100755 --- a/src/main/java/forestry/core/inventory/InvTools.java +++ b/src/main/java/forestry/core/inventory/InvTools.java @@ -10,8 +10,8 @@ ******************************************************************************/ package forestry.core.inventory; +import buildcraft.api.transport.IPipeTile; import buildcraft.api.transport.PipeManager; -import forestry.api.core.ISpecialInventory; import forestry.core.inventory.filters.ArrayStackFilter; import forestry.core.inventory.filters.IStackFilter; import forestry.core.inventory.filters.InvertedStackFilter; @@ -19,9 +19,11 @@ import forestry.core.inventory.manipulators.InventoryManipulator; import forestry.core.inventory.wrappers.ChestWrapper; import forestry.core.inventory.wrappers.IInvSlot; +import forestry.core.inventory.wrappers.InventoryCopy; import forestry.core.inventory.wrappers.InventoryIterator; import forestry.core.inventory.wrappers.InventoryMapper; import forestry.core.inventory.wrappers.SidedInventoryMapper; +import forestry.core.utils.AdjacentTileCache; import forestry.core.utils.PlainInventory; import java.util.ArrayList; import java.util.Collection; @@ -46,9 +48,9 @@ public abstract class InvTools { /*private static final String TAG_ID = "id"; - private static final String TAG_SIZE = "stackSize"; - private static final String TAG_DAMAGE = "Damage"; - private static final String TAG_COUNT = "Count";*/ + private static final String TAG_SIZE = "stackSize"; + private static final String TAG_DAMAGE = "Damage"; + private static final String TAG_COUNT = "Count";*/ private static final String TAG_SLOT = "Slot"; public static int getXOnSide(int x, ForgeDirection side) { @@ -168,15 +170,14 @@ public static int[] buildSlotArray(int start, int size) { } /*public static void addItemToolTip(ItemStack stack, String tag, String msg) { - NBTTagCompound nbt = getItemData(stack); - NBTTagCompound display = nbt.getCompoundTag("display"); - nbt.setTag("display", display); - NBTTagList lore = display.getTagList("Lore", 8); // 8 = String - display.setTag("Lore", lore); - //lore.appendTag(new NBTTagString(tag, msg)); - lore.appendTag(new NBTTagString(msg)); - }*/ - + NBTTagCompound nbt = getItemData(stack); + NBTTagCompound display = nbt.getCompoundTag("display"); + nbt.setTag("display", display); + NBTTagList lore = display.getTagList("Lore", 8); // 8 = String + display.setTag("Lore", lore); + //lore.appendTag(new NBTTagString(tag, msg)); + lore.appendTag(new NBTTagString(msg)); + }*/ public static NBTTagCompound getItemData(ItemStack stack) { NBTTagCompound nbt = stack.getTagCompound(); if (nbt == null) { @@ -321,7 +322,7 @@ public static int countItems(IInventory inv, ItemStack... filters) { return count; } - public static int countItems(Collection inventories, ItemStack... filter) { + public static int countItems(Iterable inventories, ItemStack... filter) { int count = 0; for (IInventory inv : inventories) { count += InvTools.countItems(inv, filter); @@ -409,7 +410,7 @@ public static ItemStack moveOneItem(IInventory source, IInventory dest, IStackFi * @param filters * @return */ - public static ItemStack moveOneItem(Collection sources, IInventory dest, ItemStack... filters) { + public static ItemStack moveOneItem(Iterable sources, IInventory dest, ItemStack... filters) { for (IInventory inv : sources) { ItemStack moved = InvTools.moveOneItem(inv, dest, filters); if (moved != null) @@ -426,7 +427,7 @@ public static ItemStack moveOneItem(Collection sources, IInventory d * @param filter * @return */ - public static ItemStack moveOneItem(Collection sources, IInventory dest, IStackFilter filter) { + public static ItemStack moveOneItem(Iterable sources, IInventory dest, IStackFilter filter) { for (IInventory inv : sources) { ItemStack moved = InvTools.moveOneItem(inv, dest, filter); if (moved != null) @@ -443,7 +444,7 @@ public static ItemStack moveOneItem(Collection sources, IInventory d * @param filters * @return */ - public static ItemStack moveOneItem(IInventory source, Collection destinations, ItemStack... filters) { + public static ItemStack moveOneItem(IInventory source, Iterable destinations, ItemStack... filters) { for (IInventory dest : destinations) { ItemStack moved = InvTools.moveOneItem(source, dest, filters); if (moved != null) @@ -474,7 +475,7 @@ public static ItemStack moveOneItemExcept(IInventory source, IInventory dest, It * @param filters * @return */ - public static ItemStack moveOneItemExcept(Collection sources, IInventory dest, ItemStack... filters) { + public static ItemStack moveOneItemExcept(Iterable sources, IInventory dest, ItemStack... filters) { for (IInventory inv : sources) { ItemStack moved = InvTools.moveOneItemExcept(inv, dest, filters); if (moved != null) @@ -491,7 +492,7 @@ public static ItemStack moveOneItemExcept(Collection sources, IInven * @param filters * @return */ - public static ItemStack moveOneItemExcept(IInventory source, Collection destinations, ItemStack... filters) { + public static ItemStack moveOneItemExcept(IInventory source, Iterable destinations, ItemStack... filters) { for (IInventory dest : destinations) { ItemStack moved = InvTools.moveOneItemExcept(source, dest, filters); if (moved != null) @@ -650,6 +651,41 @@ public static ItemStack moveItemStack(ItemStack stack, IInventory dest) { return im.addStack(stack); } + /** + * Attempts to move an ItemStack from one inventory to another. + * + * @param source The source IInventory. + * @param dest The destination IInventory. + * @return true if any items were moved + */ + public static boolean moveItemStack(IInventory source, IInventory dest) { + InventoryManipulator im = InventoryManipulator.get(dest); + for (IInvSlot slot : InventoryIterator.getIterable(source)) { + ItemStack stack = slot.getStackInSlot(); + if (stack != null) { + ItemStack remainder = im.addStack(stack); + slot.setStackInSlot(remainder); + return !isItemEqualStrict(stack, remainder); + } + } + return false; + } + + /** + * Attempts to move an ItemStack from one inventory to another. + * + * @param source The source IInventory. + * @param destinations The destination IInventory. + * @return true if any items were moved + */ + public static boolean moveItemStack(IInventory source, Iterable destinations) { + for (IInventory dest : destinations) { + if (moveItemStack(source, dest)) + return true; + } + return false; + } + /** * Checks if there is room for the ItemStack in the inventory. * @@ -673,8 +709,6 @@ public static boolean isRoomForStack(ItemStack stack, IInventory dest) { * @return */ public static ItemStack[] removeItems(IInventory inv, int numItems) { - if (inv instanceof ISpecialInventory) - return ((ISpecialInventory) inv).extractItem(true, ForgeDirection.UNKNOWN, numItems); PlainInventory output = new PlainInventory(27, "temp"); for (int i = 0; i < inv.getSizeInventory(); i++) { if (numItems <= 0) @@ -743,7 +777,7 @@ public static ItemStack removeOneItem(IInventory inv, IStackFilter filter) { * @param filter EnumItemType to match against * @return An ItemStack */ - public static ItemStack removeOneItem(Collection invs, IStackFilter filter) { + public static ItemStack removeOneItem(Iterable invs, IStackFilter filter) { for (IInventory inv : invs) { ItemStack stack = removeOneItem(inv, filter); if (stack != null) @@ -752,6 +786,51 @@ public static ItemStack removeOneItem(Collection invs, IStackFilter return null; } + /** + * Attempts to move a single item from the source inventory into a adjacent Buildcraft pipe. + * If the attempt fails, the source Inventory will not be modified. + * + * @param source The source inventory + * @param tileCache The tile cache of the source block. + * @return true if an item was inserted, otherwise false. + */ + public static boolean moveOneItemToPipe(IInventory source, AdjacentTileCache tileCache) { + IInventory invClone = new InventoryCopy(source); + ItemStack stackToMove = removeOneItem(invClone); + if (stackToMove == null) + return false; + if (stackToMove.stackSize <= 0) + return false; + + IPipeTile[] pipes = new IPipeTile[6]; + boolean foundPipe = false; + for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + TileEntity tile = tileCache.getTileOnSide(side); + if (tile instanceof IPipeTile) { + IPipeTile pipe = (IPipeTile) tile; + if (pipe.getPipeType() == IPipeTile.PipeType.ITEM && pipe.isPipeConnected(side.getOpposite())) { + pipes[side.ordinal()] = pipe; + foundPipe = true; + } + } + } + + if (!foundPipe) + return false; + + int choice = tileCache.getSource().getWorldObj().rand.nextInt(6); + + ForgeDirection side = ForgeDirection.getOrientation(choice); + + IPipeTile pipe = pipes[choice]; + if (pipe.injectItem(stackToMove, false, side.getOpposite()) > 0) + if (removeOneItem(source, stackToMove) != null) { + pipe.injectItem(stackToMove, true, side.getOpposite()); + return true; + } + return false; + } + public static void writeInvToNBT(IInventory inv, String tag, NBTTagCompound data) { NBTTagList list = new NBTTagList(); for (byte slot = 0; slot < inv.getSizeInventory(); slot++) { diff --git a/src/main/java/forestry/core/utils/AdjacentTileCache.java b/src/main/java/forestry/core/utils/AdjacentTileCache.java new file mode 100644 index 0000000000..9b58edddfa --- /dev/null +++ b/src/main/java/forestry/core/utils/AdjacentTileCache.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (c) 2011-2014 SirSengir. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v3 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl-3.0.txt + * + * Various Contributors including, but not limited to: + * SirSengir (original work), CovertJaguar, Player, Binnie, MysteriousAges + ******************************************************************************/ +package forestry.core.utils; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; +import net.minecraft.init.Blocks; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +/** + * + * @author CovertJaguar + */ +public final class AdjacentTileCache { + + private static final int DELAY_MIN = 20; + private static final int DELAY_MAX = 2400; + private static final int DELAY_STEP = 2; + private final Timer[] timer = new Timer[6]; + private final TileEntity[] cache = new TileEntity[6]; + private final int[] delay = new int[6]; + private final TileEntity source; + private final Set listeners = new LinkedHashSet(); + + public static interface ICacheListener { + + void changed(); + + void purge(); + + } + + public AdjacentTileCache(TileEntity tile) { + this.source = tile; + Arrays.fill(delay, DELAY_MIN); + for (int i = 0; i < timer.length; i++) { + timer[i] = new Timer(); + } + } + + public void addListener(ICacheListener listener) { + listeners.add(listener); + } + + private TileEntity searchSide(ForgeDirection side) { + World world = source.getWorldObj(); + int sx = source.xCoord + side.offsetX; + int sy = source.yCoord + side.offsetY; + int sz = source.zCoord + side.offsetZ; + if (world.blockExists(sx, sy, sz) && world.getBlock(sx, sy, sz) != Blocks.air) + return world.getTileEntity(sx, sy, sz); + return null; + } + + public void refresh() { + for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + getTileOnSide(side); + } + } + + public void purge() { + Arrays.fill(cache, null); + Arrays.fill(delay, DELAY_MIN); + for (Timer t : timer) { + t.reset(); + } + changed(); + for (ICacheListener listener : listeners) { + listener.purge(); + } + } + + public void onNeighborChange() { + Arrays.fill(delay, DELAY_MIN); + } + + protected void setTile(int side, TileEntity tile) { + if (cache[side] != tile) { + cache[side] = tile; + changed(); + } + } + + private void changed() { + for (ICacheListener listener : listeners) { + listener.changed(); + } + } + + private boolean areCoordinatesOnSide(ForgeDirection side, TileEntity target) { + return source.xCoord + side.offsetX == target.xCoord && source.yCoord + side.offsetY == target.yCoord && source.zCoord + side.offsetZ == target.zCoord; + } + + public TileEntity getTileOnSide(ForgeDirection side) { + int s = side.ordinal(); + if (cache[s] != null) + if (cache[s].isInvalid() || !areCoordinatesOnSide(side, cache[s])) + setTile(s, null); + else + return cache[s]; + + if (timer[s].hasTriggered(source.getWorldObj(), delay[s])) { + setTile(s, searchSide(side)); + if (cache[s] == null) + incrementDelay(s); + else + delay[s] = DELAY_MIN; + } + + return cache[s]; + } + + private void incrementDelay(int side) { + delay[side] += DELAY_STEP; + if (delay[side] > DELAY_MAX) + delay[side] = DELAY_MAX; + } + + public TileEntity getSource() { + return source; + } + +} diff --git a/src/main/java/forestry/core/utils/BlockUtil.java b/src/main/java/forestry/core/utils/BlockUtil.java index a6b504ce90..de67826037 100644 --- a/src/main/java/forestry/core/utils/BlockUtil.java +++ b/src/main/java/forestry/core/utils/BlockUtil.java @@ -49,10 +49,13 @@ public static ArrayList getBlockItemStack(World world, Vect posBlock) * @param blockPos * @param from * @return + * @deprecated Use AdjacentInventoryCache instead */ + @Deprecated public static IInventory[] getAdjacentInventories(World world, Vect blockPos, ForgeDirection from) { ArrayList inventories = new ArrayList(); + // WTF is this? A loop that only picks the opposite direction? -CovertJaguar for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { if (from != ForgeDirection.UNKNOWN && from != dir.getOpposite()) continue; @@ -88,12 +91,12 @@ public static ForgeDirection[] getPipeDirections(World world, Vect blockPos, For TileEntity pipeEntry = world.getTileEntity((int) posPipe.x, (int) posPipe.y, (int) posPipe.z); if (pipeEntry instanceof IPipeTile) { - IPipeTile pipe = (IPipeTile)pipeEntry; + IPipeTile pipe = (IPipeTile) pipeEntry; if (from != ForgeDirection.UNKNOWN && pipeEntry instanceof IPipeConnection) { if (((IPipeConnection) pipeEntry).overridePipeConnection(PipeType.ITEM, from) != ConnectOverride.DISCONNECT) possiblePipes.add(dir); - } else if(pipe.getPipeType() == PipeType.ITEM && pipe.isPipeConnected(dir.getOpposite())) + } else if (pipe.getPipeType() == PipeType.ITEM && pipe.isPipeConnected(dir.getOpposite())) possiblePipes.add(dir); } } @@ -106,9 +109,10 @@ public static ArrayList filterPipeDirections(ForgeDirection[] al ArrayList filtered = new ArrayList(); ArrayList excludeList = new ArrayList(Arrays.asList(exclude)); - for (ForgeDirection direction : allDirections) + for (ForgeDirection direction : allDirections) { if (!excludeList.contains(direction)) filtered.add(direction); + } return filtered; @@ -137,7 +141,7 @@ public static boolean putFromStackIntoPipe(TileEntity tile, ArrayList 0) + if (pipe.injectItem(payload, true, itemPos.orientation.getOpposite()) > 0) return true; else pipes.remove(choice); diff --git a/src/main/java/forestry/core/utils/Timer.java b/src/main/java/forestry/core/utils/Timer.java new file mode 100644 index 0000000000..68126fa6bc --- /dev/null +++ b/src/main/java/forestry/core/utils/Timer.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2011-2014 SirSengir. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v3 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl-3.0.txt + * + * Various Contributors including, but not limited to: + * SirSengir (original work), CovertJaguar, Player, Binnie, MysteriousAges + ******************************************************************************/ +package forestry.core.utils; + +import net.minecraft.world.World; + +/** + * + * @author CovertJaguar + */ +public class Timer { + + private long startTime = Long.MIN_VALUE; + + public boolean hasTriggered(World world, int ticks) { + long currentTime = world.getTotalWorldTime(); + if (currentTime >= (ticks + startTime) || startTime > currentTime) { + startTime = currentTime; + return true; + } + return false; + } + + public void reset() { + startTime = Long.MIN_VALUE; + } + +} diff --git a/src/main/java/forestry/farming/gadgets/TileFarm.java b/src/main/java/forestry/farming/gadgets/TileFarm.java index 479b342e85..448e669ae2 100755 --- a/src/main/java/forestry/farming/gadgets/TileFarm.java +++ b/src/main/java/forestry/farming/gadgets/TileFarm.java @@ -27,6 +27,7 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; @@ -315,7 +316,12 @@ protected boolean hasMaster() { } @Override - public IInventory getInventory() { + public final IInventory getInventory() { + return getStructureInventory(); + } + + @Override + public ISidedInventory getStructureInventory() { return getInternalInventory(); } diff --git a/src/main/java/forestry/farming/gadgets/TileHatch.java b/src/main/java/forestry/farming/gadgets/TileHatch.java index 9cede7c5e2..ad1e019ef4 100755 --- a/src/main/java/forestry/farming/gadgets/TileHatch.java +++ b/src/main/java/forestry/farming/gadgets/TileHatch.java @@ -13,13 +13,14 @@ import buildcraft.api.statements.ITriggerExternal; import cpw.mods.fml.common.Optional; import forestry.api.core.ITileStructure; -import forestry.core.utils.BlockUtil; -import forestry.core.utils.StackUtils; +import forestry.core.inventory.AdjacentInventoryCache; +import forestry.core.inventory.ITileFilter; +import forestry.core.inventory.InvTools; +import forestry.core.inventory.TileInventoryAdapter; +import forestry.core.inventory.wrappers.InventoryMapper; import forestry.core.utils.Utils; import forestry.farming.triggers.FarmingTriggers; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.LinkedList; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; @@ -31,6 +32,14 @@ public class TileHatch extends TileFarm implements ISidedInventory { + private final AdjacentInventoryCache inventoryCache = new AdjacentInventoryCache(this, getTileCache(), new ITileFilter() { + + @Override + public boolean matches(TileEntity tile) { + return !(tile instanceof TileFarm); + } + }, null); + public TileHatch() { fixedType = TYPE_HATCH; } @@ -47,82 +56,30 @@ protected void updateServerSide() { } /* AUTO-EJECTING */ + private IInventory getProductInventory() { + return new InventoryMapper(getStructureInventory(), TileFarmPlain.SLOT_PRODUCTION_1, TileFarmPlain.SLOT_COUNT_PRODUCTION); + } + protected void dumpStash() { if (!hasMaster()) return; - ArrayList pipes = new ArrayList(); - ForgeDirection[] tmp = BlockUtil.getPipeDirections(worldObj, Coords(), ForgeDirection.UP); - Collections.addAll(pipes, tmp); - - if (pipes.size() > 0) - dumpToPipe(pipes); - else { - IInventory[] inventories = BlockUtil.getAdjacentInventories(worldObj, Coords(), ForgeDirection.UP); - dumpToInventory(inventories); - } - } - - private void dumpToPipe(ArrayList pipes) { - - ItemStack[] products = extractItem(true, ForgeDirection.DOWN, 1); - for (ItemStack product : products) { - while (product.stackSize > 0) { - BlockUtil.putFromStackIntoPipe(this, pipes, product); - } - } - - } - - private void dumpToInventory(IInventory[] inventories) { - - ITileStructure central = getCentralTE(); - if (central == null) - return; - IInventory inv = central.getInventory(); - - for (int i = TileFarmPlain.SLOT_PRODUCTION_1; i < TileFarmPlain.SLOT_PRODUCTION_1 + TileFarmPlain.SLOT_COUNT_PRODUCTION; i++) { - if (inv.getStackInSlot(i) == null) - continue; - - ItemStack stack = inv.getStackInSlot(i); - - if (stack.stackSize <= 0) - continue; - - for (IInventory inventory : inventories) { - - // Don't dump in arboretums! - if (inventory.getSizeInventory() < 4) - continue; - - // Get complete inventory (for double chests) - IInventory completeInventory = Utils.getChest(inventory); - if (completeInventory instanceof ISidedInventory) { - ISidedInventory sidedInventory = (ISidedInventory) completeInventory; - int[] slots = sidedInventory.getAccessibleSlotsFromSide(ForgeDirection.UP.ordinal()); - for (int sl = 0; sl < slots.length; ++sl) { - StackUtils.stowInInventory(stack, sidedInventory, true, sl, 1); - } - } else { - StackUtils.stowInInventory(stack, completeInventory, true); - if (stack.stackSize <= 0) { - inv.setInventorySlotContents(i, null); - break; - } - } - } + if (!InvTools.moveOneItemToPipe(getProductInventory(), tileCache)) { + IInventory struct = getStructureInventory(); + if (struct != null) + InvTools.moveItemStack(getProductInventory(), inventoryCache.getAdjecentInventories()); } - } /* IINVENTORY */ - private ISidedInventory getStructureInventory() { + @Override + public TileInventoryAdapter getStructureInventory() { if (hasMaster()) { ITileStructure central = getCentralTE(); - if (central != null) - return (ISidedInventory) central.getInventory(); + if (central != null){ + return (TileInventoryAdapter) central.getInventory(); + } } return null; @@ -248,40 +205,6 @@ public int[] getAccessibleSlotsFromSide(int side) { return getStructureInventory().getAccessibleSlotsFromSide(side); } - public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { - - IInventory inv; - if (hasMaster()) { - ITileStructure central = getCentralTE(); - if (central == null) - return new ItemStack[0]; - inv = getCentralTE().getInventory(); - } else - return StackUtils.EMPTY_STACK_ARRAY; - - ItemStack product = null; - - for (int i = TileFarmPlain.SLOT_PRODUCTION_1; i < TileFarmPlain.SLOT_PRODUCTION_1 + TileFarmPlain.SLOT_COUNT_PRODUCTION; i++) { - if (inv.getStackInSlot(i) == null) - continue; - - ItemStack stack = inv.getStackInSlot(i); - - if (doRemove) - product = inv.decrStackSize(i, 1); - else { - product = stack.copy(); - product.stackSize = 1; - } - break; - } - - if (product != null) - return new ItemStack[]{product}; - else - return StackUtils.EMPTY_STACK_ARRAY; - } - /* ITRIGGERPROVIDER */ @Optional.Method(modid = "BuildCraftAPI|statements") @Override