diff --git a/src/main/java/de/ellpeck/prettypipes/network/ActiveCraft.java b/src/main/java/de/ellpeck/prettypipes/network/ActiveCraft.java index b573e2e..3b255f7 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/ActiveCraft.java +++ b/src/main/java/de/ellpeck/prettypipes/network/ActiveCraft.java @@ -22,6 +22,7 @@ public class ActiveCraft implements INBTSerializable { public BlockPos resultDestPipe; public ItemStack resultStackRemain; public boolean inProgress; + public boolean resultFound; // we only remove canceled requests from the queue once their items are fully delivered to the crafting location, so that unfinished recipes don't get stuck in crafters etc. public boolean canceled; @@ -48,6 +49,7 @@ public class ActiveCraft implements INBTSerializable { ret.putLong("result_dest_pipe", this.resultDestPipe.asLong()); ret.put("result_stack_remain", this.resultStackRemain.saveOptional(provider)); ret.putBoolean("in_progress", this.inProgress); + ret.putBoolean("result_found", this.resultFound); ret.putBoolean("canceled", this.canceled); return ret; } @@ -61,6 +63,7 @@ public class ActiveCraft implements INBTSerializable { this.resultDestPipe = BlockPos.of(nbt.getLong("result_dest_pipe")); this.resultStackRemain = ItemStack.parseOptional(provider, nbt.getCompound("result_stack_remain")); this.inProgress = nbt.getBoolean("in_progress"); + this.resultFound = nbt.getBoolean("result_found"); this.canceled = nbt.getBoolean("canceled"); } @@ -74,6 +77,7 @@ public class ActiveCraft implements INBTSerializable { ", resultDestPipe=" + this.resultDestPipe + ", resultStackRemain=" + this.resultStackRemain + ", inProgress=" + this.inProgress + + ", resultFound=" + this.resultFound + ", canceled=" + this.canceled + '}'; } diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleItem.java b/src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleItem.java index 2c3fa61..c8fd579 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleItem.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/modules/craft/CraftingModuleItem.java @@ -70,55 +70,80 @@ public class CraftingModuleItem extends ModuleItem { return; var slot = tile.getModuleSlot(module); var network = PipeNetwork.get(tile.getLevel()); - var crafts = tile.getActiveCrafts(); - if (!crafts.isEmpty()) { - var craft = crafts.getFirst(); - if (craft.moduleSlot == slot) { + var foundMainCraft = false; + var crafts = tile.getActiveCrafts().iterator(); + while (crafts.hasNext()) { + var craft = crafts.next(); + + // handle main crafting, which only one recipe (in the whole pipe!) should be able to do at a time so that items between recipes don't mix + if (!foundMainCraft) { + // process crafting ingredient requests if (!craft.ingredientsToRequest.isEmpty()) { - // process crafting ingredient requests - network.startProfile("crafting_ingredients"); - var lock = craft.ingredientsToRequest.getFirst(); - var equalityTypes = ItemFilter.getEqualityTypes(tile); - var dest = tile.getAvailableDestination(Direction.values(), lock.stack, true, true); - if (dest != null) { - // if we're ensuring the correct item order and the item is already on the way, don't do anything yet - if (!module.get(Contents.TYPE).ensureItemOrder || network.getPipeItemsOnTheWay(dest.getLeft()).findAny().isEmpty()) { - network.requestExistingItem(lock.location, tile.getBlockPos(), dest.getLeft(), lock, dest.getRight(), equalityTypes); - network.resolveNetworkLock(lock); - craft.ingredientsToRequest.remove(lock); - craft.travelingIngredients.add(lock.stack.copy()); - craft.inProgress = true; - } - } - network.endProfile(); - } else if (craft.travelingIngredients.isEmpty()) { - if (craft.resultStackRemain.isEmpty()) { - // the result stack is empty from the start if this was a partial craft whose results shouldn't be delivered anywhere - // (ie someone requested 3 sticks with ensureItemOrder, but the recipe always makes 4, so the 4th recipe has no destination) - crafts.remove(craft); - } else { - // pull requested crafting results from the network once they are stored - network.startProfile("crafting_results"); - var items = network.getOrderedNetworkItems(tile.getBlockPos()); + if (craft.moduleSlot == slot) { + network.startProfile("crafting_ingredients"); + var lock = craft.ingredientsToRequest.getFirst(); var equalityTypes = ItemFilter.getEqualityTypes(tile); - var destPipe = network.getPipe(craft.resultDestPipe); - if (destPipe != null) { - var dest = destPipe.getAvailableDestinationOrConnectable(craft.resultStackRemain, true, true); - if (dest != null) { - for (var item : items) { - var requestRemain = network.requestExistingItem(item, craft.resultDestPipe, dest.getLeft(), null, dest.getRight(), equalityTypes); - craft.resultStackRemain.shrink(dest.getRight().getCount() - requestRemain.getCount()); - if (craft.resultStackRemain.isEmpty()) { - crafts.remove(craft); - break; - } - } + var dest = tile.getAvailableDestination(Direction.values(), lock.stack, true, true); + if (dest != null) { + // if we're ensuring the correct item order and the item is already on the way, don't do anything yet + if (!module.get(Contents.TYPE).ensureItemOrder || craft.travelingIngredients.isEmpty()) { + network.requestExistingItem(lock.location, tile.getBlockPos(), dest.getLeft(), lock, dest.getRight(), equalityTypes); + network.resolveNetworkLock(lock); + craft.ingredientsToRequest.remove(lock); + craft.travelingIngredients.add(lock.stack.copy()); + craft.inProgress = true; } } network.endProfile(); } + foundMainCraft = true; + } else if (!craft.resultFound && craft.travelingIngredients.isEmpty()) { + if (craft.moduleSlot == slot) { + // check whether the crafting results have arrived in storage + if (craft.resultStackRemain.isEmpty()) { + // the result stack is empty from the start if this was a partial craft whose results shouldn't be delivered anywhere + // (ie someone requested 3 sticks with ensureItemOrder, but the recipe always makes 4, so the 4th recipe has no destination) + crafts.remove(); + } else { + // check if the result is in storage + var items = network.getOrderedNetworkItems(tile.getBlockPos()); + var equalityTypes = ItemFilter.getEqualityTypes(tile); + network.startProfile("check_crafting_results"); + var remain = craft.resultStackRemain.copy(); + for (var item : items) { + remain.shrink(item.getItemAmount(tile.getLevel(), remain, equalityTypes) - network.getLockedAmount(item.getPos(), remain, null, equalityTypes)); + if (remain.isEmpty()) + break; + } + craft.resultFound = remain.isEmpty(); + network.endProfile(); + } + } + foundMainCraft = true; } } + + // pull requested crafting results from the network once they are stored + if (craft.resultFound && craft.moduleSlot == slot) { + var items = network.getOrderedNetworkItems(tile.getBlockPos()); + var equalityTypes = ItemFilter.getEqualityTypes(tile); + network.startProfile("pull_crafting_results"); + var destPipe = network.getPipe(craft.resultDestPipe); + if (destPipe != null) { + var dest = destPipe.getAvailableDestinationOrConnectable(craft.resultStackRemain, true, true); + if (dest != null) { + for (var item : items) { + var requestRemain = network.requestExistingItem(item, craft.resultDestPipe, dest.getLeft(), null, dest.getRight(), equalityTypes); + craft.resultStackRemain.shrink(dest.getRight().getCount() - requestRemain.getCount()); + if (craft.resultStackRemain.isEmpty()) { + crafts.remove(); + break; + } + } + } + } + network.endProfile(); + } } } @@ -234,7 +259,7 @@ public class CraftingModuleItem extends ModuleItem { } } - if (craft.travelingIngredients.isEmpty() && craft.ingredientsToRequest.isEmpty()) { + if (craft.ingredientsToRequest.isEmpty() && craft.travelingIngredients.isEmpty()) { if (contents.emitRedstone) { tile.redstoneTicks = 5; tile.getLevel().updateNeighborsAt(tile.getBlockPos(), tile.getBlockState().getBlock());