Added error handling in crafting tasks: recursive pattern check and max time.

This commit is contained in:
raoulvdberge
2018-06-09 15:04:27 +02:00
parent 5a06d9bf46
commit cc9de91fdc
14 changed files with 223 additions and 65 deletions

View File

@@ -7,6 +7,8 @@
- Removed Storage Drawers integration (you can still attach an External Storage to drawers, though) (raoulvdberge) - Removed Storage Drawers integration (you can still attach an External Storage to drawers, though) (raoulvdberge)
- Removed blocking mode in autocrafting (raoulvdberge) - Removed blocking mode in autocrafting (raoulvdberge)
- Removed the Wrench (raoulvdberge) - Removed the Wrench (raoulvdberge)
- Rewrote autocrafting (raoulvdberge)
- Autocrafting tasks that take longer than 5 seconds to calculate are automatically stopped to avoid server strain (raoulvdberge)
- Added new storage disk system where the storage disk data (items, fluids) are stored off the disk itself, in another file (refinedstorage_disks.dat). The disk itself only stores its ID (raoulvdberge) - Added new storage disk system where the storage disk data (items, fluids) are stored off the disk itself, in another file (refinedstorage_disks.dat). The disk itself only stores its ID (raoulvdberge)
- Changed fluid storage progression to be 64k - 256k - 1024k - 4096k (raoulvdberge) - Changed fluid storage progression to be 64k - 256k - 1024k - 4096k (raoulvdberge)
- You can no longer put a Filter in filter slots to gain additional filter slots (raoulvdberge) - You can no longer put a Filter in filter slots to gain additional filter slots (raoulvdberge)

View File

@@ -0,0 +1,15 @@
package com.raoulvdberge.refinedstorage.api.autocrafting.task;
/**
* The error type.
*/
public enum CraftingTaskErrorType {
/**
* When the crafting task would cause too much server strain or is too complex.
*/
TOO_COMPLEX,
/**
* When one of the used patterns during the calculation reuses itself again and would cause an infinite loop.
*/
RECURSIVE
}

View File

@@ -7,6 +7,7 @@ import com.raoulvdberge.refinedstorage.api.util.IStackList;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import javax.annotation.Nullable;
import java.util.List; import java.util.List;
/** /**
@@ -15,8 +16,11 @@ import java.util.List;
public interface ICraftingTask { public interface ICraftingTask {
/** /**
* Calculates what this task will do, but doesn't run the task yet. * Calculates what this task will do, but doesn't run the task yet.
*
* @return the error, or null if there was no error
*/ */
void calculate(); @Nullable
ICraftingTaskError calculate();
/** /**
* Updates this task. * Updates this task.

View File

@@ -0,0 +1,23 @@
package com.raoulvdberge.refinedstorage.api.autocrafting.task;
import com.raoulvdberge.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

@@ -6,6 +6,7 @@ import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPatternContaine
import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorListener; import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorListener;
import com.raoulvdberge.refinedstorage.api.autocrafting.registry.ICraftingTaskFactory; import com.raoulvdberge.refinedstorage.api.autocrafting.registry.ICraftingTaskFactory;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTask; 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.network.node.INetworkNode;
import com.raoulvdberge.refinedstorage.api.util.IComparer; import com.raoulvdberge.refinedstorage.api.util.IComparer;
import com.raoulvdberge.refinedstorage.apiimpl.API; import com.raoulvdberge.refinedstorage.apiimpl.API;
@@ -138,14 +139,15 @@ public class CraftingManager implements ICraftingManager {
ICraftingTask task = create(stack, toSchedule); ICraftingTask task = create(stack, toSchedule);
if (task != null) { if (task != null) {
task.calculate(); ICraftingTaskError error = task.calculate();
if (error == null) {
this.add(task); this.add(task);
this.onTaskChanged();
return task; return task;
} }
} }
}
return null; return null;
} }

View File

@@ -1,6 +1,7 @@
package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.preview; package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.preview;
import com.raoulvdberge.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement; import com.raoulvdberge.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.CraftingTaskErrorType;
import com.raoulvdberge.refinedstorage.api.render.IElementDrawers; import com.raoulvdberge.refinedstorage.api.render.IElementDrawers;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import net.minecraft.item.Item; import net.minecraft.item.Item;
@@ -11,9 +12,11 @@ import net.minecraftforge.fml.common.network.ByteBufUtils;
public class CraftingPreviewElementError implements ICraftingPreviewElement<ItemStack> { public class CraftingPreviewElementError implements ICraftingPreviewElement<ItemStack> {
public static final String ID = "error"; public static final String ID = "error";
private CraftingTaskErrorType type;
private ItemStack stack; private ItemStack stack;
public CraftingPreviewElementError(ItemStack stack) { public CraftingPreviewElementError(CraftingTaskErrorType type, ItemStack stack) {
this.type = type;
this.stack = stack; this.stack = stack;
} }
@@ -39,17 +42,25 @@ public class CraftingPreviewElementError implements ICraftingPreviewElement<Item
@Override @Override
public boolean hasMissing() { public boolean hasMissing() {
return true; return false;
} }
@Override @Override
public void writeToByteBuf(ByteBuf buf) { public void writeToByteBuf(ByteBuf buf) {
buf.writeInt(type.ordinal());
buf.writeInt(Item.getIdFromItem(stack.getItem())); buf.writeInt(Item.getIdFromItem(stack.getItem()));
buf.writeInt(stack.getMetadata()); buf.writeInt(stack.getMetadata());
ByteBufUtils.writeTag(buf, stack.getTagCompound()); ByteBufUtils.writeTag(buf, stack.getTagCompound());
} }
public CraftingTaskErrorType getType() {
return type;
}
public static CraftingPreviewElementError fromByteBuf(ByteBuf buf) { public static CraftingPreviewElementError fromByteBuf(ByteBuf buf) {
int errorIdx = buf.readInt();
CraftingTaskErrorType error = errorIdx >= 0 && errorIdx < CraftingTaskErrorType.values().length ? CraftingTaskErrorType.values()[errorIdx] : CraftingTaskErrorType.TOO_COMPLEX;
Item item = Item.getItemById(buf.readInt()); Item item = Item.getItemById(buf.readInt());
int meta = buf.readInt(); int meta = buf.readInt();
NBTTagCompound tag = ByteBufUtils.readTag(buf); NBTTagCompound tag = ByteBufUtils.readTag(buf);
@@ -57,7 +68,7 @@ public class CraftingPreviewElementError implements ICraftingPreviewElement<Item
ItemStack stack = new ItemStack(item, 1, meta); ItemStack stack = new ItemStack(item, 1, meta);
stack.setTagCompound(tag); stack.setTagCompound(tag);
return new CraftingPreviewElementError(stack); return new CraftingPreviewElementError(error, stack);
} }
@Override @Override

View File

@@ -4,7 +4,9 @@ import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern;
import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElement; import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElement;
import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElementList; import com.raoulvdberge.refinedstorage.api.autocrafting.craftingmonitor.ICraftingMonitorElementList;
import com.raoulvdberge.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement; import com.raoulvdberge.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.CraftingTaskErrorType;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTask; 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.network.INetwork;
import com.raoulvdberge.refinedstorage.api.util.IComparer; import com.raoulvdberge.refinedstorage.api.util.IComparer;
import com.raoulvdberge.refinedstorage.api.util.IStackList; import com.raoulvdberge.refinedstorage.api.util.IStackList;
@@ -24,17 +26,23 @@ import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task.step.CraftingSt
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.NonNullList; import net.minecraft.util.NonNullList;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nullable;
import java.util.*; import java.util.*;
public class CraftingTask implements ICraftingTask { public class CraftingTask implements ICraftingTask {
private static final long CALCULATION_TIMEOUT_MS = 5000;
private INetwork network; private INetwork network;
private ItemStack requested; private ItemStack requested;
private int quantity; private int quantity;
private ICraftingPattern pattern; private ICraftingPattern pattern;
private List<CraftingStep> steps = new LinkedList<>(); private List<CraftingStep> steps = new LinkedList<>();
private CraftingInserter inserter; private CraftingInserter inserter;
private Set<ICraftingPattern> patternsUsed = new HashSet<>();
private int ticks = 0; private int ticks = 0;
private long calculationStarted;
private IStackList<ItemStack> toTake = API.instance().createItemStackList(); private IStackList<ItemStack> toTake = API.instance().createItemStackList();
private IStackList<ItemStack> missing = API.instance().createItemStackList(); private IStackList<ItemStack> missing = API.instance().createItemStackList();
@@ -49,7 +57,10 @@ public class CraftingTask implements ICraftingTask {
} }
@Override @Override
public void calculate() { @Nullable
public ICraftingTaskError calculate() {
this.calculationStarted = System.currentTimeMillis();
int qty = this.quantity; int qty = this.quantity;
int qtyPerCraft = getQuantityPerCraft(pattern, requested); int qtyPerCraft = getQuantityPerCraft(pattern, requested);
int crafted = 0; int crafted = 0;
@@ -58,7 +69,13 @@ public class CraftingTask implements ICraftingTask {
IStackList<ItemStack> storage = network.getItemStorageCache().getList().copy(); IStackList<ItemStack> storage = network.getItemStorageCache().getList().copy();
while (qty > 0) { while (qty > 0) {
this.steps.add(calculateInternal(storage, results, pattern)); Pair<CraftingStep, ICraftingTaskError> result = calculateInternal(storage, results, pattern);
if (result.getRight() != null) {
return result.getRight();
}
this.steps.add(result.getLeft());
qty -= qtyPerCraft; qty -= qtyPerCraft;
@@ -66,9 +83,19 @@ public class CraftingTask implements ICraftingTask {
} }
this.toCraft.add(requested, crafted); this.toCraft.add(requested, crafted);
return null;
}
private Pair<CraftingStep, ICraftingTaskError> calculateInternal(IStackList<ItemStack> mutatedStorage, IStackList<ItemStack> results, ICraftingPattern pattern) {
if (System.currentTimeMillis() - calculationStarted > CALCULATION_TIMEOUT_MS) {
return Pair.of(null, new CraftingTaskError(CraftingTaskErrorType.TOO_COMPLEX));
}
if (!patternsUsed.add(pattern)) {
return Pair.of(null, new CraftingTaskError(CraftingTaskErrorType.RECURSIVE, pattern));
} }
private CraftingStep calculateInternal(IStackList<ItemStack> mutatedStorage, IStackList<ItemStack> results, ICraftingPattern pattern) {
IStackList<ItemStack> itemsToExtract = API.instance().createItemStackList(); IStackList<ItemStack> itemsToExtract = API.instance().createItemStackList();
NonNullList<ItemStack> took = NonNullList.create(); NonNullList<ItemStack> took = NonNullList.create();
@@ -140,7 +167,13 @@ public class CraftingTask implements ICraftingTask {
if (subPattern != null) { if (subPattern != null) {
while ((fromSelf == null ? 0 : fromSelf.getCount()) < remaining) { while ((fromSelf == null ? 0 : fromSelf.getCount()) < remaining) {
this.steps.add(calculateInternal(mutatedStorage, results, subPattern)); Pair<CraftingStep, ICraftingTaskError> result = calculateInternal(mutatedStorage, results, subPattern);
if (result.getRight() != null) {
return Pair.of(null, result.getRight());
}
this.steps.add(result.getLeft());
fromSelf = results.get(possibleInput); fromSelf = results.get(possibleInput);
if (fromSelf == null) { if (fromSelf == null) {
@@ -161,12 +194,14 @@ public class CraftingTask implements ICraftingTask {
} }
} }
patternsUsed.remove(pattern);
if (pattern.isProcessing()) { if (pattern.isProcessing()) {
for (ItemStack output : pattern.getOutputs()) { for (ItemStack output : pattern.getOutputs()) {
results.add(output); results.add(output);
} }
return new CraftingStepProcess(pattern, network, new ArrayList<>(itemsToExtract.getStacks())); return Pair.of(new CraftingStepProcess(pattern, network, new ArrayList<>(itemsToExtract.getStacks())), null);
} else { } else {
results.add(pattern.getOutput(took)); results.add(pattern.getOutput(took));
@@ -174,7 +209,7 @@ public class CraftingTask implements ICraftingTask {
results.add(byproduct); results.add(byproduct);
} }
return new CraftingStepCraft(pattern, inserter, network, new ArrayList<>(itemsToExtract.getStacks()), took); return Pair.of(new CraftingStepCraft(pattern, inserter, network, new ArrayList<>(itemsToExtract.getStacks()), took), null);
} }
} }

View File

@@ -0,0 +1,32 @@
package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task;
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.CraftingTaskErrorType;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTaskError;
import javax.annotation.Nullable;
public class CraftingTaskError implements ICraftingTaskError {
private 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

@@ -4,6 +4,7 @@ import com.raoulvdberge.refinedstorage.RS;
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingManager; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingManager;
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTask; 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.network.INetwork;
import com.raoulvdberge.refinedstorage.api.network.grid.handler.IItemGridHandler; import com.raoulvdberge.refinedstorage.api.network.grid.handler.IItemGridHandler;
import com.raoulvdberge.refinedstorage.api.network.item.INetworkItem; import com.raoulvdberge.refinedstorage.api.network.item.INetworkItem;
@@ -11,6 +12,7 @@ import com.raoulvdberge.refinedstorage.api.network.item.NetworkItemAction;
import com.raoulvdberge.refinedstorage.api.network.security.Permission; import com.raoulvdberge.refinedstorage.api.network.security.Permission;
import com.raoulvdberge.refinedstorage.api.util.IStackList; import com.raoulvdberge.refinedstorage.api.util.IStackList;
import com.raoulvdberge.refinedstorage.apiimpl.API; import com.raoulvdberge.refinedstorage.apiimpl.API;
import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.preview.CraftingPreviewElementError;
import com.raoulvdberge.refinedstorage.network.MessageGridCraftingPreviewResponse; import com.raoulvdberge.refinedstorage.network.MessageGridCraftingPreviewResponse;
import com.raoulvdberge.refinedstorage.network.MessageGridCraftingStartResponse; import com.raoulvdberge.refinedstorage.network.MessageGridCraftingStartResponse;
import com.raoulvdberge.refinedstorage.util.StackUtils; import com.raoulvdberge.refinedstorage.util.StackUtils;
@@ -21,6 +23,8 @@ import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemHandlerHelper;
import java.util.Collections;
public class ItemGridHandler implements IItemGridHandler { public class ItemGridHandler implements IItemGridHandler {
private INetwork network; private INetwork network;
@@ -187,9 +191,11 @@ public class ItemGridHandler implements IItemGridHandler {
return; return;
} }
task.calculate(); ICraftingTaskError error = task.calculate();
if (noPreview && task.getMissing().isEmpty()) { if (error != null) {
RS.INSTANCE.network.sendTo(new MessageGridCraftingPreviewResponse(Collections.singletonList(new CraftingPreviewElementError(error.getType(), error.getRecursedPattern() == null ? ItemStack.EMPTY : error.getRecursedPattern().getStack())), hash, quantity), player);
} else if (noPreview && task.getMissing().isEmpty()) {
network.getCraftingManager().add(task); network.getCraftingManager().add(task);
RS.INSTANCE.network.sendTo(new MessageGridCraftingStartResponse(), player); RS.INSTANCE.network.sendTo(new MessageGridCraftingStartResponse(), player);
@@ -230,11 +236,12 @@ public class ItemGridHandler implements IItemGridHandler {
return; return;
} }
task.calculate(); ICraftingTaskError error = task.calculate();
if (error == null) {
network.getCraftingManager().add(task); network.getCraftingManager().add(task);
} }
} }
}
@Override @Override
public void onCraftingCancelRequested(EntityPlayerMP player, int id) { public void onCraftingCancelRequested(EntityPlayerMP player, int id) {

View File

@@ -3,6 +3,7 @@ package com.raoulvdberge.refinedstorage.gui;
import com.raoulvdberge.refinedstorage.RS; import com.raoulvdberge.refinedstorage.RS;
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern;
import com.raoulvdberge.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement; import com.raoulvdberge.refinedstorage.api.autocrafting.preview.ICraftingPreviewElement;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.CraftingTaskErrorType;
import com.raoulvdberge.refinedstorage.api.render.IElementDrawer; import com.raoulvdberge.refinedstorage.api.render.IElementDrawer;
import com.raoulvdberge.refinedstorage.api.render.IElementDrawers; import com.raoulvdberge.refinedstorage.api.render.IElementDrawers;
import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.preview.CraftingPreviewElementError; import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.preview.CraftingPreviewElementError;
@@ -25,6 +26,7 @@ import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.client.FMLClientHandler;
import org.lwjgl.input.Keyboard; import org.lwjgl.input.Keyboard;
import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -77,7 +79,7 @@ public class GuiCraftingPreview extends GuiBase {
public void init(int x, int y) { public void init(int x, int y) {
cancelButton = addButton(x + 16, y + 144, 50, 20, t("gui.cancel")); cancelButton = addButton(x + 16, y + 144, 50, 20, t("gui.cancel"));
startButton = addButton(x + 85, y + 144, 50, 20, t("misc.refinedstorage:start")); startButton = addButton(x + 85, y + 144, 50, 20, t("misc.refinedstorage:start"));
startButton.enabled = stacks.stream().noneMatch(ICraftingPreviewElement::hasMissing); startButton.enabled = stacks.stream().noneMatch(ICraftingPreviewElement::hasMissing) && getErrorType() == null;
} }
@Override @Override
@@ -87,13 +89,18 @@ public class GuiCraftingPreview extends GuiBase {
scrollbar.setMaxOffset(getRows() - VISIBLE_ROWS); scrollbar.setMaxOffset(getRows() - VISIBLE_ROWS);
} }
if (startButton != null && !startButton.enabled && isCtrlKeyDown() && isShiftKeyDown()) { if (startButton != null && !startButton.enabled && isCtrlKeyDown() && isShiftKeyDown() && getErrorType() == null) {
startButton.enabled = true; startButton.enabled = true;
} }
} }
private boolean hasErrored() { @Nullable
return stacks.size() == 1 && stacks.get(0) instanceof CraftingPreviewElementError; private CraftingTaskErrorType getErrorType() {
if (stacks.size() == 1 && stacks.get(0) instanceof CraftingPreviewElementError) {
return ((CraftingPreviewElementError) stacks.get(0)).getType();
}
return null;
} }
@Override @Override
@@ -102,7 +109,7 @@ public class GuiCraftingPreview extends GuiBase {
drawTexture(x, y, 0, 0, screenWidth, screenHeight); drawTexture(x, y, 0, 0, screenWidth, screenHeight);
if (hasErrored()) { if (getErrorType() != null) {
drawRect(x + 7, y + 20, x + 142, y + 139, 0xFFDBDBDB); drawRect(x + 7, y + 20, x + 142, y + 139, 0xFFDBDBDB);
} }
} }
@@ -116,28 +123,31 @@ public class GuiCraftingPreview extends GuiBase {
float scale = fontRenderer.getUnicodeFlag() ? 1F : 0.5F; float scale = fontRenderer.getUnicodeFlag() ? 1F : 0.5F;
if (hasErrored()) { if (getErrorType() != null) {
GlStateManager.pushMatrix(); GlStateManager.pushMatrix();
GlStateManager.scale(scale, scale, 1); GlStateManager.scale(scale, scale, 1);
drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 10, scale), t("gui.refinedstorage:crafting_preview.error.0")); drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 11, scale), t("gui.refinedstorage:crafting_preview.error"));
drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 20, scale), t("gui.refinedstorage:crafting_preview.error.1"));
drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 30, scale), t("gui.refinedstorage:crafting_preview.error.2"));
drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 40, scale), t("gui.refinedstorage:crafting_preview.error.3"));
drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 50, scale), t("gui.refinedstorage:crafting_preview.error.4"));
drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 60, scale), t("gui.refinedstorage:crafting_preview.error.5")); switch (getErrorType()) {
case RECURSIVE: {
drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 21, scale), t("gui.refinedstorage:crafting_preview.error.recursive.0"));
drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 31, scale), t("gui.refinedstorage:crafting_preview.error.recursive.1"));
drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 41, scale), t("gui.refinedstorage:crafting_preview.error.recursive.2"));
drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 51, scale), t("gui.refinedstorage:crafting_preview.error.recursive.3"));
drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 61, scale), t("gui.refinedstorage:crafting_preview.error.recursive.4"));
GlStateManager.popMatrix(); GlStateManager.popMatrix();
ICraftingPattern pattern = ItemPattern.getPatternFromCache(parent.mc.world, (ItemStack) stacks.get(0).getElement()); ICraftingPattern pattern = ItemPattern.getPatternFromCache(parent.mc.world, (ItemStack) stacks.get(0).getElement());
int yy = 80; int yy = 83;
for (ItemStack output : pattern.getOutputs()) { for (ItemStack output : pattern.getOutputs()) {
if (output != null) { if (output != null) {
GlStateManager.pushMatrix(); GlStateManager.pushMatrix();
GlStateManager.scale(scale, scale, 1); GlStateManager.scale(scale, scale, 1);
drawString(RenderUtils.getOffsetOnScale(x + 25, scale), RenderUtils.getOffsetOnScale(yy + 7, scale), output.getDisplayName()); drawString(RenderUtils.getOffsetOnScale(x + 25, scale), RenderUtils.getOffsetOnScale(yy + 6, scale), output.getDisplayName());
GlStateManager.popMatrix(); GlStateManager.popMatrix();
RenderHelper.enableGUIStandardItemLighting(); RenderHelper.enableGUIStandardItemLighting();
@@ -148,6 +158,18 @@ public class GuiCraftingPreview extends GuiBase {
yy += 17; yy += 17;
} }
} }
break;
}
case TOO_COMPLEX: {
drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 21, scale), t("gui.refinedstorage:crafting_preview.error.too_complex.0"));
drawString(RenderUtils.getOffsetOnScale(x + 5, scale), RenderUtils.getOffsetOnScale(y + 31, scale), t("gui.refinedstorage:crafting_preview.error.too_complex.1"));
GlStateManager.popMatrix();
break;
}
}
} else { } else {
int slot = scrollbar != null ? (scrollbar.getOffset() * 2) : 0; int slot = scrollbar != null ? (scrollbar.getOffset() * 2) : 0;

View File

@@ -2,6 +2,7 @@ package com.raoulvdberge.refinedstorage.integration.oc;
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTask; 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.network.node.INetworkNode;
import com.raoulvdberge.refinedstorage.api.util.IComparer; import com.raoulvdberge.refinedstorage.api.util.IComparer;
import com.raoulvdberge.refinedstorage.apiimpl.API; import com.raoulvdberge.refinedstorage.apiimpl.API;
@@ -129,9 +130,11 @@ public class EnvironmentNetwork extends AbstractManagedEnvironment {
throw new IllegalArgumentException("Could not create crafting task"); throw new IllegalArgumentException("Could not create crafting task");
} }
task.calculate(); ICraftingTaskError error = task.calculate();
if (error == null) {
node.getNetwork().getCraftingManager().add(task); node.getNetwork().getCraftingManager().add(task);
}
return new Object[]{}; return new Object[]{};
} }

View File

@@ -55,12 +55,14 @@ gui.refinedstorage:crafting_preview=Crafting Preview
gui.refinedstorage:crafting_preview.to_craft=To craft: %d gui.refinedstorage:crafting_preview.to_craft=To craft: %d
gui.refinedstorage:crafting_preview.available=Available: %d gui.refinedstorage:crafting_preview.available=Available: %d
gui.refinedstorage:crafting_preview.missing=Missing: %d gui.refinedstorage:crafting_preview.missing=Missing: %d
gui.refinedstorage:crafting_preview.error.0=Cannot craft gui.refinedstorage:crafting_preview.error=Request failed
gui.refinedstorage:crafting_preview.error.1=One of the crafting ingredients ended up needing gui.refinedstorage:crafting_preview.error.recursive.0=One of the crafting ingredients ended up needing
gui.refinedstorage:crafting_preview.error.2=itself. gui.refinedstorage:crafting_preview.error.recursive.1=itself.
gui.refinedstorage:crafting_preview.error.3=You need to remove the pattern or make sure gui.refinedstorage:crafting_preview.error.recursive.2=You need to remove the pattern or make sure
gui.refinedstorage:crafting_preview.error.4=the pattern is not used during crafting. gui.refinedstorage:crafting_preview.error.recursive.3=the pattern is not used during crafting.
gui.refinedstorage:crafting_preview.error.5=Offending pattern: gui.refinedstorage:crafting_preview.error.recursive.4=Offending pattern:
gui.refinedstorage:crafting_preview.error.too_complex.0=The crafting task calculation was too complex
gui.refinedstorage:crafting_preview.error.too_complex.1=and was stopped to avoid server strain.
gui.refinedstorage:crafting_preview.force_start=Press CTRL + SHIFT to ignore gui.refinedstorage:crafting_preview.force_start=Press CTRL + SHIFT to ignore
gui.refinedstorage:reader=Reader gui.refinedstorage:reader=Reader
gui.refinedstorage:writer=Writer gui.refinedstorage:writer=Writer

View File

@@ -52,12 +52,12 @@ gui.refinedstorage:crafting_preview=Avance de Fabricación
gui.refinedstorage:crafting_preview.to_craft=Para fabricar: %d gui.refinedstorage:crafting_preview.to_craft=Para fabricar: %d
gui.refinedstorage:crafting_preview.available=Disponible: %d gui.refinedstorage:crafting_preview.available=Disponible: %d
gui.refinedstorage:crafting_preview.missing=Falta: %d gui.refinedstorage:crafting_preview.missing=Falta: %d
gui.refinedstorage:crafting_preview.error.0=No puede fabricar gui.refinedstorage:crafting_preview.error=No puede fabricar
gui.refinedstorage:crafting_preview.error.1=Uno de los objetos de creación termino faltando gui.refinedstorage:crafting_preview.error.recursive.0=Uno de los objetos de creación termino faltando
gui.refinedstorage:crafting_preview.error.2=sí mismo. gui.refinedstorage:crafting_preview.error.recursive.1=sí mismo.
gui.refinedstorage:crafting_preview.error.3=Necesita remover el patrón o revisarlo gui.refinedstorage:crafting_preview.error.recursive.2=Necesita remover el patrón o revisarlo
gui.refinedstorage:crafting_preview.error.4=el patrón no se usa para la fabricación. gui.refinedstorage:crafting_preview.error.recursive.3=el patrón no se usa para la fabricación.
gui.refinedstorage:crafting_preview.error.5=Patrón ofensivo: gui.refinedstorage:crafting_preview.error.recursive.4=Patrón ofensivo:
gui.refinedstorage:crafting_preview.force_start=Presiona CTRL + SHIFT para forzar el inicio gui.refinedstorage:crafting_preview.force_start=Presiona CTRL + SHIFT para forzar el inicio
gui.refinedstorage:reader=Lector gui.refinedstorage:reader=Lector
gui.refinedstorage:writer=Escritor gui.refinedstorage:writer=Escritor

View File

@@ -52,12 +52,12 @@ gui.refinedstorage:crafting_preview=Предварительный просмо
gui.refinedstorage:crafting_preview.to_craft=Создать: %d gui.refinedstorage:crafting_preview.to_craft=Создать: %d
gui.refinedstorage:crafting_preview.available=Доступно: %d gui.refinedstorage:crafting_preview.available=Доступно: %d
gui.refinedstorage:crafting_preview.missing=Отсутствует: %d gui.refinedstorage:crafting_preview.missing=Отсутствует: %d
gui.refinedstorage:crafting_preview.error.0=Не удается создать gui.refinedstorage:crafting_preview.error=Не удается создать
gui.refinedstorage:crafting_preview.error.1=Один из ингредиентов для крафта оказался нуждающимся gui.refinedstorage:crafting_preview.error.recursive.0=Один из ингредиентов для крафта оказался нуждающимся
gui.refinedstorage:crafting_preview.error.2себе. gui.refinedstorage:crafting_preview.error.recursive.1себе.
gui.refinedstorage:crafting_preview.error.3=Вам нужно удалить шаблон или убедиться, что gui.refinedstorage:crafting_preview.error.recursive.2=Вам нужно удалить шаблон или убедиться, что
gui.refinedstorage:crafting_preview.error.4=шаблон не используется во время обработки. gui.refinedstorage:crafting_preview.error.recursive.3=шаблон не используется во время обработки.
gui.refinedstorage:crafting_preview.error.5=Нарушение шаблона: gui.refinedstorage:crafting_preview.error.recursive.4=Нарушение шаблона:
gui.refinedstorage:crafting_preview.force_start=Нажмите CTRL + SHIFT, чтобы все равно начать gui.refinedstorage:crafting_preview.force_start=Нажмите CTRL + SHIFT, чтобы все равно начать
gui.refinedstorage:reader=Устройство чтения gui.refinedstorage:reader=Устройство чтения
gui.refinedstorage:writer=Устройство записи gui.refinedstorage:writer=Устройство записи