Implement pattern chains.

This commit is contained in:
raoulvdberge
2018-06-14 14:30:12 +02:00
parent e37d403459
commit f256429051
15 changed files with 204 additions and 25 deletions

View File

@@ -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.

View File

@@ -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();
}

View File

@@ -0,0 +1,7 @@
package com.raoulvdberge.refinedstorage.api.autocrafting;
public interface ICraftingPatternChain {
ICraftingPattern current();
ICraftingPattern cycle();
}

View File

@@ -0,0 +1,5 @@
package com.raoulvdberge.refinedstorage.api.autocrafting;
public interface ICraftingPatternChainList {
ICraftingPatternChain getChain(ICraftingPattern pattern);
}

View File

@@ -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;
}
}

View File

@@ -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() {

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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.

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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));

View File

@@ -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.")

View File

@@ -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);