fully deliver items of canceled crafting requests so that containers don't get stuck with partial recipes

This commit is contained in:
Ell 2024-11-28 00:02:22 +01:00
parent 704027c3dc
commit 2c8ab9ed07
5 changed files with 42 additions and 20 deletions

View file

@ -277,7 +277,7 @@ public class PipeNetwork extends SavedData implements GraphListener<BlockPos, Ne
this.tileCache.remove(pos); this.tileCache.remove(pos);
} }
public List<Pair<BlockPos, ItemStack>> getCurrentlyCrafting(BlockPos node, ItemEquality... equalityTypes) { public List<Pair<BlockPos, ItemStack>> getCurrentlyCrafting(BlockPos node, boolean includeCanceled, ItemEquality... equalityTypes) {
this.startProfile("get_currently_crafting"); this.startProfile("get_currently_crafting");
List<Pair<BlockPos, ItemStack>> items = new ArrayList<>(); List<Pair<BlockPos, ItemStack>> items = new ArrayList<>();
var craftingPipes = this.getAllCraftables(node).stream().map(c -> this.getPipe(c.getLeft())).distinct().iterator(); var craftingPipes = this.getAllCraftables(node).stream().map(c -> this.getPipe(c.getLeft())).distinct().iterator();
@ -285,6 +285,8 @@ public class PipeNetwork extends SavedData implements GraphListener<BlockPos, Ne
var pipe = craftingPipes.next(); var pipe = craftingPipes.next();
for (var craft : pipe.activeCrafts) { for (var craft : pipe.activeCrafts) {
var data = craft.getRight(); var data = craft.getRight();
if (!includeCanceled && data.canceled)
continue;
// add up all the items that should go to the same location // add up all the items that should go to the same location
var existing = items.stream() var existing = items.stream()
.filter(s -> s.getLeft().equals(data.resultDestPipe) && ItemEquality.compareItems(s.getRight(), data.resultStackRemain, equalityTypes)) .filter(s -> s.getLeft().equals(data.resultDestPipe) && ItemEquality.compareItems(s.getRight(), data.resultStackRemain, equalityTypes))
@ -300,8 +302,8 @@ public class PipeNetwork extends SavedData implements GraphListener<BlockPos, Ne
return items; return items;
} }
public int getCurrentlyCraftingAmount(BlockPos destNode, ItemStack stack, ItemEquality... equalityTypes) { public int getCurrentlyCraftingAmount(BlockPos destNode, ItemStack stack, boolean includeCanceled, ItemEquality... equalityTypes) {
return this.getCurrentlyCrafting(destNode).stream() return this.getCurrentlyCrafting(destNode, includeCanceled).stream()
.filter(p -> p.getLeft().equals(destNode) && ItemEquality.compareItems(p.getRight(), stack, equalityTypes)) .filter(p -> p.getLeft().equals(destNode) && ItemEquality.compareItems(p.getRight(), stack, equalityTypes))
.mapToInt(p -> p.getRight().getCount()).sum(); .mapToInt(p -> p.getRight().getCount()).sum();
} }

View file

@ -95,6 +95,7 @@ public class CraftingModuleItem extends ModuleItem {
var requestRemain = network.requestExistingItem(lock.location, tile.getBlockPos(), dest.getLeft(), lock, dest.getRight(), equalityTypes); var requestRemain = network.requestExistingItem(lock.location, tile.getBlockPos(), dest.getLeft(), lock, dest.getRight(), equalityTypes);
network.resolveNetworkLock(lock); network.resolveNetworkLock(lock);
craftData.ingredientsToRequest.remove(lock); craftData.ingredientsToRequest.remove(lock);
craftData.inProgress = true;
var traveling = lock.stack.copy(); var traveling = lock.stack.copy();
traveling.shrink(requestRemain.getCount()); traveling.shrink(requestRemain.getCount());
@ -222,10 +223,12 @@ public class CraftingModuleItem extends ModuleItem {
var slot = tile.getModuleSlot(module); var slot = tile.getModuleSlot(module);
var equalityTypes = ItemFilter.getEqualityTypes(tile); var equalityTypes = ItemFilter.getEqualityTypes(tile);
var matchingCraft = tile.activeCrafts.stream() var matchingCraft = tile.activeCrafts.stream()
.filter(c -> c.getLeft() == slot && c.getRight().isMatchingIngredient(stack, equalityTypes)) .filter(c -> c.getLeft() == slot && !c.getRight().getTravelingIngredient(stack, equalityTypes).isEmpty())
.findAny().orElse(null); .findAny().orElse(null);
if (matchingCraft != null) { if (matchingCraft != null) {
matchingCraft.getRight().travelingIngredients.removeIf(s -> ItemEquality.compareItems(stack, s, equalityTypes)); var data = matchingCraft.getRight();
data.travelingIngredients.remove(data.getTravelingIngredient(stack, equalityTypes));
if (module.get(Contents.TYPE).insertSingles) { if (module.get(Contents.TYPE).insertSingles) {
var handler = tile.getItemHandler(direction); var handler = tile.getItemHandler(direction);
if (handler != null) { if (handler != null) {
@ -237,6 +240,10 @@ public class CraftingModuleItem extends ModuleItem {
} }
} }
} }
// if we canceled the request and all input items are delivered (ie the machine actually got what it expected), remove it from the queue
if (data.canceled && data.travelingIngredients.size() <= 0 && data.ingredientsToRequest.size() <= 0)
tile.activeCrafts.remove(matchingCraft);
} }
return stack; return stack;
} }
@ -276,6 +283,9 @@ public class CraftingModuleItem extends ModuleItem {
public List<ItemStack> travelingIngredients; public List<ItemStack> travelingIngredients;
public BlockPos resultDestPipe; public BlockPos resultDestPipe;
public ItemStack resultStackRemain; public ItemStack resultStackRemain;
public boolean inProgress;
// 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;
public ActiveCraft(List<NetworkLock> ingredientsToRequest, List<ItemStack> travelingIngredients, BlockPos resultDestPipe, ItemStack resultStackRemain) { public ActiveCraft(List<NetworkLock> ingredientsToRequest, List<ItemStack> travelingIngredients, BlockPos resultDestPipe, ItemStack resultStackRemain) {
this.ingredientsToRequest = ingredientsToRequest; this.ingredientsToRequest = ingredientsToRequest;
@ -295,6 +305,8 @@ public class CraftingModuleItem extends ModuleItem {
ret.put("traveling_ingredients", Utility.serializeAll(this.travelingIngredients, s -> (CompoundTag) s.save(provider, new CompoundTag()))); ret.put("traveling_ingredients", Utility.serializeAll(this.travelingIngredients, s -> (CompoundTag) s.save(provider, new CompoundTag())));
ret.putLong("result_dest_pipe", this.resultDestPipe.asLong()); ret.putLong("result_dest_pipe", this.resultDestPipe.asLong());
ret.put("result_stack_remain", this.resultStackRemain.saveOptional(provider)); ret.put("result_stack_remain", this.resultStackRemain.saveOptional(provider));
ret.putBoolean("in_progress", this.inProgress);
ret.putBoolean("canceled", this.canceled);
return ret; return ret;
} }
@ -304,14 +316,16 @@ public class CraftingModuleItem extends ModuleItem {
this.travelingIngredients = Utility.deserializeAll(nbt.getList("traveling_ingredients", Tag.TAG_COMPOUND), t -> ItemStack.parse(provider, t).orElseThrow()); this.travelingIngredients = Utility.deserializeAll(nbt.getList("traveling_ingredients", Tag.TAG_COMPOUND), t -> ItemStack.parse(provider, t).orElseThrow());
this.resultDestPipe = BlockPos.of(nbt.getLong("result_dest_pipe")); this.resultDestPipe = BlockPos.of(nbt.getLong("result_dest_pipe"));
this.resultStackRemain = ItemStack.parseOptional(provider, nbt.getCompound("result_stack_remain")); this.resultStackRemain = ItemStack.parseOptional(provider, nbt.getCompound("result_stack_remain"));
this.inProgress = nbt.getBoolean("in_progress");
this.canceled = nbt.getBoolean("canceled");
} }
public boolean isMatchingIngredient(ItemStack stack, ItemEquality... equalityTypes) { public ItemStack getTravelingIngredient(ItemStack stack, ItemEquality... equalityTypes) {
for (var traveling : this.travelingIngredients) { for (var traveling : this.travelingIngredients) {
if (ItemEquality.compareItems(stack, traveling, equalityTypes)) if (ItemEquality.compareItems(stack, traveling, equalityTypes))
return true; return traveling;
} }
return false; return ItemStack.EMPTY;
} }
} }

View file

@ -52,7 +52,7 @@ public class RetrievalModuleItem extends ModuleItem {
continue; continue;
var remain = dest.getRight().copy(); var remain = dest.getRight().copy();
// are we already waiting for crafting results? If so, don't request those again // are we already waiting for crafting results? If so, don't request those again
remain.shrink(network.getCurrentlyCraftingAmount(tile.getBlockPos(), copy, equalityTypes)); remain.shrink(network.getCurrentlyCraftingAmount(tile.getBlockPos(), copy, true, equalityTypes));
if (network.requestItem(tile.getBlockPos(), dest.getLeft(), remain, equalityTypes).isEmpty()) if (network.requestItem(tile.getBlockPos(), dest.getLeft(), remain, equalityTypes).isEmpty())
break; break;
} }

View file

@ -136,7 +136,7 @@ public class ItemTerminalBlockEntity extends BlockEntity implements IPipeConnect
if (playersToSync.length > 0) { if (playersToSync.length > 0) {
var clientItems = this.networkItems.values().stream().map(NetworkItem::asStack).collect(Collectors.toList()); var clientItems = this.networkItems.values().stream().map(NetworkItem::asStack).collect(Collectors.toList());
var clientCraftables = PipeNetwork.get(this.level).getAllCraftables(pipe.getBlockPos()).stream().map(Pair::getRight).collect(Collectors.toList()); var clientCraftables = PipeNetwork.get(this.level).getAllCraftables(pipe.getBlockPos()).stream().map(Pair::getRight).collect(Collectors.toList());
var currentlyCrafting = this.getCurrentlyCrafting().stream().sorted(Comparator.comparingInt(ItemStack::getCount).reversed()).collect(Collectors.toList()); var currentlyCrafting = this.getCurrentlyCrafting(false).stream().sorted(Comparator.comparingInt(ItemStack::getCount).reversed()).collect(Collectors.toList());
for (var player : playersToSync) { for (var player : playersToSync) {
if (!(player.containerMenu instanceof ItemTerminalContainer container)) if (!(player.containerMenu instanceof ItemTerminalContainer container))
continue; continue;
@ -200,12 +200,12 @@ public class ItemTerminalBlockEntity extends BlockEntity implements IPipeConnect
return items; return items;
} }
private List<ItemStack> getCurrentlyCrafting() { private List<ItemStack> getCurrentlyCrafting(boolean includeCanceled) {
var network = PipeNetwork.get(this.level); var network = PipeNetwork.get(this.level);
var pipe = this.getConnectedPipe(); var pipe = this.getConnectedPipe();
if (pipe == null) if (pipe == null)
return Collections.emptyList(); return Collections.emptyList();
var crafting = network.getCurrentlyCrafting(pipe.getBlockPos()); var crafting = network.getCurrentlyCrafting(pipe.getBlockPos(), includeCanceled);
return crafting.stream().map(Pair::getRight).collect(Collectors.toList()); return crafting.stream().map(Pair::getRight).collect(Collectors.toList());
} }
@ -217,11 +217,17 @@ public class ItemTerminalBlockEntity extends BlockEntity implements IPipeConnect
for (var craftable : network.getAllCraftables(pipe.getBlockPos())) { for (var craftable : network.getAllCraftables(pipe.getBlockPos())) {
var otherPipe = network.getPipe(craftable.getLeft()); var otherPipe = network.getPipe(craftable.getLeft());
if (otherPipe != null) { if (otherPipe != null) {
for (var craft : otherPipe.activeCrafts) { otherPipe.activeCrafts.removeIf(c -> {
for (var lock : craft.getRight().ingredientsToRequest) var data = c.getRight();
if (data.inProgress) {
data.canceled = true;
return false;
} else {
for (var lock : data.ingredientsToRequest)
network.resolveNetworkLock(lock); network.resolveNetworkLock(lock);
return true;
} }
otherPipe.activeCrafts.clear(); });
} }
} }
var lookingPlayers = this.getLookingPlayers(); var lookingPlayers = this.getLookingPlayers();

View file

@ -68,10 +68,10 @@
"info.prettypipes.blacklist.description": "Items in filter slots are disallowed", "info.prettypipes.blacklist.description": "Items in filter slots are disallowed",
"info.prettypipes.insert_singles_on": "\u00A72S", "info.prettypipes.insert_singles_on": "\u00A72S",
"info.prettypipes.insert_singles_off": "\u00A74\u00A7mS", "info.prettypipes.insert_singles_off": "\u00A74\u00A7mS",
"info.prettypipes.insert_singles.description": "Whether items should be inserted one at a time, rather than as a stack\nRecommended for use with the Crafter", "info.prettypipes.insert_singles.description": "Whether items should be inserted one at a time, rather than as a stack\n\u00A7oRecommended for use with the Crafter",
"info.prettypipes.ensure_item_order_on": "\u00A72O", "info.prettypipes.ensure_item_order_on": "\u00A72O",
"info.prettypipes.ensure_item_order_off": "\u00A74\u00A7mO", "info.prettypipes.ensure_item_order_off": "\u00A74\u00A7mO",
"info.prettypipes.ensure_item_order.description": "Whether the module should wait for items to be inserted in the order they appear in the input slots\nRecommended for use with the Crafter", "info.prettypipes.ensure_item_order.description": "Whether the module should wait for items to be inserted in the order they appear in the input slots\n\u00A7oRecommended for use with the Crafter",
"info.prettypipes.shift": "Hold Shift for info", "info.prettypipes.shift": "Hold Shift for info",
"info.prettypipes.populate": "P", "info.prettypipes.populate": "P",
"info.prettypipes.populate.description": "Populate filter slots with items from adjacent inventories", "info.prettypipes.populate.description": "Populate filter slots with items from adjacent inventories",
@ -94,7 +94,7 @@
"info.prettypipes.energy": "%s / %s FE", "info.prettypipes.energy": "%s / %s FE",
"info.prettypipes.crafting": "Awaiting", "info.prettypipes.crafting": "Awaiting",
"info.prettypipes.cancel_all": "Cancel", "info.prettypipes.cancel_all": "Cancel",
"info.prettypipes.cancel_all.desc": "Stops waiting for current crafting outputs\nDoesn't remove inputs from blocks", "info.prettypipes.cancel_all.desc": "Stops waiting for current crafting outputs\nOngoing crafting operations are still completed",
"info.prettypipes.no_pipe_connected": "The terminal needs to be connected to a pipe network", "info.prettypipes.no_pipe_connected": "The terminal needs to be connected to a pipe network",
"info.prettypipes.too_many_pipes_connected": "The terminal can only be connected to a single pipe at a time", "info.prettypipes.too_many_pipes_connected": "The terminal can only be connected to a single pipe at a time",
"dir.prettypipes.up": "Up", "dir.prettypipes.up": "Up",