Fix #180 dupe bug. Unified checking and removing items from inventories

This commit is contained in:
mezz committed 2014-09-15 23:27:55 -07:00
1 parent 5486be107c
commit a3c562c1b1
7 files changed
+117 -182

No files matched your search

@@ -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 */
@@ -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)
@@ -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() {
@@ -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 };
@@ -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
@@ -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();
}
@@ -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