Add better framework for extracting and inserting items for crafting.

This commit is contained in:
raoulvdberge
2018-05-28 23:17:07 +02:00
parent fb41beda6f
commit 26eb514800
21 changed files with 254 additions and 51 deletions

View File

@@ -100,6 +100,7 @@ public interface ICraftingManager {
/** /**
* Makes the network send a crafting monitor update to all players as soon as it can. * Makes the network send a crafting monitor update to all players as soon as it can.
*/ */
// TODO: rework system to be subscribed-based, per task
void markCraftingMonitorForUpdate(); void markCraftingMonitorForUpdate();
/** /**
@@ -107,6 +108,7 @@ public interface ICraftingManager {
* <p> * <p>
* WARNING: In most cases, you should just use {@link ICraftingManager#markCraftingMonitorForUpdate()}, if not, you can get high bandwidth usage. * WARNING: In most cases, you should just use {@link ICraftingManager#markCraftingMonitorForUpdate()}, if not, you can get high bandwidth usage.
*/ */
// TODO: rework system to be subscribed-based, per task
void sendCraftingMonitorUpdate(); void sendCraftingMonitorUpdate();
/** /**
@@ -114,5 +116,6 @@ public interface ICraftingManager {
* *
* @param player the player * @param player the player
*/ */
// TODO: rework system to be subscribed-based, per task
void sendCraftingMonitorUpdate(EntityPlayerMP player); void sendCraftingMonitorUpdate(EntityPlayerMP player);
} }

View File

@@ -17,7 +17,7 @@ public interface ICraftingPatternContainer {
/** /**
* @return the amount of speed upgrades in the container * @return the amount of speed upgrades in the container
*/ */
int getSpeedUpdateCount(); int getSpeedUpgradeCount();
/** /**
* @return the inventory that this container is connected to * @return the inventory that this container is connected to

View File

@@ -19,7 +19,7 @@ public interface ICraftingTask {
void calculate(); void calculate();
/** /**
* Updates this task. Gets called every few ticks, depending on the speed of the pattern container. * Updates this task.
* {@link ICraftingTask#calculate()} must be run before this! * {@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 and can be deleted from the list, false otherwise

View File

@@ -84,6 +84,8 @@ public class CraftingManager implements ICraftingManager {
@Override @Override
public void update() { public void update() {
if (network.canRun()) { if (network.canRun()) {
boolean changed = !tasksToCancel.isEmpty() || !tasksToAdd.isEmpty();
tasksToCancel.forEach(ICraftingTask::onCancelled); tasksToCancel.forEach(ICraftingTask::onCancelled);
tasks.removeAll(tasksToCancel); tasks.removeAll(tasksToCancel);
tasksToCancel.clear(); tasksToCancel.clear();
@@ -91,7 +93,11 @@ public class CraftingManager implements ICraftingManager {
tasksToAdd.stream().filter(ICraftingTask::isValid).forEach(tasks::add); tasksToAdd.stream().filter(ICraftingTask::isValid).forEach(tasks::add);
tasksToAdd.clear(); tasksToAdd.clear();
tasks.removeIf(ICraftingTask::update); changed = tasks.removeIf(ICraftingTask::update);
if (changed) {
markCraftingMonitorForUpdate();
}
} }
if (updateRequested) { if (updateRequested) {

View File

@@ -167,7 +167,16 @@ public class CraftingPattern implements ICraftingPattern {
inv.setInventorySlotContents(i, took.get(i)); inv.setInventorySlotContents(i, took.get(i));
} }
return recipe.getRemainingItems(inv); NonNullList<ItemStack> remainingItems = recipe.getRemainingItems(inv);
NonNullList<ItemStack> sanitized = NonNullList.create();
for (ItemStack item : remainingItems) {
if (!item.isEmpty()) {
sanitized.add(item);
}
}
return sanitized;
} }
@Override @Override

View File

@@ -0,0 +1,67 @@
package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task;
import com.raoulvdberge.refinedstorage.api.network.INetwork;
import net.minecraft.item.ItemStack;
import java.util.ArrayList;
import java.util.List;
public class CraftingExtractor {
private INetwork network;
private List<ItemStack> items;
private List<CraftingExtractorItemStatus> status = new ArrayList<>();
public CraftingExtractor(INetwork network, List<ItemStack> items) {
this.network = network;
this.items = items;
for (int i = 0; i < items.size(); ++i) {
status.add(CraftingExtractorItemStatus.MISSING);
}
}
public List<ItemStack> getItems() {
return items;
}
public List<CraftingExtractorItemStatus> getStatus() {
return status;
}
public void updateStatus() {
for (int i = 0; i < items.size(); ++i) {
if (status.get(i) != CraftingExtractorItemStatus.EXTRACTED) {
ItemStack stack = items.get(i);
ItemStack inNetwork = network.extractItem(stack, stack.getCount(), true);
if (inNetwork == null || inNetwork.getCount() < stack.getCount()) {
status.set(i, CraftingExtractorItemStatus.MISSING);
} else {
status.set(i, CraftingExtractorItemStatus.AVAILABLE);
}
}
}
}
public boolean isAllAvailable() {
return status.stream().allMatch(s -> s == CraftingExtractorItemStatus.AVAILABLE || s == CraftingExtractorItemStatus.EXTRACTED);
}
public boolean isAllExtracted() {
return status.stream().allMatch(s -> s == CraftingExtractorItemStatus.EXTRACTED);
}
public void extractOne() {
for (int i = 0; i < items.size(); ++i) {
if (status.get(i) == CraftingExtractorItemStatus.AVAILABLE) {
ItemStack extracted = network.extractItem(items.get(i), items.get(i).getCount(), false);
if (extracted == null) {
throw new IllegalStateException("Did not extract anything");
}
status.set(i, CraftingExtractorItemStatus.EXTRACTED);
}
}
}
}

View File

@@ -0,0 +1,7 @@
package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task;
public enum CraftingExtractorItemStatus {
AVAILABLE,
MISSING,
EXTRACTED
}

View File

@@ -0,0 +1,46 @@
package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task;
import com.raoulvdberge.refinedstorage.api.network.INetwork;
import net.minecraft.item.ItemStack;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
public class CraftingInserter {
private INetwork network;
private Deque<CraftingInserterItem> items = new ArrayDeque<>();
public CraftingInserter(INetwork network) {
this.network = network;
}
public void insert(ItemStack stack) {
items.push(new CraftingInserterItem(stack, CraftingInserterItemStatus.WAITING));
network.getCraftingManager().sendCraftingMonitorUpdate();
}
public void insertSingle() {
CraftingInserterItem item = items.peek();
if (item != null) {
if (network.insertItem(item.getStack(), item.getStack().getCount(), true) == null) {
ItemStack inserted = network.insertItem(item.getStack(), item.getStack().getCount(), false);
if (inserted != null) {
throw new IllegalStateException("Could not insert item");
}
items.pop();
} else {
item.setStatus(CraftingInserterItemStatus.FULL);
}
network.getCraftingManager().sendCraftingMonitorUpdate();
}
}
public Collection<CraftingInserterItem> getItems() {
return items;
}
}

View File

@@ -0,0 +1,25 @@
package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task;
import net.minecraft.item.ItemStack;
public class CraftingInserterItem {
private ItemStack stack;
private CraftingInserterItemStatus status;
public CraftingInserterItem(ItemStack stack, CraftingInserterItemStatus status) {
this.stack = stack;
this.status = status;
}
public ItemStack getStack() {
return stack;
}
public CraftingInserterItemStatus getStatus() {
return status;
}
public void setStatus(CraftingInserterItemStatus status) {
this.status = status;
}
}

View File

@@ -0,0 +1,6 @@
package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task;
public enum CraftingInserterItemStatus {
WAITING,
FULL
}

View File

@@ -12,7 +12,7 @@ public abstract class CraftingStep {
public abstract boolean canExecute(); public abstract boolean canExecute();
public abstract void execute(); public abstract boolean execute();
public ICraftingPattern getPattern() { public ICraftingPattern getPattern() {
return pattern; return pattern;

View File

@@ -2,57 +2,50 @@ package com.raoulvdberge.refinedstorage.apiimpl.autocrafting.task;
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern; import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingPattern;
import com.raoulvdberge.refinedstorage.api.network.INetwork; import com.raoulvdberge.refinedstorage.api.network.INetwork;
import com.raoulvdberge.refinedstorage.api.util.IStackList;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.NonNullList; import net.minecraft.util.NonNullList;
public class CraftingStepCraft extends CraftingStep { import java.util.List;
private INetwork network;
public class CraftingStepCraft extends CraftingStep {
private CraftingInserter inserter;
private CraftingExtractor extractor;
private IStackList<ItemStack> toExtract;
private NonNullList<ItemStack> took; private NonNullList<ItemStack> took;
public CraftingStepCraft(ICraftingPattern pattern, INetwork network, IStackList<ItemStack> toExtract, NonNullList<ItemStack> took) { public CraftingStepCraft(ICraftingPattern pattern, CraftingInserter inserter, INetwork network, List<ItemStack> toExtract, NonNullList<ItemStack> took) {
super(pattern); super(pattern);
this.network = network; this.inserter = inserter;
this.toExtract = toExtract; this.extractor = new CraftingExtractor(network, toExtract);
this.took = took; this.took = took;
} }
@Override @Override
public void execute() { public boolean execute() {
for (ItemStack toExtractItem : toExtract.getStacks()) { extractor.extractOne();
ItemStack extracted = network.extractItem(toExtractItem, toExtractItem.getCount(), false);
if (extracted == null) { boolean allExtracted = extractor.isAllExtracted();
throw new IllegalStateException("Did not extract anything");
}
}
ItemStack output = pattern.getOutput(took); if (allExtracted) {
inserter.insert(pattern.getOutput(took));
network.insertItem(output, output.getCount(), false);
for (ItemStack byproduct : pattern.getByproducts(took)) { for (ItemStack byproduct : pattern.getByproducts(took)) {
network.insertItem(byproduct, byproduct.getCount(), false); inserter.insert(byproduct);
} }
} }
return allExtracted;
}
@Override @Override
public boolean canExecute() { public boolean canExecute() {
for (ItemStack toExtractItem : toExtract.getStacks()) { extractor.updateStatus();
ItemStack inNetwork = network.extractItem(toExtractItem, toExtractItem.getCount(), true);
if (inNetwork == null || inNetwork.getCount() < toExtractItem.getCount()) { return extractor.isAllAvailable();
return false;
}
} }
return true; public CraftingExtractor getExtractor() {
} return extractor;
public IStackList<ItemStack> getToExtract() {
return toExtract;
} }
} }

View File

@@ -26,6 +26,8 @@ public class CraftingTask implements ICraftingTask {
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 int ticks = 0;
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();
@@ -33,6 +35,7 @@ public class CraftingTask implements ICraftingTask {
public CraftingTask(INetwork network, ItemStack requested, int quantity, ICraftingPattern pattern) { public CraftingTask(INetwork network, ItemStack requested, int quantity, ICraftingPattern pattern) {
this.network = network; this.network = network;
this.inserter = new CraftingInserter(network);
this.requested = requested; this.requested = requested;
this.quantity = quantity; this.quantity = quantity;
this.pattern = pattern; this.pattern = pattern;
@@ -128,7 +131,7 @@ public class CraftingTask implements ICraftingTask {
} }
} }
return new CraftingStepCraft(pattern, network, itemsToExtract, took); return new CraftingStepCraft(pattern, inserter, network, new ArrayList<>(itemsToExtract.getStacks()), took);
} }
private int getQuantityPerCraft(ICraftingPattern pattern, ItemStack requested) { private int getQuantityPerCraft(ICraftingPattern pattern, ItemStack requested) {
@@ -155,8 +158,7 @@ public class CraftingTask implements ICraftingTask {
if (!step.isCompleted()) { if (!step.isCompleted()) {
allCompleted = false; allCompleted = false;
if (step.canExecute()) { if (step.canExecute() && step.execute() && ticks % getTickInterval(step.getPattern().getContainer().getSpeedUpgradeCount()) == 0) { // TODO: speed upgrades handling
step.execute();
step.setCompleted(); step.setCompleted();
network.getCraftingManager().sendCraftingMonitorUpdate(); network.getCraftingManager().sendCraftingMonitorUpdate();
@@ -164,7 +166,11 @@ public class CraftingTask implements ICraftingTask {
} }
} }
return allCompleted; inserter.insertSingle();
ticks++;
return allCompleted && inserter.getItems().isEmpty();
} }
@Override @Override
@@ -211,21 +217,46 @@ public class CraftingTask implements ICraftingTask {
elements.commit(); elements.commit();
} }
if (!inserter.getItems().isEmpty()) {
elements.directAdd(new CraftingMonitorElementText("gui.refinedstorage:crafting_monitor.items_inserting", 16));
for (CraftingInserterItem item : inserter.getItems()) {
ICraftingMonitorElement element = new CraftingMonitorElementItemRender(
-1,
item.getStack(),
item.getStack().getCount(),
32
);
if (item.getStatus() == CraftingInserterItemStatus.FULL) {
element = new CraftingMonitorElementError(element, "gui.refinedstorage:crafting_monitor.network_full");
}
elements.add(element);
}
elements.commit();
}
if (steps.stream().anyMatch(s -> s instanceof CraftingStepCraft && !s.isCompleted())) { if (steps.stream().anyMatch(s -> s instanceof CraftingStepCraft && !s.isCompleted())) {
elements.directAdd(new CraftingMonitorElementText("gui.refinedstorage:crafting_monitor.items_crafting", 16)); elements.directAdd(new CraftingMonitorElementText("gui.refinedstorage:crafting_monitor.items_crafting", 16));
for (CraftingStep step : steps) { for (CraftingStep step : steps) {
if (step instanceof CraftingStepCraft && !step.isCompleted()) { if (step instanceof CraftingStepCraft && !step.isCompleted()) {
for (ItemStack stack : ((CraftingStepCraft) step).getToExtract().getStacks()) { CraftingExtractor extractor = ((CraftingStepCraft) step).getExtractor();
for (int i = 0; i < extractor.getItems().size(); ++i) {
ItemStack item = extractor.getItems().get(i);
CraftingExtractorItemStatus status = extractor.getStatus().get(i);
ICraftingMonitorElement element = new CraftingMonitorElementItemRender( ICraftingMonitorElement element = new CraftingMonitorElementItemRender(
-1, -1,
stack, item,
stack.getCount(), item.getCount(),
32 32
); );
// TODO: cache this if (status == CraftingExtractorItemStatus.MISSING) {
if (!step.canExecute()) {
element = new CraftingMonitorElementInfo(element, "gui.refinedstorage:crafting_monitor.waiting_for_items"); element = new CraftingMonitorElementInfo(element, "gui.refinedstorage:crafting_monitor.waiting_for_items");
} }
@@ -304,4 +335,20 @@ public class CraftingTask implements ICraftingTask {
public IStackList<ItemStack> getMissing() { public IStackList<ItemStack> getMissing() {
return missing; return missing;
} }
private int getTickInterval(int speedUpgrades) {
switch (speedUpgrades) {
case 1:
return 8;
case 2:
return 6;
case 3:
return 4;
case 4:
return 2;
case 0:
default:
return 10;
}
}
} }

View File

@@ -168,7 +168,7 @@ public class NetworkNodeCrafter extends NetworkNode implements ICraftingPatternC
} }
@Override @Override
public int getSpeedUpdateCount() { public int getSpeedUpgradeCount() {
return upgrades.getUpgradeCount(ItemUpgrade.TYPE_SPEED); return upgrades.getUpgradeCount(ItemUpgrade.TYPE_SPEED);
} }

View File

@@ -33,7 +33,7 @@ gui.refinedstorage:crafting_monitor.items_missing=Items missing
gui.refinedstorage:crafting_monitor.machine_in_use=Machine is in use gui.refinedstorage:crafting_monitor.machine_in_use=Machine is in use
gui.refinedstorage:crafting_monitor.machine_none=No machine found gui.refinedstorage:crafting_monitor.machine_none=No machine found
gui.refinedstorage:crafting_monitor.waiting_for_items=Waiting for items gui.refinedstorage:crafting_monitor.waiting_for_items=Waiting for items
gui.refinedstorage:crafting_monitor.blocked=Blocked, waiting on other task gui.refinedstorage:crafting_monitor.network_full=Network is full
gui.refinedstorage:wireless_transmitter=Wireless Transmitter gui.refinedstorage:wireless_transmitter=Wireless Transmitter
gui.refinedstorage:wireless_transmitter.distance=%d block(s) gui.refinedstorage:wireless_transmitter.distance=%d block(s)
gui.refinedstorage:crafter=Crafter gui.refinedstorage:crafter=Crafter

View File

@@ -33,7 +33,6 @@ gui.refinedstorage:crafting_monitor.items_missing=Faltan objetos
gui.refinedstorage:crafting_monitor.machine_in_use=Maquina en uso gui.refinedstorage:crafting_monitor.machine_in_use=Maquina en uso
gui.refinedstorage:crafting_monitor.machine_none=Maquina no Hallada gui.refinedstorage:crafting_monitor.machine_none=Maquina no Hallada
gui.refinedstorage:crafting_monitor.waiting_for_items=Esperando Objetos gui.refinedstorage:crafting_monitor.waiting_for_items=Esperando Objetos
gui.refinedstorage:crafting_monitor.blocked=Bloqueado, esperando otra tarea
gui.refinedstorage:wireless_transmitter=Emisor inalámbrico gui.refinedstorage:wireless_transmitter=Emisor inalámbrico
gui.refinedstorage:wireless_transmitter.distance=%d bloque(s) gui.refinedstorage:wireless_transmitter.distance=%d bloque(s)
gui.refinedstorage:crafter=Fabricador gui.refinedstorage:crafter=Fabricador

View File

@@ -32,7 +32,6 @@ gui.refinedstorage:crafting_monitor.items_missing=Items manquants
gui.refinedstorage:crafting_monitor.machine_in_use=Machine en cours d'utilisation gui.refinedstorage:crafting_monitor.machine_in_use=Machine en cours d'utilisation
gui.refinedstorage:crafting_monitor.machine_none=Pas de machine disponible gui.refinedstorage:crafting_monitor.machine_none=Pas de machine disponible
gui.refinedstorage:crafting_monitor.waiting_for_items=En attente d'items gui.refinedstorage:crafting_monitor.waiting_for_items=En attente d'items
gui.refinedstorage:crafting_monitor.blocked=Bloqué, en attente d'autres taches
gui.refinedstorage:wireless_transmitter=Emetteur sans-fil gui.refinedstorage:wireless_transmitter=Emetteur sans-fil
gui.refinedstorage:wireless_transmitter.distance=%d bloc(s) gui.refinedstorage:wireless_transmitter.distance=%d bloc(s)
gui.refinedstorage:crafter=Crafteur gui.refinedstorage:crafter=Crafteur

View File

@@ -31,7 +31,6 @@ gui.refinedstorage:crafting_monitor.items_missing=부족한 아이템
gui.refinedstorage:crafting_monitor.machine_in_use=기계가 이미 사용 중임 gui.refinedstorage:crafting_monitor.machine_in_use=기계가 이미 사용 중임
gui.refinedstorage:crafting_monitor.machine_none=기계를 찾을 수 없음 gui.refinedstorage:crafting_monitor.machine_none=기계를 찾을 수 없음
gui.refinedstorage:crafting_monitor.waiting_for_items=아이템을 기다리는 중 gui.refinedstorage:crafting_monitor.waiting_for_items=아이템을 기다리는 중
gui.refinedstorage:crafting_monitor.blocked=막힘 - 다른 작업에서 대기 중
gui.refinedstorage:wireless_transmitter=무선 송신기 gui.refinedstorage:wireless_transmitter=무선 송신기
gui.refinedstorage:wireless_transmitter.distance=%d블럭 gui.refinedstorage:wireless_transmitter.distance=%d블럭
gui.refinedstorage:crafter=조합기 gui.refinedstorage:crafter=조합기

View File

@@ -32,7 +32,6 @@ gui.refinedstorage:crafting_monitor.items_missing=Ausência de itens
gui.refinedstorage:crafting_monitor.machine_in_use=A máquina está em uso gui.refinedstorage:crafting_monitor.machine_in_use=A máquina está em uso
gui.refinedstorage:crafting_monitor.machine_none=Nenhuma máquina encontrada gui.refinedstorage:crafting_monitor.machine_none=Nenhuma máquina encontrada
gui.refinedstorage:crafting_monitor.waiting_for_items=Esperando itens gui.refinedstorage:crafting_monitor.waiting_for_items=Esperando itens
gui.refinedstorage:crafting_monitor.blocked=Bloqueado, aguardando outra tarefa
gui.refinedstorage:wireless_transmitter=Transmissor Wireless gui.refinedstorage:wireless_transmitter=Transmissor Wireless
gui.refinedstorage:wireless_transmitter.distance=%d Blocos gui.refinedstorage:wireless_transmitter.distance=%d Blocos
gui.refinedstorage:crafter=Fabricador gui.refinedstorage:crafter=Fabricador

View File

@@ -33,7 +33,6 @@ gui.refinedstorage:crafting_monitor.items_missing=Отсутствуют пре
gui.refinedstorage:crafting_monitor.machine_in_use=Машина используется gui.refinedstorage:crafting_monitor.machine_in_use=Машина используется
gui.refinedstorage:crafting_monitor.machine_none=Машина не найдена gui.refinedstorage:crafting_monitor.machine_none=Машина не найдена
gui.refinedstorage:crafting_monitor.waiting_for_items=Ожидание предметов gui.refinedstorage:crafting_monitor.waiting_for_items=Ожидание предметов
gui.refinedstorage:crafting_monitor.blocked=Заблокировано, ожидание другой задачи
gui.refinedstorage:wireless_transmitter=Передатчик gui.refinedstorage:wireless_transmitter=Передатчик
gui.refinedstorage:wireless_transmitter.distance=%d блоков gui.refinedstorage:wireless_transmitter.distance=%d блоков
gui.refinedstorage:crafter=Крафтер gui.refinedstorage:crafter=Крафтер

View File

@@ -33,7 +33,6 @@ gui.refinedstorage:crafting_monitor.items_missing=物品丢失中
gui.refinedstorage:crafting_monitor.machine_in_use=该机器正在处理其他工作,请稍等 gui.refinedstorage:crafting_monitor.machine_in_use=该机器正在处理其他工作,请稍等
gui.refinedstorage:crafting_monitor.machine_none=找不到机器 gui.refinedstorage:crafting_monitor.machine_none=找不到机器
gui.refinedstorage:crafting_monitor.waiting_for_items=正在等待物品 gui.refinedstorage:crafting_monitor.waiting_for_items=正在等待物品
gui.refinedstorage:crafting_monitor.blocked=被阻塞,正在等待其他任务
gui.refinedstorage:wireless_transmitter=无线访问点 gui.refinedstorage:wireless_transmitter=无线访问点
gui.refinedstorage:wireless_transmitter.distance=%d 方块 gui.refinedstorage:wireless_transmitter.distance=%d 方块
gui.refinedstorage:crafter=装配室 gui.refinedstorage:crafter=装配室