mirror of
https://github.com/GTNewHorizons/ForestryMC.git
synced 2026-11-14 01:04:12 +00:00
Fix #180 dupe bug. Unified checking and removing items from inventories
This commit is contained in:
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
|
||||
|
||||
Reference in new issue
Block a user