diff --git a/src/main/java/de/ellpeck/prettypipes/misc/Events.java b/src/main/java/de/ellpeck/prettypipes/misc/Events.java index 5fc373a..87aa484 100644 --- a/src/main/java/de/ellpeck/prettypipes/misc/Events.java +++ b/src/main/java/de/ellpeck/prettypipes/misc/Events.java @@ -19,31 +19,37 @@ public final class Events { @SubscribeEvent public static void onServerStarting(ServerStartingEvent event) { event.getServer().getCommands().getDispatcher().register(Commands.literal(PrettyPipes.ID).requires(s -> s.hasPermission(2)) - .then(Commands.literal("dump").executes(c -> { - var source = c.getSource(); - var file = Paths.get('_' + PrettyPipes.ID + "dump.txt"); - var dump = PipeNetwork.get(source.getLevel()).toString(); - try { - Files.writeString(file, dump, StandardCharsets.UTF_8); - source.sendSuccess(() -> Component.literal("Wrote network dump to file " + file.toAbsolutePath()), true); - } catch (IOException e) { - source.sendFailure(Component.literal("Failed to write network dump to file " + file.toAbsolutePath())); - return -1; - } - return 0; - })) - .then(Commands.literal("uncache").executes(c -> { - var source = c.getSource(); - PipeNetwork.get(source.getLevel()).clearCaches(); - source.sendSuccess(() -> Component.literal("Cleared all pipe caches in the world"), true); - return 0; - })) - .then(Commands.literal("unlock").executes(c -> { - var source = c.getSource(); - PipeNetwork.get(source.getLevel()).unlock(); - source.sendSuccess(() -> Component.literal("Resolved all network locks in the world"), true); - return 0; - }))); + .then(Commands.literal("dump").executes(c -> { + var source = c.getSource(); + var file = Paths.get('_' + PrettyPipes.ID + "dump.txt"); + var dump = PipeNetwork.get(source.getLevel()).toString(); + try { + Files.writeString(file, dump, StandardCharsets.UTF_8); + source.sendSuccess(() -> Component.literal("Wrote network dump to file " + file.toAbsolutePath()), true); + } catch (IOException e) { + source.sendFailure(Component.literal("Failed to write network dump to file " + file.toAbsolutePath())); + return -1; + } + return 0; + })) + .then(Commands.literal("uncache").executes(c -> { + var source = c.getSource(); + PipeNetwork.get(source.getLevel()).clearCaches(); + source.sendSuccess(() -> Component.literal("Cleared all pipe caches in the world"), true); + return 0; + })) + .then(Commands.literal("unlock").executes(c -> { + var source = c.getSource(); + PipeNetwork.get(source.getLevel()).unlock(); + source.sendSuccess(() -> Component.literal("Resolved all network locks in the world"), true); + return 0; + })) + .then(Commands.literal("uncraft").executes(c -> { + var source = c.getSource(); + PipeNetwork.get(source.getLevel()).cancelCrafts(); + source.sendSuccess(() -> Component.literal("Canceled all active crafts in the world"), true); + return 0; + }))); } } diff --git a/src/main/java/de/ellpeck/prettypipes/network/ActiveCraft.java b/src/main/java/de/ellpeck/prettypipes/network/ActiveCraft.java index a684a79..aad9b1b 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/ActiveCraft.java +++ b/src/main/java/de/ellpeck/prettypipes/network/ActiveCraft.java @@ -15,6 +15,8 @@ import java.util.List; public class ActiveCraft implements INBTSerializable { + public BlockPos pipe; + public int moduleSlot; public List travelingIngredients = new ArrayList<>(); public List ingredientsToRequest; public BlockPos resultDestPipe; @@ -23,7 +25,9 @@ public class ActiveCraft implements INBTSerializable { // 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 ingredientsToRequest, BlockPos resultDestPipe, ItemStack resultStackRemain) { + public ActiveCraft(BlockPos pipe, int moduleSlot, List ingredientsToRequest, BlockPos resultDestPipe, ItemStack resultStackRemain) { + this.pipe = pipe; + this.moduleSlot = moduleSlot; this.ingredientsToRequest = ingredientsToRequest; this.resultDestPipe = resultDestPipe; this.resultStackRemain = resultStackRemain; @@ -36,6 +40,8 @@ public class ActiveCraft implements INBTSerializable { @Override public @UnknownNullability CompoundTag serializeNBT(HolderLookup.Provider provider) { var ret = new CompoundTag(); + ret.putLong("pipe", this.pipe.asLong()); + ret.putInt("module_slot", this.moduleSlot); ret.put("ingredients_to_request", Utility.serializeAll(this.ingredientsToRequest, n -> n.serializeNBT(provider))); ret.put("traveling_ingredients", Utility.serializeAll(this.travelingIngredients, s -> (CompoundTag) s.save(provider, new CompoundTag()))); ret.putLong("result_dest_pipe", this.resultDestPipe.asLong()); @@ -47,6 +53,8 @@ public class ActiveCraft implements INBTSerializable { @Override public void deserializeNBT(HolderLookup.Provider provider, CompoundTag nbt) { + this.pipe = BlockPos.of(nbt.getLong("pipe")); + this.moduleSlot = nbt.getInt("module_slot"); this.ingredientsToRequest = Utility.deserializeAll(nbt.getList("ingredients_to_request", Tag.TAG_COMPOUND), t -> new NetworkLock(provider, t)); 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")); diff --git a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java index ac53498..8eeea93 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java +++ b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java @@ -55,6 +55,7 @@ public class PipeNetwork extends SavedData implements GraphListener tileCache = new HashMap<>(); private final ListMultimap pipeItems = ArrayListMultimap.create(); private final ListMultimap networkLocks = ArrayListMultimap.create(); + private final ListMultimap activeCrafts = ArrayListMultimap.create(); private Level level; public PipeNetwork() { @@ -74,6 +75,8 @@ public class PipeNetwork extends SavedData implements GraphListener new NetworkLock(provider, t))) this.createNetworkLock(lock); + for (var craft : Utility.deserializeAll(nbt.getList("crafts", Tag.TAG_COMPOUND), t -> new ActiveCraft(provider, t))) + this.activeCrafts.put(craft.pipe, craft); } @Override @@ -121,6 +124,7 @@ public class PipeNetwork extends SavedData implements GraphListener i.serializeNBT(provider))); nbt.put("locks", Utility.serializeAll(this.networkLocks.values(), l -> l.serializeNBT(provider))); + nbt.put("crafts", Utility.serializeAll(this.activeCrafts.values(), c -> c.serializeNBT(provider))); return nbt; } @@ -321,18 +325,17 @@ public class PipeNetwork extends SavedData implements GraphListener this.getPipe(c.getLeft())).distinct().iterator(); while (craftingPipes.hasNext()) { var pipe = craftingPipes.next(); - for (var craft : pipe.activeCrafts) { - var data = craft.getRight(); - if (!includeCanceled && data.canceled) + for (var craft : pipe.getActiveCrafts()) { + if (!includeCanceled && craft.canceled) continue; // add up all the items that should go to the same location var existing = items.stream() - .filter(s -> s.getLeft().equals(data.resultDestPipe) && ItemEquality.compareItems(s.getRight(), data.resultStackRemain, equalityTypes)) + .filter(s -> s.getLeft().equals(craft.resultDestPipe) && ItemEquality.compareItems(s.getRight(), craft.resultStackRemain, equalityTypes)) .findFirst(); if (existing.isPresent()) { - existing.get().getRight().grow(data.resultStackRemain.getCount()); + existing.get().getRight().grow(craft.resultStackRemain.getCount()); } else { - items.add(Pair.of(data.resultDestPipe, data.resultStackRemain.copy())); + items.add(Pair.of(craft.resultDestPipe, craft.resultStackRemain.copy())); } } } @@ -456,6 +459,10 @@ public class PipeNetwork extends SavedData implements GraphListener c.getValue().markCanceledOrResolve(this)); + } + private List createAllEdges(BlockPos pos, BlockState state, boolean ignoreCurrBlocked) { this.startProfile("create_all_edges"); List edges = new ArrayList<>(); @@ -534,7 +541,7 @@ public class PipeNetwork extends SavedData implements GraphListener nodes.stream().anyMatch(cached::contains)); this.endProfile(); @@ -544,6 +551,10 @@ public class PipeNetwork extends SavedData implements GraphListener getActiveCrafts(BlockPos pos) { + return this.activeCrafts.get(pos); + } + public Stream getPipeItemsOnTheWay(BlockPos goalInv) { this.startProfile("get_pipe_items_on_the_way"); var ret = this.pipeItems.values().stream().filter(i -> i.getDestInventory().equals(goalInv)); diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlock.java b/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlock.java index 741af77..1d29bb5 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlock.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlock.java @@ -270,8 +270,8 @@ public class PipeBlock extends BaseEntityBlock implements SimpleWaterloggedBlock network.onPipeChanged(pos, state); if (worldIn.getBlockEntity(pos) instanceof PipeBlockEntity pipe) { pipe.getItems().clear(); - for (var craft : pipe.activeCrafts) { - for (var lock : craft.getRight().ingredientsToRequest) + for (var craft : pipe.getActiveCrafts()) { + for (var lock : craft.ingredientsToRequest) network.resolveNetworkLock(lock); } } diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlockEntity.java b/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlockEntity.java index bf502b5..16f6f76 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlockEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlockEntity.java @@ -70,11 +70,11 @@ public class PipeBlockEntity extends BlockEntity implements MenuProvider, IPipeC PipeBlockEntity.this.setChanged(); } }; - public final List> activeCrafts = new ArrayList<>(); public PressurizerBlockEntity pressurizer; public BlockState cover; public int moduleDropCheck; - protected List items; + private List itemCache; + private List activeCraftCache; private int lastItemAmount; private int priority; private final Lazy workRandomizer = Lazy.of(() -> this.level.random.nextInt(200)); @@ -99,14 +99,6 @@ public class PipeBlockEntity extends BlockEntity implements MenuProvider, IPipeC compound.putInt("module_drop_check", this.moduleDropCheck); if (this.cover != null) compound.put("cover", NbtUtils.writeBlockState(this.cover)); - var crafts = new ListTag(); - for (var craft : this.activeCrafts) { - var tag = new CompoundTag(); - tag.putInt("module_slot", craft.getLeft()); - tag.put("data", craft.getRight().serializeNBT(provider)); - crafts.add(tag); - } - compound.put("active_crafts", crafts); } @Override @@ -114,12 +106,6 @@ public class PipeBlockEntity extends BlockEntity implements MenuProvider, IPipeC this.modules.deserializeNBT(provider, compound.getCompound("modules")); this.moduleDropCheck = compound.getInt("module_drop_check"); this.cover = compound.contains("cover") ? NbtUtils.readBlockState(this.level != null ? this.level.holderLookup(Registries.BLOCK) : BuiltInRegistries.BLOCK.asLookup(), compound.getCompound("cover")) : null; - this.activeCrafts.clear(); - var crafts = compound.getList("active_crafts", Tag.TAG_COMPOUND); - for (var i = 0; i < crafts.size(); i++) { - var tag = crafts.getCompound(i); - this.activeCrafts.add(Pair.of(tag.getInt("module_slot"), new ActiveCraft(provider, tag.getCompound("data")))); - } super.loadAdditional(compound, provider); } @@ -145,9 +131,15 @@ public class PipeBlockEntity extends BlockEntity implements MenuProvider, IPipeC } public List getItems() { - if (this.items == null) - this.items = PipeNetwork.get(this.level).getItemsInPipe(this.worldPosition); - return this.items; + if (this.itemCache == null) + this.itemCache = PipeNetwork.get(this.level).getItemsInPipe(this.worldPosition); + return this.itemCache; + } + + public List getActiveCrafts() { + if (this.activeCraftCache == null) + this.activeCraftCache = PipeNetwork.get(this.level).getActiveCrafts(this.worldPosition); + return this.activeCraftCache; } public void addNewItem(IPipeItem item) { 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 ccf9d03..34d5488 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,15 +70,14 @@ public class CraftingModuleItem extends ModuleItem { return; var slot = tile.getModuleSlot(module); var network = PipeNetwork.get(tile.getLevel()); - if (!tile.activeCrafts.isEmpty()) { - var activeCraft = tile.activeCrafts.getFirst(); - if (activeCraft.getLeft() == slot) { - var craftData = activeCraft.getRight(); - + var crafts = tile.getActiveCrafts(); + if (!crafts.isEmpty()) { + var craft = crafts.getFirst(); + if (craft.moduleSlot == slot) { // process crafting ingredient requests - if (!craftData.ingredientsToRequest.isEmpty()) { + if (!craft.ingredientsToRequest.isEmpty()) { network.startProfile("crafting_ingredients"); - var lock = craftData.ingredientsToRequest.getFirst(); + var lock = craft.ingredientsToRequest.getFirst(); var equalityTypes = ItemFilter.getEqualityTypes(tile); var dest = tile.getAvailableDestination(Direction.values(), lock.stack, true, true); if (dest != null) { @@ -87,12 +86,12 @@ public class CraftingModuleItem extends ModuleItem { if (!ensureItemOrder || network.getPipeItemsOnTheWay(dest.getLeft()).findAny().isEmpty()) { var requestRemain = network.requestExistingItem(lock.location, tile.getBlockPos(), dest.getLeft(), lock, dest.getRight(), equalityTypes); network.resolveNetworkLock(lock); - craftData.ingredientsToRequest.remove(lock); - craftData.inProgress = true; + craft.ingredientsToRequest.remove(lock); + craft.inProgress = true; var traveling = lock.stack.copy(); traveling.shrink(requestRemain.getCount()); - craftData.travelingIngredients.add(traveling); + craft.travelingIngredients.add(traveling); // if we couldn't fit all items into the destination, create another request for the rest var remain = lock.stack.copy(); @@ -100,8 +99,8 @@ public class CraftingModuleItem extends ModuleItem { if (!remain.isEmpty()) { var remainRequest = new NetworkLock(lock.location, remain); // if we're ensuring item order, we need to insert the remaining request at the start so that it gets processed first - var index = ensureItemOrder ? 0 : craftData.ingredientsToRequest.size(); - craftData.ingredientsToRequest.add(index, remainRequest); + var index = ensureItemOrder ? 0 : craft.ingredientsToRequest.size(); + craft.ingredientsToRequest.add(index, remainRequest); network.createNetworkLock(remainRequest); } } @@ -110,19 +109,19 @@ public class CraftingModuleItem extends ModuleItem { } // pull requested crafting results from the network once they are stored - if (!craftData.resultStackRemain.isEmpty()) { + if (!craft.resultStackRemain.isEmpty()) { network.startProfile("crafting_results"); var items = network.getOrderedNetworkItems(tile.getBlockPos()); var equalityTypes = ItemFilter.getEqualityTypes(tile); - var destPipe = network.getPipe(craftData.resultDestPipe); + var destPipe = network.getPipe(craft.resultDestPipe); if (destPipe != null) { - var dest = destPipe.getAvailableDestinationOrConnectable(craftData.resultStackRemain, true, true); + var dest = destPipe.getAvailableDestinationOrConnectable(craft.resultStackRemain, true, true); if (dest != null) { for (var item : items) { - var requestRemain = network.requestExistingItem(item, craftData.resultDestPipe, dest.getLeft(), null, dest.getRight(), equalityTypes); - craftData.resultStackRemain.shrink(dest.getRight().getCount() - requestRemain.getCount()); - if (craftData.resultStackRemain.isEmpty()) { - tile.activeCrafts.remove(activeCraft); + 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; } } @@ -210,8 +209,8 @@ public class CraftingModuleItem extends ModuleItem { var result = stack.copy(); result.shrink(remain.getCount()); - var activeCraft = new ActiveCraft(locks, destPipe, result); - tile.activeCrafts.add(Pair.of(slot, activeCraft)); + var activeCraft = new ActiveCraft(tile.getBlockPos(), slot, locks, destPipe, result); + tile.getActiveCrafts().add(activeCraft); crafts.add(activeCraft); return Pair.of(remain, crafts); @@ -221,12 +220,12 @@ public class CraftingModuleItem extends ModuleItem { public ItemStack store(ItemStack module, PipeBlockEntity tile, ItemStack stack, Direction direction) { var slot = tile.getModuleSlot(module); var equalityTypes = ItemFilter.getEqualityTypes(tile); - var matchingCraft = tile.activeCrafts.stream() - .filter(c -> c.getLeft() == slot && !c.getRight().getTravelingIngredient(stack, equalityTypes).isEmpty()) + var crafts = tile.getActiveCrafts(); + var craft = crafts.stream() + .filter(c -> c.moduleSlot == slot && !c.getTravelingIngredient(stack, equalityTypes).isEmpty()) .findAny().orElse(null); - if (matchingCraft != null) { - var data = matchingCraft.getRight(); - data.travelingIngredients.remove(data.getTravelingIngredient(stack, equalityTypes)); + if (craft != null) { + craft.travelingIngredients.remove(craft.getTravelingIngredient(stack, equalityTypes)); if (module.get(Contents.TYPE).insertSingles) { var handler = tile.getItemHandler(direction); @@ -241,8 +240,8 @@ 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); + if (craft.canceled && craft.travelingIngredients.size() <= 0 && craft.ingredientsToRequest.size() <= 0) + crafts.remove(craft); } return stack; } @@ -259,6 +258,7 @@ public class CraftingModuleItem extends ModuleItem { } private static Stack addDependency(Stack deps, ItemStack module) { + // noinspection unchecked deps = (Stack) deps.clone(); deps.push(module); return deps; diff --git a/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalBlockEntity.java b/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalBlockEntity.java index 76d2e4f..f75a8bf 100644 --- a/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalBlockEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalBlockEntity.java @@ -215,7 +215,7 @@ public class ItemTerminalBlockEntity extends BlockEntity implements IPipeConnect for (var craftable : network.getAllCraftables(pipe.getBlockPos())) { var otherPipe = network.getPipe(craftable.getLeft()); if (otherPipe != null) - otherPipe.activeCrafts.removeIf(c -> c.getRight().markCanceledOrResolve(network)); + otherPipe.getActiveCrafts().removeIf(c -> c.markCanceledOrResolve(network)); } var lookingPlayers = this.getLookingPlayers(); if (lookingPlayers.length > 0)