diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/util/IFluidStackList.java b/src/main/java/com/raoulvdberge/refinedstorage/api/util/IFluidStackList.java index 81fb17841..5772a6d1d 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/util/IFluidStackList.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/util/IFluidStackList.java @@ -39,6 +39,34 @@ public interface IFluidStackList { return remove(stack, stack.amount, removeIfReachedZero); } + /** + * Decrements the count of that stack in the list. + * Keeps track of remove items and can be undone by calling {@link #undo()} + * + * @param stack the stack + * @param size the size to remove + * @param removeIfReachedZero true to remove the stack if the count reaches 0, false otherwise + * @return whether the remove was successful for the full amount + */ + boolean trackedRemove(@Nonnull FluidStack stack, int size, boolean removeIfReachedZero); + + /** + * Decrements the count of that stack in the list. + * Keeps track of remove items and can be undone by calling {@link #undo()} + * + * @param stack the stack + * @param removeIfReachedZero true to remove the stack if the count reaches 0, false otherwise + * @return whether the remove was successful for the full amount + */ + default boolean trackedRemove(@Nonnull FluidStack stack, boolean removeIfReachedZero) { + return trackedRemove(stack, stack.amount, removeIfReachedZero); + } + + /** + * Restore all tracked removes + */ + void undo(); + /** * Returns a stack. * diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/util/IItemStackList.java b/src/main/java/com/raoulvdberge/refinedstorage/api/util/IItemStackList.java index 9a3941be6..3c8d09bdc 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/util/IItemStackList.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/util/IItemStackList.java @@ -39,6 +39,34 @@ public interface IItemStackList { return remove(stack, stack.stackSize, removeIfReachedZero); } + /** + * Decrements the count of that stack in the list. + * Keeps track of remove items and can be undone by calling {@link #undo()} + * + * @param stack the stack + * @param size the size to remove + * @param removeIfReachedZero true to remove the stack if the count reaches 0, false otherwise + * @return whether the remove was successful for the full amount + */ + boolean trackedRemove(@Nonnull ItemStack stack, int size, boolean removeIfReachedZero); + + /** + * Decrements the count of that stack in the list. + * Keeps track of remove items and can be undone by calling {@link #undo()} + * + * @param stack the stack + * @param removeIfReachedZero true to remove the stack if the count reaches 0, false otherwise + * @return whether the remove was successful for the full amount + */ + default boolean trackedRemove(@Nonnull ItemStack stack, boolean removeIfReachedZero) { + return trackedRemove(stack, stack.stackSize, removeIfReachedZero); + } + + /** + * Restore all tracked removes + */ + void undo(); + /** * Returns a stack. * diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStep.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStep.java index 9513e02d9..3efa158a4 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStep.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStep.java @@ -82,17 +82,15 @@ public abstract class CraftingStep implements ICraftingStep { @Override public boolean canStartProcessing(IItemStackList items, IFluidStackList fluids) { - items = items.copy(); // So we can edit the list - items.clean();// Clean the list so the zero stacks aren't there - for (ItemStack stack : getToInsert()) { ItemStack actualStack = items.get(stack, IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT | (pattern.isOredict() ? IComparer.COMPARE_OREDICT : 0)); - if (actualStack == null || actualStack.stackSize == 0 || !items.remove(actualStack, stack.stackSize, true)) { + if (actualStack == null || actualStack.stackSize == 0 || !items.trackedRemove(actualStack, stack.stackSize, true)) { + items.undo(); return false; } } - + items.undo(); return true; } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStepCraft.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStepCraft.java index d59e70ab4..91e69caaa 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStepCraft.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStepCraft.java @@ -27,31 +27,26 @@ public class CraftingStepCraft extends CraftingStep { @Override public boolean canStartProcessing(IItemStackList items, IFluidStackList fluids) { - // So we can edit the lists - items = items.copy(); - fluids = fluids.copy(); - // Clean the lists so the zero stacks aren't there - items.clean(); - fluids.clear(); - int compare = IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT | (pattern.isOredict() ? IComparer.COMPARE_OREDICT : 0); for (ItemStack stack : getToInsert()) { ItemStack actualStack = items.get(stack, compare); - if (actualStack == null || actualStack.stackSize == 0 || !items.remove(actualStack, stack.stackSize, true)) { + if (actualStack == null || actualStack.stackSize == 0 || !items.trackedRemove(actualStack, stack.stackSize, true)) { FluidStack fluidInItem = RSUtils.getFluidFromStack(stack, true); if (fluidInItem != null && RSUtils.hasFluidBucket(fluidInItem)) { FluidStack fluidStack = fluids.get(fluidInItem, compare); - if (fluidStack != null && fluids.remove(fluidStack, fluidInItem.amount, true)) { + if (fluidStack != null && fluids.trackedRemove(fluidStack, fluidInItem.amount, true)) { continue; } } - + items.undo(); + fluids.undo(); return false; } } - + items.undo(); + fluids.undo(); return true; } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingTask.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingTask.java index 529e0220a..2dacda389 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingTask.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingTask.java @@ -72,6 +72,7 @@ public class CraftingTask implements ICraftingTask { @Override public void calculate() { + // Copy here might be expensive but since it is only executed once it isn't a big impact IItemStackList networkList = network.getItemStorageCache().getList().copy(); networkList.clean(); // Remove the zero stacks IItemStackList toInsert = API.instance().createItemStackList(); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/FluidStackList.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/FluidStackList.java index 763854db3..21312e42b 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/FluidStackList.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/FluidStackList.java @@ -9,11 +9,13 @@ import net.minecraftforge.fluids.FluidStack; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Collection; +import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; public class FluidStackList implements IFluidStackList { private ArrayListMultimap stacks = ArrayListMultimap.create(); + private List removeTracker = new LinkedList<>(); @Override public void add(FluidStack stack) { @@ -46,6 +48,32 @@ public class FluidStackList implements IFluidStackList { return false; } + @Override + public boolean trackedRemove(@Nonnull FluidStack stack, int size, boolean removeIfReachedZero) { + for (FluidStack otherStack : stacks.get(stack.getFluid())) { + if (otherStack.amount > 0 && stack.isFluidEqual(otherStack)) { + FluidStack removed = new FluidStack(otherStack.getFluid(), Math.min(size, otherStack.amount)); + this.removeTracker.add(removed); + otherStack.amount -= size; + boolean success = otherStack.amount >= 0; + + if (otherStack.amount <= 0 && removeIfReachedZero) { + stacks.remove(otherStack.getFluid(), otherStack); + } + + return success; + } + } + + return false; + } + + @Override + public void undo() { + removeTracker.forEach(this::add); + removeTracker.clear(); + } + @Override @Nullable public FluidStack get(@Nonnull FluidStack stack, int flags) { diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/ItemStackList.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/ItemStackList.java index a5f62df9c..6f3dfa613 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/ItemStackList.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/ItemStackList.java @@ -6,15 +6,19 @@ import com.raoulvdberge.refinedstorage.api.util.IItemStackList; import com.raoulvdberge.refinedstorage.apiimpl.API; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraftforge.items.ItemHandlerHelper; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Collection; +import java.util.Deque; +import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; public class ItemStackList implements IItemStackList { private ArrayListMultimap stacks = ArrayListMultimap.create(); + private List removeTracker = new LinkedList<>(); @Override public void add(ItemStack stack) { @@ -36,7 +40,7 @@ public class ItemStackList implements IItemStackList { @Override public boolean remove(@Nonnull ItemStack stack, int size, boolean removeIfReachedZero) { for (ItemStack otherStack : stacks.get(stack.getItem())) { - if (API.instance().getComparer().isEqualNoQuantity(otherStack, stack)) { + if (otherStack.stackSize > 0 && API.instance().getComparer().isEqualNoQuantity(otherStack, stack)) { otherStack.stackSize -= size; boolean success = otherStack.stackSize >= 0; @@ -51,12 +55,38 @@ public class ItemStackList implements IItemStackList { return false; } + @Override + public boolean trackedRemove(@Nonnull ItemStack stack, int size, boolean removeIfReachedZero) { + for (ItemStack otherStack : stacks.get(stack.getItem())) { + if (otherStack.stackSize > 0 && API.instance().getComparer().isEqualNoQuantity(otherStack, stack)) { + ItemStack removed = ItemHandlerHelper.copyStackWithSize(otherStack, Math.min(size, otherStack.stackSize)); + this.removeTracker.add(removed); + otherStack.stackSize -= size; + boolean success = otherStack.stackSize >= 0; + + if (otherStack.stackSize <= 0 && removeIfReachedZero) { + stacks.remove(otherStack.getItem(), otherStack); + } + + return success; + } + } + + return false; + } + + @Override + public void undo() { + removeTracker.forEach(this::add); + removeTracker.clear(); + } + @Override @Nullable public ItemStack get(@Nonnull ItemStack stack, int flags) { // When the oredict flag is set all stacks need to be checked not just the ones matching the item for (ItemStack otherStack : (flags & IComparer.COMPARE_OREDICT) == IComparer.COMPARE_OREDICT ? stacks.values() : stacks.get(stack.getItem())) { - if (API.instance().getComparer().isEqual(otherStack, stack, flags)) { + if (otherStack.stackSize > 0 && API.instance().getComparer().isEqual(otherStack, stack, flags)) { return otherStack; } }