Implement pattern chains.
This commit is contained in:
@@ -2,7 +2,6 @@ package com.raoulvdberge.refinedstorage.api.autocrafting;
|
||||
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorListener;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTask;
|
||||
import com.raoulvdberge.refinedstorage.api.util.IComparer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||
@@ -50,16 +49,17 @@ public interface ICraftingManager {
|
||||
@Nullable
|
||||
ICraftingTask create(ItemStack stack, int quantity);
|
||||
|
||||
ICraftingPatternChainList createPatternChainList();
|
||||
|
||||
/**
|
||||
* Schedules a crafting task if the task isn't scheduled yet.
|
||||
*
|
||||
* @param stack the stack
|
||||
* @param toSchedule the amount of tasks to schedule
|
||||
* @param compare the compare value to find patterns, see {@link IComparer}
|
||||
* @return the crafting task created, or null if no task is created
|
||||
*/
|
||||
@Nullable
|
||||
ICraftingTask schedule(ItemStack stack, int toSchedule, int compare);
|
||||
ICraftingTask schedule(ItemStack stack, int toSchedule);
|
||||
|
||||
/**
|
||||
* Tracks an incoming stack.
|
||||
@@ -82,11 +82,10 @@ public interface ICraftingManager {
|
||||
* Return a crafting pattern from an item stack.
|
||||
*
|
||||
* @param pattern the stack to get a pattern for
|
||||
* @param flags the flags to compare on, see {@link IComparer}
|
||||
* @return the crafting pattern, or null if none is found
|
||||
*/
|
||||
@Nullable
|
||||
ICraftingPattern getPattern(ItemStack pattern, int flags);
|
||||
ICraftingPattern getPattern(ItemStack pattern);
|
||||
|
||||
/**
|
||||
* Updates the tasks in this manager.
|
||||
|
||||
@@ -65,4 +65,8 @@ public interface ICraftingPattern {
|
||||
* @return the id of the factory that creates a crafting task for this pattern, as defined in the {@link com.raoulvdberge.refinedstorage.api.autocrafting.registry.ICraftingTaskRegistry}
|
||||
*/
|
||||
String getId();
|
||||
|
||||
boolean canBeInChainWith(ICraftingPattern other);
|
||||
|
||||
int getChainHashCode();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.raoulvdberge.refinedstorage.api.autocrafting;
|
||||
|
||||
public interface ICraftingPatternChain {
|
||||
ICraftingPattern current();
|
||||
|
||||
ICraftingPattern cycle();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.raoulvdberge.refinedstorage.api.autocrafting;
|
||||
|
||||
public interface ICraftingPatternChainList {
|
||||
ICraftingPatternChain getChain(ICraftingPattern pattern);
|
||||
}
|
||||
@@ -2,13 +2,13 @@ package com.raoulvdberge.refinedstorage.apiimpl.autocrafting;
|
||||
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingManager;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternChainList;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternContainer;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorListener;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.registry.ICraftingTaskFactory;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTask;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTaskError;
|
||||
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode;
|
||||
import com.raoulvdberge.refinedstorage.api.util.IComparer;
|
||||
import com.raoulvdberge.refinedstorage.apiimpl.API;
|
||||
import com.raoulvdberge.refinedstorage.tile.TileController;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -63,7 +63,7 @@ public class CraftingManager implements ICraftingManager {
|
||||
@Override
|
||||
@Nullable
|
||||
public ICraftingTask create(ItemStack stack, int quantity) {
|
||||
ICraftingPattern pattern = getPattern(stack, IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT);
|
||||
ICraftingPattern pattern = getPattern(stack);
|
||||
if (pattern == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -76,6 +76,11 @@ public class CraftingManager implements ICraftingManager {
|
||||
return factory.create(network, stack, quantity, pattern, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICraftingPatternChainList createPatternChainList() {
|
||||
return new CraftingPatternChainList(patterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
if (network.canRun()) {
|
||||
@@ -126,10 +131,10 @@ public class CraftingManager implements ICraftingManager {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ICraftingTask schedule(ItemStack stack, int toSchedule, int compare) {
|
||||
public ICraftingTask schedule(ItemStack stack, int toSchedule) {
|
||||
for (ICraftingTask task : getTasks()) {
|
||||
for (ItemStack output : task.getPattern().getOutputs()) {
|
||||
if (API.instance().getComparer().isEqual(output, stack, compare)) {
|
||||
if (API.instance().getComparer().isEqual(output, stack)) {
|
||||
toSchedule -= output.getCount() * task.getQuantity();
|
||||
}
|
||||
}
|
||||
@@ -195,10 +200,10 @@ public class CraftingManager implements ICraftingManager {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ICraftingPattern getPattern(ItemStack pattern, int flags) {
|
||||
public ICraftingPattern getPattern(ItemStack pattern) {
|
||||
for (ICraftingPattern patternInList : patterns) {
|
||||
for (ItemStack output : patternInList.getOutputs()) {
|
||||
if (API.instance().getComparer().isEqual(output, pattern, flags)) {
|
||||
if (API.instance().getComparer().isEqual(output, pattern)) {
|
||||
return patternInList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.raoulvdberge.refinedstorage.apiimpl.autocrafting;
|
||||
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternContainer;
|
||||
import com.raoulvdberge.refinedstorage.apiimpl.API;
|
||||
import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.registry.CraftingTaskFactory;
|
||||
import com.raoulvdberge.refinedstorage.item.ItemPattern;
|
||||
import com.raoulvdberge.refinedstorage.util.StackUtils;
|
||||
@@ -41,7 +42,7 @@ public class CraftingPattern implements ICraftingPattern {
|
||||
if (input == null) {
|
||||
inputs.add(NonNullList.create());
|
||||
} else if (oredict) {
|
||||
inputs.add(StackUtils.getEquivalentStacks(input));
|
||||
inputs.add(StackUtils.getEquivalentStacks(input)); // TODO: set stacksize?
|
||||
} else {
|
||||
inputs.add(NonNullList.from(ItemStack.EMPTY, input));
|
||||
}
|
||||
@@ -198,6 +199,76 @@ public class CraftingPattern implements ICraftingPattern {
|
||||
return CraftingTaskFactory.ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeInChainWith(ICraftingPattern other) {
|
||||
if (other.isProcessing() != processing || other.isOredict() != oredict) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((other.getInputs().size() != inputs.size()) || (other.getOutputs().size() != outputs.size())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!processing && other.getByproducts().size() != byproducts.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < inputs.size(); ++i) {
|
||||
List<ItemStack> inputs = this.inputs.get(i);
|
||||
List<ItemStack> otherInputs = other.getInputs().get(i);
|
||||
|
||||
if (inputs.size() != otherInputs.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int j = 0; j < inputs.size(); ++j) {
|
||||
if (!API.instance().getComparer().isEqual(inputs.get(j), otherInputs.get(j))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < outputs.size(); ++i) {
|
||||
if (!API.instance().getComparer().isEqual(outputs.get(i), other.getOutputs().get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!processing) {
|
||||
for (int i = 0; i < byproducts.size(); ++i) {
|
||||
if (!API.instance().getComparer().isEqual(byproducts.get(i), other.getByproducts().get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChainHashCode() {
|
||||
int result = 0;
|
||||
|
||||
result = 31 * result + (processing ? 1 : 0);
|
||||
result = 31 * result + (oredict ? 1 : 0);
|
||||
|
||||
for (List<ItemStack> inputs : this.inputs) {
|
||||
for (ItemStack input : inputs) {
|
||||
result = 31 * result + API.instance().getItemStackHashCode(input, true);
|
||||
}
|
||||
}
|
||||
|
||||
for (ItemStack output : this.outputs) {
|
||||
result = 31 * result + API.instance().getItemStackHashCode(output, true);
|
||||
}
|
||||
|
||||
for (ItemStack byproduct : this.byproducts) {
|
||||
result = 31 * result + API.instance().getItemStackHashCode(byproduct, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private class InventoryCraftingDummy extends InventoryCrafting {
|
||||
public InventoryCraftingDummy() {
|
||||
super(new Container() {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.raoulvdberge.refinedstorage.apiimpl.autocrafting;
|
||||
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternChain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CraftingPatternChain implements ICraftingPatternChain {
|
||||
private 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.raoulvdberge.refinedstorage.apiimpl.autocrafting;
|
||||
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternChain;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternChainList;
|
||||
import gnu.trove.map.hash.TCustomHashMap;
|
||||
import gnu.trove.strategy.HashingStrategy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class CraftingPatternChainList implements ICraftingPatternChainList {
|
||||
private Map<ICraftingPattern, CraftingPatternChain> map = new TCustomHashMap<>(new HashingStrategy<ICraftingPattern>() {
|
||||
@Override
|
||||
public int computeHashCode(ICraftingPattern pattern) {
|
||||
return pattern.getChainHashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(ICraftingPattern left, ICraftingPattern right) {
|
||||
return left.canBeInChainWith(right);
|
||||
}
|
||||
});
|
||||
|
||||
public CraftingPatternChainList(List<ICraftingPattern> patterns) {
|
||||
for (ICraftingPattern pattern : patterns) {
|
||||
CraftingPatternChain chain = map.get(pattern);
|
||||
if (chain == null) {
|
||||
map.put(pattern, chain = new CraftingPatternChain());
|
||||
}
|
||||
|
||||
chain.addPattern(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICraftingPatternChain getChain(ICraftingPattern pattern) {
|
||||
ICraftingPatternChain chain = map.get(pattern);
|
||||
if (chain == null) {
|
||||
throw new IllegalStateException("Pattern was not found in pattern chain");
|
||||
}
|
||||
|
||||
return chain;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task;
|
||||
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternChain;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternChainList;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElement;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElementList;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement;
|
||||
@@ -8,7 +10,6 @@ import com.raoulvdberge.refinedstorage.api.autocrafting.task.CraftingTaskErrorTy
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTask;
|
||||
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTaskError;
|
||||
import com.raoulvdberge.refinedstorage.api.network.INetwork;
|
||||
import com.raoulvdberge.refinedstorage.api.util.IComparer;
|
||||
import com.raoulvdberge.refinedstorage.api.util.IStackList;
|
||||
import com.raoulvdberge.refinedstorage.apiimpl.API;
|
||||
import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.craftingmonitor.CraftingMonitorElementColor;
|
||||
@@ -68,8 +69,12 @@ public class CraftingTask implements ICraftingTask {
|
||||
IStackList<ItemStack> results = API.instance().createItemStackList();
|
||||
IStackList<ItemStack> storage = network.getItemStorageCache().getList().copy();
|
||||
|
||||
ICraftingPatternChainList patternChainList = network.getCraftingManager().createPatternChainList();
|
||||
|
||||
ICraftingPatternChain patternChain = patternChainList.getChain(pattern);
|
||||
|
||||
while (qty > 0) {
|
||||
Pair<CraftingStep, ICraftingTaskError> result = calculateInternal(storage, results, pattern);
|
||||
Pair<CraftingStep, ICraftingTaskError> result = calculateInternal(storage, results, patternChainList, patternChain.current());
|
||||
|
||||
if (result.getRight() != null) {
|
||||
return result.getRight();
|
||||
@@ -80,6 +85,8 @@ public class CraftingTask implements ICraftingTask {
|
||||
qty -= qtyPerCraft;
|
||||
|
||||
crafted += qtyPerCraft;
|
||||
|
||||
patternChain.cycle();
|
||||
}
|
||||
|
||||
this.toCraft.add(requested, crafted);
|
||||
@@ -87,7 +94,7 @@ public class CraftingTask implements ICraftingTask {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Pair<CraftingStep, ICraftingTaskError> calculateInternal(IStackList<ItemStack> mutatedStorage, IStackList<ItemStack> results, ICraftingPattern pattern) {
|
||||
private Pair<CraftingStep, ICraftingTaskError> calculateInternal(IStackList<ItemStack> mutatedStorage, IStackList<ItemStack> results, ICraftingPatternChainList patternChainList, ICraftingPattern pattern) {
|
||||
if (System.currentTimeMillis() - calculationStarted > CALCULATION_TIMEOUT_MS) {
|
||||
return Pair.of(null, new CraftingTaskError(CraftingTaskErrorType.TOO_COMPLEX));
|
||||
}
|
||||
@@ -163,11 +170,13 @@ public class CraftingTask implements ICraftingTask {
|
||||
|
||||
fromNetwork = mutatedStorage.get(possibleInput);
|
||||
} else {
|
||||
ICraftingPattern subPattern = network.getCraftingManager().getPattern(possibleInput, IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT);
|
||||
ICraftingPattern subPattern = network.getCraftingManager().getPattern(possibleInput);
|
||||
|
||||
if (subPattern != null) {
|
||||
ICraftingPatternChain subPatternChain = patternChainList.getChain(subPattern);
|
||||
|
||||
while ((fromSelf == null ? 0 : fromSelf.getCount()) < remaining) {
|
||||
Pair<CraftingStep, ICraftingTaskError> result = calculateInternal(mutatedStorage, results, subPattern);
|
||||
Pair<CraftingStep, ICraftingTaskError> result = calculateInternal(mutatedStorage, results, patternChainList, subPatternChain.current());
|
||||
|
||||
if (result.getRight() != null) {
|
||||
return Pair.of(null, result.getRight());
|
||||
@@ -181,6 +190,8 @@ public class CraftingTask implements ICraftingTask {
|
||||
}
|
||||
|
||||
fromNetwork = mutatedStorage.get(possibleInput);
|
||||
|
||||
subPatternChain.cycle();
|
||||
}
|
||||
|
||||
// fromSelf contains the amount crafted after the loop.
|
||||
|
||||
@@ -212,6 +212,7 @@ public abstract class NetworkNode implements INetworkNode, INetworkNodeVisitor {
|
||||
return direction;
|
||||
}
|
||||
|
||||
// TODO: Move to network node.
|
||||
public void loadDirection() {
|
||||
EnumFacing direction = ((TileBase) world.getTileEntity(pos)).getDirection();
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ public class NetworkNodeConstructor extends NetworkNode implements IComparable,
|
||||
} else if (upgrades.hasUpgrade(ItemUpgrade.TYPE_CRAFTING)) {
|
||||
ItemStack craft = itemFilters.getStackInSlot(0);
|
||||
|
||||
network.getCraftingManager().schedule(craft, 1, compare);
|
||||
network.getCraftingManager().schedule(craft, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ public class NetworkNodeConstructor extends NetworkNode implements IComparable,
|
||||
} else if (upgrades.hasUpgrade(ItemUpgrade.TYPE_CRAFTING)) {
|
||||
ItemStack craft = itemFilters.getStackInSlot(0);
|
||||
|
||||
network.getCraftingManager().schedule(craft, 1, compare);
|
||||
network.getCraftingManager().schedule(craft, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ public class NetworkNodeExporter extends NetworkNode implements IComparable, ITy
|
||||
|
||||
if (took == null) {
|
||||
if (upgrades.hasUpgrade(ItemUpgrade.TYPE_CRAFTING)) {
|
||||
network.getCraftingManager().schedule(slot, stackSize, compare);
|
||||
network.getCraftingManager().schedule(slot, stackSize);
|
||||
}
|
||||
} else if (ItemHandlerHelper.insertItem(handler, took, true).isEmpty()) {
|
||||
took = network.extractItem(slot, Math.min(slot.getMaxStackSize(), stackSize), compare, false);
|
||||
|
||||
@@ -104,7 +104,7 @@ public class NetworkNodeInterface extends NetworkNode implements IComparable {
|
||||
delta -= result == null ? 0 : result.getCount();
|
||||
|
||||
if (delta > 0 && upgrades.hasUpgrade(ItemUpgrade.TYPE_CRAFTING)) {
|
||||
network.getCraftingManager().schedule(wanted, delta, compare);
|
||||
network.getCraftingManager().schedule(wanted, delta);
|
||||
}
|
||||
} else if (delta < 0) {
|
||||
ItemStack remainder = network.insertItemTracked(got, Math.abs(delta));
|
||||
|
||||
@@ -69,7 +69,7 @@ public class EnvironmentNetwork extends AbstractManagedEnvironment {
|
||||
}
|
||||
|
||||
ItemStack stack = args.checkItemStack(0);
|
||||
return new Object[]{node.getNetwork().getCraftingManager().getPattern(stack, IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT)};
|
||||
return new Object[]{node.getNetwork().getCraftingManager().getPattern(stack)};
|
||||
}
|
||||
|
||||
@Callback(doc = "function():table -- Gets the patterns of this network.")
|
||||
@@ -94,7 +94,7 @@ public class EnvironmentNetwork extends AbstractManagedEnvironment {
|
||||
|
||||
ItemStack stack = args.checkItemStack(0);
|
||||
|
||||
return new Object[]{node.getNetwork().getCraftingManager().getPattern(stack, IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT) != null};
|
||||
return new Object[]{node.getNetwork().getCraftingManager().getPattern(stack) != null};
|
||||
}
|
||||
|
||||
@Callback(doc = "function(stack:table[, count: number]):table -- Gets a list of missing items for a crafting task.")
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.raoulvdberge.refinedstorage.util;
|
||||
import com.raoulvdberge.refinedstorage.api.network.INetwork;
|
||||
import com.raoulvdberge.refinedstorage.api.storage.disk.IStorageDisk;
|
||||
import com.raoulvdberge.refinedstorage.api.storage.disk.IStorageDiskProvider;
|
||||
import com.raoulvdberge.refinedstorage.api.util.IComparer;
|
||||
import com.raoulvdberge.refinedstorage.api.util.IStackList;
|
||||
import com.raoulvdberge.refinedstorage.apiimpl.API;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
@@ -119,7 +118,7 @@ public final class StackUtils {
|
||||
buf.writeInt(API.instance().getItemStackHashCode(stack));
|
||||
|
||||
if (network != null) {
|
||||
buf.writeBoolean(network.getCraftingManager().getPattern(stack, IComparer.COMPARE_DAMAGE | IComparer.COMPARE_NBT) != null);
|
||||
buf.writeBoolean(network.getCraftingManager().getPattern(stack) != null);
|
||||
buf.writeBoolean(displayCraftText);
|
||||
} else {
|
||||
buf.writeBoolean(false);
|
||||
|
||||
Reference in New Issue
Block a user