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 5da5d3687..4e886c59e 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 @@ -19,9 +19,9 @@ public interface ICraftingStep { ICraftingPattern getPattern(); /** - * @return the stacks to insert + * @return the input stacks */ - List getToInsert(); + List getInputs(); /** * @return a list of steps the have to be done before this one can be started diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/CraftingPattern.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/CraftingPattern.java index 5884861b7..77a8e4ed6 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/CraftingPattern.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/CraftingPattern.java @@ -55,6 +55,7 @@ public class CraftingPattern implements ICraftingPattern { for (IRecipe r : CraftingManager.REGISTRY) { if (r.matches(inv, world)) { recipe = r; + break; } } @@ -86,7 +87,7 @@ public class CraftingPattern implements ICraftingPattern { } for (ItemStack remaining : recipe.getRemainingItems(inv)) { - if (remaining != null) { + if (!remaining.isEmpty()) { ItemStack cleaned = Comparer.stripTags(remaining.copy()); byproducts.add(cleaned); } @@ -94,34 +95,34 @@ public class CraftingPattern implements ICraftingPattern { } } } else { - outputs = ItemPattern.getOutputs(stack).stream().collect(Collectors.toList()); - } + outputs = ItemPattern.getOutputs(stack); - if (oreInputs.isEmpty()) { - for (ItemStack input : inputs) { - if (input == null) { - oreInputs.add(Collections.emptyList()); - } else if (!input.isEmpty()) { - int[] ids = OreDictionary.getOreIDs(input); - if (ids == null || ids.length == 0) { - oreInputs.add(Collections.singletonList(Comparer.stripTags(input))); - } else if (isOredict()) { - List oredict = Arrays.stream(ids) - .mapToObj(OreDictionary::getOreName) - .map(OreDictionary::getOres) - .flatMap(List::stream) - .map(ItemStack::copy) - .map(Comparer::stripTags) - .map(s -> { - s.setCount(input.getCount()); - return s; - }) - .collect(Collectors.toList()); - // Add original stack as first, should prevent some issues - oredict.add(0, Comparer.stripTags(input.copy())); - oreInputs.add(oredict); - } else { - oreInputs.add(Collections.singletonList(Comparer.stripTags(input))); + if (oreInputs.isEmpty()) { + for (ItemStack input : inputs) { + if (input == null) { + oreInputs.add(Collections.emptyList()); + } else if (!input.isEmpty()) { + int[] ids = OreDictionary.getOreIDs(input); + + if (ids.length == 0) { + oreInputs.add(Collections.singletonList(Comparer.stripTags(input))); + } else if (isOredict()) { + List oredict = Arrays.stream(ids) + .mapToObj(OreDictionary::getOreName) + .map(OreDictionary::getOres) + .flatMap(List::stream) + .map(ItemStack::copy) + .map(Comparer::stripTags) + .peek(s -> s.setCount(input.getCount())) + .collect(Collectors.toList()); + + // Add original stack as first, should prevent some issues + oredict.add(0, Comparer.stripTags(input.copy())); + + oreInputs.add(oredict); + } else { + oreInputs.add(Collections.singletonList(Comparer.stripTags(input))); + } } } } @@ -218,7 +219,7 @@ public class CraftingPattern implements ICraftingPattern { } for (ItemStack remaining : recipe.getRemainingItems(inv)) { - if (remaining != null) { + if (!remaining.isEmpty()) { byproducts.add(remaining.copy()); } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/preview/CraftingPreviewElementFluidStack.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/preview/CraftingPreviewElementFluidStack.java index 7005874c2..238f2d54c 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/preview/CraftingPreviewElementFluidStack.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/preview/CraftingPreviewElementFluidStack.java @@ -20,8 +20,8 @@ public class CraftingPreviewElementFluidStack implements ICraftingPreviewElement private FluidStack stack; private int available; private boolean missing; + // If missing is true then toCraft is the missing amount private int toCraft; - // if missing is true then toCraft is the missing amount public CraftingPreviewElementFluidStack(FluidStack stack) { this.stack = stack.copy(); @@ -65,8 +65,10 @@ public class CraftingPreviewElementFluidStack implements ICraftingPreviewElement if (missing) { drawers.getOverlayDrawer().draw(x, y, 0xFFF2DEDE); } + x += 5; y += 7; + drawers.getFluidDrawer().draw(x, y, getElement()); float scale = drawers.getFontRenderer().getUnicodeFlag() ? 1F : 0.5F; diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/preview/CraftingPreviewElementItemStack.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/preview/CraftingPreviewElementItemStack.java index f39edb248..8d43abb28 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/preview/CraftingPreviewElementItemStack.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/preview/CraftingPreviewElementItemStack.java @@ -20,8 +20,8 @@ public class CraftingPreviewElementItemStack implements ICraftingPreviewElement< private ItemStack stack; private int available; private boolean missing; + // If missing is true then toCraft is the missing amount private int toCraft; - // if missing is true then toCraft is the missing amount public CraftingPreviewElementItemStack(ItemStack stack) { this.stack = ItemHandlerHelper.copyStackWithSize(stack, 1); @@ -54,6 +54,7 @@ public class CraftingPreviewElementItemStack implements ICraftingPreviewElement< ItemStack stack = new ItemStack(item, 1, meta); stack.setTagCompound(tag); + return new CraftingPreviewElementItemStack(stack, available, missing, toCraft); } 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 4466ed886..d8ae9909e 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 @@ -21,6 +21,7 @@ import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; +import javax.annotation.Nullable; import java.util.*; import java.util.stream.Collectors; @@ -34,7 +35,9 @@ public abstract class CraftingStep implements ICraftingStep { protected INetwork network; protected ICraftingPattern pattern; + protected Map satisfied; + protected boolean startedProcessing; protected List preliminarySteps; @@ -57,12 +60,14 @@ public abstract class CraftingStep implements ICraftingStep { if (container instanceof INetworkNodeProxy) { INetworkNodeProxy proxy = (INetworkNodeProxy) container; + if (proxy.getNode() instanceof ICraftingPatternContainer) { this.pattern = ((ICraftingPatternProvider) patternStack.getItem()).create(network.world(), patternStack, (ICraftingPatternContainer) proxy.getNode()); this.satisfied = new HashMap<>(pattern.getOutputs().size()); for (ItemStack stack : pattern.getOutputs()) { int hashcode = API.instance().getItemStackHashCode(stack); + String id = String.format(NBT_SATISFIED, hashcode); if (tag.hasKey(id)) { @@ -73,7 +78,9 @@ 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); @@ -98,7 +105,7 @@ public abstract class CraftingStep implements ICraftingStep { } @Override - public List getToInsert() { + public List getInputs() { return pattern.getInputs().stream().filter(Objects::nonNull).collect(Collectors.toList()); } @@ -112,7 +119,6 @@ public abstract class CraftingStep implements ICraftingStep { return getPreliminarySteps().size() == 0; } - @Override public void setStartedProcessing() { if (getPattern().isBlocking()) { @@ -131,6 +137,7 @@ public abstract class CraftingStep implements ICraftingStep { public boolean hasReceivedOutputs() { for (ItemStack stack : pattern.getOutputs()) { Integer received = satisfied.get(API.instance().getItemStackHashCode(stack)); + if (received == null || stack.getCount() > received) { return false; } @@ -145,34 +152,40 @@ public abstract class CraftingStep implements ICraftingStep { @Override public boolean hasReceivedOutput(ItemStack stack) { - Integer received = satisfied.get(API.instance().getItemStackHashCode(stack)); - return received != null && received >= stack.getCount(); + return getReceivedOutput(stack) >= stack.getCount(); } @Override public int getReceivedOutput(ItemStack stack) { Integer received = satisfied.get(API.instance().getItemStackHashCode(stack)); + return received == null ? 0 : received; } @Override public boolean onReceiveOutput(ItemStack stack) { ItemStack compareStack = Comparer.stripTags(stack.copy()); + for (ItemStack output : pattern.getOutputs()) { - int hashcode = API.instance().getItemStackHashCode(output); - Integer received = satisfied.get(hashcode); + int hash = API.instance().getItemStackHashCode(output); + + Integer received = satisfied.get(hash); + if (received == null) { received = 0; } + if (API.instance().getComparer().isEqual(compareStack, output, CraftingTask.DEFAULT_COMPARE | (getPattern().isOredict() ? IComparer.COMPARE_OREDICT : 0))) { if (received < output.getCount()) { int toReceive = Math.min(output.getCount() - received, stack.getCount()); - satisfied.put(hashcode, received + toReceive); + + satisfied.put(hash, received + toReceive); + stack.shrink(toReceive); network.markCraftingMonitorForUpdate(); - if (stack.getCount() == 0) { + if (stack.isEmpty()) { return true; } } @@ -207,6 +220,7 @@ public abstract class CraftingStep implements ICraftingStep { ITEM, FLUID } + @Nullable protected AvailableType isItemAvailable(IStackList items, IStackList fluids, ItemStack stack, ItemStack actualStack, int compare) { if (actualStack == null || actualStack.isEmpty() || !items.trackedRemove(actualStack, stack.getCount())) { FluidStack fluidInItem; @@ -214,56 +228,69 @@ public abstract class CraftingStep implements ICraftingStep { if (API.instance().getComparer().isEqual(stack, StackUtils.WATER_BOTTLE)) { FluidStack fluidStack = fluids.get(new FluidStack(FluidRegistry.WATER, Fluid.BUCKET_VOLUME), compare); ItemStack emptyBottle = items.get(StackUtils.EMPTY_BOTTLE, compare); + if (emptyBottle != null && fluidStack != null && !emptyBottle.isEmpty() && items.trackedRemove(StackUtils.EMPTY_BOTTLE, 1)) { return AvailableType.FLUID; } } else if ((fluidInItem = StackUtils.getFluid(stack, true).getValue()) != null && StackUtils.hasFluidBucket(fluidInItem)) { FluidStack fluidStack = fluids.get(fluidInItem, compare); ItemStack bucket = items.get(StackUtils.EMPTY_BUCKET, compare); + if (bucket != null && fluidStack != null && !bucket.isEmpty() && fluids.trackedRemove(fluidStack, fluidInItem.amount) && items.trackedRemove(bucket, 1)) { return AvailableType.FLUID; } } + return null; } + return AvailableType.ITEM; } - protected boolean extractItems(List actualInputs, int compare, Deque toInsertItems) { - for (ItemStack insertStack : getToInsert()) { + protected boolean extractItems(List extractedItems, int compare, Deque toInsertItems) { + for (ItemStack input : getInputs()) { // This will be a tool, like a hammer - if (insertStack.isItemStackDamageable()) { + if (input.isItemStackDamageable()) { compare &= ~IComparer.COMPARE_DAMAGE; } else { compare |= IComparer.COMPARE_DAMAGE; } - ItemStack input = network.extractItem(insertStack, insertStack.getCount(), compare, false); - if (input != null) { - actualInputs.add(input); + ItemStack extracted = network.extractItem(input, input.getCount(), compare, false); + + if (extracted != null) { + extractedItems.add(extracted); } else { boolean abort = true; + FluidStack fluidInItem; - if (API.instance().getComparer().isEqual(insertStack, StackUtils.WATER_BOTTLE)) { + + if (API.instance().getComparer().isEqual(input, StackUtils.WATER_BOTTLE)) { FluidStack fluidStack = network.extractFluid(new FluidStack(FluidRegistry.WATER, Fluid.BUCKET_VOLUME), Fluid.BUCKET_VOLUME, compare, true); // Simulate is true because we won't actually get the fluid out of the storage for bottles! ItemStack emptyBottleStack = network.extractItem(StackUtils.EMPTY_BOTTLE, 1, compare, false); + if (fluidStack != null && fluidStack.amount == Fluid.BUCKET_VOLUME && emptyBottleStack != null) { abort = false; - actualInputs.add(insertStack.copy()); + + extractedItems.add(input.copy()); } - } else if ((fluidInItem = StackUtils.getFluid(insertStack, true).getValue()) != null) { + } else if ((fluidInItem = StackUtils.getFluid(input, true).getValue()) != null) { FluidStack fluidStack = network.extractFluid(fluidInItem, fluidInItem.amount, compare, false); ItemStack bucketStack = network.extractItem(StackUtils.EMPTY_BUCKET, 1, compare, false); + if (fluidStack != null && fluidStack.amount == fluidInItem.amount && bucketStack != null) { abort = false; - actualInputs.add(insertStack.copy()); + + extractedItems.add(input.copy()); } } if (abort) { // Abort task re-insert taken stacks and reset state - toInsertItems.addAll(actualInputs); + toInsertItems.addAll(extractedItems); + startedProcessing = false; + return false; } } @@ -272,10 +299,11 @@ public abstract class CraftingStep implements ICraftingStep { return true; } - public static ICraftingStep toCraftingStep(NBTTagCompound compound, INetwork network) { + @Nullable + public static ICraftingStep toCraftingStep(NBTTagCompound tag, INetwork network) { CraftingStep step = null; - switch (compound.getString(CraftingStep.NBT_CRAFTING_STEP_TYPE)) { + switch (tag.getString(CraftingStep.NBT_CRAFTING_STEP_TYPE)) { case CraftingStepCraft.ID: step = new CraftingStepCraft(network); break; @@ -284,7 +312,7 @@ public abstract class CraftingStep implements ICraftingStep { break; } - if (step != null && step.readFromNBT(compound)) { + if (step != null && step.readFromNBT(tag)) { return step; } 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 75ea76c3c..d42631ec0 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 @@ -20,12 +20,16 @@ public class CraftingStepCraft extends CraftingStep { public static final String ID = "craft"; private static final String NBT_TO_INSERT = "ToInsert"; - private List toInsert; + private List inputs; - public CraftingStepCraft(INetwork network, ICraftingPattern pattern, List toInsert, List preliminarySteps) { + public CraftingStepCraft(INetwork network, ICraftingPattern pattern, List inputs, List preliminarySteps) { super(network, pattern, preliminarySteps); - this.toInsert = new LinkedList<>(); - toInsert.forEach(stack -> this.toInsert.add(stack == null ? null : stack.copy())); + + this.inputs = new LinkedList<>(); + + for (ItemStack input : inputs) { + this.inputs.add(input == null ? null : input.copy()); + } } public CraftingStepCraft(INetwork network) { @@ -33,8 +37,8 @@ public class CraftingStepCraft extends CraftingStep { } @Override - public List getToInsert() { - return toInsert == null ? super.getToInsert() : toInsert.stream().filter(Objects::nonNull).collect(Collectors.toList()); + public List getInputs() { + return inputs == null ? super.getInputs() : inputs.stream().filter(Objects::nonNull).collect(Collectors.toList()); } @Override @@ -42,8 +46,10 @@ public class CraftingStepCraft extends CraftingStep { if (!super.canStartProcessing()) { return false; } + int compare = CraftingTask.DEFAULT_COMPARE; - for (ItemStack stack : getToInsert()) { + + for (ItemStack stack : getInputs()) { // This will be a tool, like a hammer if (stack.isItemStackDamageable()) { compare &= ~IComparer.COMPARE_DAMAGE; @@ -52,30 +58,38 @@ public class CraftingStepCraft extends CraftingStep { } ItemStack actualStack = items.get(stack, compare); + if (isItemAvailable(items, fluids, stack, actualStack, compare) == null) { items.undo(); fluids.undo(); + return false; } } + items.undo(); fluids.undo(); + return true; } @Override public void execute(Deque toInsertItems, Deque toInsertFluids) { - List actualInputs = new LinkedList<>(); - if (extractItems(actualInputs, CraftingTask.DEFAULT_COMPARE, toInsertItems)) { - IStackList stackList = API.instance().createItemStackList(); - actualInputs.forEach(stackList::add); + List extracted = new LinkedList<>(); - ItemStack[] took = StackListItem.toCraftingGrid(stackList, toInsert, CraftingTask.DEFAULT_COMPARE | (pattern.isOredict() ? IComparer.COMPARE_OREDICT : 0)); + if (extractItems(extracted, CraftingTask.DEFAULT_COMPARE, toInsertItems)) { + IStackList extractedStacks = API.instance().createItemStackList(); + + extracted.forEach(extractedStacks::add); + + ItemStack[] took = StackListItem.toCraftingGrid(extractedStacks, inputs, CraftingTask.DEFAULT_COMPARE | (pattern.isOredict() ? IComparer.COMPARE_OREDICT : 0)); List outputs = pattern.isOredict() ? pattern.getOutputs(took) : pattern.getOutputs(); if (outputs == null) { - toInsertItems.addAll(actualInputs); + toInsertItems.addAll(extracted); + startedProcessing = false; + return; } @@ -103,7 +117,7 @@ public class CraftingStepCraft extends CraftingStep { NBTTagList toInsertList = new NBTTagList(); - for (ItemStack insert : toInsert) { + for (ItemStack insert : inputs) { toInsertList.appendTag(insert == null ? new NBTTagCompound() : insert.serializeNBT()); } @@ -117,13 +131,16 @@ public class CraftingStepCraft extends CraftingStep { if (super.readFromNBT(tag)) { if (tag.hasKey(NBT_TO_INSERT)) { NBTTagList toInsertList = tag.getTagList(NBT_TO_INSERT, Constants.NBT.TAG_COMPOUND); - toInsert = new ArrayList<>(toInsertList.tagCount()); + + inputs = new ArrayList<>(toInsertList.tagCount()); + for (int i = 0; i < toInsertList.tagCount(); ++i) { ItemStack stack = new ItemStack(toInsertList.getCompoundTagAt(i)); + if (stack.isEmpty()) { - toInsert.add(null); + inputs.add(null); } else { - toInsert.add(stack); + inputs.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 a266f1fc8..12c2401bb 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 @@ -34,11 +34,15 @@ public class CraftingStepProcess extends CraftingStep { if (!super.canStartProcessing()) { return false; } + IItemHandler inventory = getPattern().getContainer().getFacingInventory(); + int compare = CraftingTask.DEFAULT_COMPARE | (pattern.isOredict() ? IComparer.COMPARE_OREDICT : 0); + if (inventory != null) { Deque toInsert = new LinkedList<>(); - for (ItemStack stack : getToInsert()) { + + for (ItemStack stack : getInputs()) { // This will be a tool, like a hammer if (stack.isItemStackDamageable()) { compare &= ~IComparer.COMPARE_DAMAGE; @@ -56,14 +60,17 @@ public class CraftingStepProcess extends CraftingStep { } else { items.undo(); fluids.undo(); + return false; } } items.undo(); fluids.undo(); - return insert(inventory, toInsert, true); + + return insertItems(inventory, toInsert, true); } + return false; } @@ -72,21 +79,26 @@ public class CraftingStepProcess extends CraftingStep { if (!super.canStartProcessing()) { return false; } + IItemHandler inventory = getPattern().getContainer().getFacingInventory(); - return inventory != null && insert(inventory, new LinkedList<>(getToInsert()), true); + + return inventory != null && insertItems(inventory, new LinkedList<>(getInputs()), true); } @Override public void execute(Deque toInsertItems, Deque toInsertFluids) { - LinkedList actualInputs = new LinkedList<>(); + LinkedList extracted = new LinkedList<>(); + int compare = CraftingTask.DEFAULT_COMPARE | (getPattern().isOredict() ? IComparer.COMPARE_OREDICT : 0); - if (extractItems(actualInputs, compare, toInsertItems)) { + + if (extractItems(extracted, compare, toInsertItems)) { IItemHandler inventory = getPattern().getContainer().getFacingInventory(); - if (insert(inventory, new ArrayDeque<>(actualInputs), true)) { - insert(inventory, actualInputs, false); + + if (insertItems(inventory, new ArrayDeque<>(extracted), true)) { + insertItems(inventory, extracted, false); } else { // Something went wrong here, redo! - toInsertItems.addAll(actualInputs); + toInsertItems.addAll(extracted); startedProcessing = false; } } @@ -99,26 +111,23 @@ public class CraftingStepProcess extends CraftingStep { return super.writeToNBT(tag); } - /** - * Insert or simulate insertion of {@link ItemStack}s into an {@link IItemHandler} - * - * @param dest target {@link IItemHandler} - * @param stacks a {@link Deque} of {@link ItemStack}s - * @param simulate simulate or actually insert the {@link ItemStack}s - * @return true when all can be inserted, false otherwise - */ - private static boolean insert(IItemHandler dest, Deque stacks, boolean simulate) { + private static boolean insertItems(IItemHandler inventory, Deque stacks, boolean simulate) { ItemStack current = stacks.poll(); - List availableSlots = IntStream.range(0, dest.getSlots()).boxed().collect(Collectors.toList()); + + List availableSlots = IntStream.range(0, inventory.getSlots()).boxed().collect(Collectors.toList()); + while (current != null && !availableSlots.isEmpty()) { ItemStack remainder = null; + for (Integer slot : availableSlots) { - remainder = dest.insertItem(slot, current, simulate); + remainder = inventory.insertItem(slot, current, simulate); + if (remainder.isEmpty() || current.getCount() != remainder.getCount()) { availableSlots.remove(slot); break; } } + if (remainder == null || remainder.isEmpty()) { current = stacks.poll(); } else if (current.getCount() == remainder.getCount()) { @@ -127,6 +136,7 @@ public class CraftingStepProcess extends CraftingStep { current = remainder; } } + return current == null && stacks.isEmpty(); } } 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 12ad092fe..69e35a120 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 @@ -46,14 +46,19 @@ public class CraftingTask implements ICraftingTask { private ItemStack requested; private ICraftingPattern pattern; private ICraftingPatternChain chain; + private int quantity; private boolean automated; + private List mainSteps = new LinkedList<>(); + private IStackList toTake = API.instance().createItemStackList(); private IStackList toCraft = API.instance().createItemStackList(); private IStackList missing = API.instance().createItemStackList(); + private Set usedPatterns = new HashSet<>(); private boolean recurseFound = false; + private Deque toInsertItems = new ArrayDeque<>(); private Deque toInsertFluids = new ArrayDeque<>(); private IStackList toTakeFluids = API.instance().createFluidStackList(); @@ -87,10 +92,13 @@ public class CraftingTask implements ICraftingTask { IStackList networkList = network.getItemStorageCache().getList().copy(); networkList.clean(); // Remove the zero stacks networkList = networkList.getOredicted(); + IStackList networkFluidList = network.getFluidStorageCache().getList().copy(); + IStackList toInsert = API.instance().createItemStackList(); ItemStack requested = this.requested != null ? this.requested : pattern.getOutputs().get(0); + toCraft.add(ItemHandlerHelper.copyStackWithSize(requested, quantity)); int quantity = this.quantity; @@ -98,14 +106,17 @@ public class CraftingTask implements ICraftingTask { ICraftingPattern currentPattern; while (quantity > 0 && !recurseFound) { currentPattern = this.chain == null ? this.pattern : this.chain.cycle(); + mainSteps.add(calculate(networkList, networkFluidList, currentPattern, toInsert)); + quantity -= currentPattern.getQuantityPerRequest(requested); } usedPatterns.clear(); } - private ICraftingStep calculate(IStackList networkList, IStackList networkFluidList, ICraftingPattern pattern, IStackList toInsert) { + @Nullable + private ICraftingStep calculate(IStackList networkItems, IStackList networkFluids, ICraftingPattern pattern, IStackList toInsert) { recurseFound |= !usedPatterns.add(pattern); if (recurseFound) { return null; @@ -118,7 +129,7 @@ public class CraftingTask implements ICraftingTask { List previousSteps = new LinkedList<>(); IStackList byproductList = API.instance().createItemStackList(); - pattern.getByproducts().stream().filter(Objects::nonNull).forEach(byproductList::add); + pattern.getByproducts().stream().filter(s -> !s.isEmpty()).forEach(byproductList::add); for (List inputs : pattern.getOreInputs()) { if (inputs == null || inputs.isEmpty()) { @@ -130,6 +141,7 @@ public class CraftingTask implements ICraftingTask { ItemStack input, extraStack, networkStack; do { input = inputs.get(i).copy(); + // This will be a tool, like a hammer if (input.isItemStackDamageable()) { compare &= ~IComparer.COMPARE_DAMAGE; @@ -138,12 +150,15 @@ public class CraftingTask implements ICraftingTask { } extraStack = toInsert.get(input, compare); - networkStack = networkList.get(input, compare); + networkStack = networkItems.get(input, compare); } while (extraStack == null && networkStack == null && ++i < inputs.size() && !network.getCraftingManager().hasPattern(input, compare)); + + // Stack not found, just take first if (i == inputs.size()) { input = inputs.get(0).copy(); } + usedStacks.add(input.copy()); // This will be a tool, like a hammer @@ -157,16 +172,20 @@ public class CraftingTask implements ICraftingTask { final int lambdaCompare = compare; final ItemStack lambdaInput = input; ICraftingPattern inputPattern = null; + int available = (extraStack == null ? 0 : extraStack.getCount()) + (networkStack == null ? 0 : networkStack.getCount()); + if (available < input.getCount()) { - inputPattern = network.getCraftingManager().getPattern(input, compare, networkList); + inputPattern = network.getCraftingManager().getPattern(input, compare, networkItems); + if (inputPattern != null) { if (inputPattern.getInputs().stream().anyMatch(s -> API.instance().getComparer().isEqual(s, lambdaInput, lambdaCompare))) { int craftQuantity = inputPattern.getQuantityPerRequest(input, compare); // 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, lambdaInput, lambdaCompare)).count() * 2; + do { - previousSteps.add(calculate(networkList, networkFluidList, inputPattern, toInsert)); + previousSteps.add(calculate(networkItems, networkFluids, inputPattern, toInsert)); toCraft.add(ItemHandlerHelper.copyStackWithSize(input, craftQuantity)); extraStack = toInsert.get(input, compare); } while (extraStack != null && extraStack.getCount() < needed); @@ -175,48 +194,66 @@ public class CraftingTask implements ICraftingTask { } while (input.getCount() > 0) { - if (extraStack != null && extraStack.getCount() > 0) { + if (extraStack != null && !extraStack.isEmpty()) { int takeQuantity = Math.min(extraStack.getCount(), input.getCount()); + ItemStack inputStack = ItemHandlerHelper.copyStackWithSize(extraStack, takeQuantity); - actualInputs.add(inputStack.copy()); + + actualInputs.add(inputStack); + input.shrink(takeQuantity); + if (byproductList.get(inputStack, compare) == null) { toCraft.add(inputStack); } + toInsert.remove(inputStack); + if (input.getCount() > 0) { i = 0; do { extraStack = toInsert.get(inputs.get(i), compare); - } while ((extraStack == null || extraStack.getCount() == 0) && ++i < inputs.size()); + } while ((extraStack == null || extraStack.isEmpty()) && ++i < inputs.size()); } } else if (networkStack != null && networkStack.getCount() > 0) { int takeQuantity = Math.min(networkStack.getCount(), input.getCount()); + ItemStack inputStack = ItemHandlerHelper.copyStackWithSize(networkStack, takeQuantity); - toTake.add(inputStack.copy()); - actualInputs.add(inputStack.copy()); + + toTake.add(inputStack); + actualInputs.add(inputStack); + input.shrink(takeQuantity); - networkList.remove(inputStack); + + networkItems.remove(inputStack); + if (input.getCount() > 0) { i = 0; do { - networkStack = networkList.get(inputs.get(i), compare); + networkStack = networkItems.get(inputs.get(i), compare); } while ((extraStack == null || extraStack.getCount() == 0) && ++i < inputs.size()); } } else { int oreDictedCompare = compare | (pattern.isOredict() ? IComparer.COMPARE_OREDICT : 0); + if (inputPattern == null) { - inputPattern = network.getCraftingManager().getPattern(input, oreDictedCompare, networkList); + inputPattern = network.getCraftingManager().getPattern(input, oreDictedCompare, networkItems); } if (inputPattern != null) { ItemStack actualCraft = inputPattern.getActualOutput(input, oreDictedCompare); + int craftQuantity = Math.min(inputPattern.getQuantityPerRequest(input, oreDictedCompare), input.getCount()); + ItemStack inputCrafted = ItemHandlerHelper.copyStackWithSize(actualCraft, craftQuantity); - toCraft.add(inputCrafted.copy()); - actualInputs.add(inputCrafted.copy()); - previousSteps.add(calculate(networkList, networkFluidList, inputPattern, toInsert)); + + toCraft.add(inputCrafted); + actualInputs.add(inputCrafted); + + previousSteps.add(calculate(networkItems, networkFluids, inputPattern, toInsert)); + input.shrink(craftQuantity); + if (!recurseFound) { // Calculate added all the crafted outputs toInsert // So we remove the ones we use from toInsert @@ -226,7 +263,8 @@ 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, previousSteps)) { + + while (!input.isEmpty() && doFluidCalculation(networkItems, networkFluids, fluidCheck, toInsert, previousSteps)) { actualInputs.add(fluidCheck); input.shrink(1); } @@ -234,10 +272,13 @@ public class CraftingTask implements ICraftingTask { // When it isn't a fluid or just doesn't have the needed fluids if (input.getCount() > 0) { ItemStack copy = input.copy(); + if (copy.getItemDamage() == OreDictionary.WILDCARD_VALUE) { copy.setItemDamage(0); } + missing.add(copy); + input.setCount(0); } } @@ -246,26 +287,24 @@ public class CraftingTask implements ICraftingTask { } ItemStack[] took = null; - if (missing.isEmpty()) { - if (!pattern.isProcessing()) { - took = StackListItem.toCraftingGrid(actualInputs, usedStacks, compare | (pattern.isOredict() ? IComparer.COMPARE_OREDICT : 0)); - } + if (missing.isEmpty() && !pattern.isProcessing()) { + took = StackListItem.toCraftingGrid(actualInputs, usedStacks, compare | (pattern.isOredict() ? IComparer.COMPARE_OREDICT : 0)); } - List outputs = !pattern.isProcessing() && pattern.isOredict() && missing.isEmpty() ? pattern.getOutputs(took) : pattern.getOutputs(); - if (outputs == null) { // Bla Bla what evs + List outputs = (!pattern.isProcessing() && pattern.isOredict() && missing.isEmpty()) ? pattern.getOutputs(took) : pattern.getOutputs(); + if (outputs == null) { outputs = pattern.getOutputs(); } for (ItemStack output : outputs) { if (output != null && !output.isEmpty()) { - toInsert.add(output.copy()); + toInsert.add(output); } } - for (ItemStack byproduct : (!pattern.isProcessing() && pattern.isOredict() && missing.isEmpty() ? pattern.getByproducts(took) : pattern.getByproducts())) { + for (ItemStack byproduct : (!pattern.isProcessing() && pattern.isOredict() && missing.isEmpty()) ? pattern.getByproducts(took) : pattern.getByproducts()) { if (byproduct != null && !byproduct.isEmpty()) { - toInsert.add(byproduct.copy()); + toInsert.add(byproduct); } } @@ -299,16 +338,16 @@ public class CraftingTask implements ICraftingTask { if (!hasBottle) { if (emptyBottlePattern == null) { - missing.add(StackUtils.EMPTY_BOTTLE.copy()); + missing.add(StackUtils.EMPTY_BOTTLE); } else { - toCraft.add(StackUtils.EMPTY_BOTTLE.copy()); + toCraft.add(StackUtils.EMPTY_BOTTLE); previousSteps.add(calculate(networkList, networkFluidList, emptyBottlePattern, toInsert)); toInsert.remove(StackUtils.EMPTY_BOTTLE, 1); } } if (hasBottle || emptyBottlePattern != null) { - toTake.add(StackUtils.EMPTY_BOTTLE.copy()); + toTake.add(StackUtils.EMPTY_BOTTLE); networkList.remove(StackUtils.EMPTY_BOTTLE); } } @@ -336,16 +375,16 @@ public class CraftingTask implements ICraftingTask { if (!hasBucket) { if (bucketPattern == null) { - missing.add(StackUtils.EMPTY_BUCKET.copy()); + missing.add(StackUtils.EMPTY_BUCKET); } else { - toCraft.add(StackUtils.EMPTY_BUCKET.copy()); + toCraft.add(StackUtils.EMPTY_BUCKET); previousSteps.add(calculate(networkList, networkFluidList, bucketPattern, toInsert)); toInsert.remove(StackUtils.EMPTY_BUCKET, 1); } } if (hasBucket || bucketPattern != null) { - toTakeFluids.add(fluidInItem.copy()); + toTakeFluids.add(fluidInItem); networkFluidList.remove(fluidInItem); } } @@ -386,18 +425,21 @@ public class CraftingTask implements ICraftingTask { @Override public boolean update(Map usedContainers) { - IStackList oreDictPrepped = network.getItemStorageCache().getList().getOredicted(); + IStackList networkItems = network.getItemStorageCache().getList().getOredicted(); IStackList networkFluids = network.getFluidStorageCache().getList(); if (!missing.isEmpty()) { for (ItemStack missing : this.missing.getStacks()) { - if (!oreDictPrepped.trackedRemove(missing)) { - oreDictPrepped.undo(); + if (!networkItems.trackedRemove(missing)) { + networkItems.undo(); + return false; } } - oreDictPrepped.undo(); + + networkItems.undo(); reschedule(); + return false; } @@ -419,9 +461,12 @@ public class CraftingTask implements ICraftingTask { // 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 { @@ -440,10 +485,13 @@ public class CraftingTask implements ICraftingTask { if (timesUsed++ <= container.getSpeedUpdateCount()) { if (!step.getPattern().isProcessing() || !container.isBlocked()) { - if (step.canStartProcessing(oreDictPrepped, networkFluids)) { + if (step.canStartProcessing(networkItems, networkFluids)) { step.setStartedProcessing(); + step.execute(toInsertItems, toInsertFluids); + usedContainers.put(container, timesUsed); + network.markCraftingMonitorForUpdate(); } } @@ -451,7 +499,6 @@ public class CraftingTask implements ICraftingTask { } } - if (getSteps().stream().filter(ICraftingStep::hasStartedProcessing).count() == 0) { // When there is no started processes, restart the task. reschedule(); @@ -459,8 +506,11 @@ public class CraftingTask implements ICraftingTask { // Remove finished tasks 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); @@ -473,18 +523,24 @@ public class CraftingTask implements ICraftingTask { @Override public void reschedule() { List mainSteps = this.mainSteps.stream().filter(s -> s.getPattern().alike(pattern)).collect(Collectors.toList()); + missing.clear(); 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); + for (ICraftingStep step : mainSteps) { quantity += quantityPerRequest - step.getReceivedOutput(requested); } + if (quantity > 0) { calculate(); } + network.markCraftingMonitorForUpdate(); } } @@ -640,12 +696,17 @@ public class CraftingTask implements ICraftingTask { public List getSteps() { 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; } @@ -669,32 +730,44 @@ public class CraftingTask implements ICraftingTask { for (ItemStack stack : toCraft.getStacks()) { int hash = API.instance().getItemStackHashCode(stack); + CraftingPreviewElementItemStack previewStack = map.get(hash); + if (previewStack == null) { previewStack = new CraftingPreviewElementItemStack(stack); } + previewStack.addToCraft(stack.getCount()); + map.put(hash, previewStack); } for (ItemStack stack : missing.getStacks()) { int hash = API.instance().getItemStackHashCode(stack); + CraftingPreviewElementItemStack previewStack = map.get(hash); + if (previewStack == null) { previewStack = new CraftingPreviewElementItemStack(stack); } + previewStack.setMissing(true); previewStack.addToCraft(stack.getCount()); + map.put(hash, previewStack); } for (ItemStack stack : toTake.getStacks()) { int hash = API.instance().getItemStackHashCode(stack); + CraftingPreviewElementItemStack previewStack = map.get(hash); + if (previewStack == null) { previewStack = new CraftingPreviewElementItemStack(stack); } + previewStack.addAvailable(stack.getCount()); + map.put(hash, previewStack); } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/Comparer.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/Comparer.java index 29aab49b2..85022f762 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/Comparer.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/Comparer.java @@ -140,7 +140,8 @@ public class Comparer implements IComparer { return EnumActionResult.PASS; } - public static ItemStack stripTags(ItemStack stack) { + @Nullable + public static ItemStack stripTags(@Nullable ItemStack stack) { if (stack != null && stack.hasTagCompound()) { switch (stack.getItem().getRegistryName().getResourceDomain()) { case "mekanism": diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/StackListItem.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/StackListItem.java index 8cac89a7d..98720935b 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/StackListItem.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/StackListItem.java @@ -187,8 +187,10 @@ public class StackListItem implements IStackList { public static ItemStack[] toCraftingGrid(IStackList list, List grid, int compare) { ItemStack[] took = new ItemStack[Math.max(9, grid.size())]; + for (int i = 0; i < grid.size(); i++) { ItemStack input = grid.get(i); + if (input != null) { // This will be a tool, like a hammer if (input.isItemStackDamageable()) { @@ -196,14 +198,19 @@ public class StackListItem implements IStackList { } else { compare |= IComparer.COMPARE_DAMAGE; } + ItemStack actualInput = list.get(input, compare); + if (actualInput != null) { ItemStack taken = ItemHandlerHelper.copyStackWithSize(actualInput, input.getCount()); + took[i] = taken; + list.remove(taken, taken.getCount()); } } } + return took; } }