diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/IRSAPI.java b/src/main/java/com/raoulvdberge/refinedstorage/api/IRSAPI.java index 66af5bd39..1e916b8b2 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/IRSAPI.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/IRSAPI.java @@ -1,5 +1,6 @@ package com.raoulvdberge.refinedstorage.api; +import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElementList; import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElementRegistry; import com.raoulvdberge.refinedstorage.api.autocrafting.preview.ICraftingPreviewElementRegistry; import com.raoulvdberge.refinedstorage.api.autocrafting.registry.ICraftingTaskRegistry; @@ -59,6 +60,9 @@ public interface IRSAPI { @Nonnull IFluidStackList createFluidStackList(); + @Nonnull + ICraftingMonitorElementList createCraftingMonitorElementList(); + /** * @param stack the stack * @return a hashcode for the given stack diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingPatternContainer.java b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingPatternContainer.java index 9eca03671..5c3cd6526 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingPatternContainer.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/ICraftingPatternContainer.java @@ -11,11 +11,9 @@ import java.util.List; */ public interface ICraftingPatternContainer { /** - * The speed that crafting tasks that have a pattern in this container can run. - * - * @return the speed of this container + * @return the amount of speed upgrades in the container. */ - int getSpeed(); + int getSpeedUpdateCount(); /** * @return the inventory that this container is facing diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/craftingmonitor/ICraftingMonitorElement.java b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/craftingmonitor/ICraftingMonitorElement.java index 1e1b6f0bd..fecc81cf1 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/craftingmonitor/ICraftingMonitorElement.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/craftingmonitor/ICraftingMonitorElement.java @@ -8,7 +8,7 @@ import net.minecraftforge.fml.relauncher.SideOnly; /** * Represents a crafting monitor element. */ -public interface ICraftingMonitorElement { +public interface ICraftingMonitorElement { /** * @param x position on the x axis to render * @param y position on the y axis to render @@ -50,4 +50,18 @@ public interface ICraftingMonitorElement { * @param buf the buffer */ void write(ByteBuf buf); + + /** + * Merge an element into the current element + * Used to in {@link ICraftingMonitorElementList} + * + * @param element the element to merged with the current one + * @return true if merge was successful + */ + boolean merge(ICraftingMonitorElement element); + + /** + * @return the hash code for the underlying element + */ + int elementHashCode(); } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/craftingmonitor/ICraftingMonitorElementList.java b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/craftingmonitor/ICraftingMonitorElementList.java new file mode 100644 index 000000000..102f7d729 --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/craftingmonitor/ICraftingMonitorElementList.java @@ -0,0 +1,41 @@ +package com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor; + +import java.util.Collection; +import java.util.List; + +public interface ICraftingMonitorElementList { + /** + * Directly add to the underlying list without trying to merge + * + * @param element the {@link ICraftingMonitorElement} + */ + void directAdd(ICraftingMonitorElement element); + + /** + * Add a element to the list + * Similar elements will be merged + * A {@link #commit()} will stop any following adds to be merged with previous ones + * + * @param element the {@link ICraftingMonitorElement} + */ + void add(ICraftingMonitorElement element); + + /** + * @param elements a {@link Collection} of {@link ICraftingMonitorElement}s to be added + */ + default void addAll(Collection elements) { + elements.forEach(this::add); + } + + /** + * Finish a current merge operation + */ + void commit(); + + /** + * This also commits the last changes + * + * @return Get the current list of elements + */ + List getElements(); +} 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 new file mode 100644 index 000000000..0efa95bb1 --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/task/ICraftingStep.java @@ -0,0 +1,74 @@ +package com.raoulvdberge.refinedstorage.api.autocrafting.task; + +import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; +import com.raoulvdberge.refinedstorage.api.util.IFluidStackList; +import com.raoulvdberge.refinedstorage.api.util.IItemStackList; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.fluids.FluidStack; + +import java.util.Deque; +import java.util.List; + +/** + * Represents a step in a crafting task that. + */ +public interface ICraftingStep { + /** + * @return the pattern + */ + ICraftingPattern getPattern(); + + /** + * @return the stacks to insert, no null entries + */ + List getToInsert(); + + /** + * Check if the processing can start + * + * @param items a list to compare the needed {@link ItemStack} inputs against + * @param fluids a list to compare the needed {@link net.minecraftforge.fluids.FluidStack} inputs against (eg. a bucket, machine insert) + * @return true if processing can start + */ + boolean canStartProcessing(IItemStackList items, IFluidStackList fluids); + + void setStartedProcessing(); + + boolean hasStartedProcessing(); + + /** + * Execute this step + * Any items to be added to the network should be inserting into these queues + * and they'll be managed by the {@link ICraftingTask} + * + * @param toInsertItems a queue of items to be inserted into the network + * @param toInsertFluids a queue of fluids to be inserted into the network + */ + void execute(Deque toInsertItems, Deque toInsertFluids); + + /** + * @return true if we received all outputs, false otherwise + */ + boolean hasReceivedOutputs(); + + /** + * @param stack the output to check, + * @return true if we received the given output (based upon item and stacksize), false otherwise + */ + boolean hasReceivedOutput(ItemStack stack); + + /** + * @param stack the stack that was inserted in the storage system + * @return true if this item belonged to the processable item, false otherwise + */ + boolean onReceiveOutput(ItemStack stack); + + /** + * Writes the processable to NBT. + * + * @param tag the tag + * @return the written tag + */ + NBTTagCompound writeToNBT(NBTTagCompound tag); +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/task/ICraftingTask.java b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/task/ICraftingTask.java index ec10d5be1..b869800d3 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/task/ICraftingTask.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/task/ICraftingTask.java @@ -1,6 +1,7 @@ package com.raoulvdberge.refinedstorage.api.autocrafting.task; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; +import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternContainer; import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElement; import com.raoulvdberge.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement; import net.minecraft.item.ItemStack; @@ -8,6 +9,7 @@ import net.minecraft.nbt.NBTTagCompound; import javax.annotation.Nullable; import java.util.List; +import java.util.Map; /** * Represents a crafting task. @@ -33,9 +35,10 @@ public interface ICraftingTask { * Updates this task. Gets called every few ticks, depending on the speed of the pattern container. * {@link ICraftingTask#calculate()} must be run before this * + * @param usedContainers a map keeping track of used containers and how many times * @return true if this crafting task is finished and can be deleted from the list, false otherwise */ - boolean update(); + boolean update(Map usedContainers); /** * @return the amount of items that have to be crafted @@ -92,7 +95,7 @@ public interface ICraftingTask { * * @return the processable items in this task */ - List getToProcess(); + List getSteps(); /** * Used to check if the crafting task has recursive elements diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/task/IProcessable.java b/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/task/IProcessable.java deleted file mode 100755 index 57ba9859e..000000000 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/autocrafting/task/IProcessable.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.raoulvdberge.refinedstorage.api.autocrafting.task; - -import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; -import com.raoulvdberge.refinedstorage.api.util.IItemStackList; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; - -/** - * Represents a item in a crafting task that can be processed. - */ -public interface IProcessable { - /** - * @return the pattern - */ - ICraftingPattern getPattern(); - - /** - * @return the stacks to insert - */ - IItemStackList getToInsert(); - - /** - * Check if the processing can start - * - * @param list a list to compare the need inputs against - * @return true if processing can start - */ - boolean canStartProcessing(IItemStackList list); - - void setStartedProcessing(); - - boolean hasStartedProcessing(); - - /** - * @return true if we received all outputs, false otherwise - */ - boolean hasReceivedOutputs(); - - /** - * @param i the output to check - * @return true if we received the given output, false otherwise - */ - boolean hasReceivedOutput(int i); - - /** - * @param stack the stack that was inserted in the storage system - * @return true if this item belonged to the processable item, false otherwise - */ - boolean onReceiveOutput(ItemStack stack); - - /** - * Writes the processable to NBT. - * - * @param tag the tag - * @return the written tag - */ - NBTTagCompound writeToNBT(NBTTagCompound tag); -} 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 8eed20cea..81fb17841 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/util/IFluidStackList.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/util/IFluidStackList.java @@ -24,7 +24,7 @@ public interface IFluidStackList { * @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 + * @return whether the remove was successful for the full amount */ boolean remove(@Nonnull FluidStack stack, int size, boolean removeIfReachedZero); @@ -33,7 +33,7 @@ public interface IFluidStackList { * * @param stack the stack * @param removeIfReachedZero true to remove the stack if the count reaches 0, false otherwise - * @return whether the remove was successful + * @return whether the remove was successful for the full amount */ default boolean remove(@Nonnull FluidStack stack, boolean removeIfReachedZero) { return remove(stack, stack.amount, removeIfReachedZero); @@ -74,6 +74,11 @@ public interface IFluidStackList { */ void clear(); + /** + * Removes all stacks with size zero + */ + void clean(); + /** * @return true if the list is empty, false otherwise */ 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 98c192174..9a3941be6 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/util/IItemStackList.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/util/IItemStackList.java @@ -24,7 +24,7 @@ public interface IItemStackList { * @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 + * @return whether the remove was successful for the full amount */ boolean remove(@Nonnull ItemStack stack, int size, boolean removeIfReachedZero); @@ -33,7 +33,7 @@ public interface IItemStackList { * * @param stack the stack * @param removeIfReachedZero true to remove the stack if the count reaches 0, false otherwise - * @return whether the remove was successful + * @return whether the remove was successful for the full amount */ default boolean remove(@Nonnull ItemStack stack, boolean removeIfReachedZero) { return remove(stack, stack.stackSize, removeIfReachedZero); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/API.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/API.java index 30f60b269..c186cf314 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/API.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/API.java @@ -2,6 +2,7 @@ package com.raoulvdberge.refinedstorage.apiimpl; import com.raoulvdberge.refinedstorage.api.IRSAPI; import com.raoulvdberge.refinedstorage.api.RSAPIInject; +import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElementList; import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElementRegistry; import com.raoulvdberge.refinedstorage.api.autocrafting.preview.ICraftingPreviewElementRegistry; import com.raoulvdberge.refinedstorage.api.autocrafting.registry.ICraftingTaskRegistry; @@ -9,6 +10,7 @@ import com.raoulvdberge.refinedstorage.api.solderer.ISoldererRegistry; import com.raoulvdberge.refinedstorage.api.util.IComparer; import com.raoulvdberge.refinedstorage.api.util.IFluidStackList; import com.raoulvdberge.refinedstorage.api.util.IItemStackList; +import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.craftingmonitor.CraftingMonitorElementList; import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.craftingmonitor.CraftingMonitorElementRegistry; import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.preview.CraftingPreviewElementRegistry; import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.registry.CraftingTaskRegistry; @@ -75,6 +77,12 @@ public class API implements IRSAPI { return new FluidStackList(); } + @Nonnull + @Override + public ICraftingMonitorElementList createCraftingMonitorElementList() { + return new CraftingMonitorElementList(); + } + @Override public int getItemStackHashCode(ItemStack stack) { return stack.getItem().hashCode() * (stack.getItemDamage() + 1) * (stack.hasTagCompound() ? stack.getTagCompound().hashCode() : 1); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementError.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementError.java index 2286d2599..01ba026c5 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementError.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementError.java @@ -50,4 +50,14 @@ public class CraftingMonitorElementError implements ICraftingMonitorElement { base.write(buf); } + + @Override + public boolean merge(ICraftingMonitorElement element) { + return element.getId().equals(getId()) && elementHashCode() == element.elementHashCode() && base.merge(((CraftingMonitorElementError)element).base); + } + + @Override + public int elementHashCode() { + return base.elementHashCode() ^ tooltip.hashCode(); + } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementFluidRender.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementFluidRender.java index dded0bb42..aa9684ef6 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementFluidRender.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementFluidRender.java @@ -3,6 +3,7 @@ package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.craftingmonitor; import com.raoulvdberge.refinedstorage.RSUtils; import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElement; import com.raoulvdberge.refinedstorage.api.render.IElementDrawers; +import com.raoulvdberge.refinedstorage.apiimpl.API; import com.raoulvdberge.refinedstorage.gui.GuiBase; import io.netty.buffer.ByteBuf; import net.minecraft.client.renderer.GlStateManager; @@ -10,7 +11,7 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -public class CraftingMonitorElementFluidRender implements ICraftingMonitorElement { +public class CraftingMonitorElementFluidRender implements ICraftingMonitorElement { public static final String ID = "fluid_render"; private int taskId; @@ -59,4 +60,18 @@ public class CraftingMonitorElementFluidRender implements ICraftingMonitorElemen RSUtils.writeFluidStack(buf, stack); buf.writeInt(offset); } + + @Override + public boolean merge(ICraftingMonitorElement element) { + if (element.getId().equals(getId()) && elementHashCode() == element.elementHashCode()) { + this.stack.amount += ((CraftingMonitorElementFluidRender) element).stack.amount; + return true; + } + return false; + } + + @Override + public int elementHashCode() { + return API.instance().getFluidStackHashCode(stack); + } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementItemRender.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementItemRender.java index 5c1ede8c2..4c7e36e47 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementItemRender.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementItemRender.java @@ -2,6 +2,7 @@ package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.craftingmonitor; import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElement; import com.raoulvdberge.refinedstorage.api.render.IElementDrawers; +import com.raoulvdberge.refinedstorage.apiimpl.API; import com.raoulvdberge.refinedstorage.gui.GuiBase; import io.netty.buffer.ByteBuf; import net.minecraft.client.renderer.GlStateManager; @@ -10,7 +11,7 @@ import net.minecraftforge.fml.common.network.ByteBufUtils; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -public class CraftingMonitorElementItemRender implements ICraftingMonitorElement { +public class CraftingMonitorElementItemRender implements ICraftingMonitorElement { public static final String ID = "item_render"; private int taskId; @@ -62,4 +63,18 @@ public class CraftingMonitorElementItemRender implements ICraftingMonitorElement buf.writeInt(quantity); buf.writeInt(offset); } + + @Override + public boolean merge(ICraftingMonitorElement element) { + if (element.getId().equals(getId()) && elementHashCode() == element.elementHashCode()) { + this.quantity += ((CraftingMonitorElementItemRender) element).quantity; + return true; + } + return false; + } + + @Override + public int elementHashCode() { + return API.instance().getItemStackHashCode(stack); + } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementList.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementList.java new file mode 100644 index 000000000..7d5c6cd26 --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementList.java @@ -0,0 +1,46 @@ +package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.craftingmonitor; + +import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElement; +import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElementList; + +import java.util.*; + +public class CraftingMonitorElementList implements ICraftingMonitorElementList { + public List elements = new LinkedList<>(); + public Map> currentLists = new LinkedHashMap<>(); + + @Override + public void directAdd(ICraftingMonitorElement element) { + elements.add(element); + } + + @Override + public void add(ICraftingMonitorElement element) { + Map currentElements = currentLists.get(element.getId()); + if (currentElements == null) { + currentElements = new HashMap<>(); + } + ICraftingMonitorElement exitingElement = currentElements.get(element.elementHashCode()); + if (exitingElement == null) { + exitingElement = element; + } else { + exitingElement.merge(element); + } + currentElements.put(exitingElement.elementHashCode(), exitingElement); + currentLists.put(exitingElement.getId(), currentElements); + } + + @Override + public void commit() { + currentLists.values().stream().map(Map::values).flatMap(Collection::stream).forEach(elements::add); + currentLists.clear(); + } + + @Override + public List getElements() { + if (!currentLists.isEmpty()) { + commit(); + } + return elements; + } +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementText.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementText.java index 90e12bc26..d6ae314b6 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementText.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/craftingmonitor/CraftingMonitorElementText.java @@ -10,7 +10,7 @@ import net.minecraftforge.fml.common.network.ByteBufUtils; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -public class CraftingMonitorElementText implements ICraftingMonitorElement { +public class CraftingMonitorElementText implements ICraftingMonitorElement { public static final String ID = "text"; private String text; @@ -62,4 +62,14 @@ public class CraftingMonitorElementText implements ICraftingMonitorElement toProcess = new ArrayList<>(); + List toProcess = new ArrayList<>(); for (int i = 0; i < toProcessList.tagCount(); ++i) { - Processable processable = new Processable(network); + NBTTagCompound compound = toProcessList.getCompoundTagAt(i); + AbstractCraftingStep abstractCraftingStep; + switch (compound.getString(AbstractCraftingStep.NBT_CRAFTING_STEP_TYPE)) + { + case CraftCraftingStep.ID: + abstractCraftingStep = new CraftCraftingStep(network); + break; + case ProcessCraftingStep.ID: + abstractCraftingStep = new ProcessCraftingStep(network); + break; + default: + abstractCraftingStep = null; + break; + } - if (processable.readFromNBT(toProcessList.getCompoundTagAt(i))) { - toProcess.add(processable); + if (abstractCraftingStep != null && abstractCraftingStep.readFromNBT(compound)) { + toProcess.add(abstractCraftingStep); } } - IItemStackList toTake = RSUtils.readItemStackList(tag.getTagList(CraftingTask.NBT_TO_TAKE, Constants.NBT.TAG_COMPOUND)); - IItemStackList internalToTake = RSUtils.readItemStackList(tag.getTagList(CraftingTask.NBT_INTERNAL_TO_TAKE, Constants.NBT.TAG_COMPOUND)); - IFluidStackList toTakeFluids = RSUtils.readFluidStackList(tag.getTagList(CraftingTask.NBT_TO_TAKE_FLUIDS, Constants.NBT.TAG_COMPOUND)); - NBTTagList toInsertList = tag.getTagList(CraftingTask.NBT_TO_INSERT, Constants.NBT.TAG_COMPOUND); + NBTTagList toInsertList = tag.getTagList(CraftingTask.NBT_TO_INSERT_ITEMS, Constants.NBT.TAG_COMPOUND); - ArrayDeque toInsert = new ArrayDeque<>(); + Deque toInsert = new ArrayDeque<>(); for (int i = 0; i < toInsertList.tagCount(); ++i) { ItemStack insertStack = ItemStack.loadItemStackFromNBT(toInsertList.getCompoundTagAt(i)); @@ -58,23 +70,22 @@ public class CraftingTaskFactory implements ICraftingTaskFactory { } } - NBTTagList tookList = tag.getTagList(CraftingTask.NBT_TOOK, Constants.NBT.TAG_COMPOUND); + IFluidStackList toTakeFluids = RSUtils.readFluidStackList(tag.getTagList(CraftingTask.NBT_TO_TAKE_FLUIDS, Constants.NBT.TAG_COMPOUND)); + IFluidStackList tookFluids = RSUtils.readFluidStackList(tag.getTagList(CraftingTask.NBT_TOOK_FLUIDS, Constants.NBT.TAG_COMPOUND)); - IItemStackList took = RSUtils.readItemStackList(tookList); + NBTTagList toInsertFluidsList = tag.getTagList(CraftingTask.NBT_TO_INSERT_FLUIDS, Constants.NBT.TAG_COMPOUND); - NBTTagList tookFluidsList = tag.getTagList(CraftingTask.NBT_TOOK_FLUIDS, Constants.NBT.TAG_COMPOUND); + Deque toInsertFluids = new ArrayDeque<>(); - List tookFluids = new ArrayList<>(); - - for (int i = 0; i < tookFluidsList.tagCount(); ++i) { - FluidStack tookStack = FluidStack.loadFluidStackFromNBT(tookList.getCompoundTagAt(i)); + for (int i = 0; i < toInsertFluidsList.tagCount(); ++i) { + FluidStack tookStack = FluidStack.loadFluidStackFromNBT(toInsertFluidsList.getCompoundTagAt(i)); if (tookStack != null) { - tookFluids.add(tookStack); + toInsertFluids.add(tookStack); } } - return new CraftingTask(network, stack, pattern, quantity, toProcess, toTake, internalToTake, toTakeFluids, toInsert, took, tookFluids); + return new CraftingTask(network, stack, pattern, quantity, toProcess, toInsert, toTakeFluids, tookFluids, toInsertFluids); } return new CraftingTask(network, stack, pattern, quantity); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/Processable.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/AbstractCraftingStep.java old mode 100755 new mode 100644 similarity index 52% rename from src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/Processable.java rename to src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/AbstractCraftingStep.java index e3ae87d11..4b0dda3a5 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/Processable.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/AbstractCraftingStep.java @@ -1,46 +1,41 @@ package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task; -import com.raoulvdberge.refinedstorage.RSUtils; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternContainer; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternProvider; -import com.raoulvdberge.refinedstorage.api.autocrafting.task.IProcessable; +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.IFluidStackList; import com.raoulvdberge.refinedstorage.api.util.IItemStackList; import com.raoulvdberge.refinedstorage.apiimpl.API; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagCompound;; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; -import net.minecraftforge.common.util.Constants; -public class Processable implements IProcessable { +import java.util.*; +import java.util.stream.Collectors; + +public abstract class AbstractCraftingStep implements ICraftingStep { + public static final String NBT_CRAFTING_STEP_TYPE = "CraftingStepType"; private static final String NBT_SATISFIED = "Satisfied_%d"; - private static final String NBT_TO_INSERT = "ToInsert"; private static final String NBT_PATTERN = "Pattern"; private static final String NBT_PATTERN_CONTAINER = "PatternContainer"; private static final String NBT_STARTED_PROCESSING = "StartedProcessing"; - private INetworkMaster network; - private ICraftingPattern pattern; - private IItemStackList toInsert = API.instance().createItemStackList(); - private boolean satisfied[]; - private boolean startedProcessing; + protected INetworkMaster network; + protected ICraftingPattern pattern; + protected Map satisfied; + protected boolean startedProcessing; - public Processable(INetworkMaster network, ICraftingPattern pattern) { + public AbstractCraftingStep(INetworkMaster network, ICraftingPattern pattern) { this.network = network; this.pattern = pattern; - this.satisfied = new boolean[pattern.getOutputs().size()]; - - for (ItemStack input : pattern.getInputs()) { - if (input != null) { - toInsert.add(input.copy()); - } - } + this.satisfied = new HashMap<>(getPattern().getOutputs().size()); } - public Processable(INetworkMaster network) { + public AbstractCraftingStep(INetworkMaster network) { this.network = network; } @@ -52,17 +47,17 @@ public class Processable implements IProcessable { if (container instanceof ICraftingPatternContainer) { this.pattern = ((ICraftingPatternProvider) patternStack.getItem()).create(network.getNetworkWorld(), patternStack, (ICraftingPatternContainer) container); - this.satisfied = new boolean[pattern.getOutputs().size()]; + this.satisfied = new HashMap<>(pattern.getOutputs().size()); - for (int i = 0; i < satisfied.length; ++i) { - String id = String.format(NBT_SATISFIED, i); + for (ItemStack stack : pattern.getOutputs()) { + int hashcode = API.instance().getItemStackHashCode(stack); + String id = String.format(NBT_SATISFIED, hashcode); if (tag.hasKey(id)) { - this.satisfied[i] = tag.getBoolean(id); + this.satisfied.put(hashcode, tag.getInteger(id)); } } - this.toInsert = RSUtils.readItemStackList(tag.getTagList(NBT_TO_INSERT, Constants.NBT.TAG_COMPOUND)); this.startedProcessing = tag.getBoolean(NBT_STARTED_PROCESSING); return true; @@ -78,18 +73,18 @@ public class Processable implements IProcessable { } @Override - public IItemStackList getToInsert() { - return toInsert; + public List getToInsert() { + return pattern.getInputs().stream().filter(Objects::nonNull).collect(Collectors.toList()); } @Override - public boolean canStartProcessing(IItemStackList list) { - list = list.copy(); // So we can edit the list + public boolean canStartProcessing(IItemStackList items, IFluidStackList fluids) { + items = items.copy(); // So we can edit the list - for (ItemStack stack : toInsert.getStacks()) { - ItemStack actualStack = list.get(stack, IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT | (pattern.isOredict() ? IComparer.COMPARE_OREDICT : 0)); + 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 || !list.remove(actualStack, true)) { + if (actualStack == null || actualStack.stackSize == 0 || !items.remove(actualStack, stack.stackSize, true)) { return false; } } @@ -109,8 +104,9 @@ public class Processable implements IProcessable { @Override public boolean hasReceivedOutputs() { - for (boolean item : satisfied) { - if (!item) { + for (ItemStack stack : pattern.getOutputs()) { + Integer received = satisfied.get(API.instance().getItemStackHashCode(stack)); + if (received == null || stack.stackSize > received) { return false; } } @@ -119,18 +115,22 @@ public class Processable implements IProcessable { } @Override - public boolean hasReceivedOutput(int i) { - return satisfied[i]; + public boolean hasReceivedOutput(ItemStack stack) { + Integer received = satisfied.get(API.instance().getItemStackHashCode(stack)); + return received != null && received >= stack.stackSize; } @Override public boolean onReceiveOutput(ItemStack stack) { - for (int i = 0; i < pattern.getOutputs().size(); ++i) { - if (!satisfied[i]) { - ItemStack item = pattern.getOutputs().get(i); - - if (API.instance().getComparer().isEqualNoQuantity(stack, item)) { - satisfied[i] = true; + for (ItemStack output : pattern.getOutputs()) { + int hashcode = API.instance().getItemStackHashCode(output); + Integer received = satisfied.get(hashcode); + if (received == null) { + received = 0; + } + if (API.instance().getComparer().isEqual(stack, output, CraftingTask.DEFAULT_COMPARE | (getPattern().isOredict() ? IComparer.COMPARE_OREDICT : 0))) { + if (received < output.stackSize) { + satisfied.put(hashcode, received + stack.stackSize); network.sendCraftingMonitorUpdate(); @@ -144,11 +144,10 @@ public class Processable implements IProcessable { @Override public NBTTagCompound writeToNBT(NBTTagCompound tag) { - for (int i = 0; i < satisfied.length; ++i) { - tag.setBoolean(String.format(NBT_SATISFIED, i), satisfied[i]); + for (Map.Entry entry : satisfied.entrySet()) { + tag.setInteger(String.format(NBT_SATISFIED, entry.getKey()), entry.getValue()); } - tag.setTag(NBT_TO_INSERT, RSUtils.serializeItemStackList(toInsert)); tag.setTag(NBT_PATTERN, pattern.getStack().serializeNBT()); tag.setLong(NBT_PATTERN_CONTAINER, pattern.getContainer().getPosition().toLong()); tag.setBoolean(NBT_STARTED_PROCESSING, startedProcessing); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftCraftingStep.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftCraftingStep.java new file mode 100644 index 000000000..7529fcc19 --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftCraftingStep.java @@ -0,0 +1,94 @@ +package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task; + +import com.raoulvdberge.refinedstorage.RSUtils; +import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; +import com.raoulvdberge.refinedstorage.api.network.INetworkMaster; +import com.raoulvdberge.refinedstorage.api.util.IComparer; +import com.raoulvdberge.refinedstorage.api.util.IFluidStackList; +import com.raoulvdberge.refinedstorage.api.util.IItemStackList; +import com.raoulvdberge.refinedstorage.apiimpl.API; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.items.ItemHandlerHelper; + +import java.util.Deque; + +public class CraftCraftingStep extends AbstractCraftingStep { + public static final String ID = "CraftCraftingStep"; + + public CraftCraftingStep(INetworkMaster network, ICraftingPattern pattern) { + super(network, pattern); + } + + public CraftCraftingStep(INetworkMaster network) { + super(network); + } + + @Override + public boolean canStartProcessing(IItemStackList items, IFluidStackList fluids) { + // So we can edit the lists + items = items.copy(); + fluids = fluids.copy(); + + 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)) { + 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)) { + continue; + } + } + + return false; + } + } + + return true; + } + + @Override + public void execute(Deque toInsertItems, Deque toInsertFluids) { + IItemStackList actualInputs = API.instance().createItemStackList(); + int compare = CraftingTask.DEFAULT_COMPARE | (getPattern().isOredict() ? IComparer.COMPARE_OREDICT : 0); + for (ItemStack insertStack : getToInsert()) { + FluidStack fluidInItem = RSUtils.getFluidFromStack(insertStack, true); + if (fluidInItem != null) { + network.extractFluid(fluidInItem, fluidInItem.amount, compare); + actualInputs.add(insertStack.copy()); + } else { + actualInputs.add(network.extractItem(insertStack, insertStack.stackSize, compare)); + } + } + + ItemStack[] took = new ItemStack[9]; + for (int i = 0; i < pattern.getInputs().size(); i++) { + ItemStack input = pattern.getInputs().get(i); + if (input != null) { + ItemStack actualInput = actualInputs.get(input, compare); + ItemStack taken = ItemHandlerHelper.copyStackWithSize(actualInput, input.stackSize); + took[i] = taken; + actualInputs.remove(taken, true); + } + } + + for (ItemStack byproduct : (pattern.isOredict()? pattern.getByproducts(took) : pattern.getByproducts())) { + toInsertItems.add(byproduct.copy()); + } + + for (ItemStack output : (pattern.isOredict() ? pattern.getOutputs(took) : pattern.getOutputs())) { + toInsertItems.add(output.copy()); + } + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound tag) { + tag.setString(NBT_CRAFTING_STEP_TYPE, ID); + return super.writeToNBT(tag); + } +} 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 6434d6ac2..6123933ed 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 @@ -2,10 +2,12 @@ package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task; import com.raoulvdberge.refinedstorage.RSUtils; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; +import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternContainer; import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElement; +import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElementList; import com.raoulvdberge.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement; import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTask; -import com.raoulvdberge.refinedstorage.api.autocrafting.task.IProcessable; +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.IFluidStackList; @@ -21,7 +23,6 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.ItemHandlerHelper; import javax.annotation.Nullable; @@ -29,14 +30,12 @@ import java.util.*; import java.util.stream.Collectors; public class CraftingTask implements ICraftingTask { - private static final int DEFAULT_COMPARE = IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT; + protected static final int DEFAULT_COMPARE = IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT; public static final String NBT_TO_PROCESS = "ToProcess"; - public static final String NBT_TO_TAKE = "ToTake"; - public static final String NBT_INTERNAL_TO_TAKE = "InternalToTake"; public static final String NBT_TO_TAKE_FLUIDS = "ToTakeFluids"; - public static final String NBT_TO_INSERT = "ToInsert"; - public static final String NBT_TOOK = "Took"; + public static final String NBT_TO_INSERT_ITEMS = "ToInsertItems"; + public static final String NBT_TO_INSERT_FLUIDS = "ToInsertFluids"; public static final String NBT_TOOK_FLUIDS = "TookFluids"; private INetworkMaster network; @@ -44,17 +43,16 @@ public class CraftingTask implements ICraftingTask { private ItemStack requested; private ICraftingPattern pattern; private int quantity; - private List toProcess = new ArrayList<>(); + private List steps = new ArrayList<>(); private IItemStackList toTake = API.instance().createItemStackList(); - private IItemStackList internalToTake = API.instance().createItemStackList(); private IItemStackList toCraft = API.instance().createItemStackList(); - private IFluidStackList toTakeFluids = API.instance().createFluidStackList(); private IItemStackList missing = API.instance().createItemStackList(); private Set usedPatterns = new HashSet<>(); private boolean recurseFound = false; - private Deque toInsert = new ArrayDeque<>(); - private IItemStackList took = API.instance().createItemStackList(); - private List tookFluids = new ArrayList<>(); + private Deque toInsertItems = new ArrayDeque<>(); + private Deque toInsertFluids = new ArrayDeque<>(); + private IFluidStackList toTakeFluids = API.instance().createFluidStackList(); + private IFluidStackList tookFluids = API.instance().createFluidStackList(); public CraftingTask(INetworkMaster network, @Nullable ItemStack requested, ICraftingPattern pattern, int quantity) { this.network = network; @@ -63,16 +61,13 @@ public class CraftingTask implements ICraftingTask { this.quantity = quantity; } - public CraftingTask(INetworkMaster network, @Nullable ItemStack requested, ICraftingPattern pattern, int quantity, List toProcess, IItemStackList toTake, IItemStackList internalToTake, IFluidStackList toTakeFluids, Deque toInsert, IItemStackList took, List tookFluids) { + public CraftingTask(INetworkMaster network, @Nullable ItemStack requested, ICraftingPattern pattern, int quantity, List steps, Deque toInsertItems, IFluidStackList toTakeFluids, IFluidStackList tookFluids, Deque toInsertFluids) { this(network, requested, pattern, quantity); - - this.toProcess = toProcess; - this.toTake = toTake; - this.internalToTake = internalToTake; + this.steps = steps; + this.toInsertItems = toInsertItems; this.toTakeFluids = toTakeFluids; - this.toInsert = toInsert; - this.took = took; this.tookFluids = tookFluids; + this.toInsertFluids = toInsertFluids; } @Override @@ -87,10 +82,6 @@ public class CraftingTask implements ICraftingTask { quantity -= pattern.getQuantityPerRequest(requested); } - if (!recurseFound) { - this.toInsert.addAll(toInsert.getStacks()); - } - usedPatterns.clear(); } @@ -122,6 +113,7 @@ public class CraftingTask implements ICraftingTask { ItemStack inputStack = ItemHandlerHelper.copyStackWithSize(extraStack, takeQuantity); actualInputs.add(inputStack.copy()); input.stackSize -= takeQuantity; + toCraft.add(inputStack); toInsert.remove(inputStack, true); } else if (networkStack != null && networkStack.stackSize > 0) { int takeQuantity = Math.min(networkStack.stackSize, input.stackSize); @@ -140,13 +132,9 @@ public class CraftingTask implements ICraftingTask { actualInputs.add(inputCrafted.copy()); calculate(networkList, inputPattern, toInsert); input.stackSize -= craftQuantity; - // Calculate added all the crafted outputs toInsert - // So we remove the ones we use from toInsert + // Calculate added all the crafted outputs toInsertItems + // So we remove the ones we use from toInsertItems toInsert.remove(inputCrafted, true); - // If the pattern is processing the have to be taken. - if (pattern.isProcessing()) { - internalToTake.add(inputCrafted.copy()); - } } else if (doFluidCalculation(networkList, input, toInsert)) { actualInputs.add(ItemHandlerHelper.copyStackWithSize(input, 1)); input.stackSize -= 1; @@ -159,7 +147,9 @@ public class CraftingTask implements ICraftingTask { } if (pattern.isProcessing()) { - toProcess.add(new Processable(network, pattern)); + steps.add(new ProcessCraftingStep(network, pattern)); + } else { + steps.add(new CraftCraftingStep(network, pattern)); } if (missing.isEmpty()) { @@ -221,120 +211,85 @@ public class CraftingTask implements ICraftingTask { @Override public void onCancelled() { - for (ItemStack stack : took.getStacks()) { + for (ItemStack stack : toInsertItems) { network.insertItem(stack, stack.stackSize, false); } - for (FluidStack stack : tookFluids) { + for (FluidStack stack : tookFluids.getStacks()) { network.insertFluid(stack, stack.amount, false); } + + network.sendCraftingMonitorUpdate(); } @Override public String toString() { return "\nCraftingTask{quantity=" + quantity + "\n, toTake=" + toTake + - "\n, internalToTake=" + internalToTake + "\n, toTakeFluids=" + toTakeFluids + - "\n, toProcess=" + toProcess + - "\n, toCraft=" + toProcess + - "\n, toInsert=" + toInsert + + "\n, toCraft=" + toCraft + + "\n, toInsertItems=" + toInsertItems + + "\n, toInsertFluids=" + toInsertFluids + + "\n, steps=" + steps + '}'; } @Override - public boolean update() { - for (ItemStack stack : toTake.getStacks()) { - ItemStack stackExtracted = network.extractItem(stack, Math.min(stack.stackSize, 64)); - + public boolean update(Map usedContainers) { + for (FluidStack stack : toTakeFluids.getStacks()) { + FluidStack stackExtracted = network.extractFluid(stack, stack.amount); if (stackExtracted != null) { - toTake.remove(stack, stackExtracted.stackSize, true); - - took.add(stackExtracted); - - network.sendCraftingMonitorUpdate(); - - break; - } - } - - // Fetches results from processing patterns - for (ItemStack stack : internalToTake.getStacks()) { - ItemStack stackExtracted = network.extractItem(stack, Math.min(stack.stackSize, 64)); - - if (stackExtracted != null) { - internalToTake.remove(stack, stackExtracted.stackSize, false); - - took.add(stackExtracted); - + toTakeFluids.remove(stack, stack.amount, false); + tookFluids.add(stackExtracted); network.sendCraftingMonitorUpdate(); } } - // Clean up zero stacks, cause we can't remove them in the loop (CME ahoy!) - internalToTake.clean(); - for (IProcessable processable : toProcess) { - IItemHandler inventory = processable.getPattern().getContainer().getFacingInventory(); - - if (inventory != null && !processable.hasStartedProcessing() && processable.canStartProcessing(took) && canProcess(processable)) { - processable.setStartedProcessing(); - - for (ItemStack insertStack : processable.getToInsert().getStacks()) { - ItemStack tookStack = took.get(insertStack, DEFAULT_COMPARE | (processable.getPattern().isOredict() ? IComparer.COMPARE_OREDICT : 0)); - ItemStack toInsert = ItemHandlerHelper.copyStackWithSize(tookStack, insertStack.stackSize); - - if (ItemHandlerHelper.insertItem(inventory, toInsert, true) == null) { - ItemHandlerHelper.insertItem(inventory, toInsert, false); - - took.remove(tookStack, toInsert.stackSize, true); - - network.sendCraftingMonitorUpdate(); - } - } - } - } - - // If we took all the items, we can start taking fluids - if (toTake.isEmpty()) { - for (FluidStack stack : toTakeFluids.getStacks()) { - FluidStack stackExtracted = network.extractFluid(stack, stack.amount); - - if (stackExtracted != null) { - toTakeFluids.remove(stack, stack.amount, true); - - tookFluids.add(stackExtracted); + toTakeFluids.clean(); + for (ICraftingStep step : steps) { + ICraftingPatternContainer container = step.getPattern().getContainer(); + Integer timesUsed = usedContainers.get(container); + if (timesUsed == null) timesUsed = 0; + if (timesUsed++ <= container.getSpeedUpdateCount()) { + if (!step.hasStartedProcessing() && step.canStartProcessing(network.getItemStorageCache().getList(), tookFluids) && canProcess(step)) { + step.setStartedProcessing(); + step.execute(toInsertItems, toInsertFluids); + usedContainers.put(container, timesUsed); network.sendCraftingMonitorUpdate(); - - break; } } } - if (isFinished()) { - ItemStack insert = toInsert.peek(); - - if (insert != null && network.insertItem(insert, insert.stackSize, true) == null) { - network.insertItem(insert, insert.stackSize, false); - - toInsert.pop(); - - network.sendCraftingMonitorUpdate(); + // We need to copy the size cause we'll readd unadded stacks to the queue + int times = toInsertItems.size(); + for (int i = 0; i < times; i++) + { + ItemStack insert = toInsertItems.poll(); + if (insert != null) { + ItemStack remainder = network.insertItem(insert, insert.stackSize, false); + if (remainder != null) { + toInsertItems.add(remainder); + } } - - return toInsert.isEmpty(); } - return false; + steps.removeIf(ICraftingStep::hasReceivedOutputs); + + return isFinished(); } - private boolean canProcess(IProcessable processable) { - for (ICraftingTask otherTask : network.getCraftingTasks()) { - for (IProcessable otherProcessable : otherTask.getToProcess()) { - if (otherProcessable != processable && !otherProcessable.hasReceivedOutputs() && otherProcessable.hasStartedProcessing() && otherProcessable.getPattern().getContainer().getFacingTile() != null) { - if (!arePatternsEqual(processable.getPattern(), otherProcessable.getPattern())) { - if (processable.getPattern().getContainer().getFacingTile().getPos().equals(otherProcessable.getPattern().getContainer().getFacingTile().getPos())) { - return false; + private boolean canProcess(ICraftingStep processable) { + if (processable.getPattern().isProcessing()) { + for (ICraftingTask otherTask : network.getCraftingTasks()) { + for (ICraftingStep otherProcessable : otherTask.getSteps()) { + if (otherProcessable.getPattern().isProcessing()) { + if (otherProcessable != processable && !otherProcessable.hasReceivedOutputs() && otherProcessable.hasStartedProcessing() && otherProcessable.getPattern().getContainer().getFacingTile() != null) { + if (!arePatternsEqual(processable.getPattern(), otherProcessable.getPattern())) { + if (processable.getPattern().getContainer().getFacingTile().getPos().equals(otherProcessable.getPattern().getContainer().getFacingTile().getPos())) { + return false; + } + } } } } @@ -374,115 +329,119 @@ public class CraftingTask implements ICraftingTask { NBTTagList processablesList = new NBTTagList(); - for (IProcessable processable : toProcess) { + for (ICraftingStep processable : steps) { processablesList.appendTag(processable.writeToNBT(new NBTTagCompound())); } tag.setTag(NBT_TO_PROCESS, processablesList); - tag.setTag(NBT_TO_TAKE, RSUtils.serializeItemStackList(toTake)); - tag.setTag(NBT_INTERNAL_TO_TAKE, RSUtils.serializeItemStackList(internalToTake)); + NBTTagList toInsertItemsList = new NBTTagList(); + + for (ItemStack insert : toInsertItems) { + toInsertItemsList.appendTag(insert.serializeNBT()); + } + + tag.setTag(NBT_TO_INSERT_ITEMS, toInsertItemsList); + tag.setTag(NBT_TO_TAKE_FLUIDS, RSUtils.serializeFluidStackList(toTakeFluids)); - NBTTagList toInsertList = new NBTTagList(); + NBTTagList toInsertFluidsList = new NBTTagList(); - for (ItemStack insert : new ArrayList<>(toInsert)) { - toInsertList.appendTag(insert.serializeNBT()); + for (FluidStack insert : toInsertFluids) { + toInsertFluidsList.appendTag(insert.writeToNBT(new NBTTagCompound())); } - tag.setTag(NBT_TO_INSERT, toInsertList); + tag.setTag(NBT_TO_INSERT_FLUIDS, toInsertFluidsList); - tag.setTag(NBT_TOOK, RSUtils.serializeItemStackList(took)); - - NBTTagList fluidsTookList = new NBTTagList(); - - for (FluidStack took : this.tookFluids) { - fluidsTookList.appendTag(took.writeToNBT(new NBTTagCompound())); - } - - tag.setTag(NBT_TOOK_FLUIDS, fluidsTookList); + tag.setTag(NBT_TOOK_FLUIDS, RSUtils.serializeFluidStackList(tookFluids)); return tag; } @Override public List getCraftingMonitorElements() { - List elements = new ArrayList<>(); + ICraftingMonitorElementList elements = API.instance().createCraftingMonitorElementList(); - elements.add(new CraftingMonitorElementItemRender( + elements.directAdd(new CraftingMonitorElementItemRender( network.getCraftingTasks().indexOf(this), requested != null ? requested : pattern.getOutputs().get(0), quantity, 0 )); - if (isFinished() && !toInsert.isEmpty()) { - elements.add(new CraftingMonitorElementText("gui.refinedstorage:crafting_monitor.items_inserting", 16)); + if (!toInsertItems.isEmpty()) { + elements.directAdd(new CraftingMonitorElementText("gui.refinedstorage:crafting_monitor.items_inserting", 16)); - elements.addAll(toInsert.stream() - .map(stack -> new CraftingMonitorElementItemRender( - -1, - stack, - stack.stackSize, - 32 - )) - .collect(Collectors.toList()) - ); - } else { - if (!toTake.isEmpty()) { - elements.add(new CraftingMonitorElementText("gui.refinedstorage:crafting_monitor.items_taking", 16)); - - elements.addAll(toTake.getStacks().stream() + toInsertItems.stream() .map(stack -> new CraftingMonitorElementItemRender( - -1, - stack, - stack.stackSize, - 32 + -1, + stack, + stack.stackSize, + 32 )) - .collect(Collectors.toList()) - ); - } + .forEach(elements::add); - if (!toTakeFluids.isEmpty()) { - elements.add(new CraftingMonitorElementText("gui.refinedstorage:crafting_monitor.fluids_taking", 16)); + elements.commit(); + } - elements.addAll(toTakeFluids.getStacks().stream() - .map(stack -> new CraftingMonitorElementFluidRender( - -1, - stack, - 32 - )) - .collect(Collectors.toList()) - ); - } + if (!isFinished()) { + if (steps.stream().filter(s -> !s.getPattern().isProcessing()).count() > 0) { + elements.directAdd(new CraftingMonitorElementText("gui.refinedstorage:crafting_monitor.items_crafting", 16)); - if (!hasProcessedItems()) { - elements.add(new CraftingMonitorElementText("gui.refinedstorage:crafting_monitor.items_processing", 16)); - - for (IProcessable processable : toProcess) { + for (ICraftingStep processable : steps.stream().filter(s -> !s.getPattern().isProcessing()).collect(Collectors.toList())) { for (int i = 0; i < processable.getPattern().getOutputs().size(); ++i) { - if (!processable.hasReceivedOutput(i)) { - ICraftingMonitorElement element = new CraftingMonitorElementItemRender( + elements.add(new CraftingMonitorElementItemRender( -1, processable.getPattern().getOutputs().get(i), processable.getPattern().getOutputs().get(i).stackSize, 32 - ); - - if (processable.getPattern().getContainer().getFacingTile() == null) { - element = new CraftingMonitorElementError(element, "gui.refinedstorage:crafting_monitor.machine_none"); - } else if (!canProcess(processable)) { - element = new CraftingMonitorElementError(element, "gui.refinedstorage:crafting_monitor.machine_in_use"); - } - - elements.add(element); - } + )); } } + + elements.commit(); + } + + if (steps.stream().filter(s -> s.getPattern().isProcessing()).count() > 0) { + elements.directAdd(new CraftingMonitorElementText("gui.refinedstorage:crafting_monitor.items_processing", 16)); + + for (ICraftingStep processable : steps.stream().filter(s -> s.getPattern().isProcessing()).collect(Collectors.toList())) { + for (int i = 0; i < processable.getPattern().getOutputs().size(); ++i) { + ICraftingMonitorElement element = new CraftingMonitorElementItemRender( + -1, + processable.getPattern().getOutputs().get(i), + processable.getPattern().getOutputs().get(i).stackSize, + 32 + ); + + if (processable.getPattern().getContainer().getFacingTile() == null) { + element = new CraftingMonitorElementError(element, "gui.refinedstorage:crafting_monitor.machine_none"); + } else if (!canProcess(processable)) { + element = new CraftingMonitorElementError(element, "gui.refinedstorage:crafting_monitor.machine_in_use"); + } + + elements.add(element); + } + } + + elements.commit(); + } + + if (!toTakeFluids.isEmpty()) { + elements.directAdd(new CraftingMonitorElementText("gui.refinedstorage:crafting_monitor.fluids_taking", 16)); + + toTakeFluids.getStacks().stream() + .map(stack -> new CraftingMonitorElementFluidRender( + -1, + stack, + 32 + )).forEach(elements::add); + + elements.commit(); } } - return elements; + return elements.getElements(); } @Override @@ -490,9 +449,8 @@ public class CraftingTask implements ICraftingTask { return pattern; } - @Override - public List getToProcess() { - return toProcess; + public List getSteps() { + return steps; } @Override @@ -547,10 +505,6 @@ public class CraftingTask implements ICraftingTask { } private boolean isFinished() { - return toTake.isEmpty() && internalToTake.isEmpty() && toTakeFluids.isEmpty() && missing.isEmpty() && hasProcessedItems(); - } - - private boolean hasProcessedItems() { - return toProcess.stream().allMatch(IProcessable::hasReceivedOutputs); + return steps.stream().allMatch(ICraftingStep::hasReceivedOutputs); } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/ProcessCraftingStep.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/ProcessCraftingStep.java new file mode 100644 index 000000000..90b83678f --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/ProcessCraftingStep.java @@ -0,0 +1,40 @@ +package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task; + +import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; +import com.raoulvdberge.refinedstorage.api.network.INetworkMaster; +import com.raoulvdberge.refinedstorage.api.util.IComparer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; + +import java.util.Deque; + +public class ProcessCraftingStep extends AbstractCraftingStep { + public static final String ID = "ProcessCraftingStep"; + + public ProcessCraftingStep(INetworkMaster network, ICraftingPattern pattern) { + super(network, pattern); + } + + public ProcessCraftingStep(INetworkMaster network) { + super(network); + } + + @Override + public void execute(Deque toInsertItems, Deque toInsertFluids) { + // TODO fluid handling + IItemHandler inventory = getPattern().getContainer().getFacingInventory(); + for (ItemStack insertStack : getToInsert()) { + ItemStack tookStack = network.extractItem(insertStack, insertStack.stackSize, CraftingTask.DEFAULT_COMPARE | (getPattern().isOredict() ? IComparer.COMPARE_OREDICT : 0)); + ItemHandlerHelper.insertItem(inventory, tookStack, false); + } + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound tag) { + tag.setString(NBT_CRAFTING_STEP_TYPE, ID); + return super.writeToNBT(tag); + } +} 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 7bbeb1d59..054216340 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/FluidStackList.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/FluidStackList.java @@ -3,12 +3,15 @@ package com.raoulvdberge.refinedstorage.apiimpl.util; import com.google.common.collect.ArrayListMultimap; import com.raoulvdberge.refinedstorage.api.util.IFluidStackList; import com.raoulvdberge.refinedstorage.apiimpl.API; +import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; public class FluidStackList implements IFluidStackList { private ArrayListMultimap stacks = ArrayListMultimap.create(); @@ -31,12 +34,13 @@ public class FluidStackList implements IFluidStackList { for (FluidStack otherStack : stacks.get(stack.getFluid())) { if (stack.isFluidEqual(otherStack)) { otherStack.amount -= size; + boolean success = otherStack.amount >= 0; if (otherStack.amount <= 0 && removeIfReachedZero) { stacks.remove(otherStack.getFluid(), otherStack); } - return true; + return success; } } @@ -72,6 +76,14 @@ public class FluidStackList implements IFluidStackList { stacks.clear(); } + @Override + public void clean() { + List toRemove = stacks.values().stream() + .filter(stack -> stack.amount <= 0) + .collect(Collectors.toList()); + toRemove.forEach(stack -> stacks.remove(stack.getFluid(), stack)); + } + @Override public boolean isEmpty() { return stacks.isEmpty(); 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 c09b16fd6..0e1c877a9 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/ItemStackList.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/util/ItemStackList.java @@ -38,12 +38,13 @@ public class ItemStackList implements IItemStackList { for (ItemStack otherStack : stacks.get(stack.getItem())) { if (API.instance().getComparer().isEqualNoQuantity(otherStack, stack)) { otherStack.stackSize -= size; + boolean success = otherStack.stackSize >= 0; if (otherStack.stackSize <= 0 && removeIfReachedZero) { stacks.remove(otherStack.getItem(), otherStack); } - return true; + return success; } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/tile/TileController.java b/src/main/java/com/raoulvdberge/refinedstorage/tile/TileController.java index 447cced99..f5db2f830 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/tile/TileController.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/tile/TileController.java @@ -10,7 +10,7 @@ import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternContaine import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternProvider; import com.raoulvdberge.refinedstorage.api.autocrafting.registry.ICraftingTaskFactory; import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTask; -import com.raoulvdberge.refinedstorage.api.autocrafting.task.IProcessable; +import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingStep; import com.raoulvdberge.refinedstorage.api.network.INetworkMaster; import com.raoulvdberge.refinedstorage.api.network.INetworkNode; import com.raoulvdberge.refinedstorage.api.network.INetworkNodeGraph; @@ -290,26 +290,29 @@ public class TileController extends TileBase implements INetworkMaster, IEnergyR craftingTasksToAdd.clear(); - Iterator craftingTaskIterator = craftingTasks.iterator(); + // Only run task updates every 5 ticks + if (ticks % 5 == 0) { + Iterator craftingTaskIterator = craftingTasks.iterator(); + Map usedCrafters = new HashMap<>(); - while (craftingTaskIterator.hasNext()) { - ICraftingTask task = craftingTaskIterator.next(); - ICraftingPatternContainer container = task.getPattern().getContainer(); + while (craftingTaskIterator.hasNext()) { + ICraftingTask task = craftingTaskIterator.next(); - if (container != null && ticks % container.getSpeed() == 0 && task.update()) { - craftingTaskIterator.remove(); + if (task.update(usedCrafters)) { + craftingTaskIterator.remove(); - craftingTasksChanged = true; + craftingTasksChanged = true; + } } - } - if (craftingTasksChanged) { - craftingMonitorUpdateRequested = true; - } + if (craftingTasksChanged) { + craftingMonitorUpdateRequested = true; + } - if (!craftingTasks.isEmpty()) { - markDirty(); + if (!craftingTasks.isEmpty()) { + markDirty(); + } } if (craftingMonitorUpdateRequested) { @@ -321,6 +324,7 @@ public class TileController extends TileBase implements INetworkMaster, IEnergyR } } } + } wirelessGridHandler.update(); @@ -457,7 +461,7 @@ public class TileController extends TileBase implements INetworkMaster, IEnergyR for (ItemStack input : patterns.get(i).getInputs()) { if (input != null) { - ItemStack stored = itemStorage.getList().get(input, IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT); + ItemStack stored = itemStorage.getList().get(input, IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT | (patterns.get(i).isOredict() ? IComparer.COMPARE_OREDICT : 0)); score += stored != null ? stored.stackSize : 0; } @@ -578,21 +582,11 @@ public class TileController extends TileBase implements INetworkMaster, IEnergyR if (!simulate && inserted > 0 && accessType != AccessType.WRITE) { itemStorage.add(ItemHandlerHelper.copyStackWithSize(stack, inserted), false); - for (int i = 0; i < inserted; ++i) { - for (ICraftingTask task : craftingTasks) { - if (inserted == 0) { + for (ICraftingTask task : craftingTasks) { + for (ICraftingStep processable : task.getSteps()) { + if (processable.onReceiveOutput(stack)) { break; } - - for (IProcessable processable : task.getToProcess()) { - if (inserted == 0) { - break; - } - - if (processable.onReceiveOutput(stack)) { - inserted--; - } - } } } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/tile/TileCrafter.java b/src/main/java/com/raoulvdberge/refinedstorage/tile/TileCrafter.java index cd5a47b6a..7337db247 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/tile/TileCrafter.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/tile/TileCrafter.java @@ -152,8 +152,8 @@ public class TileCrafter extends TileNode implements ICraftingPatternContainer { } @Override - public int getSpeed() { - return 20 - (upgrades.getUpgradeCount(ItemUpgrade.TYPE_SPEED) * 4); + public int getSpeedUpdateCount() { + return upgrades.getUpgradeCount(ItemUpgrade.TYPE_SPEED); } @Override diff --git a/src/main/resources/assets/refinedstorage/lang/en_US.lang b/src/main/resources/assets/refinedstorage/lang/en_US.lang index 58fe33c76..d041328dd 100755 --- a/src/main/resources/assets/refinedstorage/lang/en_US.lang +++ b/src/main/resources/assets/refinedstorage/lang/en_US.lang @@ -19,8 +19,8 @@ gui.refinedstorage:relay=Relay gui.refinedstorage:interface.import=Interface Import gui.refinedstorage:interface.export=Interface Export gui.refinedstorage:crafting_monitor=Crafting Monitor -gui.refinedstorage:crafting_monitor.items_taking=Items taking gui.refinedstorage:crafting_monitor.fluids_taking=Fluids taking +gui.refinedstorage:crafting_monitor.items_crafting=Items crafting gui.refinedstorage:crafting_monitor.items_processing=Items processing gui.refinedstorage:crafting_monitor.items_inserting=Items inserting gui.refinedstorage:crafting_monitor.machine_in_use=Machine is in use