Autocrafting refactor (#2625)

* Extract some methods to other classes to reduce LOC, rename Craft/Crafting/Processing.

* Remove CraftingTaskState as it's unused.

* Move creation of preview elements.

* Move creation of monitor elements.

* Move node management.

* Move recipe node update.

* Move processing node update.

* Clean up List<Pair<NonNullList<ItemStack>, Integer>> mess.

* Introduce CraftingPreviewInfo

* CraftingTask#calculate returns non-null value now

* Split calculate method up some more.

* Rename nodes a bit for readability.

* Make sure that no CraftingTask instance exists that has missing items.

* More cleanup.

* More cleanup.

* Rename some stuff.

* Introduce a NodeListener.

* Improve ProcessingNode a bit.

* Improve some naming.

* Add missing doc

* Merge PossibleInputs.

* Fix breaking out of wrong loop.

* Remove crafting pattern chain stuff and fix forgotten changes to IoUtil calls.
This commit is contained in:
Raoul
2020-07-22 19:29:58 +02:00
committed by GitHub
parent b72a19942f
commit df458e64c6
50 changed files with 2306 additions and 1938 deletions

View File

@@ -1,6 +1,7 @@
package com.refinedmods.refinedstorage.api.autocrafting;
import com.refinedmods.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorListener;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICalculationResult;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingTask;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
@@ -54,25 +55,18 @@ public interface ICraftingManager {
*
* @param stack the stack to craft
* @param quantity the quantity to craft
* @return the crafting task, or null if no pattern was found for the given stack
* @return the calculation result
*/
@Nullable
ICraftingTask create(ItemStack stack, int quantity);
ICalculationResult create(ItemStack stack, int quantity);
/**
* Creates a crafting task for a given stack, but doesn't add it to the list.
*
* @param stack the stack to craft
* @param quantity the quantity to craft
* @return the crafting task, or null if no pattern was found for the given stack
* @return the calculation result
*/
@Nullable
ICraftingTask create(FluidStack stack, int quantity);
/**
* @return a new pattern chain list
*/
ICraftingPatternChainList createPatternChainList();
ICalculationResult create(FluidStack stack, int quantity);
/**
* Schedules a crafting task if the task isn't scheduled yet.
@@ -170,9 +164,8 @@ public interface ICraftingManager {
void onTaskChanged();
/**
* @param pattern to look for
* @return a LinkedHashSet with all container that have this pattern
* @param pattern pattern to look for
* @return a set with all containers that have this pattern
*/
Set<ICraftingPatternContainer> getAllContainer(ICraftingPattern pattern);
Set<ICraftingPatternContainer> getAllContainers(ICraftingPattern pattern);
}

View File

@@ -81,15 +81,4 @@ public interface ICraftingPattern {
* @return the id of the factory that creates a crafting task for this pattern, as defined in the {@link ICraftingTaskRegistry}
*/
ResourceLocation getCraftingTaskFactoryId();
/**
* @param other the other pattern
* @return true if this pattern chain be in a chain with the other pattern, false otherwise
*/
boolean canBeInChainWith(ICraftingPattern other);
/**
* @return the hashcode used to store the pattern chains
*/
int getChainHashCode();
}

View File

@@ -1,18 +0,0 @@
package com.refinedmods.refinedstorage.api.autocrafting;
/**
* A crafting pattern chain, which stores equivalent patterns.
*/
public interface ICraftingPatternChain {
/**
* @return the current pattern in the chain
*/
ICraftingPattern current();
/**
* Cycles the pattern in the chain.
*
* @return the cycled (and now current) pattern
*/
ICraftingPattern cycle();
}

View File

@@ -1,12 +0,0 @@
package com.refinedmods.refinedstorage.api.autocrafting;
/**
* A list of pattern chains per pattern.
*/
public interface ICraftingPatternChainList {
/**
* @param pattern the pattern
* @return a chain for the pattern
*/
ICraftingPatternChain getChain(ICraftingPattern pattern);
}

View File

@@ -22,8 +22,8 @@ public interface ICraftingMonitorElementList {
* Add a element to the Processing or Crafting 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}
* @param isProcessing wether to add to the processing list or the crafting list
* @param element the {@link ICraftingMonitorElement}
* @param isProcessing whether to add to the processing list or the crafting list
*/
void add(ICraftingMonitorElement element, boolean isProcessing);

View File

@@ -1,9 +1,21 @@
package com.refinedmods.refinedstorage.api.autocrafting.task;
/**
* The error type.
* The result type.
*/
public enum CraftingTaskErrorType {
public enum CalculationResultType {
/**
* No problems.
*/
OK,
/**
* Some requirements are missing.
*/
MISSING,
/**
* There is no pattern for the requested stack.
*/
NO_PATTERN,
/**
* When the crafting task would cause too much server strain or is too complex.
*/
@@ -11,5 +23,5 @@ public enum CraftingTaskErrorType {
/**
* When one of the used patterns during the calculation reuses itself again and would cause an infinite loop.
*/
RECURSIVE
RECURSIVE;
}

View File

@@ -1,9 +0,0 @@
package com.refinedmods.refinedstorage.api.autocrafting.task;
public enum CraftingTaskState {
UNKNOWN,
CALCULATING,
CALCULATED,
RUNNING,
DONE
}

View File

@@ -0,0 +1,41 @@
package com.refinedmods.refinedstorage.api.autocrafting.task;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement;
import javax.annotation.Nullable;
import java.util.List;
/**
* The result of the crafting calculation.
*/
public interface ICalculationResult {
/**
* @return the type
*/
CalculationResultType getType();
/**
* @return get a list of {@link ICraftingPreviewElement}s
*/
List<ICraftingPreviewElement<?>> getPreviewElements();
/**
* @return the task if the calculation {@link #isOk()}, otherwise null
*/
@Nullable
ICraftingTask getTask();
/**
* @return whether the calculation succeeded
*/
boolean isOk();
/**
* If this result type is a {@link CalculationResultType#RECURSIVE}, the recursed pattern will be returned here.
*
* @return the recursed pattern, or null if this result is not {@link CalculationResultType#RECURSIVE}
*/
@Nullable
ICraftingPattern getRecursedPattern();
}

View File

@@ -2,14 +2,11 @@ package com.refinedmods.refinedstorage.api.autocrafting.task;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElement;
import com.refinedmods.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.api.util.IStackList;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraftforge.fluids.FluidStack;
import javax.annotation.Nullable;
import java.util.List;
import java.util.UUID;
@@ -17,19 +14,10 @@ import java.util.UUID;
* Represents a crafting task.
*/
public interface ICraftingTask {
/**
* Calculates what this task will do, but doesn't run the task yet.
*
* @return the error, or null if there was no error
*/
@Nullable
ICraftingTaskError calculate();
/**
* Updates this task.
* {@link ICraftingTask#calculate()} must be run before this!
*
* @return true if this crafting task is finished and can be deleted from the list, false otherwise
* @return true if this crafting task is finished, false otherwise
*/
boolean update();
@@ -57,6 +45,7 @@ public interface ICraftingTask {
* Called when a stack is inserted into the system through {@link INetwork#insertItemTracked(ItemStack, int)}.
*
* @param stack the stack
* @return the remainder of this stack after processing of the task
*/
int onTrackedInsert(ItemStack stack, int size);
@@ -64,6 +53,7 @@ public interface ICraftingTask {
* Called when a stack is inserted into the system through {@link INetwork#insertFluidTracked(FluidStack, int)}.
*
* @param stack the stack
* @return the remainder of this stack after processing of the task
*/
int onTrackedInsert(FluidStack stack, int size);
@@ -76,56 +66,25 @@ public interface ICraftingTask {
CompoundNBT writeToNbt(CompoundNBT tag);
/**
* {@link ICraftingTask#calculate()} must be run before this!
*
* @return the elements of this task for display in the crafting monitor
*/
List<ICraftingMonitorElement> getCraftingMonitorElements();
/**
* {@link ICraftingTask#calculate()} must be run before this!
*
* @return get a list of {@link ICraftingPreviewElement}s
*/
List<ICraftingPreviewElement<?>> getPreviewStacks();
/**
* @return the crafting pattern corresponding to this task
*/
ICraftingPattern getPattern();
/**
* @return the time in ms when this task has started
* @return the unix time in ms when this task has started
*/
long getExecutionStarted();
/**
* @return the missing items
*/
IStackList<ItemStack> getMissing();
/**
* @return the missing fluids
*/
IStackList<FluidStack> getMissingFluids();
/**
* @return true if any items or fluids are missing, false otherwise
*/
default boolean hasMissing() {
return !getMissing().isEmpty() || !getMissingFluids().isEmpty();
}
long getStartTime();
/**
* @return the id of this task
*/
UUID getId();
/**
* @return the state of this crafting task
*/
CraftingTaskState getState();
/**
* Start the CraftingTask
*/

View File

@@ -1,23 +0,0 @@
package com.refinedmods.refinedstorage.api.autocrafting.task;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import javax.annotation.Nullable;
/**
* Returned from {@link ICraftingTask#calculate()} when an error occurs during the calculation.
*/
public interface ICraftingTaskError {
/**
* @return the type
*/
CraftingTaskErrorType getType();
/**
* If this error type is a {@link CraftingTaskErrorType#RECURSIVE}, the recursed pattern will be returned here.
*
* @return the recursed pattern, or null if this error is not {@link CraftingTaskErrorType#RECURSIVE}
*/
@Nullable
ICraftingPattern getRecursedPattern();
}

View File

@@ -4,8 +4,6 @@ import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.network.INetwork;
import net.minecraft.nbt.CompoundNBT;
import javax.annotation.Nonnull;
/**
* A factory that creates a crafting task.
* Register this factory in the {@link ICraftingTaskRegistry}.
@@ -18,10 +16,9 @@ public interface ICraftingTaskFactory {
* @param requested the request info
* @param pattern the pattern
* @param quantity the quantity
* @return the crafting task
* @return the calculation result
*/
@Nonnull
ICraftingTask create(INetwork network, ICraftingRequestInfo requested, int quantity, ICraftingPattern pattern);
ICalculationResult create(INetwork network, ICraftingRequestInfo requested, int quantity, ICraftingPattern pattern);
/**
* Returns a crafting task for a given NBT tag.

View File

@@ -56,6 +56,23 @@ public interface IStackList<T> {
return get(stack, IComparer.COMPARE_NBT);
}
/**
* Returns the amount in this list, based on the stack and the flags.
*
* @param stack the stack
* @param flags the flags
* @return the count, 0 if not found
*/
int getCount(@Nonnull T stack, int flags);
/**
* @param stack the stack
* @return the count, 0 if not found
*/
default int getCount(@Nonnull T stack) {
return getCount(stack, IComparer.COMPARE_NBT);
}
/**
* Returns a stack.
*

View File

@@ -2,18 +2,14 @@ package com.refinedmods.refinedstorage.apiimpl.autocrafting;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingManager;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPatternChainList;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPatternContainer;
import com.refinedmods.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorListener;
import com.refinedmods.refinedstorage.api.autocrafting.task.CraftingTaskReadException;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingTask;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingTaskError;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingTaskFactory;
import com.refinedmods.refinedstorage.api.autocrafting.task.*;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.api.network.node.INetworkNode;
import com.refinedmods.refinedstorage.api.util.IComparer;
import com.refinedmods.refinedstorage.apiimpl.API;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.CraftingTask;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.calculator.CalculationResult;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
@@ -94,40 +90,33 @@ public class CraftingManager implements ICraftingManager {
}
@Override
@Nullable
public ICraftingTask create(ItemStack stack, int quantity) {
public ICalculationResult create(ItemStack stack, int quantity) {
ICraftingPattern pattern = getPattern(stack);
if (pattern == null) {
return null;
return new CalculationResult(CalculationResultType.NO_PATTERN);
}
ICraftingTaskFactory factory = API.instance().getCraftingTaskRegistry().get(pattern.getCraftingTaskFactoryId());
if (factory == null) {
return null;
}
return factory.create(network, API.instance().createCraftingRequestInfo(stack), quantity, pattern);
}
@Nullable
@Override
public ICraftingTask create(FluidStack stack, int quantity) {
ICraftingPattern pattern = getPattern(stack);
if (pattern == null) {
return null;
}
ICraftingTaskFactory factory = API.instance().getCraftingTaskRegistry().get(pattern.getCraftingTaskFactoryId());
if (factory == null) {
return null;
return new CalculationResult(CalculationResultType.NO_PATTERN);
}
return factory.create(network, API.instance().createCraftingRequestInfo(stack), quantity, pattern);
}
@Override
public ICraftingPatternChainList createPatternChainList() {
return new CraftingPatternChainList(patterns);
public ICalculationResult create(FluidStack stack, int quantity) {
ICraftingPattern pattern = getPattern(stack);
if (pattern == null) {
return new CalculationResult(CalculationResultType.NO_PATTERN);
}
ICraftingTaskFactory factory = API.instance().getCraftingTaskRegistry().get(pattern.getCraftingTaskFactoryId());
if (factory == null) {
return new CalculationResult(CalculationResultType.NO_PATTERN);
}
return factory.create(network, API.instance().createCraftingRequestInfo(stack), quantity, pattern);
}
@Override
@@ -249,18 +238,10 @@ public class CraftingManager implements ICraftingManager {
}
if (amount > 0) {
ICraftingTask task = create(stack, amount);
ICalculationResult result = create(stack, amount);
if (task != null) {
ICraftingTaskError error = task.calculate();
if (error == null && !task.hasMissing()) {
this.start(task);
return task;
} else {
throttle(source);
}
if (result.isOk()) {
start(result.getTask());
} else {
throttle(source);
}
@@ -285,18 +266,10 @@ public class CraftingManager implements ICraftingManager {
}
if (amount > 0) {
ICraftingTask task = create(stack, amount);
ICalculationResult result = create(stack, amount);
if (task != null) {
ICraftingTaskError error = task.calculate();
if (error == null && !task.hasMissing()) {
this.start(task);
return task;
} else {
throttle(source);
}
if (result.isOk()) {
start(result.getTask());
} else {
throttle(source);
}
@@ -413,8 +386,8 @@ public class CraftingManager implements ICraftingManager {
}
@Override
public Set<ICraftingPatternContainer> getAllContainer(ICraftingPattern pattern) {
return patternToContainer.getOrDefault(pattern, new LinkedHashSet<>());
public Set<ICraftingPatternContainer> getAllContainers(ICraftingPattern pattern) {
return patternToContainer.getOrDefault(pattern, Collections.emptySet());
}
@Nullable

View File

@@ -169,7 +169,13 @@ public class CraftingPattern implements ICraftingPattern {
}
@Override
public boolean canBeInChainWith(ICraftingPattern other) {
public boolean equals(Object otherObj) {
if (!(otherObj instanceof ICraftingPattern)) {
return false;
}
ICraftingPattern other = (ICraftingPattern) otherObj;
if (other.isProcessing() != processing) {
return false;
}
@@ -239,7 +245,7 @@ public class CraftingPattern implements ICraftingPattern {
}
@Override
public int getChainHashCode() {
public int hashCode() {
int result = 0;
result = 31 * result + (processing ? 1 : 0);
@@ -272,19 +278,6 @@ public class CraftingPattern implements ICraftingPattern {
return result;
}
@Override
public int hashCode() {
return getChainHashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof CraftingPattern) {
return canBeInChainWith((CraftingPattern) obj);
}
return false;
}
public static class DummyCraftingInventory extends CraftingInventory {
public DummyCraftingInventory() {
super(new Container(null, 0) {

View File

@@ -1,32 +0,0 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPatternChain;
import java.util.ArrayList;
import java.util.List;
public class CraftingPatternChain implements ICraftingPatternChain {
private final List<ICraftingPattern> patterns = new ArrayList<>();
private int pos;
public void addPattern(ICraftingPattern pattern) {
patterns.add(pattern);
}
@Override
public ICraftingPattern current() {
return patterns.get(pos);
}
@Override
public ICraftingPattern cycle() {
if (pos + 1 >= patterns.size()) {
this.pos = 0;
} else {
this.pos++;
}
return current();
}
}

View File

@@ -1,56 +0,0 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPatternChain;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPatternChainList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class CraftingPatternChainList implements ICraftingPatternChainList {
private final Map<Key, CraftingPatternChain> map = new HashMap<>();
public CraftingPatternChainList(Collection<ICraftingPattern> patterns) {
for (ICraftingPattern pattern : patterns) {
Key key = new Key(pattern);
CraftingPatternChain chain = map.get(key);
if (chain == null) {
map.put(key, chain = new CraftingPatternChain());
}
chain.addPattern(pattern);
}
}
@Override
public ICraftingPatternChain getChain(ICraftingPattern pattern) {
ICraftingPatternChain chain = map.get(new Key(pattern));
if (chain == null) {
throw new IllegalStateException("Pattern was not found in pattern chain");
}
return chain;
}
private static class Key {
private final ICraftingPattern pattern;
public Key(ICraftingPattern pattern) {
this.pattern = pattern;
}
@Override
public boolean equals(Object other) {
return other instanceof Key && pattern.canBeInChainWith(((Key) other).pattern);
}
@Override
public int hashCode() {
return pattern.getChainHashCode();
}
}
}

View File

@@ -158,4 +158,50 @@ public class FluidCraftingMonitorElement implements ICraftingMonitorElement {
public int elementHashCode() {
return API.instance().getFluidStackHashCode(stack);
}
public static class Builder {
private final FluidStack stack;
private int stored;
private int missing;
private int processing;
private int scheduled;
private int crafting;
public Builder(FluidStack stack) {
this.stack = stack;
}
public FluidCraftingMonitorElement.Builder stored(int stored) {
this.stored = stored;
return this;
}
public FluidCraftingMonitorElement.Builder missing(int missing) {
this.missing = missing;
return this;
}
public FluidCraftingMonitorElement.Builder processing(int processing) {
this.processing = processing;
return this;
}
public FluidCraftingMonitorElement.Builder scheduled(int scheduled) {
this.scheduled = scheduled;
return this;
}
public FluidCraftingMonitorElement.Builder crafting(int crafting) {
this.crafting = crafting;
return this;
}
public FluidCraftingMonitorElement build() {
return new FluidCraftingMonitorElement(stack, stored, missing, processing, scheduled, crafting);
}
public static FluidCraftingMonitorElement.Builder forStack(FluidStack stack) {
return new FluidCraftingMonitorElement.Builder(stack);
}
}
}

View File

@@ -158,4 +158,50 @@ public class ItemCraftingMonitorElement implements ICraftingMonitorElement {
public int elementHashCode() {
return API.instance().getItemStackHashCode(stack);
}
public static class Builder {
private final ItemStack stack;
private int stored;
private int missing;
private int processing;
private int scheduled;
private int crafting;
public Builder(ItemStack stack) {
this.stack = stack;
}
public Builder stored(int stored) {
this.stored = stored;
return this;
}
public Builder missing(int missing) {
this.missing = missing;
return this;
}
public Builder processing(int processing) {
this.processing = processing;
return this;
}
public Builder scheduled(int scheduled) {
this.scheduled = scheduled;
return this;
}
public Builder crafting(int crafting) {
this.crafting = crafting;
return this;
}
public ItemCraftingMonitorElement build() {
return new ItemCraftingMonitorElement(stack, stored, missing, processing, scheduled, crafting);
}
public static Builder forStack(ItemStack stack) {
return new Builder(stack);
}
}
}

View File

@@ -3,7 +3,7 @@ package com.refinedmods.refinedstorage.apiimpl.autocrafting.preview;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.refinedmods.refinedstorage.RS;
import com.refinedmods.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement;
import com.refinedmods.refinedstorage.api.autocrafting.task.CraftingTaskErrorType;
import com.refinedmods.refinedstorage.api.autocrafting.task.CalculationResultType;
import com.refinedmods.refinedstorage.api.render.IElementDrawers;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
@@ -12,10 +12,10 @@ import net.minecraft.util.ResourceLocation;
public class ErrorCraftingPreviewElement implements ICraftingPreviewElement<ItemStack> {
public static final ResourceLocation ID = new ResourceLocation(RS.ID, "error");
private final CraftingTaskErrorType type;
private final CalculationResultType type;
private final ItemStack stack;
public ErrorCraftingPreviewElement(CraftingTaskErrorType type, ItemStack stack) {
public ErrorCraftingPreviewElement(CalculationResultType type, ItemStack stack) {
this.type = type;
this.stack = stack;
}
@@ -51,13 +51,13 @@ public class ErrorCraftingPreviewElement implements ICraftingPreviewElement<Item
buf.writeItemStack(stack);
}
public CraftingTaskErrorType getType() {
public CalculationResultType getType() {
return type;
}
public static ErrorCraftingPreviewElement read(PacketBuffer buf) {
int errorIdx = buf.readInt();
CraftingTaskErrorType error = errorIdx >= 0 && errorIdx < CraftingTaskErrorType.values().length ? CraftingTaskErrorType.values()[errorIdx] : CraftingTaskErrorType.TOO_COMPLEX;
CalculationResultType error = errorIdx >= 0 && errorIdx < CalculationResultType.values().length ? CalculationResultType.values()[errorIdx] : CalculationResultType.TOO_COMPLEX;
ItemStack stack = buf.readItemStack();
return new ErrorCraftingPreviewElement(error, stack);

View File

@@ -1,145 +0,0 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6;
import com.google.common.primitives.Ints;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.task.CraftingTaskReadException;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.api.util.IStackList;
import com.refinedmods.refinedstorage.api.util.StackListEntry;
import com.refinedmods.refinedstorage.apiimpl.API;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraftforge.common.util.Constants;
import org.apache.logging.log4j.LogManager;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public abstract class Craft {
private static final String NBT_PATTERN = "Pattern";
private static final String NBT_ROOT = "Root";
private static final String NBT_IS_PROCESSING = "IsProcessing";
private static final String NBT_ITEMS_TO_USE = "ItemsToUse";
private static final String NBT_QUANTITY = "Quantity";
private static final String NBT_NEEDED_PER_CRAFT = "NeededPerCraft";
private final boolean root;
protected int quantity;
private final ICraftingPattern pattern;
private final Map<Integer, IStackList<ItemStack>> itemsToUse = new LinkedHashMap<>();
private final Map<Integer, Integer> neededPerCraft = new LinkedHashMap<>();
Craft(ICraftingPattern pattern, boolean root) {
this.pattern = pattern;
this.root = root;
}
Craft(INetwork network, CompoundNBT tag) throws CraftingTaskReadException {
this.quantity = tag.getInt(NBT_QUANTITY);
this.pattern = CraftingTask.readPatternFromNbt(tag.getCompound(NBT_PATTERN), network.getWorld());
this.root = tag.getBoolean(NBT_ROOT);
ListNBT list = tag.getList(NBT_ITEMS_TO_USE, Constants.NBT.TAG_LIST);
for (int i = 0; i < list.size(); i++) {
this.itemsToUse.put(i, CraftingTask.readItemStackList(list.getList(i)));
}
List<Integer> perCraftList = Ints.asList(tag.getIntArray(NBT_NEEDED_PER_CRAFT));
for (int i = 0; i < perCraftList.size(); i++) {
neededPerCraft.put(i, perCraftList.get(i));
}
}
static Craft createCraftFromNBT(INetwork network, CompoundNBT tag) throws CraftingTaskReadException {
return tag.getBoolean(NBT_IS_PROCESSING) ? new Processing(network, tag) : new Crafting(network, tag);
}
ICraftingPattern getPattern() {
return pattern;
}
int getQuantity() {
return quantity;
}
void addQuantity(int quantity) {
this.quantity += quantity;
}
void next() {
quantity--;
}
boolean isRoot() {
return root;
}
boolean hasItems() {
return !itemsToUse.isEmpty();
}
IStackList<ItemStack> getItemsToUse(boolean simulate) {
IStackList<ItemStack> toReturn = API.instance().createItemStackList();
for (int i = 0; i < itemsToUse.size(); i++) {
int needed = neededPerCraft.get(i);
if (!itemsToUse.get(i).isEmpty()) {
Iterator<StackListEntry<ItemStack>> it = itemsToUse.get(i).getStacks().iterator();
while (needed > 0 && it.hasNext()) {
ItemStack toUse = it.next().getStack();
if (needed < toUse.getCount()) {
if (!simulate) {
itemsToUse.get(i).remove(toUse, needed);
}
toReturn.add(toUse, needed);
needed = 0;
} else {
if (!simulate) {
it.remove();
}
needed -= toUse.getCount();
toReturn.add(toUse);
}
}
} else {
LogManager.getLogger(Craft.class).warn("Craft requested more Items than available");
this.quantity = 0; // stop crafting
break;
}
}
return toReturn;
}
void addItemsToUse(int ingredientNumber, ItemStack stack, int size, int perCraft) {
if (!neededPerCraft.containsKey(ingredientNumber)) {
neededPerCraft.put(ingredientNumber, perCraft);
}
if (!itemsToUse.containsKey(ingredientNumber)) {
itemsToUse.put(ingredientNumber, API.instance().createItemStackList());
}
itemsToUse.get(ingredientNumber).add(stack, size);
}
CompoundNBT writeToNbt() {
CompoundNBT tag = new CompoundNBT();
tag.putInt(NBT_QUANTITY, quantity);
tag.putBoolean(NBT_IS_PROCESSING, this instanceof Processing);
tag.putBoolean(NBT_ROOT, root);
tag.put(NBT_PATTERN, CraftingTask.writePatternToNbt(pattern));
ListNBT list = new ListNBT();
for (IStackList<ItemStack> stackList : itemsToUse.values()) {
list.add(CraftingTask.writeItemStackList(stackList));
}
tag.put(NBT_ITEMS_TO_USE, list);
tag.putIntArray(NBT_NEEDED_PER_CRAFT, Ints.toArray(neededPerCraft.values()));
return tag;
}
void finishCalculation() {
//NOOP
}
}

View File

@@ -1,50 +0,0 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.task.CraftingTaskReadException;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.util.StackUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.NonNullList;
import net.minecraftforge.common.util.Constants;
class Crafting extends Craft {
private static final String NBT_RECIPE = "Recipe";
private final NonNullList<ItemStack> recipe;
Crafting(ICraftingPattern pattern, boolean root, NonNullList<ItemStack> recipe) {
super(pattern, root);
this.recipe = recipe;
}
Crafting(INetwork network, CompoundNBT tag) throws CraftingTaskReadException {
super(network, tag);
this.recipe = NonNullList.create();
ListNBT tookList = tag.getList(NBT_RECIPE, Constants.NBT.TAG_COMPOUND);
for (int i = 0; i < tookList.size(); ++i) {
ItemStack stack = StackUtils.deserializeStackFromNbt(tookList.getCompound(i));
// Can be empty.
recipe.add(stack);
}
}
NonNullList<ItemStack> getRecipe() {
return recipe;
}
CompoundNBT writeToNbt() {
CompoundNBT tag = super.writeToNbt();
ListNBT tookList = new ListNBT();
for (ItemStack took : this.recipe) {
tookList.add(StackUtils.serializeStackToNbt(took));
}
tag.put(NBT_RECIPE, tookList);
return tag;
}
}

View File

@@ -0,0 +1,144 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.util.IComparer;
import com.refinedmods.refinedstorage.apiimpl.API;
import net.minecraft.item.ItemStack;
import net.minecraft.util.NonNullList;
import net.minecraftforge.fluids.FluidStack;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class CraftingPatternInputs {
private final NonNullList<ItemStack> recipe = NonNullList.create();
private final List<Ingredient<ItemStack>> itemIngredients = new ArrayList<>();
private final List<Ingredient<FluidStack>> fluidIngredients = new ArrayList<>();
public CraftingPatternInputs(ICraftingPattern pattern) {
fillOutRecipe(pattern);
combineItemInputs(pattern);
combineFluidInputs(pattern);
}
private void fillOutRecipe(ICraftingPattern pattern) {
for (NonNullList<ItemStack> inputsForSlot : pattern.getInputs()) {
if (inputsForSlot.isEmpty()) {
recipe.add(ItemStack.EMPTY);
} else {
recipe.add(inputsForSlot.get(0));
}
}
}
private void combineItemInputs(ICraftingPattern pattern) {
for (NonNullList<ItemStack> inputsForSlot : pattern.getInputs()) {
if (inputsForSlot.isEmpty()) {
continue;
}
Ingredient<ItemStack> matchingIngredient = findMatchingItemIngredient(inputsForSlot);
if (matchingIngredient == null) {
itemIngredients.add(new Ingredient<>(inputsForSlot, inputsForSlot.get(0).getCount()));
} else {
matchingIngredient.increaseCount(inputsForSlot.get(0).getCount());
}
}
}
private void combineFluidInputs(ICraftingPattern pattern) {
for (NonNullList<FluidStack> inputsForSlot : pattern.getFluidInputs()) {
if (inputsForSlot.isEmpty()) {
continue;
}
Ingredient<FluidStack> matchingIngredient = findMatchingFluidIngredient(inputsForSlot);
if (matchingIngredient == null) {
fluidIngredients.add(new Ingredient<>(inputsForSlot, inputsForSlot.get(0).getAmount()));
} else {
matchingIngredient.increaseCount(inputsForSlot.get(0).getAmount());
}
}
}
@Nullable
private Ingredient<ItemStack> findMatchingItemIngredient(NonNullList<ItemStack> inputsForSlot) {
for (Ingredient<ItemStack> existingIngredient : itemIngredients) {
if (existingIngredient.getInputs().size() == inputsForSlot.size()) {
boolean found = true;
for (int i = 0; i < inputsForSlot.size(); i++) {
if (!API.instance().getComparer().isEqualNoQuantity(existingIngredient.getInputs().get(i), inputsForSlot.get(i))) {
found = false;
break;
}
}
if (found) {
return existingIngredient;
}
}
}
return null;
}
@Nullable
private Ingredient<FluidStack> findMatchingFluidIngredient(NonNullList<FluidStack> inputsForSlot) {
for (Ingredient<FluidStack> existingIngredient : fluidIngredients) {
if (existingIngredient.getInputs().size() == inputsForSlot.size()) {
boolean found = true;
for (int i = 0; i < inputsForSlot.size(); i++) {
if (!API.instance().getComparer().isEqual(existingIngredient.getInputs().get(i), inputsForSlot.get(i), IComparer.COMPARE_NBT)) {
found = false;
break;
}
}
if (found) {
return existingIngredient;
}
}
}
return null;
}
public NonNullList<ItemStack> getRecipe() {
return recipe;
}
public List<Ingredient<ItemStack>> getItemIngredients() {
return itemIngredients;
}
public List<Ingredient<FluidStack>> getFluidIngredients() {
return fluidIngredients;
}
public static class Ingredient<T> {
private final NonNullList<T> inputs;
private int count;
public Ingredient(NonNullList<T> inputs, int count) {
this.inputs = inputs;
this.count = count;
}
public NonNullList<T> getInputs() {
return inputs;
}
public int getCount() {
return count;
}
public void increaseCount(int count) {
this.count += count;
}
}
}

View File

@@ -1,32 +0,0 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.task.CraftingTaskErrorType;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingTaskError;
import javax.annotation.Nullable;
public class CraftingTaskError implements ICraftingTaskError {
private final CraftingTaskErrorType type;
private ICraftingPattern recursedPattern;
public CraftingTaskError(CraftingTaskErrorType type) {
this.type = type;
}
public CraftingTaskError(CraftingTaskErrorType type, ICraftingPattern recursedPattern) {
this.type = type;
this.recursedPattern = recursedPattern;
}
@Override
public CraftingTaskErrorType getType() {
return type;
}
@Override
@Nullable
public ICraftingPattern getRecursedPattern() {
return recursedPattern;
}
}

View File

@@ -2,23 +2,19 @@ package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6;
import com.refinedmods.refinedstorage.RS;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.task.CraftingTaskReadException;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingRequestInfo;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingTask;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingTaskFactory;
import com.refinedmods.refinedstorage.api.autocrafting.task.*;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.calculator.CraftingCalculator;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ResourceLocation;
import javax.annotation.Nonnull;
public class CraftingTaskFactory implements ICraftingTaskFactory {
public static final ResourceLocation ID = new ResourceLocation(RS.ID, "v6");
@Nonnull
@Override
public ICraftingTask create(INetwork network, ICraftingRequestInfo requested, int quantity, ICraftingPattern pattern) {
return new CraftingTask(network, requested, quantity, pattern);
public ICalculationResult create(INetwork network, ICraftingRequestInfo requested, int quantity, ICraftingPattern pattern) {
CraftingCalculator calculator = new CraftingCalculator(network, requested, quantity, pattern);
return calculator.calculate();
}
@Override

View File

@@ -0,0 +1,187 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.api.storage.disk.IStorageDisk;
import com.refinedmods.refinedstorage.api.util.Action;
import com.refinedmods.refinedstorage.api.util.IComparer;
import com.refinedmods.refinedstorage.api.util.IStackList;
import com.refinedmods.refinedstorage.api.util.StackListEntry;
import com.refinedmods.refinedstorage.apiimpl.API;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.IItemHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public final class IoUtil {
private static final Logger LOGGER = LogManager.getLogger(IoUtil.class);
private static final int DEFAULT_EXTRACT_FLAGS = IComparer.COMPARE_NBT;
public static IStackList<ItemStack> extractFromInternalItemStorage(IStackList<ItemStack> list, IStorageDisk<ItemStack> storage, Action action) {
IStackList<ItemStack> extracted = API.instance().createItemStackList();
for (StackListEntry<ItemStack> entry : list.getStacks()) {
ItemStack result = storage.extract(entry.getStack(), entry.getStack().getCount(), DEFAULT_EXTRACT_FLAGS, action);
if (result.isEmpty() || result.getCount() != entry.getStack().getCount()) {
if (action == Action.PERFORM) {
throw new IllegalStateException("The internal crafting inventory reported that " + entry.getStack() + " was available but we got " + result);
}
return null;
}
extracted.add(result);
}
return extracted;
}
public static IStackList<FluidStack> extractFromInternalFluidStorage(IStackList<FluidStack> list, IStorageDisk<FluidStack> storage, Action action) {
IStackList<FluidStack> extracted = API.instance().createFluidStackList();
for (StackListEntry<FluidStack> entry : list.getStacks()) {
FluidStack result = storage.extract(entry.getStack(), entry.getStack().getAmount(), DEFAULT_EXTRACT_FLAGS, action);
if (result.isEmpty() || result.getAmount() != entry.getStack().getAmount()) {
if (action == Action.PERFORM) {
throw new IllegalStateException("The internal crafting inventory reported that " + entry.getStack() + " was available but we got " + result);
}
return null;
}
extracted.add(result);
}
return extracted;
}
public static boolean insertIntoInventory(@Nullable IItemHandler dest, Collection<StackListEntry<ItemStack>> toInsert, Action action) {
if (dest == null) {
return false;
}
if (toInsert.isEmpty()) {
return true;
}
Deque<StackListEntry<ItemStack>> stacks = new ArrayDeque<>(toInsert);
StackListEntry<ItemStack> currentEntry = stacks.poll();
ItemStack current = currentEntry != null ? currentEntry.getStack() : null;
List<Integer> availableSlots = IntStream.range(0, dest.getSlots()).boxed().collect(Collectors.toList());
while (current != null && !availableSlots.isEmpty()) {
ItemStack remainder = ItemStack.EMPTY;
for (int i = 0; i < availableSlots.size(); ++i) {
int slot = availableSlots.get(i);
// .copy() is mandatory!
remainder = dest.insertItem(slot, current.copy(), action == Action.SIMULATE);
// If we inserted *something*
if (remainder.isEmpty() || current.getCount() != remainder.getCount()) {
availableSlots.remove(i);
break;
}
}
if (remainder.isEmpty()) { // If we inserted successfully, get a next stack.
currentEntry = stacks.poll();
current = currentEntry != null ? currentEntry.getStack() : null;
} else if (current.getCount() == remainder.getCount()) { // If we didn't insert anything over ALL these slots, stop here.
break;
} else { // If we didn't insert all, continue with other slots and use our remainder.
current = remainder;
}
}
boolean success = current == null && stacks.isEmpty();
if (!success && action == Action.PERFORM) {
LOGGER.warn("Inventory unexpectedly didn't accept " + (current != null ? current.getTranslationKey() : null) + ", the remainder has been voided!");
}
return success;
}
public static boolean insertIntoInventory(IFluidHandler dest, Collection<StackListEntry<FluidStack>> toInsert, Action action) {
for (StackListEntry<FluidStack> entry : toInsert) {
int filled = dest.fill(entry.getStack(), action == Action.SIMULATE ? IFluidHandler.FluidAction.SIMULATE : IFluidHandler.FluidAction.EXECUTE);
if (filled != entry.getStack().getAmount()) {
if (action == Action.PERFORM) {
LOGGER.warn("Inventory unexpectedly didn't accept all of " + entry.getStack().getTranslationKey() + ", the remainder has been voided!");
}
return false;
}
}
return true;
}
public static void extractItemsFromNetwork(IStackList<ItemStack> toExtractInitial, INetwork network, IStorageDisk<ItemStack> internalStorage) {
if (toExtractInitial.isEmpty()) {
return;
}
List<ItemStack> toRemove = new ArrayList<>();
for (StackListEntry<ItemStack> toExtract : toExtractInitial.getStacks()) {
ItemStack result = network.extractItem(toExtract.getStack(), toExtract.getStack().getCount(), Action.PERFORM);
if (!result.isEmpty()) {
internalStorage.insert(toExtract.getStack(), result.getCount(), Action.PERFORM);
toRemove.add(result);
}
}
for (ItemStack stack : toRemove) {
toExtractInitial.remove(stack);
}
if (!toRemove.isEmpty()) {
network.getCraftingManager().onTaskChanged();
}
}
public static void extractFluidsFromNetwork(IStackList<FluidStack> toExtractInitial, INetwork network, IStorageDisk<FluidStack> internalStorage) {
if (toExtractInitial.isEmpty()) {
return;
}
List<FluidStack> toRemove = new ArrayList<>();
for (StackListEntry<FluidStack> toExtract : toExtractInitial.getStacks()) {
FluidStack result = network.extractFluid(toExtract.getStack(), toExtract.getStack().getAmount(), Action.PERFORM);
if (!result.isEmpty()) {
internalStorage.insert(toExtract.getStack(), result.getAmount(), Action.PERFORM);
toRemove.add(result);
}
}
for (FluidStack stack : toRemove) {
toExtractInitial.remove(stack);
}
if (!toRemove.isEmpty()) {
network.getCraftingManager().onTaskChanged();
}
}
}

View File

@@ -1,189 +0,0 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.task.CraftingTaskReadException;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.api.util.IStackList;
import com.refinedmods.refinedstorage.api.util.StackListEntry;
import com.refinedmods.refinedstorage.apiimpl.API;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fluids.FluidStack;
class Processing extends Craft {
private static final String NBT_ITEMS_TO_RECEIVE = "ItemsToReceive";
private static final String NBT_FLUIDS_TO_RECEIVE = "FluidsToReceive";
private static final String NBT_FLUIDS_TO_USE = "FluidsToUse";
private static final String NBT_STATE = "State";
private static final String NBT_QUANTITY_TOTAL = "TotalQuantity";
private static final String NBT_ITEMS_RECEIVED = "ItemsReceived";
private static final String NBT_FLUIDS_RECEIVED = "FluidsReceived";
private static final String NBT_ITEMS_TO_DISPLAY = "ItemsToDisplay";
private IStackList<ItemStack> itemsToReceive = API.instance().createItemStackList();
private IStackList<ItemStack> itemsReceived = API.instance().createItemStackList();
private IStackList<FluidStack> fluidsToReceive = API.instance().createFluidStackList();
private IStackList<FluidStack> fluidsReceived = API.instance().createFluidStackList();
private IStackList<FluidStack> fluidsToUse = API.instance().createFluidStackList();
private IStackList<ItemStack> itemsToDisplay;
private ProcessingState state = ProcessingState.READY;
private int finished;
private int totalQuantity;
Processing(ICraftingPattern pattern, boolean root) {
super(pattern, root);
}
Processing(INetwork network, CompoundNBT tag) throws CraftingTaskReadException {
super(network, tag);
this.itemsToReceive = CraftingTask.readItemStackList(tag.getList(NBT_ITEMS_TO_RECEIVE, Constants.NBT.TAG_COMPOUND));
this.fluidsToReceive = CraftingTask.readFluidStackList(tag.getList(NBT_FLUIDS_TO_RECEIVE, Constants.NBT.TAG_COMPOUND));
this.state = ProcessingState.values()[tag.getInt(NBT_STATE)];
this.totalQuantity = tag.getInt(NBT_QUANTITY_TOTAL);
this.itemsReceived = CraftingTask.readItemStackList(tag.getList(NBT_ITEMS_RECEIVED, Constants.NBT.TAG_COMPOUND));
this.fluidsReceived = CraftingTask.readFluidStackList(tag.getList(NBT_FLUIDS_RECEIVED, Constants.NBT.TAG_COMPOUND));
this.fluidsToUse = CraftingTask.readFluidStackList(tag.getList(NBT_FLUIDS_TO_USE, Constants.NBT.TAG_COMPOUND));
this.itemsToDisplay = CraftingTask.readItemStackList(tag.getList(NBT_ITEMS_TO_DISPLAY, Constants.NBT.TAG_COMPOUND));
}
@Override
void finishCalculation() {
this.totalQuantity = quantity;
updateItemsToDisplay();
}
int getNeeded(ItemStack stack) {
if (itemsToReceive.get(stack) != null) {
int needed = itemsToReceive.get(stack).getCount() * totalQuantity;
if (itemsReceived.get(stack) != null) {
needed -= itemsReceived.get(stack).getCount();
}
return needed;
}
return 0;
}
int getNeeded(FluidStack stack) {
if (fluidsToReceive.get(stack) != null) {
int needed = fluidsToReceive.get(stack).getAmount() * totalQuantity;
if (fluidsReceived.get(stack) != null) {
needed -= fluidsReceived.get(stack).getAmount();
}
return needed;
}
return 0;
}
boolean updateFinished() {
int fin = finished;
updateFinishedPatterns();
if (finished == totalQuantity) {
this.setState(ProcessingState.PROCESSED);
}
return fin != finished;
}
/*
Calculates how many patterns were already finished
by calculating the number finished patterns for every output
and then taking the minimum of those
*/
private void updateFinishedPatterns() {
int temp = totalQuantity;
if (!itemsToReceive.isEmpty()) {
for (StackListEntry<ItemStack> stack : itemsToReceive.getStacks()) {
if (itemsReceived.get(stack.getStack()) != null) {
if (temp > itemsReceived.get(stack.getStack()).getCount() / (itemsToReceive.get(stack.getStack()).getCount())) {
temp = itemsReceived.get(stack.getStack()).getCount() / (itemsToReceive.get(stack.getStack()).getCount());
}
} else {
temp = 0;
}
}
}
if (!fluidsToReceive.isEmpty()) {
for (StackListEntry<FluidStack> stack : fluidsToReceive.getStacks()) {
if (fluidsReceived.get(stack.getStack()) != null) {
if (temp > fluidsReceived.get(stack.getStack()).getAmount() / (fluidsToReceive.get(stack.getStack()).getAmount())) {
temp = fluidsReceived.get(stack.getStack()).getAmount() / (fluidsToReceive.get(stack.getStack()).getAmount());
}
} else {
temp = 0;
}
}
}
finished = temp;
}
IStackList<ItemStack> getItemsToReceive() {
return itemsToReceive;
}
IStackList<FluidStack> getFluidsToReceive() {
return fluidsToReceive;
}
IStackList<ItemStack> getItemsToDisplay() {
return itemsToDisplay;
}
private void updateItemsToDisplay() {
itemsToDisplay = getItemsToUse(true);
}
IStackList<FluidStack> getFluidsToUse() {
return fluidsToUse;
}
void addFluidsToUse(FluidStack stack) {
fluidsToUse.add(stack);
}
void addItemsToReceive(ItemStack stack) {
itemsToReceive.add(stack);
}
void addFluidsToReceive(FluidStack stack) {
fluidsToReceive.add(stack);
}
int getProcessing() {
return totalQuantity - quantity - finished;
}
void addFinished(ItemStack received, int size) {
itemsReceived.add(received, size);
}
void addFinished(FluidStack received, int size) {
fluidsReceived.add(received, size);
}
void setState(ProcessingState state) {
this.state = state;
}
ProcessingState getState() {
return state;
}
boolean hasFluids() {
return !fluidsToUse.isEmpty();
}
CompoundNBT writeToNbt() {
CompoundNBT tag = super.writeToNbt();
tag.put(NBT_ITEMS_TO_RECEIVE, CraftingTask.writeItemStackList(itemsToReceive));
tag.put(NBT_FLUIDS_TO_RECEIVE, CraftingTask.writeFluidStackList(fluidsToReceive));
tag.putInt(NBT_STATE, state.ordinal());
tag.putInt(NBT_QUANTITY_TOTAL, totalQuantity);
tag.put(NBT_ITEMS_RECEIVED, CraftingTask.writeItemStackList(itemsReceived));
tag.put(NBT_FLUIDS_RECEIVED, CraftingTask.writeFluidStackList(fluidsReceived));
tag.put(NBT_FLUIDS_TO_USE, CraftingTask.writeFluidStackList(fluidsToUse));
tag.put(NBT_ITEMS_TO_DISPLAY, CraftingTask.writeItemStackList(itemsToDisplay));
return tag;
}
}

View File

@@ -0,0 +1,102 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPatternContainer;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPatternProvider;
import com.refinedmods.refinedstorage.api.autocrafting.task.CraftingTaskReadException;
import com.refinedmods.refinedstorage.api.network.node.INetworkNode;
import com.refinedmods.refinedstorage.api.util.IStackList;
import com.refinedmods.refinedstorage.api.util.StackListEntry;
import com.refinedmods.refinedstorage.apiimpl.API;
import com.refinedmods.refinedstorage.util.StackUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.fluids.FluidStack;
public class SerializationUtil {
private static final String NBT_PATTERN_STACK = "Stack";
private static final String NBT_PATTERN_CONTAINER_POS = "ContainerPos";
public static ListNBT writeItemStackList(IStackList<ItemStack> stacks) {
ListNBT list = new ListNBT();
for (StackListEntry<ItemStack> entry : stacks.getStacks()) {
list.add(StackUtils.serializeStackToNbt(entry.getStack()));
}
return list;
}
public static IStackList<ItemStack> readItemStackList(ListNBT list) throws CraftingTaskReadException {
IStackList<ItemStack> stacks = API.instance().createItemStackList();
for (int i = 0; i < list.size(); ++i) {
ItemStack stack = StackUtils.deserializeStackFromNbt(list.getCompound(i));
if (stack.isEmpty()) {
throw new CraftingTaskReadException("Empty stack!");
}
stacks.add(stack);
}
return stacks;
}
public static ListNBT writeFluidStackList(IStackList<FluidStack> stacks) {
ListNBT list = new ListNBT();
for (StackListEntry<FluidStack> entry : stacks.getStacks()) {
list.add(entry.getStack().writeToNBT(new CompoundNBT()));
}
return list;
}
public static IStackList<FluidStack> readFluidStackList(ListNBT list) throws CraftingTaskReadException {
IStackList<FluidStack> stacks = API.instance().createFluidStackList();
for (int i = 0; i < list.size(); ++i) {
FluidStack stack = FluidStack.loadFluidStackFromNBT(list.getCompound(i));
if (stack.isEmpty()) {
throw new CraftingTaskReadException("Empty stack!");
}
stacks.add(stack);
}
return stacks;
}
public static CompoundNBT writePatternToNbt(ICraftingPattern pattern) {
CompoundNBT tag = new CompoundNBT();
tag.put(NBT_PATTERN_STACK, pattern.getStack().serializeNBT());
tag.putLong(NBT_PATTERN_CONTAINER_POS, pattern.getContainer().getPosition().toLong());
return tag;
}
public static ICraftingPattern readPatternFromNbt(CompoundNBT tag, World world) throws CraftingTaskReadException {
BlockPos containerPos = BlockPos.fromLong(tag.getLong(NBT_PATTERN_CONTAINER_POS));
INetworkNode node = API.instance().getNetworkNodeManager((ServerWorld) world).getNode(containerPos);
if (node instanceof ICraftingPatternContainer) {
ItemStack stack = ItemStack.read(tag.getCompound(NBT_PATTERN_STACK));
if (stack.getItem() instanceof ICraftingPatternProvider) {
return ((ICraftingPatternProvider) stack.getItem()).create(world, stack, (ICraftingPatternContainer) node);
} else {
throw new CraftingTaskReadException("Pattern stack is not a crafting pattern provider");
}
} else {
throw new CraftingTaskReadException("Crafting pattern container doesn't exist anymore");
}
}
}

View File

@@ -0,0 +1,66 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.calculator;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement;
import com.refinedmods.refinedstorage.api.autocrafting.task.CalculationResultType;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICalculationResult;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingTask;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
public class CalculationResult implements ICalculationResult {
private final CalculationResultType type;
private final ICraftingPattern recursedPattern;
private final List<ICraftingPreviewElement<?>> previewElements;
private final ICraftingTask craftingTask;
public CalculationResult(CalculationResultType type) {
this.type = type;
this.recursedPattern = null;
this.previewElements = Collections.emptyList();
this.craftingTask = null;
}
public CalculationResult(CalculationResultType type, ICraftingPattern recursedPattern) {
this.type = type;
this.recursedPattern = recursedPattern;
this.previewElements = Collections.emptyList();
this.craftingTask = null;
}
public CalculationResult(CalculationResultType type, List<ICraftingPreviewElement<?>> previewElements, @Nullable ICraftingTask craftingTask) {
this.type = type;
this.recursedPattern = null;
this.previewElements = previewElements;
this.craftingTask = craftingTask;
}
@Override
public CalculationResultType getType() {
return type;
}
@Override
public List<ICraftingPreviewElement<?>> getPreviewElements() {
return previewElements;
}
@Nullable
@Override
public ICraftingTask getTask() {
return craftingTask;
}
@Override
public boolean isOk() {
return type == CalculationResultType.OK;
}
@Override
@Nullable
public ICraftingPattern getRecursedPattern() {
return recursedPattern;
}
}

View File

@@ -0,0 +1,360 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.calculator;
import com.refinedmods.refinedstorage.RS;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement;
import com.refinedmods.refinedstorage.api.autocrafting.task.CalculationResultType;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICalculationResult;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingRequestInfo;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.api.util.IComparer;
import com.refinedmods.refinedstorage.api.util.IStackList;
import com.refinedmods.refinedstorage.apiimpl.API;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.CraftingPatternInputs;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.CraftingTask;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node.CraftingNode;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node.Node;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node.NodeList;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node.ProcessingNode;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.preview.CraftingPreviewElementFactory;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.preview.CraftingPreviewInfo;
import com.refinedmods.refinedstorage.util.StackUtils;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.items.ItemHandlerHelper;
import javax.annotation.Nullable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class CraftingCalculator {
private final INetwork network;
private final ICraftingRequestInfo requested;
private final int quantity;
private final ICraftingPattern pattern;
private final Set<ICraftingPattern> patternsUsed = new HashSet<>();
private final CraftingPreviewInfo craftingPreviewInfo = new CraftingPreviewInfo();
private final NodeList nodes = new NodeList();
private final IStackList<ItemStack> toExtractInitial = API.instance().createItemStackList();
private final IStackList<FluidStack> toExtractInitialFluids = API.instance().createFluidStackList();
private long calculationStarted = -1;
public CraftingCalculator(INetwork network, ICraftingRequestInfo requested, int quantity, ICraftingPattern pattern) {
this.network = network;
this.requested = requested;
this.quantity = quantity;
this.pattern = pattern;
}
public ICalculationResult calculate() {
this.calculationStarted = System.currentTimeMillis();
IStackList<ItemStack> results = API.instance().createItemStackList();
IStackList<FluidStack> fluidResults = API.instance().createFluidStackList();
IStackList<ItemStack> storageSource = network.getItemStorageCache().getList().copy();
IStackList<FluidStack> fluidStorageSource = network.getFluidStorageCache().getList().copy();
int qtyPerCraft = getQuantityPerCraft(requested.getItem(), requested.getFluid(), pattern);
int qty = ((quantity - 1) / qtyPerCraft) + 1;
try {
calculateInternal(qty, storageSource, fluidStorageSource, results, fluidResults, pattern, true);
} catch (CraftingCalculatorException e) {
return new CalculationResult(e.getType(), e.getRecursedPattern());
}
if (requested.getItem() != null) {
craftingPreviewInfo.getToCraft().add(ItemHandlerHelper.copyStackWithSize(requested.getItem(), qty * qtyPerCraft));
} else if (requested.getFluid() != null) {
craftingPreviewInfo.getToCraftFluids().add(StackUtils.copy(requested.getFluid(), qty * qtyPerCraft));
}
List<ICraftingPreviewElement<?>> previewElements = new CraftingPreviewElementFactory().getElements(craftingPreviewInfo);
if (craftingPreviewInfo.hasMissing()) {
return new CalculationResult(CalculationResultType.MISSING, previewElements, null);
}
return new CalculationResult(
CalculationResultType.OK,
previewElements,
new CraftingTask(network, requested, quantity, pattern, nodes, toExtractInitial, toExtractInitialFluids)
);
}
private void calculateInternal(
int qty,
IStackList<ItemStack> storageSource,
IStackList<FluidStack> fluidStorageSource,
IStackList<ItemStack> results,
IStackList<FluidStack> fluidResults,
ICraftingPattern pattern,
boolean root) throws CraftingCalculatorException {
if (System.currentTimeMillis() - calculationStarted > RS.SERVER_CONFIG.getAutocrafting().getCalculationTimeoutMs()) {
throw new CraftingCalculatorException(CalculationResultType.TOO_COMPLEX, null);
}
if (!patternsUsed.add(pattern)) {
throw new CraftingCalculatorException(CalculationResultType.RECURSIVE, pattern);
}
IStackList<ItemStack> itemsToExtract = API.instance().createItemStackList();
IStackList<FluidStack> fluidsToExtract = API.instance().createFluidStackList();
CraftingPatternInputs inputs = new CraftingPatternInputs(pattern);
Node node = nodes.createOrAddToExistingNode(pattern, root, inputs.getRecipe(), qty);
calculateForItems(qty, storageSource, fluidStorageSource, results, fluidResults, itemsToExtract, inputs, node);
if (node instanceof CraftingNode) {
ItemStack output = pattern.getOutput(inputs.getRecipe());
results.add(output, output.getCount() * qty);
for (ItemStack byproduct : pattern.getByproducts(inputs.getRecipe())) {
results.add(byproduct, byproduct.getCount() * qty);
}
} else if (node instanceof ProcessingNode) {
ProcessingNode processing = (ProcessingNode) node;
calculateForFluids(qty, storageSource, fluidStorageSource, results, fluidResults, pattern, inputs, fluidsToExtract, processing);
for (ItemStack output : pattern.getOutputs()) {
results.add(output, output.getCount() * qty);
}
for (FluidStack output : pattern.getFluidOutputs()) {
fluidResults.add(output, output.getAmount() * qty);
}
}
patternsUsed.remove(pattern);
}
private void calculateForItems(int qty,
IStackList<ItemStack> storageSource,
IStackList<FluidStack> fluidStorageSource,
IStackList<ItemStack> results,
IStackList<FluidStack> fluidResults,
IStackList<ItemStack> itemsToExtract,
CraftingPatternInputs inputs,
Node node) throws CraftingCalculatorException {
int ingredientNumber = -1;
for (CraftingPatternInputs.Ingredient<ItemStack> ingredient : inputs.getItemIngredients()) {
ingredientNumber++;
PossibleInputs<ItemStack> possibleInputs = new PossibleInputs<>(ingredient.getInputs());
possibleInputs.sort(storageSource, results);
ItemStack possibleInput = possibleInputs.get();
ItemStack fromSelf = results.get(possibleInput);
ItemStack fromNetwork = storageSource.get(possibleInput);
int remaining = ingredient.getCount() * qty;
if (remaining < 0) { // int overflow
throw new CraftingCalculatorException(CalculationResultType.TOO_COMPLEX);
}
while (remaining > 0) {
if (fromSelf != null) {
int toTake = Math.min(remaining, fromSelf.getCount());
node.getRequirements().addItemRequirement(ingredientNumber, possibleInput, toTake, ingredient.getCount());
results.remove(fromSelf, toTake);
remaining -= toTake;
fromSelf = results.get(possibleInput);
}
if (fromNetwork != null && remaining > 0) {
int toTake = Math.min(remaining, fromNetwork.getCount());
craftingPreviewInfo.getToTake().add(possibleInput, toTake);
node.getRequirements().addItemRequirement(ingredientNumber, possibleInput, toTake, ingredient.getCount());
storageSource.remove(fromNetwork, toTake);
remaining -= toTake;
fromNetwork = storageSource.get(possibleInput);
toExtractInitial.add(possibleInput, toTake);
}
if (remaining > 0) {
ICraftingPattern subPattern = network.getCraftingManager().getPattern(possibleInput);
if (subPattern != null) {
int qtyPerCraft = getQuantityPerCraft(possibleInput, null, subPattern);
int subQty = ((remaining - 1) / qtyPerCraft) + 1;
calculateInternal(subQty, storageSource, fluidStorageSource, results, fluidResults, subPattern, false);
fromSelf = results.get(possibleInput);
if (fromSelf == null) {
throw new IllegalStateException("Recursive calculation didn't yield anything");
}
fromNetwork = storageSource.get(possibleInput);
// fromSelf contains the amount crafted after the loop.
craftingPreviewInfo.getToCraft().add(fromSelf.copy());
} else {
if (!possibleInputs.cycle()) {
// Give up.
possibleInput = possibleInputs.get(); // Revert back to 0.
craftingPreviewInfo.getMissing().add(possibleInput, remaining);
itemsToExtract.add(possibleInput, remaining);
remaining = 0;
} else {
// Retry with new input...
possibleInput = possibleInputs.get();
fromSelf = results.get(possibleInput);
fromNetwork = storageSource.get(possibleInput);
}
}
}
}
}
}
private void calculateForFluids(int qty,
IStackList<ItemStack> storageSource,
IStackList<FluidStack> fluidStorageSource,
IStackList<ItemStack> results,
IStackList<FluidStack> fluidResults,
ICraftingPattern pattern,
CraftingPatternInputs inputs,
IStackList<FluidStack> fluidsToExtract,
ProcessingNode node) throws CraftingCalculatorException {
int ingredientNumber = -1;
for (CraftingPatternInputs.Ingredient<FluidStack> ingredient : inputs.getFluidIngredients()) {
ingredientNumber++;
PossibleInputs<FluidStack> possibleInputs = new PossibleInputs<>(ingredient.getInputs());
possibleInputs.sort(fluidStorageSource, fluidResults);
FluidStack possibleInput = possibleInputs.get();
FluidStack fromSelf = fluidResults.get(possibleInput, IComparer.COMPARE_NBT);
FluidStack fromNetwork = fluidStorageSource.get(possibleInput, IComparer.COMPARE_NBT);
int remaining = possibleInput.getAmount() * qty;
if (remaining < 0) { // int overflow
throw new CraftingCalculatorException(CalculationResultType.TOO_COMPLEX);
}
while (remaining > 0) {
if (fromSelf != null) {
int toTake = Math.min(remaining, fromSelf.getAmount());
node.getRequirements().addFluidRequirement(ingredientNumber, possibleInput, toTake, ingredient.getCount());
fluidResults.remove(possibleInput, toTake);
remaining -= toTake;
fromSelf = fluidResults.get(possibleInput, IComparer.COMPARE_NBT);
}
if (fromNetwork != null && remaining > 0) {
int toTake = Math.min(remaining, fromNetwork.getAmount());
node.getRequirements().addFluidRequirement(ingredientNumber, possibleInput, toTake, ingredient.getCount());
craftingPreviewInfo.getToTakeFluids().add(possibleInput, toTake);
fluidStorageSource.remove(fromNetwork, toTake);
remaining -= toTake;
fromNetwork = fluidStorageSource.get(possibleInput, IComparer.COMPARE_NBT);
toExtractInitialFluids.add(possibleInput, toTake);
}
if (remaining > 0) {
ICraftingPattern subPattern = network.getCraftingManager().getPattern(possibleInput);
if (subPattern != null) {
int qtyPerCraft = getQuantityPerCraft(null, possibleInput, subPattern);
int subQty = ((remaining - 1) / qtyPerCraft) + 1;
calculateInternal(subQty, storageSource, fluidStorageSource, results, fluidResults, subPattern, false);
fromSelf = fluidResults.get(possibleInput, IComparer.COMPARE_NBT);
if (fromSelf == null) {
throw new IllegalStateException("Recursive fluid calculation didn't yield anything");
}
fromNetwork = fluidStorageSource.get(possibleInput, IComparer.COMPARE_NBT);
// fromSelf contains the amount crafted after the loop.
craftingPreviewInfo.getToCraftFluids().add(fromSelf.copy());
} else {
if (!possibleInputs.cycle()) {
// Give up.
possibleInput = possibleInputs.get(); // Revert back to 0.
craftingPreviewInfo.getMissingFluids().add(possibleInput, remaining);
fluidsToExtract.add(possibleInput, remaining);
remaining = 0;
} else {
// Retry with new input...
possibleInput = possibleInputs.get();
fromSelf = fluidResults.get(possibleInput);
fromNetwork = fluidStorageSource.get(possibleInput);
}
}
}
}
}
}
private int getQuantityPerCraft(@Nullable ItemStack item, @Nullable FluidStack fluid, ICraftingPattern pattern) {
int qty = 0;
if (item != null) {
for (ItemStack output : pattern.getOutputs()) {
if (API.instance().getComparer().isEqualNoQuantity(output, item)) {
qty += output.getCount();
if (!pattern.isProcessing()) {
break;
}
}
}
} else if (fluid != null) {
for (FluidStack output : pattern.getFluidOutputs()) {
if (API.instance().getComparer().isEqual(output, fluid, IComparer.COMPARE_NBT)) {
qty += output.getAmount();
}
}
}
return qty;
}
}

View File

@@ -0,0 +1,31 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.calculator;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.task.CalculationResultType;
import javax.annotation.Nullable;
public class CraftingCalculatorException extends Exception {
private final CalculationResultType type;
@Nullable
private final ICraftingPattern recursedPattern;
public CraftingCalculatorException(CalculationResultType type) {
this.type = type;
this.recursedPattern = null;
}
public CraftingCalculatorException(CalculationResultType type, @Nullable ICraftingPattern recursedPattern) {
this.type = type;
this.recursedPattern = recursedPattern;
}
public CalculationResultType getType() {
return type;
}
@Nullable
public ICraftingPattern getRecursedPattern() {
return recursedPattern;
}
}

View File

@@ -0,0 +1,48 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.calculator;
import com.refinedmods.refinedstorage.api.util.IStackList;
import java.util.ArrayList;
import java.util.List;
public class PossibleInputs<T> {
private final List<T> possibilities;
private int pos;
public PossibleInputs(List<T> possibilities) {
this.possibilities = new ArrayList<>(possibilities);
}
public T get() {
return possibilities.get(pos);
}
// Return false if we're exhausted.
public boolean cycle() {
if (pos + 1 >= possibilities.size()) {
pos = 0;
return false;
}
pos++;
return true;
}
public void sort(IStackList<T> mutatedStorage, IStackList<T> results) {
possibilities.sort((a, b) -> {
int ar = mutatedStorage.getCount(a);
int br = mutatedStorage.getCount(b);
return br - ar;
});
possibilities.sort((a, b) -> {
int ar = results.getCount(a);
int br = results.getCount(b);
return br - ar;
});
}
}

View File

@@ -0,0 +1,123 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.monitor;
import com.refinedmods.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElement;
import com.refinedmods.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElementList;
import com.refinedmods.refinedstorage.api.storage.disk.IStorageDisk;
import com.refinedmods.refinedstorage.api.util.StackListEntry;
import com.refinedmods.refinedstorage.apiimpl.API;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.craftingmonitor.ErrorCraftingMonitorElement;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.craftingmonitor.FluidCraftingMonitorElement;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.craftingmonitor.ItemCraftingMonitorElement;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node.CraftingNode;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node.Node;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node.ProcessingNode;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node.ProcessingState;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import java.util.Collection;
import java.util.List;
public class CraftingMonitorElementFactory {
public List<ICraftingMonitorElement> getElements(Collection<Node> nodes, IStorageDisk<ItemStack> internalStorage, IStorageDisk<FluidStack> internalFluidStorage) {
ICraftingMonitorElementList list = API.instance().createCraftingMonitorElementList();
for (Node node : nodes) {
if (node instanceof CraftingNode) {
addForRecipe(list, (CraftingNode) node);
} else {
addForProcessing(list, (ProcessingNode) node);
}
}
for (ItemStack stack : internalStorage.getStacks()) {
list.addStorage(new ItemCraftingMonitorElement(stack, stack.getCount(), 0, 0, 0, 0));
}
for (FluidStack stack : internalFluidStorage.getStacks()) {
list.addStorage(new FluidCraftingMonitorElement(stack, stack.getAmount(), 0, 0, 0, 0));
}
list.commit();
return list.getElements();
}
private void addForProcessing(ICraftingMonitorElementList list, ProcessingNode node) {
if (node.getState() == ProcessingState.PROCESSED) {
return;
}
for (StackListEntry<ItemStack> requirement : node.getSingleItemSetToRequire().getStacks()) {
if (node.getCurrentlyProcessing() > 0) {
ICraftingMonitorElement element = ItemCraftingMonitorElement.Builder
.forStack(requirement.getStack())
.processing(requirement.getStack().getCount() * node.getCurrentlyProcessing())
.build();
list.add(element, true);
}
}
for (StackListEntry<ItemStack> toReceive : node.getSingleItemSetToReceive().getStacks()) {
int needed = node.getNeeded(toReceive.getStack());
if (needed > 0) {
ICraftingMonitorElement element = ItemCraftingMonitorElement.Builder
.forStack(toReceive.getStack())
.scheduled(needed)
.build();
element = wrapWithProcessingState(element, node.getState(), "item");
list.add(element, true);
}
}
for (StackListEntry<FluidStack> requirement : node.getSingleFluidSetToRequire().getStacks()) {
if (node.getCurrentlyProcessing() > 0) {
ICraftingMonitorElement element = FluidCraftingMonitorElement.Builder
.forStack(requirement.getStack())
.processing(requirement.getStack().getAmount() * node.getCurrentlyProcessing())
.build();
list.add(element, true);
}
}
for (StackListEntry<FluidStack> toReceive : node.getSingleFluidSetToReceive().getStacks()) {
int needed = node.getNeeded(toReceive.getStack());
if (needed > 0) {
ICraftingMonitorElement element = FluidCraftingMonitorElement.Builder
.forStack(toReceive.getStack())
.scheduled(needed)
.build();
element = wrapWithProcessingState(element, node.getState(), "fluid");
list.add(element, true);
}
}
}
private ICraftingMonitorElement wrapWithProcessingState(ICraftingMonitorElement element, ProcessingState state, String type) {
if (state == ProcessingState.MACHINE_DOES_NOT_ACCEPT) {
return new ErrorCraftingMonitorElement(element, "gui.refinedstorage.crafting_monitor.machine_does_not_accept_" + type);
} else if (state == ProcessingState.MACHINE_NONE) {
return new ErrorCraftingMonitorElement(element, "gui.refinedstorage.crafting_monitor.machine_none");
} else if (state == ProcessingState.LOCKED) {
return new ErrorCraftingMonitorElement(element, "gui.refinedstorage.crafting_monitor.crafter_is_locked");
}
return element;
}
private void addForRecipe(ICraftingMonitorElementList list, CraftingNode node) {
if (node.getQuantity() > 0) {
for (ItemStack receive : node.getPattern().getOutputs()) {
list.add(new ItemCraftingMonitorElement(receive, 0, 0, 0, 0, receive.getCount() * node.getQuantity()), false);
}
}
}
}

View File

@@ -0,0 +1,98 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPatternContainer;
import com.refinedmods.refinedstorage.api.autocrafting.task.CraftingTaskReadException;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.api.storage.disk.IStorageDisk;
import com.refinedmods.refinedstorage.api.util.Action;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.IoUtil;
import com.refinedmods.refinedstorage.util.StackUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.NonNullList;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fluids.FluidStack;
public class CraftingNode extends Node {
private static final String NBT_RECIPE = "Recipe";
private final NonNullList<ItemStack> recipe;
public CraftingNode(ICraftingPattern pattern, boolean root, NonNullList<ItemStack> recipe) {
super(pattern, root);
this.recipe = recipe;
}
public CraftingNode(INetwork network, CompoundNBT tag) throws CraftingTaskReadException {
super(network, tag);
this.recipe = NonNullList.create();
ListNBT tookList = tag.getList(NBT_RECIPE, Constants.NBT.TAG_COMPOUND);
for (int i = 0; i < tookList.size(); ++i) {
recipe.add(StackUtils.deserializeStackFromNbt(tookList.getCompound(i)));
}
}
@Override
public void update(INetwork network, int ticks, NodeList nodes, IStorageDisk<ItemStack> internalStorage, IStorageDisk<FluidStack> internalFluidStorage, NodeListener listener) {
for (ICraftingPatternContainer container : network.getCraftingManager().getAllContainers(getPattern())) {
int interval = container.getUpdateInterval();
if (interval < 0) {
throw new IllegalStateException(container + " has an update interval of < 0");
}
if (interval == 0 || ticks % interval == 0) {
for (int i = 0; i < container.getMaximumSuccessfulCraftingUpdates(); i++) {
if (IoUtil.extractFromInternalItemStorage(requirements.getSingleItemRequirementSet(true), internalStorage, Action.SIMULATE) != null) {
IoUtil.extractFromInternalItemStorage(requirements.getSingleItemRequirementSet(false), internalStorage, Action.PERFORM);
ItemStack output = getPattern().getOutput(recipe);
if (!isRoot()) {
internalStorage.insert(output, output.getCount(), Action.PERFORM);
} else {
ItemStack remainder = network.insertItem(output, output.getCount(), Action.PERFORM);
internalStorage.insert(remainder, remainder.getCount(), Action.PERFORM);
}
// Byproducts need to always be inserted in the internal storage for later reuse further in the task.
// Regular outputs can be inserted into the network *IF* it's a root since it's *NOT* expected to be used later on.
for (ItemStack byp : getPattern().getByproducts(recipe)) {
internalStorage.insert(byp, byp.getCount(), Action.PERFORM);
}
next();
listener.onSingleDone(this);
if (getQuantity() <= 0) {
listener.onAllDone(this);
return;
}
} else {
break;
}
}
}
}
}
@Override
public CompoundNBT writeToNbt() {
CompoundNBT tag = super.writeToNbt();
ListNBT tookList = new ListNBT();
for (ItemStack took : this.recipe) {
tookList.add(StackUtils.serializeStackToNbt(took));
}
tag.put(NBT_RECIPE, tookList);
return tag;
}
}

View File

@@ -0,0 +1,86 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.task.CraftingTaskReadException;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.api.storage.disk.IStorageDisk;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.SerializationUtil;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraftforge.fluids.FluidStack;
public abstract class Node {
private static final String NBT_PATTERN = "Pattern";
private static final String NBT_ROOT = "Root";
private static final String NBT_IS_PROCESSING = "IsProcessing";
private static final String NBT_QUANTITY = "Quantity";
private static final String NBT_QUANTITY_TOTAL = "TotalQuantity";
private final boolean root;
private final ICraftingPattern pattern;
protected int quantity;
protected int totalQuantity;
protected final NodeRequirements requirements = new NodeRequirements();
public Node(ICraftingPattern pattern, boolean root) {
this.pattern = pattern;
this.root = root;
}
public Node(INetwork network, CompoundNBT tag) throws CraftingTaskReadException {
this.quantity = tag.getInt(NBT_QUANTITY);
this.totalQuantity = tag.getInt(NBT_QUANTITY_TOTAL);
this.pattern = SerializationUtil.readPatternFromNbt(tag.getCompound(NBT_PATTERN), network.getWorld());
this.root = tag.getBoolean(NBT_ROOT);
this.requirements.readFromNbt(tag);
}
public static Node fromNbt(INetwork network, CompoundNBT tag) throws CraftingTaskReadException {
return tag.getBoolean(NBT_IS_PROCESSING) ? new ProcessingNode(network, tag) : new CraftingNode(network, tag);
}
public abstract void update(INetwork network, int ticks, NodeList nodes, IStorageDisk<ItemStack> internalStorage, IStorageDisk<FluidStack> internalFluidStorage, NodeListener listener);
public void onCalculationFinished() {
this.totalQuantity = quantity;
}
public ICraftingPattern getPattern() {
return pattern;
}
public int getQuantity() {
return quantity;
}
public void addQuantity(int quantity) {
this.quantity += quantity;
}
protected void next() {
quantity--;
}
public boolean isRoot() {
return root;
}
public NodeRequirements getRequirements() {
return requirements;
}
public CompoundNBT writeToNbt() {
CompoundNBT tag = new CompoundNBT();
tag.putInt(NBT_QUANTITY, quantity);
tag.putInt(NBT_QUANTITY_TOTAL, totalQuantity);
tag.putBoolean(NBT_IS_PROCESSING, this instanceof ProcessingNode);
tag.putBoolean(NBT_ROOT, root);
tag.put(NBT_PATTERN, SerializationUtil.writePatternToNbt(pattern));
tag = requirements.writeToNbt(tag);
return tag;
}
}

View File

@@ -0,0 +1,60 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPatternContainer;
import com.refinedmods.refinedstorage.api.network.INetwork;
import net.minecraft.item.ItemStack;
import net.minecraft.util.NonNullList;
import java.util.*;
public class NodeList {
private final Map<ICraftingPattern, Node> nodes = new LinkedHashMap<>();
private final List<Node> nodesToRemove = new ArrayList<>();
public void removeMarkedForRemoval() {
for (Node node : nodesToRemove) {
nodes.remove(node.getPattern());
}
nodesToRemove.clear();
}
public Collection<Node> all() {
return nodes.values();
}
public void unlockAll(INetwork network) {
for (Node node : nodes.values()) {
if (node instanceof ProcessingNode) {
network.getCraftingManager().getAllContainers(node.getPattern()).forEach(ICraftingPatternContainer::unlock);
}
}
}
public boolean isEmpty() {
return nodes.isEmpty();
}
public void remove(Node node) {
nodesToRemove.add(node);
}
public Node createOrAddToExistingNode(ICraftingPattern pattern, boolean root, NonNullList<ItemStack> recipe, int qty) {
Node node = nodes.get(pattern);
if (node == null) {
nodes.put(pattern, node = createNode(pattern, root, recipe));
}
node.addQuantity(qty);
return node;
}
private Node createNode(ICraftingPattern pattern, boolean root, NonNullList<ItemStack> recipe) {
return pattern.isProcessing() ? new ProcessingNode(pattern, root) : new CraftingNode(pattern, root, recipe);
}
public void put(ICraftingPattern pattern, Node node) {
nodes.put(pattern, node);
}
}

View File

@@ -0,0 +1,7 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node;
public interface NodeListener {
void onAllDone(Node node);
void onSingleDone(Node node);
}

View File

@@ -0,0 +1,176 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node;
import com.google.common.primitives.Ints;
import com.refinedmods.refinedstorage.api.autocrafting.task.CraftingTaskReadException;
import com.refinedmods.refinedstorage.api.util.IStackList;
import com.refinedmods.refinedstorage.api.util.StackListEntry;
import com.refinedmods.refinedstorage.apiimpl.API;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.SerializationUtil;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fluids.FluidStack;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class NodeRequirements {
private static final String NBT_ITEMS_TO_USE = "ItemsToUse";
private static final String NBT_FLUIDS_TO_USE = "FluidsToUse";
private static final String NBT_ITEMS_NEEDED_PER_CRAFT = "ItemsNeededPerCraft";
private static final String NBT_FLUIDS_NEEDED_PER_CRAFT = "FluidsNeededPerCraft";
private final Map<Integer, IStackList<ItemStack>> itemRequirements = new LinkedHashMap<>();
private final Map<Integer, Integer> itemsNeededPerCraft = new LinkedHashMap<>();
private final Map<Integer, IStackList<FluidStack>> fluidRequirements = new LinkedHashMap<>();
private final Map<Integer, Integer> fluidsNeededPerCraft = new LinkedHashMap<>();
public void addItemRequirement(int ingredientNumber, ItemStack stack, int size, int perCraft) {
if (!itemsNeededPerCraft.containsKey(ingredientNumber)) {
itemsNeededPerCraft.put(ingredientNumber, perCraft);
}
IStackList<ItemStack> list = itemRequirements.get(ingredientNumber);
if (list == null) {
itemRequirements.put(ingredientNumber, list = API.instance().createItemStackList());
}
list.add(stack, size);
}
public void addFluidRequirement(int ingredientNumber, FluidStack stack, int size, int perCraft) {
if (!fluidsNeededPerCraft.containsKey(ingredientNumber)) {
fluidsNeededPerCraft.put(ingredientNumber, perCraft);
}
IStackList<FluidStack> list = fluidRequirements.get(ingredientNumber);
if (list == null) {
fluidRequirements.put(ingredientNumber, list = API.instance().createFluidStackList());
}
list.add(stack, size);
}
public IStackList<ItemStack> getSingleItemRequirementSet(boolean simulate) {
IStackList<ItemStack> toReturn = API.instance().createItemStackList();
for (int i = 0; i < itemRequirements.size(); i++) {
int needed = itemsNeededPerCraft.get(i);
if (!itemRequirements.get(i).isEmpty()) {
Iterator<StackListEntry<ItemStack>> it = itemRequirements.get(i).getStacks().iterator();
while (needed > 0 && it.hasNext()) {
ItemStack toUse = it.next().getStack();
if (needed < toUse.getCount()) {
if (!simulate) {
itemRequirements.get(i).remove(toUse, needed);
}
toReturn.add(toUse, needed);
needed = 0;
} else {
if (!simulate) {
it.remove();
}
toReturn.add(toUse);
needed -= toUse.getCount();
}
}
} else {
throw new IllegalStateException("Bad!");
}
}
return toReturn;
}
public IStackList<FluidStack> getSingleFluidRequirementSet(boolean simulate) {
IStackList<FluidStack> toReturn = API.instance().createFluidStackList();
for (int i = 0; i < fluidRequirements.size(); i++) {
int needed = fluidsNeededPerCraft.get(i);
if (!fluidRequirements.get(i).isEmpty()) {
Iterator<StackListEntry<FluidStack>> it = fluidRequirements.get(i).getStacks().iterator();
while (needed > 0 && it.hasNext()) {
FluidStack toUse = it.next().getStack();
if (needed < toUse.getAmount()) {
if (!simulate) {
fluidRequirements.get(i).remove(toUse, needed);
}
toReturn.add(toUse, needed);
needed = 0;
} else {
if (!simulate) {
it.remove();
}
toReturn.add(toUse);
needed -= toUse.getAmount();
}
}
} else {
throw new IllegalStateException("Bad!");
}
}
return toReturn;
}
public void readFromNbt(CompoundNBT tag) throws CraftingTaskReadException {
ListNBT itemRequirements = tag.getList(NBT_ITEMS_TO_USE, Constants.NBT.TAG_LIST);
for (int i = 0; i < itemRequirements.size(); i++) {
this.itemRequirements.put(i, SerializationUtil.readItemStackList(itemRequirements.getList(i)));
}
List<Integer> itemsNeededPerCraft = Ints.asList(tag.getIntArray(NBT_ITEMS_NEEDED_PER_CRAFT));
for (int i = 0; i < itemsNeededPerCraft.size(); i++) {
this.itemsNeededPerCraft.put(i, itemsNeededPerCraft.get(i));
}
ListNBT fluidRequirements = tag.getList(NBT_FLUIDS_TO_USE, Constants.NBT.TAG_LIST);
for (int i = 0; i < fluidRequirements.size(); i++) {
this.fluidRequirements.put(i, SerializationUtil.readFluidStackList(fluidRequirements.getList(i)));
}
List<Integer> fluidsNeededPerCraft = Ints.asList(tag.getIntArray(NBT_FLUIDS_NEEDED_PER_CRAFT));
for (int i = 0; i < fluidsNeededPerCraft.size(); i++) {
this.fluidsNeededPerCraft.put(i, fluidsNeededPerCraft.get(i));
}
}
public CompoundNBT writeToNbt(CompoundNBT tag) {
ListNBT itemRequirements = new ListNBT();
for (IStackList<ItemStack> list : this.itemRequirements.values()) {
itemRequirements.add(SerializationUtil.writeItemStackList(list));
}
tag.put(NBT_ITEMS_TO_USE, itemRequirements);
tag.putIntArray(NBT_ITEMS_NEEDED_PER_CRAFT, Ints.toArray(itemsNeededPerCraft.values()));
ListNBT fluidRequirements = new ListNBT();
for (IStackList<FluidStack> list : this.fluidRequirements.values()) {
fluidRequirements.add(SerializationUtil.writeFluidStackList(list));
}
tag.put(NBT_FLUIDS_TO_USE, fluidRequirements);
tag.putIntArray(NBT_FLUIDS_NEEDED_PER_CRAFT, Ints.toArray(fluidsNeededPerCraft.values()));
return tag;
}
}

View File

@@ -0,0 +1,272 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPatternContainer;
import com.refinedmods.refinedstorage.api.autocrafting.task.CraftingTaskReadException;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.api.storage.disk.IStorageDisk;
import com.refinedmods.refinedstorage.api.util.Action;
import com.refinedmods.refinedstorage.api.util.IStackList;
import com.refinedmods.refinedstorage.api.util.StackListEntry;
import com.refinedmods.refinedstorage.apiimpl.API;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.IoUtil;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.SerializationUtil;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fluids.FluidStack;
public class ProcessingNode extends Node {
private static final String NBT_ITEMS_RECEIVED = "ItemsReceived";
private static final String NBT_FLUIDS_RECEIVED = "FluidsReceived";
private static final String NBT_SINGLE_ITEM_SET_TO_REQUIRE = "SingleItemSetToRequire";
private static final String NBT_SINGLE_FLUID_SET_TO_REQUIRE = "SingleFluidSetToRequire";
private static final String NBT_STATE = "State";
private final IStackList<ItemStack> singleItemSetToReceive = API.instance().createItemStackList();
private final IStackList<FluidStack> singleFluidSetToReceive = API.instance().createFluidStackList();
private IStackList<ItemStack> singleItemSetToRequire;
private IStackList<FluidStack> singleFluidSetToRequire;
private IStackList<ItemStack> itemsReceived = API.instance().createItemStackList();
private IStackList<FluidStack> fluidsReceived = API.instance().createFluidStackList();
private ProcessingState state;
private int quantityFinished;
public ProcessingNode(ICraftingPattern pattern, boolean root) {
super(pattern, root);
initSetsToReceive();
}
public ProcessingNode(INetwork network, CompoundNBT tag) throws CraftingTaskReadException {
super(network, tag);
this.itemsReceived = SerializationUtil.readItemStackList(tag.getList(NBT_ITEMS_RECEIVED, Constants.NBT.TAG_COMPOUND));
this.fluidsReceived = SerializationUtil.readFluidStackList(tag.getList(NBT_FLUIDS_RECEIVED, Constants.NBT.TAG_COMPOUND));
this.singleItemSetToRequire = SerializationUtil.readItemStackList(tag.getList(NBT_SINGLE_ITEM_SET_TO_REQUIRE, Constants.NBT.TAG_COMPOUND));
this.singleFluidSetToRequire = SerializationUtil.readFluidStackList(tag.getList(NBT_SINGLE_FLUID_SET_TO_REQUIRE, Constants.NBT.TAG_COMPOUND));
this.state = ProcessingState.values()[tag.getInt(NBT_STATE)];
initSetsToReceive();
}
private void initSetsToReceive() {
for (ItemStack output : getPattern().getOutputs()) {
singleItemSetToReceive.add(output, output.getCount());
}
for (FluidStack output : getPattern().getFluidOutputs()) {
singleFluidSetToReceive.add(output, output.getAmount());
}
}
@Override
public void update(INetwork network, int ticks, NodeList nodes, IStorageDisk<ItemStack> internalStorage, IStorageDisk<FluidStack> internalFluidStorage, NodeListener listener) {
if (state == ProcessingState.PROCESSED) {
listener.onAllDone(this);
return;
}
if (getQuantity() <= 0) {
return;
}
boolean allLocked = true;
boolean allMissingMachine = true;
boolean allRejected = true;
ProcessingState originalState = state;
for (ICraftingPatternContainer container : network.getCraftingManager().getAllContainers(getPattern())) {
int interval = container.getUpdateInterval();
if (interval < 0) {
throw new IllegalStateException(container + " has an update interval of < 0");
}
if (interval == 0 || ticks % interval == 0) {
for (int i = 0; i < container.getMaximumSuccessfulCraftingUpdates(); i++) {
if (getQuantity() <= 0) {
return;
}
if (container.isLocked()) {
if (allLocked) {
this.state = ProcessingState.LOCKED;
}
break;
} else {
allLocked = false;
}
if ((!singleItemSetToReceive.isEmpty() && container.getConnectedInventory() == null) ||
(!singleFluidSetToReceive.isEmpty() && container.getConnectedFluidInventory() == null)) {
if (allMissingMachine) {
this.state = ProcessingState.MACHINE_NONE;
}
break;
} else {
allMissingMachine = false;
}
boolean hasAllRequirements = false;
IStackList<ItemStack> extractedItems = IoUtil.extractFromInternalItemStorage(requirements.getSingleItemRequirementSet(true), internalStorage, Action.SIMULATE);
IStackList<FluidStack> extractedFluids = null;
if (extractedItems != null) {
extractedFluids = IoUtil.extractFromInternalFluidStorage(requirements.getSingleFluidRequirementSet(true), internalFluidStorage, Action.SIMULATE);
if (extractedFluids != null) {
hasAllRequirements = true;
}
}
boolean canInsertFullAmount = false;
if (hasAllRequirements) {
canInsertFullAmount = IoUtil.insertIntoInventory(container.getConnectedInventory(), extractedItems.getStacks(), Action.SIMULATE);
if (canInsertFullAmount) {
canInsertFullAmount = IoUtil.insertIntoInventory(container.getConnectedFluidInventory(), extractedFluids.getStacks(), Action.SIMULATE);
}
}
if (hasAllRequirements && !canInsertFullAmount) {
if (allRejected) {
this.state = ProcessingState.MACHINE_DOES_NOT_ACCEPT;
}
break;
} else {
allRejected = false;
}
if (hasAllRequirements && canInsertFullAmount) {
this.state = ProcessingState.READY;
extractedItems = IoUtil.extractFromInternalItemStorage(requirements.getSingleItemRequirementSet(false), internalStorage, Action.PERFORM);
extractedFluids = IoUtil.extractFromInternalFluidStorage(requirements.getSingleFluidRequirementSet(false), internalFluidStorage, Action.PERFORM);
IoUtil.insertIntoInventory(container.getConnectedInventory(), extractedItems.getStacks(), Action.PERFORM);
IoUtil.insertIntoInventory(container.getConnectedFluidInventory(), extractedFluids.getStacks(), Action.PERFORM);
next();
listener.onSingleDone(this);
container.onUsedForProcessing();
}
}
}
}
if (originalState != state) {
network.getCraftingManager().onTaskChanged();
}
}
public ProcessingState getState() {
return state;
}
public IStackList<ItemStack> getSingleItemSetToReceive() {
return singleItemSetToReceive;
}
public IStackList<FluidStack> getSingleFluidSetToReceive() {
return singleFluidSetToReceive;
}
public IStackList<ItemStack> getSingleItemSetToRequire() {
return singleItemSetToRequire;
}
public IStackList<FluidStack> getSingleFluidSetToRequire() {
return singleFluidSetToRequire;
}
public int getNeeded(ItemStack stack) {
return (singleItemSetToReceive.getCount(stack) * totalQuantity) - itemsReceived.getCount(stack);
}
public int getNeeded(FluidStack stack) {
return (singleFluidSetToReceive.getCount(stack) * totalQuantity) - fluidsReceived.getCount(stack);
}
public int getCurrentlyProcessing() {
int unprocessed = totalQuantity - quantity;
return unprocessed - quantityFinished;
}
public void markReceived(ItemStack stack, int count) {
itemsReceived.add(stack, count);
updateFinishedQuantity();
}
public void markReceived(FluidStack stack, int count) {
fluidsReceived.add(stack, count);
updateFinishedQuantity();
}
public void updateFinishedQuantity() {
int quantityFinished = totalQuantity;
for (StackListEntry<ItemStack> toReceive : singleItemSetToReceive.getStacks()) {
if (itemsReceived.get(toReceive.getStack()) != null) {
int ratioReceived = itemsReceived.get(toReceive.getStack()).getCount() / toReceive.getStack().getCount();
if (quantityFinished > ratioReceived) {
quantityFinished = ratioReceived;
}
} else {
quantityFinished = 0;
}
}
for (StackListEntry<FluidStack> toReceive : singleFluidSetToReceive.getStacks()) {
if (fluidsReceived.get(toReceive.getStack()) != null) {
int ratioReceived = fluidsReceived.get(toReceive.getStack()).getAmount() / toReceive.getStack().getAmount();
if (quantityFinished > ratioReceived) {
quantityFinished = ratioReceived;
}
} else {
quantityFinished = 0;
}
}
this.quantityFinished = quantityFinished;
if (this.quantityFinished == this.totalQuantity) {
this.state = ProcessingState.PROCESSED;
}
}
@Override
public void onCalculationFinished() {
super.onCalculationFinished();
this.singleItemSetToRequire = requirements.getSingleItemRequirementSet(true);
this.singleFluidSetToRequire = requirements.getSingleFluidRequirementSet(true);
}
@Override
public CompoundNBT writeToNbt() {
CompoundNBT tag = super.writeToNbt();
tag.put(NBT_ITEMS_RECEIVED, SerializationUtil.writeItemStackList(itemsReceived));
tag.put(NBT_FLUIDS_RECEIVED, SerializationUtil.writeFluidStackList(fluidsReceived));
tag.put(NBT_SINGLE_ITEM_SET_TO_REQUIRE, SerializationUtil.writeItemStackList(singleItemSetToRequire));
tag.put(NBT_SINGLE_FLUID_SET_TO_REQUIRE, SerializationUtil.writeFluidStackList(singleFluidSetToRequire));
tag.putInt(NBT_STATE, state.ordinal());
return tag;
}
}

View File

@@ -1,6 +1,6 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6;
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.node;
enum ProcessingState {
public enum ProcessingState {
READY,
MACHINE_NONE,
MACHINE_DOES_NOT_ACCEPT,

View File

@@ -0,0 +1,115 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.preview;
import com.google.common.collect.ImmutableList;
import com.refinedmods.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement;
import com.refinedmods.refinedstorage.api.util.StackListEntry;
import com.refinedmods.refinedstorage.apiimpl.API;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.preview.FluidCraftingPreviewElement;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.preview.ItemCraftingPreviewElement;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class CraftingPreviewElementFactory {
public List<ICraftingPreviewElement<?>> getElements(CraftingPreviewInfo info) {
Map<Integer, ItemCraftingPreviewElement> map = new LinkedHashMap<>();
Map<Integer, FluidCraftingPreviewElement> mapFluids = new LinkedHashMap<>();
for (StackListEntry<ItemStack> stack : info.getMissing().getStacks()) {
int hash = API.instance().getItemStackHashCode(stack.getStack());
ItemCraftingPreviewElement previewStack = map.get(hash);
if (previewStack == null) {
previewStack = new ItemCraftingPreviewElement(stack.getStack());
}
previewStack.setMissing(true);
previewStack.addToCraft(stack.getStack().getCount());
map.put(hash, previewStack);
}
for (StackListEntry<FluidStack> stack : info.getMissingFluids().getStacks()) {
int hash = API.instance().getFluidStackHashCode(stack.getStack());
FluidCraftingPreviewElement previewStack = mapFluids.get(hash);
if (previewStack == null) {
previewStack = new FluidCraftingPreviewElement(stack.getStack());
}
previewStack.setMissing(true);
previewStack.addToCraft(stack.getStack().getAmount());
mapFluids.put(hash, previewStack);
}
for (ItemStack stack : ImmutableList.copyOf(info.getToCraft()).reverse()) {
int hash = API.instance().getItemStackHashCode(stack);
ItemCraftingPreviewElement previewStack = map.get(hash);
if (previewStack == null) {
previewStack = new ItemCraftingPreviewElement(stack.getStack());
}
previewStack.addToCraft(stack.getCount());
map.put(hash, previewStack);
}
for (FluidStack stack : ImmutableList.copyOf(info.getToCraftFluids()).reverse()) {
int hash = API.instance().getFluidStackHashCode(stack);
FluidCraftingPreviewElement previewStack = mapFluids.get(hash);
if (previewStack == null) {
previewStack = new FluidCraftingPreviewElement(stack);
}
previewStack.addToCraft(stack.getAmount());
mapFluids.put(hash, previewStack);
}
for (StackListEntry<ItemStack> stack : info.getToTake().getStacks()) {
int hash = API.instance().getItemStackHashCode(stack.getStack());
ItemCraftingPreviewElement previewStack = map.get(hash);
if (previewStack == null) {
previewStack = new ItemCraftingPreviewElement(stack.getStack());
}
previewStack.addAvailable(stack.getStack().getCount());
map.put(hash, previewStack);
}
for (StackListEntry<FluidStack> stack : info.getToTakeFluids().getStacks()) {
int hash = API.instance().getFluidStackHashCode(stack.getStack());
FluidCraftingPreviewElement previewStack = mapFluids.get(hash);
if (previewStack == null) {
previewStack = new FluidCraftingPreviewElement(stack.getStack());
}
previewStack.addAvailable(stack.getStack().getAmount());
mapFluids.put(hash, previewStack);
}
List<ICraftingPreviewElement<?>> elements = new ArrayList<>();
elements.addAll(map.values());
elements.addAll(mapFluids.values());
return elements;
}
}

View File

@@ -0,0 +1,48 @@
package com.refinedmods.refinedstorage.apiimpl.autocrafting.task.v6.preview;
import com.refinedmods.refinedstorage.api.util.IStackList;
import com.refinedmods.refinedstorage.apiimpl.API;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import java.util.ArrayList;
import java.util.List;
public class CraftingPreviewInfo {
private final IStackList<ItemStack> missing = API.instance().createItemStackList();
private final IStackList<FluidStack> missingFluids = API.instance().createFluidStackList();
private final IStackList<ItemStack> toTake = API.instance().createItemStackList();
private final IStackList<FluidStack> toTakeFluids = API.instance().createFluidStackList();
private final List<ItemStack> toCraft = new ArrayList<>();
private final List<FluidStack> toCraftFluids = new ArrayList<>();
public IStackList<ItemStack> getMissing() {
return missing;
}
public IStackList<FluidStack> getMissingFluids() {
return missingFluids;
}
public boolean hasMissing() {
return !missing.isEmpty() || !missingFluids.isEmpty();
}
public IStackList<ItemStack> getToTake() {
return toTake;
}
public IStackList<FluidStack> getToTakeFluids() {
return toTakeFluids;
}
public List<ItemStack> getToCraft() {
return toCraft;
}
public List<FluidStack> getToCraftFluids() {
return toCraftFluids;
}
}

View File

@@ -1,8 +1,8 @@
package com.refinedmods.refinedstorage.apiimpl.network.grid.handler;
import com.refinedmods.refinedstorage.RS;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingTask;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingTaskError;
import com.refinedmods.refinedstorage.api.autocrafting.task.CalculationResultType;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICalculationResult;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.api.network.grid.handler.IFluidGridHandler;
import com.refinedmods.refinedstorage.api.network.security.Permission;
@@ -15,7 +15,6 @@ import com.refinedmods.refinedstorage.util.StackUtils;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fluids.FluidAttributes;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
@@ -101,36 +100,30 @@ public class FluidGridHandler implements IFluidGridHandler {
if (stack != null) {
Thread calculationThread = new Thread(() -> {
ICraftingTask task = network.getCraftingManager().create(stack, quantity);
if (task == null) {
ICalculationResult result = network.getCraftingManager().create(stack, quantity);
if (result == null) {
return;
}
ICraftingTaskError error = task.calculate();
ResourceLocation factoryId = task.getPattern().getCraftingTaskFactoryId();
if (error != null) {
if (!result.isOk() && result.getType() != CalculationResultType.MISSING) {
RS.NETWORK_HANDLER.sendTo(
player,
new GridCraftingPreviewResponseMessage(
factoryId,
Collections.singletonList(new ErrorCraftingPreviewElement(error.getType(), error.getRecursedPattern() == null ? ItemStack.EMPTY : error.getRecursedPattern().getStack())),
Collections.singletonList(new ErrorCraftingPreviewElement(result.getType(), result.getRecursedPattern() == null ? ItemStack.EMPTY : result.getRecursedPattern().getStack())),
id,
quantity,
true
)
);
} else if (noPreview && !task.hasMissing()) {
network.getCraftingManager().start(task);
} else if (result.isOk() && noPreview) {
network.getCraftingManager().start(result.getTask());
RS.NETWORK_HANDLER.sendTo(player, new GridCraftingStartResponseMessage());
} else {
RS.NETWORK_HANDLER.sendTo(
player,
new GridCraftingPreviewResponseMessage(
factoryId,
task.getPreviewStacks(),
result.getPreviewElements(),
id,
quantity,
true
@@ -152,14 +145,9 @@ public class FluidGridHandler implements IFluidGridHandler {
FluidStack stack = network.getFluidStorageCache().getCraftablesList().get(id);
if (stack != null) {
ICraftingTask task = network.getCraftingManager().create(stack, quantity);
if (task == null) {
return;
}
ICraftingTaskError error = task.calculate();
if (error == null && !task.hasMissing()) {
network.getCraftingManager().start(task);
ICalculationResult result = network.getCraftingManager().create(stack, quantity);
if (result.isOk()) {
network.getCraftingManager().start(result.getTask());
}
}
}

View File

@@ -1,8 +1,8 @@
package com.refinedmods.refinedstorage.apiimpl.network.grid.handler;
import com.refinedmods.refinedstorage.RS;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingTask;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICraftingTaskError;
import com.refinedmods.refinedstorage.api.autocrafting.task.CalculationResultType;
import com.refinedmods.refinedstorage.api.autocrafting.task.ICalculationResult;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.api.network.grid.handler.IItemGridHandler;
import com.refinedmods.refinedstorage.api.network.security.Permission;
@@ -14,7 +14,6 @@ import com.refinedmods.refinedstorage.network.grid.GridCraftingStartResponseMess
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
@@ -159,36 +158,27 @@ public class ItemGridHandler implements IItemGridHandler {
if (stack != null) {
Thread calculationThread = new Thread(() -> {
ICraftingTask task = network.getCraftingManager().create(stack, quantity);
if (task == null) {
return;
}
ICalculationResult result = network.getCraftingManager().create(stack, quantity);
ICraftingTaskError error = task.calculate();
ResourceLocation factoryId = task.getPattern().getCraftingTaskFactoryId();
if (error != null) {
if (!result.isOk() && result.getType() != CalculationResultType.MISSING) {
RS.NETWORK_HANDLER.sendTo(
player,
new GridCraftingPreviewResponseMessage(
factoryId,
Collections.singletonList(new ErrorCraftingPreviewElement(error.getType(), error.getRecursedPattern() == null ? ItemStack.EMPTY : error.getRecursedPattern().getStack())),
Collections.singletonList(new ErrorCraftingPreviewElement(result.getType(), result.getRecursedPattern() == null ? ItemStack.EMPTY : result.getRecursedPattern().getStack())),
id,
quantity,
false
)
);
} else if (noPreview && !task.hasMissing()) {
network.getCraftingManager().start(task);
} else if (result.isOk() && noPreview) {
network.getCraftingManager().start(result.getTask());
RS.NETWORK_HANDLER.sendTo(player, new GridCraftingStartResponseMessage());
} else {
RS.NETWORK_HANDLER.sendTo(
player,
new GridCraftingPreviewResponseMessage(
factoryId,
task.getPreviewStacks(),
result.getPreviewElements(),
id,
quantity,
false
@@ -210,14 +200,9 @@ public class ItemGridHandler implements IItemGridHandler {
ItemStack stack = network.getItemStorageCache().getCraftablesList().get(id);
if (stack != null) {
ICraftingTask task = network.getCraftingManager().create(stack, quantity);
if (task == null) {
return;
}
ICraftingTaskError error = task.calculate();
if (error == null && !task.hasMissing()) {
network.getCraftingManager().start(task);
ICalculationResult result = network.getCraftingManager().create(stack, quantity);
if (result.isOk()) {
network.getCraftingManager().start(result.getTask());
}
}
}

View File

@@ -82,6 +82,16 @@ public class FluidStackList implements IStackList<FluidStack> {
return remove(stack, stack.getAmount());
}
@Override
public int getCount(@Nonnull FluidStack stack, int flags) {
FluidStack found = get(stack, flags);
if (found == null) {
return 0;
}
return found.getAmount();
}
@Override
@Nullable
public FluidStack get(@Nonnull FluidStack stack, int flags) {

View File

@@ -80,6 +80,16 @@ public class ItemStackList implements IStackList<ItemStack> {
return remove(stack, stack.getCount());
}
@Override
public int getCount(@Nonnull ItemStack stack, int flags) {
ItemStack found = get(stack, flags);
if (found == null) {
return 0;
}
return found.getCount();
}
@Override
@Nullable
public ItemStack get(@Nonnull ItemStack stack, int flags) {

View File

@@ -20,8 +20,7 @@ public class ClientProxy {
Minecraft.getInstance().displayGuiScreen(new CraftingPreviewScreen(
screen,
message.getFactoryId(),
message.getStacks(),
message.getElements(),
message.getId(),
message.getQuantity(),
message.isFluids(),

View File

@@ -83,7 +83,7 @@ public class CraftingMonitorUpdateMessage {
buf.writeUniqueId(task.getId());
buf.writeCompoundTag(task.getRequested().writeToNbt());
buf.writeInt(task.getQuantity());
buf.writeLong(task.getExecutionStarted());
buf.writeLong(task.getStartTime());
buf.writeInt(task.getCompletionPercentage());
List<ICraftingMonitorElement> elements = task.getCraftingMonitorElements();

View File

@@ -13,26 +13,20 @@ import java.util.UUID;
import java.util.function.Supplier;
public class GridCraftingPreviewResponseMessage {
private final ResourceLocation factoryId;
private final List<ICraftingPreviewElement<?>> stacks;
private final List<ICraftingPreviewElement<?>> elements;
private final UUID id;
private final int quantity;
private final boolean fluids;
public GridCraftingPreviewResponseMessage(ResourceLocation factoryId, List<ICraftingPreviewElement<?>> stacks, UUID id, int quantity, boolean fluids) {
this.factoryId = factoryId;
this.stacks = stacks;
public GridCraftingPreviewResponseMessage(List<ICraftingPreviewElement<?>> elements, UUID id, int quantity, boolean fluids) {
this.elements = elements;
this.id = id;
this.quantity = quantity;
this.fluids = fluids;
}
public ResourceLocation getFactoryId() {
return factoryId;
}
public List<ICraftingPreviewElement<?>> getStacks() {
return stacks;
public List<ICraftingPreviewElement<?>> getElements() {
return elements;
}
public UUID getId() {
@@ -48,7 +42,6 @@ public class GridCraftingPreviewResponseMessage {
}
public static GridCraftingPreviewResponseMessage decode(PacketBuffer buf) {
ResourceLocation factoryId = buf.readResourceLocation();
UUID id = buf.readUniqueId();
int quantity = buf.readInt();
boolean fluids = buf.readBoolean();
@@ -62,17 +55,16 @@ public class GridCraftingPreviewResponseMessage {
stacks.add(API.instance().getCraftingPreviewElementRegistry().get(type).apply(buf));
}
return new GridCraftingPreviewResponseMessage(factoryId, stacks, id, quantity, fluids);
return new GridCraftingPreviewResponseMessage(stacks, id, quantity, fluids);
}
public static void encode(GridCraftingPreviewResponseMessage message, PacketBuffer buf) {
buf.writeResourceLocation(message.factoryId);
buf.writeUniqueId(message.id);
buf.writeInt(message.quantity);
buf.writeBoolean(message.fluids);
buf.writeInt(message.stacks.size());
buf.writeInt(message.elements.size());
for (ICraftingPreviewElement<?> stack : message.stacks) {
for (ICraftingPreviewElement<?> stack : message.elements) {
buf.writeResourceLocation(stack.getId());
stack.write(buf);
}

View File

@@ -5,7 +5,7 @@ import com.mojang.blaze3d.systems.RenderSystem;
import com.refinedmods.refinedstorage.RS;
import com.refinedmods.refinedstorage.api.autocrafting.ICraftingPattern;
import com.refinedmods.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement;
import com.refinedmods.refinedstorage.api.autocrafting.task.CraftingTaskErrorType;
import com.refinedmods.refinedstorage.api.autocrafting.task.CalculationResultType;
import com.refinedmods.refinedstorage.api.render.IElementDrawers;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.preview.ErrorCraftingPreviewElement;
import com.refinedmods.refinedstorage.apiimpl.autocrafting.preview.FluidCraftingPreviewElement;
@@ -25,7 +25,6 @@ import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.container.Container;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraftforge.fluids.FluidStack;
@@ -36,14 +35,12 @@ import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
public class CraftingPreviewScreen extends BaseScreen<Container> {
private static final int VISIBLE_ROWS = 5;
private final List<ICraftingPreviewElement<?>> stacks;
private final Screen parent;
private final ResourceLocation factoryId;
private final ScrollbarWidget scrollbar;
@@ -56,7 +53,7 @@ public class CraftingPreviewScreen extends BaseScreen<Container> {
private final IElementDrawers drawers = new CraftingPreviewElementDrawers(this, font);
public CraftingPreviewScreen(Screen parent, ResourceLocation factoryId, List<ICraftingPreviewElement<?>> stacks, UUID id, int quantity, boolean fluids, ITextComponent title) {
public CraftingPreviewScreen(Screen parent, List<ICraftingPreviewElement<?>> stacks, UUID id, int quantity, boolean fluids, ITextComponent title) {
super(new Container(null, 0) {
@Override
public boolean canInteractWith(@Nonnull PlayerEntity player) {
@@ -66,7 +63,6 @@ public class CraftingPreviewScreen extends BaseScreen<Container> {
this.stacks = new ArrayList<>(stacks);
this.parent = parent;
this.factoryId = factoryId;
this.id = id;
this.quantity = quantity;
@@ -90,7 +86,7 @@ public class CraftingPreviewScreen extends BaseScreen<Container> {
}
@Nullable
private CraftingTaskErrorType getErrorType() {
private CalculationResultType getErrorType() {
if (stacks.size() == 1 && stacks.get(0) instanceof ErrorCraftingPreviewElement) {
return ((ErrorCraftingPreviewElement) stacks.get(0)).getType();
}
@@ -135,8 +131,6 @@ public class CraftingPreviewScreen extends BaseScreen<Container> {
renderString(matrixStack, RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 61, scale), I18n.format("gui.refinedstorage.crafting_preview.error.recursive.4"));
RenderSystem.popMatrix();
ICraftingPattern pattern = PatternItem.fromCache(parent.getMinecraft().world, (ItemStack) stacks.get(0).getElement());
int yy = 83;
@@ -162,11 +156,11 @@ public class CraftingPreviewScreen extends BaseScreen<Container> {
renderString(matrixStack, RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 21, scale), I18n.format("gui.refinedstorage.crafting_preview.error.too_complex.0"));
renderString(matrixStack, RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 31, scale), I18n.format("gui.refinedstorage.crafting_preview.error.too_complex.1"));
RenderSystem.popMatrix();
break;
}
}
RenderSystem.popMatrix();
} else {
int slot = scrollbar != null ? (scrollbar.getOffset() * 3) : 0;