diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/task/ICraftingStep.java b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/task/ICraftingStep.java index eca72286c..e4976f9a5 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/task/ICraftingStep.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/task/ICraftingStep.java @@ -23,6 +23,11 @@ public interface ICraftingStep { */ List getToInsert(); + /** + * @return a list of steps the have to be done before this one can be started + */ + List getPreliminarySteps(); + /** * Check if the processing can start. * diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/registry/CraftingTaskFactory.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/registry/CraftingTaskFactory.java index e8635f45c..7eaa13a54 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/registry/CraftingTaskFactory.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/registry/CraftingTaskFactory.java @@ -39,18 +39,9 @@ public class CraftingTaskFactory implements ICraftingTaskFactory { for (int i = 0; i < stepsList.tagCount(); ++i) { NBTTagCompound stepTag = stepsList.getCompoundTagAt(i); - CraftingStep step = null; + ICraftingStep step = CraftingStep.toCraftingStep(stepTag, network); - switch (stepTag.getString(CraftingStep.NBT_CRAFTING_STEP_TYPE)) { - case CraftingStepCraft.ID: - step = new CraftingStepCraft(network); - break; - case CraftingStepProcess.ID: - step = new CraftingStepProcess(network); - break; - } - - if (step != null && step.readFromNBT(stepTag)) { + if (step != null) { steps.add(step); } } 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 d33c98fa4..23fec632a 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 @@ -11,8 +11,10 @@ import com.raoulvdberge.refinedstorage.api.util.IStackList; import com.raoulvdberge.refinedstorage.apiimpl.API; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; +import net.minecraftforge.common.util.Constants; import net.minecraftforge.fluids.FluidStack; import java.util.*; @@ -24,16 +26,19 @@ public abstract class CraftingStep implements ICraftingStep { private static final String NBT_PATTERN = "Pattern"; private static final String NBT_PATTERN_CONTAINER = "PatternContainer"; private static final String NBT_STARTED_PROCESSING = "StartedProcessing"; + private static final String NBT_PRELIMINARY_STEPS = "PreliminarySteps"; protected INetworkMaster network; protected ICraftingPattern pattern; protected Map satisfied; protected boolean startedProcessing; + protected List preliminarySteps; - public CraftingStep(INetworkMaster network, ICraftingPattern pattern) { + public CraftingStep(INetworkMaster network, ICraftingPattern pattern, List preliminarySteps) { this.network = network; this.pattern = pattern; this.satisfied = new HashMap<>(getPattern().getOutputs().size()); + this.preliminarySteps = new ArrayList<>(preliminarySteps); } public CraftingStep(INetworkMaster network) { @@ -61,6 +66,18 @@ public abstract class CraftingStep implements ICraftingStep { this.startedProcessing = tag.getBoolean(NBT_STARTED_PROCESSING); + NBTTagList preliminaryTagList = tag.getTagList(NBT_PRELIMINARY_STEPS, Constants.NBT.TAG_COMPOUND); + this.preliminarySteps = new LinkedList<>(); + for (int i = 0; i < preliminaryTagList.tagCount(); i++) { + NBTTagCompound stepTag = preliminaryTagList.getCompoundTagAt(i); + + ICraftingStep step = CraftingStep.toCraftingStep(stepTag, network); + + if (step != null) { + this.preliminarySteps.add(step); + } + } + return true; } } @@ -78,9 +95,14 @@ public abstract class CraftingStep implements ICraftingStep { return pattern.getInputs().stream().filter(Objects::nonNull).collect(Collectors.toList()); } + @Override + public List getPreliminarySteps() { + return preliminarySteps; + } + @Override public boolean canStartProcessing() { - return true; + return getPreliminarySteps().size() == 0; } @@ -154,6 +176,14 @@ public abstract class CraftingStep implements ICraftingStep { tag.setLong(NBT_PATTERN_CONTAINER, pattern.getContainer().getPosition().toLong()); tag.setBoolean(NBT_STARTED_PROCESSING, startedProcessing); + + NBTTagList preliminaryTagList = new NBTTagList(); + for (ICraftingStep step : preliminarySteps) { + preliminaryTagList.appendTag(step.writeToNBT(new NBTTagCompound())); + } + + tag.setTag(NBT_PRELIMINARY_STEPS, preliminaryTagList); + return tag; } @@ -212,4 +242,23 @@ public abstract class CraftingStep implements ICraftingStep { return true; } + + public static ICraftingStep toCraftingStep(NBTTagCompound compound, INetworkMaster network) { + CraftingStep step = null; + + switch (compound.getString(CraftingStep.NBT_CRAFTING_STEP_TYPE)) { + case CraftingStepCraft.ID: + step = new CraftingStepCraft(network); + break; + case CraftingStepProcess.ID: + step = new CraftingStepProcess(network); + break; + } + + if (step != null && step.readFromNBT(compound)) { + return step; + } + + return null; + } } 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 45b1adf28..f4dbd2226 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 @@ -1,6 +1,7 @@ package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; +import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingStep; import com.raoulvdberge.refinedstorage.api.network.INetworkMaster; import com.raoulvdberge.refinedstorage.api.util.IComparer; import com.raoulvdberge.refinedstorage.api.util.IStackList; @@ -21,8 +22,8 @@ public class CraftingStepCraft extends CraftingStep { private List toInsert; - public CraftingStepCraft(INetworkMaster network, ICraftingPattern pattern, List toInsert) { - super(network, pattern); + public CraftingStepCraft(INetworkMaster network, ICraftingPattern pattern, List toInsert, List preliminarySteps) { + super(network, pattern, preliminarySteps); this.toInsert = new LinkedList<>(); toInsert.forEach(stack -> this.toInsert.add(stack == null ? null : stack.copy())); } @@ -38,6 +39,9 @@ public class CraftingStepCraft extends CraftingStep { @Override public boolean canStartProcessing(IStackList items, IStackList fluids) { + if (!super.canStartProcessing()) { + return false; + } int compare = CraftingTask.DEFAULT_COMPARE | (pattern.isOredict() ? IComparer.COMPARE_OREDICT : 0); for (ItemStack stack : getToInsert()) { // This will be a tool, like a hammer @@ -77,13 +81,13 @@ public class CraftingStepCraft extends CraftingStep { } for (ItemStack output : outputs) { - if (output != null) { + if (output != null && !output.isEmpty()) { toInsertItems.add(output.copy()); } } for (ItemStack byproduct : (pattern.isOredict() ? pattern.getByproducts(took) : pattern.getByproducts())) { - if (byproduct != null) { + if (byproduct != null && !byproduct.isEmpty()) { toInsertItems.add(byproduct.copy()); } } @@ -113,7 +117,12 @@ public class CraftingStepCraft extends CraftingStep { NBTTagList toInsertList = tag.getTagList(NBT_TO_INSERT, Constants.NBT.TAG_COMPOUND); toInsert = new ArrayList<>(toInsertList.tagCount()); for (int i = 0; i < toInsertList.tagCount(); ++i) { - toInsert.add(new ItemStack(toInsertList.getCompoundTagAt(i))); + ItemStack stack = new ItemStack(toInsertList.getCompoundTagAt(i)); + if (stack.isEmpty()) { + toInsert.add(null); + } else { + toInsert.add(stack); + } } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStepProcess.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStepProcess.java index b4a5a83b1..4e228f75a 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStepProcess.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingStepProcess.java @@ -1,6 +1,7 @@ package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; +import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingStep; import com.raoulvdberge.refinedstorage.api.network.INetworkMaster; import com.raoulvdberge.refinedstorage.api.util.IComparer; import com.raoulvdberge.refinedstorage.api.util.IStackList; @@ -21,8 +22,8 @@ import java.util.stream.IntStream; public class CraftingStepProcess extends CraftingStep { public static final String ID = "process"; - public CraftingStepProcess(INetworkMaster network, ICraftingPattern pattern) { - super(network, pattern); + public CraftingStepProcess(INetworkMaster network, ICraftingPattern pattern, List preliminarySteps) { + super(network, pattern, preliminarySteps); } public CraftingStepProcess(INetworkMaster network) { @@ -31,6 +32,9 @@ public class CraftingStepProcess extends CraftingStep { @Override public boolean canStartProcessing(IStackList items, IStackList fluids) { + if (!super.canStartProcessing()) { + return false; + } IItemHandler inventory = getPattern().getContainer().getFacingInventory(); int compare = CraftingTask.DEFAULT_COMPARE | (pattern.isOredict() ? IComparer.COMPARE_OREDICT : 0); if (inventory != null) { @@ -66,6 +70,9 @@ public class CraftingStepProcess extends CraftingStep { @Override public boolean canStartProcessing() { + if (!super.canStartProcessing()) { + return false; + } IItemHandler inventory = getPattern().getContainer().getFacingInventory(); return inventory != null && insert(inventory, new LinkedList<>(getToInsert()), 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 b087d5ae8..d444e342c 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 @@ -42,7 +42,7 @@ public class CraftingTask implements ICraftingTask { private ItemStack requested; private ICraftingPattern pattern; private int quantity; - private List steps = new ArrayList<>(); + private List mainSteps = new LinkedList<>(); private IStackList toTake = API.instance().createItemStackList(); private IStackList toCraft = API.instance().createItemStackList(); private IStackList missing = API.instance().createItemStackList(); @@ -59,9 +59,9 @@ public class CraftingTask implements ICraftingTask { this.quantity = quantity; } - public CraftingTask(INetworkMaster network, @Nullable ItemStack requested, ICraftingPattern pattern, int quantity, List steps, Deque toInsertItems, IStackList toTakeFluids, Deque toInsertFluids) { + public CraftingTask(INetworkMaster network, @Nullable ItemStack requested, ICraftingPattern pattern, int quantity, List mainSteps, Deque toInsertItems, IStackList toTakeFluids, Deque toInsertFluids) { this(network, requested, pattern, quantity); - this.steps = steps; + this.mainSteps = mainSteps; this.toInsertItems = toInsertItems; this.toTakeFluids = toTakeFluids; this.toInsertFluids = toInsertFluids; @@ -82,17 +82,17 @@ public class CraftingTask implements ICraftingTask { int quantity = this.quantity; while (quantity > 0 && !recurseFound) { - calculate(networkList, networkFluidList, pattern, toInsert); + mainSteps.add(calculate(networkList, networkFluidList, pattern, toInsert)); quantity -= pattern.getQuantityPerRequest(requested); } usedPatterns.clear(); } - private void calculate(IStackList networkList, IStackList networkFluidList, ICraftingPattern pattern, IStackList toInsert) { + private ICraftingStep calculate(IStackList networkList, IStackList networkFluidList, ICraftingPattern pattern, IStackList toInsert) { recurseFound |= !usedPatterns.add(pattern); if (recurseFound) { - return; + return null; } int compare = DEFAULT_COMPARE | (pattern.isOredict() ? IComparer.COMPARE_OREDICT : 0); @@ -100,6 +100,7 @@ public class CraftingTask implements ICraftingTask { IStackList inputs = API.instance().createItemStackList(); IStackList actualInputs = API.instance().createItemStackList(); List usedStacks = new LinkedList<>(); + List previousSteps = new LinkedList<>(); for (List oreInputs : pattern.getOreInputs()) { boolean added = false; @@ -145,7 +146,7 @@ public class CraftingTask implements ICraftingTask { // The needed amount is the actual needed amount of extraStacks + the needed input (twice so you can keep repeating it) long needed = (networkStack == null ? 0 : -networkStack.getCount()) + input.getCount() + inputPattern.getInputs().stream().filter(s -> API.instance().getComparer().isEqual(s, input, lambdaCompare)).count() * 2; do { - calculate(networkList, networkFluidList, inputPattern, toInsert); + previousSteps.add(calculate(networkList, networkFluidList, inputPattern, toInsert)); toCraft.add(ItemHandlerHelper.copyStackWithSize(input, craftQuantity)); extraStack = toInsert.get(input, compare); } while (extraStack != null && extraStack.getCount() < needed); @@ -187,7 +188,7 @@ public class CraftingTask implements ICraftingTask { ItemStack inputCrafted = ItemHandlerHelper.copyStackWithSize(actualCraft, craftQuantity); toCraft.add(inputCrafted.copy()); actualInputs.add(inputCrafted.copy()); - calculate(networkList, networkFluidList, inputPattern, toInsert); + previousSteps.add(calculate(networkList, networkFluidList, inputPattern, toInsert)); input.shrink(craftQuantity); if (!recurseFound) { // Calculate added all the crafted outputs toInsert @@ -198,7 +199,7 @@ public class CraftingTask implements ICraftingTask { } else { // Fluid checks are with a stack size of one ItemStack fluidCheck = ItemHandlerHelper.copyStackWithSize(input, 1); - while (input.getCount() > 0 && doFluidCalculation(networkList, networkFluidList, fluidCheck, toInsert)) { + while (input.getCount() > 0 && doFluidCalculation(networkList, networkFluidList, fluidCheck, toInsert, previousSteps)) { actualInputs.add(fluidCheck); input.shrink(1); } @@ -213,12 +214,6 @@ public class CraftingTask implements ICraftingTask { } } - if (pattern.isProcessing()) { - steps.add(new CraftingStepProcess(network, pattern)); - } else { - steps.add(new CraftingStepCraft(network, pattern, usedStacks)); - } - ItemStack[] took = null; if (missing.isEmpty()) { if (!pattern.isProcessing()) { @@ -232,17 +227,23 @@ public class CraftingTask implements ICraftingTask { } for (ItemStack output : outputs) { - toInsert.add(output.copy()); + if (output != null && !output.isEmpty()) { + toInsert.add(output.copy()); + } } for (ItemStack byproduct : (!pattern.isProcessing() && pattern.isOredict() && missing.isEmpty() ? pattern.getByproducts(took) : pattern.getByproducts())) { - toInsert.add(byproduct.copy()); + if (byproduct != null && !byproduct.isEmpty()) { + toInsert.add(byproduct.copy()); + } } usedPatterns.remove(pattern); + + return pattern.isProcessing() ? new CraftingStepProcess(network, pattern, previousSteps) : new CraftingStepCraft(network, pattern, usedStacks, previousSteps); } - private boolean doFluidCalculation(IStackList networkList, IStackList networkFluidList, ItemStack input, IStackList toInsert) { + private boolean doFluidCalculation(IStackList networkList, IStackList networkFluidList, ItemStack input, IStackList toInsert, List previousSteps) { FluidStack fluidInItem = RSUtils.getFluidFromStack(input, true).getValue(); if (fluidInItem != null && RSUtils.hasFluidBucket(fluidInItem)) { @@ -270,7 +271,7 @@ public class CraftingTask implements ICraftingTask { missing.add(RSUtils.EMPTY_BUCKET.copy()); } else { toCraft.add(RSUtils.EMPTY_BUCKET.copy()); - calculate(networkList, networkFluidList, bucketPattern, toInsert); + previousSteps.add(calculate(networkList, networkFluidList, bucketPattern, toInsert)); toInsert.remove(RSUtils.EMPTY_BUCKET, 1); } } @@ -304,7 +305,7 @@ public class CraftingTask implements ICraftingTask { "\n, toCraft=" + toCraft + "\n, toInsertItems=" + toInsertItems + "\n, toInsertFluids=" + toInsertFluids + - "\n, steps=" + steps + + "\n, mainSteps=" + mainSteps + '}'; } @@ -325,7 +326,20 @@ public class CraftingTask implements ICraftingTask { return false; } - for (ICraftingStep step : steps) { + // Collect all leaf steps + List leafSteps = new LinkedList<>(); + Queue steps = new LinkedList<>(); + steps.addAll(mainSteps); + while (steps.size() > 0) { + ICraftingStep step = steps.poll(); + if (step.getPreliminarySteps().size() > 0) { + steps.addAll(step.getPreliminarySteps()); + } else { + leafSteps.add(step); + } + } + + for (ICraftingStep step : leafSteps) { ICraftingPatternContainer container = step.getPattern().getContainer(); Integer timesUsed = usedContainers.get(container); @@ -356,23 +370,30 @@ public class CraftingTask implements ICraftingTask { } } - if (steps.stream().filter(ICraftingStep::hasStartedProcessing).count() == 0) { + if (getSteps().stream().filter(ICraftingStep::hasStartedProcessing).count() == 0) { // When there is no started processes, restart the task. reschedule(); } // Remove finished tasks - steps.removeIf(ICraftingStep::hasReceivedOutputs); + steps.clear(); // Re use Queue from earlier + mainSteps.removeIf(ICraftingStep::hasReceivedOutputs); + steps.addAll(mainSteps); + while (steps.size() > 0) { + ICraftingStep step = steps.poll(); + step.getPreliminarySteps().removeIf(ICraftingStep::hasReceivedOutputs); + steps.addAll(step.getPreliminarySteps()); + } return isFinished(); } @Override public void reschedule() { - List mainSteps = steps.stream().filter(s -> s.getPattern() == pattern).collect(Collectors.toList()); + List mainSteps = this.mainSteps.stream().filter(s -> s.getPattern() == pattern).collect(Collectors.toList()); missing.clear(); - steps.clear(); - // if the list of main steps is empty there is no point in rescheduling + this.mainSteps.clear(); + // if the list of main mainSteps is empty there is no point in rescheduling if (!mainSteps.isEmpty()) { quantity = 0; int quantityPerRequest = pattern.getQuantityPerRequest(requested); @@ -403,7 +424,7 @@ public class CraftingTask implements ICraftingTask { NBTTagList stepsList = new NBTTagList(); - for (ICraftingStep step : steps) { + for (ICraftingStep step : mainSteps) { stepsList.appendTag(step.writeToNBT(new NBTTagCompound())); } @@ -472,13 +493,13 @@ public class CraftingTask implements ICraftingTask { } if (!isFinished()) { - if (steps.stream().filter(s -> !s.getPattern().isProcessing()).count() > 0) { + if (getSteps().stream().filter(s -> !s.getPattern().isProcessing()).count() > 0) { elements.directAdd(new CraftingMonitorElementText("gui.refinedstorage:crafting_monitor.items_crafting", 16)); IStackList oreDictPrepped = network.getItemStorageCache().getList().getOredicted(); IStackList networkFluids = network.getFluidStorageCache().getList(); - for (ICraftingStep step : steps.stream().filter(s -> !s.getPattern().isProcessing()).collect(Collectors.toList())) { + for (ICraftingStep step : getSteps().stream().filter(s -> !s.getPattern().isProcessing()).collect(Collectors.toList())) { for (int i = 0; i < step.getPattern().getOutputs().size(); ++i) { ICraftingMonitorElement element = new CraftingMonitorElementItemRender( -1, @@ -498,10 +519,10 @@ public class CraftingTask implements ICraftingTask { elements.commit(); } - if (steps.stream().filter(s -> s.getPattern().isProcessing()).count() > 0) { + if (getSteps().stream().filter(s -> s.getPattern().isProcessing()).count() > 0) { elements.directAdd(new CraftingMonitorElementText("gui.refinedstorage:crafting_monitor.items_processing", 16)); - for (ICraftingStep step : steps.stream().filter(s -> s.getPattern().isProcessing()).collect(Collectors.toList())) { + for (ICraftingStep step : getSteps().stream().filter(s -> s.getPattern().isProcessing()).collect(Collectors.toList())) { for (int i = 0; i < step.getPattern().getOutputs().size(); ++i) { ICraftingMonitorElement element = new CraftingMonitorElementItemRender( -1, @@ -533,7 +554,15 @@ public class CraftingTask implements ICraftingTask { } public List getSteps() { - return steps; + List allSteps = new LinkedList<>(); + Queue steps = new LinkedList<>(); + steps.addAll(mainSteps); + while (steps.size() > 0) { + ICraftingStep step = steps.poll(); + allSteps.add(step); + steps.addAll(step.getPreliminarySteps()); + } + return allSteps; } @Override @@ -593,6 +622,6 @@ public class CraftingTask implements ICraftingTask { } private boolean isFinished() { - return steps.stream().allMatch(ICraftingStep::hasReceivedOutputs); + return mainSteps.stream().allMatch(ICraftingStep::hasReceivedOutputs); } }