From a3c562c1b14eee4ebe2cb20a114900f68a47c3fd Mon Sep 17 00:00:00 2001 From: mezz Date: Mon, 15 Sep 2014 23:27:55 -0700 Subject: [PATCH] Fix #180 dupe bug. Unified checking and removing items from inventories --- .../forestry/core/utils/InventoryAdapter.java | 96 +++++++++---------- .../java/forestry/core/utils/StackUtils.java | 25 ++++- .../factory/gadgets/MachineCarpenter.java | 47 ++++----- .../factory/gadgets/MachineFabricator.java | 50 +++------- .../factory/gadgets/MachineSqueezer.java | 34 ++----- .../factory/gadgets/TileWorktable.java | 43 ++------- .../farming/gadgets/TileFarmPlain.java | 4 +- 7 files changed, 117 insertions(+), 182 deletions(-) diff --git a/src/main/java/forestry/core/utils/InventoryAdapter.java b/src/main/java/forestry/core/utils/InventoryAdapter.java index 70737cc71..0c2fc4d8d 100755 --- a/src/main/java/forestry/core/utils/InventoryAdapter.java +++ b/src/main/java/forestry/core/utils/InventoryAdapter.java @@ -191,68 +191,60 @@ public class InventoryAdapter implements IInventory, INBTTagable { /* CONTAINS */ public boolean contains(ItemStack[] query, int startSlot, int slots) { - for (ItemStack queried : query) { - - int itemCount = 0; - for (int i = startSlot; i < startSlot + slots; i++) { - ItemStack stack = inventory.getStackInSlot(i); - - if (stack == null) - continue; - - if (StackUtils.equals(Blocks.bedrock, queried)) { - itemCount += stack.stackSize; - continue; - } - if (queried.getItemDamage() < 0) { - - if (stack.getItem() == queried.getItem()) - itemCount += stack.stackSize; - continue; - } - - if (stack.isItemEqual(queried) && ItemStack.areItemStackTagsEqual(stack, queried)) - itemCount += stack.stackSize; - } - - if (itemCount < queried.stackSize) - return false; - - } - - return true; + ItemStack[] stock = getStacks(startSlot, slots); + return StackUtils.containsSets(query, stock) > 0; } /* REMOVAL */ - public void removeResources(ItemStack[] query, int startSlot, int slots) { - for (ItemStack queried : query) { + /** + * Removes a set of items from an inventory. + * Removes the exact items first if they exist, and then removes crafting equivalents. + * If the inventory doesn't have all the required items, returns false without removing anything. + * If stowContainer is true, items with containers will have their container stowed. + */ + public boolean removeSets(int count, ItemStack[] set, int firstSlotIndex, int slotCount, EntityPlayer player, boolean stowContainer, boolean oreDictionary, boolean craftingTools) { - ItemStack remain = queried.copy(); + ItemStack[] condensedSet = StackUtils.condenseStacks(set, -1, false); - for (int i = startSlot; i < startSlot + slots; i++) { - ItemStack stack = inventory.getStackInSlot(i); + ItemStack[] stock = getStacks(firstSlotIndex, slotCount); + if (StackUtils.containsSets(condensedSet, stock, null, oreDictionary, craftingTools) < count) + return false; - if (stack == null) - continue; + for (ItemStack stackToRemove : condensedSet) { + stackToRemove.stackSize *= count; - if (queried.getItemDamage() < 0) { - - if (stack.getItem() == queried.getItem()) { - ItemStack removed = decrStackSize(i, remain.stackSize); - remain.stackSize -= removed.stackSize; - } - - } else if (stack.isItemEqual(remain) && ItemStack.areItemStackTagsEqual(stack, remain)) { - ItemStack removed = decrStackSize(i, remain.stackSize); - remain.stackSize -= removed.stackSize; - } - - if (remain.stackSize <= 0) - break; - } + // try to remove the exact stack first + removeStack(stackToRemove, firstSlotIndex, slotCount, player, stowContainer, false, false); + // remove crafting equivalents next + if (stackToRemove.stackSize > 0) + removeStack(stackToRemove, firstSlotIndex, slotCount, player, stowContainer, oreDictionary, craftingTools); } + return true; + } + /** + * Private Helper for removeSetsFromInventory. Assumes removal is possible. + */ + private void removeStack(ItemStack stackToRemove, int firstSlotIndex, int slotCount, EntityPlayer player, boolean stowContainer, boolean oreDictionary, boolean craftingTools) { + for (int j = firstSlotIndex; j < firstSlotIndex + slotCount; j++) { + ItemStack stackInSlot = getStackInSlot(j); + if (stackInSlot == null) + continue; + + if (!StackUtils.isCraftingEquivalent(stackToRemove, stackInSlot, oreDictionary, craftingTools)) + continue; + + + ItemStack removed = decrStackSize(j, stackToRemove.stackSize); + stackToRemove.stackSize -= removed.stackSize; + + if (stowContainer && stackToRemove.getItem().hasContainerItem(stackToRemove)) + StackUtils.stowContainerItem(removed, this, j, player); + + if (stackToRemove.stackSize == 0) + return; + } } /* IINVENTORY */ diff --git a/src/main/java/forestry/core/utils/StackUtils.java b/src/main/java/forestry/core/utils/StackUtils.java index b97d593a8..ee5891f06 100755 --- a/src/main/java/forestry/core/utils/StackUtils.java +++ b/src/main/java/forestry/core/utils/StackUtils.java @@ -267,7 +267,7 @@ public class StackUtils { public static int containsSets(ItemStack[] set, ItemStack[] stock, ItemStack exclude, boolean oreDictionary, boolean craftingTools) { int count = 0; - ItemStack[] condensedRequired = StackUtils.condenseStacks(set); + ItemStack[] condensedRequired = StackUtils.condenseStacks(set, -1, oreDictionary); ItemStack[] condensedOffered = StackUtils.condenseStacks(stock, -1, oreDictionary); for (ItemStack req : condensedRequired) { @@ -297,6 +297,27 @@ public class StackUtils { return count; } + /** + * Compare two item stacks for crafting equivalency without oreDictionary or craftingTools + */ + public static boolean isCraftingEquivalent(ItemStack base, ItemStack comparison) { + if (base == null || comparison == null) + return false; + + if (base.getItem() != comparison.getItem()) + return false; + + if (base.getItemDamage() != Defaults.WILDCARD) + if (base.getItemDamage() != comparison.getItemDamage()) + return false; + + // When the base stackTagCompound is null, treat it as a wildcard for crafting + if (base.stackTagCompound != null && !ItemStack.areItemStackTagsEqual(base, comparison)) + return false; + + return true; + } + /** * Compare two item stacks for crafting equivalency. * @@ -306,7 +327,7 @@ public class StackUtils { * @return */ public static boolean isCraftingEquivalent(ItemStack base, ItemStack comparison, boolean oreDictionary, boolean craftingTools) { - if (isIdenticalItem(base, comparison)) + if (isCraftingEquivalent(base, comparison)) return true; if (base == null || comparison == null) diff --git a/src/main/java/forestry/factory/gadgets/MachineCarpenter.java b/src/main/java/forestry/factory/gadgets/MachineCarpenter.java index dff58d5a9..ac52592d0 100755 --- a/src/main/java/forestry/factory/gadgets/MachineCarpenter.java +++ b/src/main/java/forestry/factory/gadgets/MachineCarpenter.java @@ -384,7 +384,8 @@ public class MachineCarpenter extends TilePowered implements ISidedInventory, IL totalTime = 0; // Remove resources - removeResources(currentRecipe); + if (!removeResources(currentRecipe)) + return false; // Update product display if (activeContainer != null) @@ -432,37 +433,29 @@ public class MachineCarpenter extends TilePowered implements ISidedInventory, IL return StackUtils.containsSets(craftingInventory.getStacks(SLOT_CRAFTING_1, 9), accessibleInventory.getStacks(SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT), null, true, false) > 0; } - private void removeResources(Recipe recipe) { + private boolean removeResources(Recipe recipe) { // Remove resources - if (recipe.liquid != null) - resourceTank.drain(recipe.liquid.amount, true); + if (recipe.liquid != null) { + FluidStack amountDrained = resourceTank.drain(recipe.liquid.amount, false); + if (amountDrained != null && amountDrained.amount == recipe.liquid.amount) + resourceTank.drain(recipe.liquid.amount, true); + else + return false; + } // Remove boxes - if (recipe.box != null) - accessibleInventory.decrStackSize(SLOT_BOX, 1); - - removeSets(1, craftingInventory.getStacks(SLOT_CRAFTING_1, 9)); - - } - - private void removeSets(int count, ItemStack[] set) { - - for (int i = 0; i < count; i++) { - ItemStack[] condensedSet = StackUtils.condenseStacks(set); - for (ItemStack req : condensedSet) { - for (int j = SLOT_INVENTORY_1; j < SLOT_INVENTORY_1 + SLOT_INVENTORY_COUNT; j++) { - ItemStack pol = accessibleInventory.getStackInSlot(j); - if (pol == null) - continue; - if (!StackUtils.isCraftingEquivalent(pol, req, true, false)) - continue; - - ItemStack removed = accessibleInventory.decrStackSize(j, req.stackSize); - req.stackSize -= removed.stackSize; - } - } + if (recipe.box != null) { + ItemStack removed = accessibleInventory.decrStackSize(SLOT_BOX, 1); + if (removed == null || removed.stackSize == 0) + return false; } + return removeSets(1, craftingInventory.getStacks(SLOT_CRAFTING_1, 9)); + } + + private boolean removeSets(int count, ItemStack[] set) { + EntityPlayer player = worldObj.getPlayerEntityByName(owner.getName()); + return accessibleInventory.removeSets(count, set, SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT, player, true, true, true); } private boolean tryAddPending() { diff --git a/src/main/java/forestry/factory/gadgets/MachineFabricator.java b/src/main/java/forestry/factory/gadgets/MachineFabricator.java index b48331af8..f4d4004bc 100755 --- a/src/main/java/forestry/factory/gadgets/MachineFabricator.java +++ b/src/main/java/forestry/factory/gadgets/MachineFabricator.java @@ -397,8 +397,8 @@ public class MachineFabricator extends TilePowered implements ICrafter, ISpecial FluidStack liquid = myRecipe.molten; // Remove resources - if (removeFromInventory(1, inventory.getStacks(SLOT_CRAFTING_1, 9), false)) { - removeFromInventory(1, inventory.getStacks(SLOT_CRAFTING_1, 9), true); + if (removeFromInventory(1, inventory.getStacks(SLOT_CRAFTING_1, 9), player, false)) { + removeFromInventory(1, inventory.getStacks(SLOT_CRAFTING_1, 9), player, true); moltenTank.drain(liquid.amount, true); } else if (consumeRecipe) { removeFromCraftMatrix(myRecipe); @@ -428,39 +428,13 @@ public class MachineFabricator extends TilePowered implements ICrafter, ISpecial } - private boolean removeFromInventory(int count, ItemStack[] set, boolean doRemove) { - - boolean hasRemoved = true; - for (int i = 0; i < count; i++) { - ItemStack[] condensedSet = StackUtils.condenseStacks(set, 1, true); - for (ItemStack req : condensedSet) - for (int j = SLOT_INVENTORY_1; j < SLOT_INVENTORY_1 + SLOT_INVENTORY_COUNT; j++) { - ItemStack pol = inventory.getStackInSlot(j); - if (pol == null) - continue; - if (!StackUtils.isCraftingEquivalent(pol, req, true, false)) - continue; - - int available = pol.stackSize; - if (doRemove) { - inventory.decrStackSize(j, req.stackSize); - } - req.stackSize -= available; - - if(req.stackSize <= 0) - break; - } - - boolean hasLeft = false; - for (ItemStack req : condensedSet) - if (req != null && req.stackSize > 0) - hasLeft = true; - if (hasLeft) - hasRemoved = false; - + private boolean removeFromInventory(int count, ItemStack[] set, EntityPlayer player, boolean doRemove) { + if (doRemove) { + return inventory.removeSets(count, set, SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT, player, true, true, true); + } else { + ItemStack[] stock = inventory.getStacks(SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT); + return StackUtils.containsSets(set, stock) >= count; } - - return hasRemoved; } @Override @@ -527,10 +501,12 @@ public class MachineFabricator extends TilePowered implements ICrafter, ISpecial @Override public ItemStack[] extractItem(boolean doRemove, ForgeDirection from, int maxItemCount) { ItemStack taken; - if (doRemove) - taken = this.takenFromSlot(SLOT_RESULT, false, null); - else + if (doRemove) { + EntityPlayer player = worldObj.getPlayerEntityByName(owner.getName()); + taken = this.takenFromSlot(SLOT_RESULT, false, player); + } else { taken = this.getResult(); + } if (taken != null) return new ItemStack[] { taken }; diff --git a/src/main/java/forestry/factory/gadgets/MachineSqueezer.java b/src/main/java/forestry/factory/gadgets/MachineSqueezer.java index ea78aff6c..58776c862 100755 --- a/src/main/java/forestry/factory/gadgets/MachineSqueezer.java +++ b/src/main/java/forestry/factory/gadgets/MachineSqueezer.java @@ -76,29 +76,7 @@ public class MachineSqueezer extends TilePowered implements ISpecialInventory, I } public boolean matches(ItemStack[] res) { - // No recipe without resource! - if (res == null || res.length <= 0) - return false; - - boolean matchedAll = true; - - for (ItemStack stack : resources) { - boolean matched = false; - for (ItemStack matchStack : res) { - if (matchStack == null) - continue; - - // If the item matches, we need enough items - if (matchStack.isItemEqual(stack)) - if (matchStack.stackSize >= stack.stackSize) { - matched = true; - break; - } - } - if (!matched) - matchedAll = false; - } - return matchedAll; + return StackUtils.containsSets(resources, res, null, true, true) > 0; } } @@ -290,13 +268,14 @@ public class MachineSqueezer extends TilePowered implements ISpecialInventory, I return true; } + if (!removeResources(currentRecipe.resources)) + return false; + // We are done, add products to queue pendingLiquids.push(currentRecipe.liquid.copy()); if (currentRecipe.remnants != null && worldObj.rand.nextInt(100) < currentRecipe.chance) pendingRemnants.push(currentRecipe.remnants.copy()); - removeResources(currentRecipe.resources); - checkRecipe(); resetRecipe(); @@ -365,8 +344,9 @@ public class MachineSqueezer extends TilePowered implements ISpecialInventory, I return inventory.tryAddStack(stack, SLOT_REMNANT, 1, true); } - private void removeResources(ItemStack[] stacks) { - inventory.removeResources(stacks, SLOT_RESOURCE_1, SLOTS_RESOURCE_COUNT); + private boolean removeResources(ItemStack[] stacks) { + EntityPlayer player = worldObj.getPlayerEntityByName(owner.getName()); + return inventory.removeSets(1, stacks, SLOT_RESOURCE_1, SLOTS_RESOURCE_COUNT, player, false, true, true); } @Override diff --git a/src/main/java/forestry/factory/gadgets/TileWorktable.java b/src/main/java/forestry/factory/gadgets/TileWorktable.java index 6ae55cde3..7b33d2c78 100755 --- a/src/main/java/forestry/factory/gadgets/TileWorktable.java +++ b/src/main/java/forestry/factory/gadgets/TileWorktable.java @@ -462,43 +462,14 @@ public class TileWorktable extends TileBase implements ICrafter { } private boolean validateResources() { - // Need at least one matched set - if (currentRecipe == null) - return false; - - ItemStack[] set = currentRecipe.getMatrix().getStacks(); - ItemStack[] stock = accessibleInventory.getStacks(); + ItemStack[] set = craftingInventory.getStacks(SLOT_CRAFTING_1, 9); + ItemStack[] stock = accessibleInventory.getStacks(SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT); return StackUtils.containsSets(set, stock, currentRecipe.getRecipeOutput(), true, true) > 0; } - private void removeResources(EntityPlayer player) { - removeSets(1, craftingInventory.getStacks(SLOT_CRAFTING_1, 9), player); - } - - private void removeSets(int count, ItemStack[] set, EntityPlayer player) { - - for (int i = 0; i < count; i++) { - ItemStack[] condensedSet = StackUtils.condenseStacks(set); - for (ItemStack req : condensedSet) { - for (int j = SLOT_INVENTORY_1; j < SLOT_INVENTORY_1 + SLOT_INVENTORY_COUNT; j++) { - ItemStack pol = accessibleInventory.getStackInSlot(j); - if (pol == null) - continue; - - if (!StackUtils.isCraftingEquivalent(pol, req, true, true)) - continue; - - ItemStack removed = accessibleInventory.decrStackSize(j, req.stackSize); - req.stackSize -= removed.stackSize; - - if (req.getItem().hasContainerItem(req)) - StackUtils.stowContainerItem(removed, accessibleInventory, j, player); - if (req.stackSize <= 0) - break; - } - } - } - + private boolean removeResources(EntityPlayer player) { + ItemStack[] set = craftingInventory.getStacks(SLOT_CRAFTING_1, 9); + return accessibleInventory.removeSets(1, set, SLOT_INVENTORY_1, SLOT_INVENTORY_COUNT, player, true, true, true); } @Override @@ -508,12 +479,12 @@ public class TileWorktable extends TileBase implements ICrafter { @Override public ItemStack takenFromSlot(int slotIndex, boolean consumeRecipe, EntityPlayer player) { - if (!validateResources()) + if (!removeResources(player)) return null; if (Proxies.common.isSimulating(worldObj)) memorized.memorizeRecipe(worldObj, currentRecipe, currentCrafting); - removeResources(player); + updateCraftResult(currentCrafting); return currentRecipe.getRecipeOutput().copy(); } diff --git a/src/main/java/forestry/farming/gadgets/TileFarmPlain.java b/src/main/java/forestry/farming/gadgets/TileFarmPlain.java index ec3123714..30a48125b 100755 --- a/src/main/java/forestry/farming/gadgets/TileFarmPlain.java +++ b/src/main/java/forestry/farming/gadgets/TileFarmPlain.java @@ -19,6 +19,7 @@ import java.util.Set; import java.util.Stack; import java.util.TreeMap; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.Container; import net.minecraft.inventory.ICrafting; import net.minecraft.item.ItemStack; @@ -757,7 +758,8 @@ public class TileFarmPlain extends TileFarm implements IFarmHousing, ISocketable @Override public void removeResources(ItemStack[] resources) { - inventory.removeResources(resources, SLOT_RESOURCES_1, SLOT_COUNT_RESERVOIRS); + EntityPlayer player = worldObj.getPlayerEntityByName(owner.getName()); + inventory.removeSets(1, resources, SLOT_RESOURCES_1, SLOT_RESOURCES_1, player, false, true, true); } @Override