diff --git a/src/main/java/de/ellpeck/prettypipes/items/IModule.java b/src/main/java/de/ellpeck/prettypipes/items/IModule.java index 2c3d2fc..459a362 100644 --- a/src/main/java/de/ellpeck/prettypipes/items/IModule.java +++ b/src/main/java/de/ellpeck/prettypipes/items/IModule.java @@ -2,6 +2,7 @@ import de.ellpeck.prettypipes.misc.DirectionSelector; import de.ellpeck.prettypipes.misc.ItemFilter; +import de.ellpeck.prettypipes.network.ActiveCraft; import de.ellpeck.prettypipes.pipe.PipeBlockEntity; import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; import net.minecraft.core.BlockPos; @@ -10,7 +11,9 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.neoforged.neoforge.items.IItemHandler; +import org.apache.commons.lang3.tuple.Pair; +import java.util.Collection; import java.util.List; import java.util.Stack; import java.util.function.Consumer; @@ -41,7 +44,7 @@ public interface IModule { int getCraftableAmount(ItemStack module, PipeBlockEntity tile, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain); - ItemStack craft(ItemStack module, PipeBlockEntity tile, BlockPos destPipe, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain); + Pair> craft(ItemStack module, PipeBlockEntity tile, BlockPos destPipe, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain); Integer getCustomNextNode(ItemStack module, PipeBlockEntity tile, List nodes, int index); diff --git a/src/main/java/de/ellpeck/prettypipes/items/ModuleItem.java b/src/main/java/de/ellpeck/prettypipes/items/ModuleItem.java index a594164..8afd513 100644 --- a/src/main/java/de/ellpeck/prettypipes/items/ModuleItem.java +++ b/src/main/java/de/ellpeck/prettypipes/items/ModuleItem.java @@ -3,6 +3,7 @@ import de.ellpeck.prettypipes.Utility; import de.ellpeck.prettypipes.misc.DirectionSelector; import de.ellpeck.prettypipes.misc.ItemFilter; +import de.ellpeck.prettypipes.network.ActiveCraft; import de.ellpeck.prettypipes.pipe.PipeBlockEntity; import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; import net.minecraft.core.BlockPos; @@ -16,7 +17,9 @@ import net.neoforged.api.distmarker.Dist; import net.neoforged.api.distmarker.OnlyIn; import net.neoforged.neoforge.items.IItemHandler; +import org.apache.commons.lang3.tuple.Pair; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Stack; @@ -89,8 +92,8 @@ public int getCraftableAmount(ItemStack module, PipeBlockEntity tile, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain) { - return stack; + public Pair> craft(ItemStack module, PipeBlockEntity tile, BlockPos destPipe, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain) { + return Pair.of(stack, List.of()); } @Override diff --git a/src/main/java/de/ellpeck/prettypipes/network/ActiveCraft.java b/src/main/java/de/ellpeck/prettypipes/network/ActiveCraft.java new file mode 100644 index 0000000..a684a79 --- /dev/null +++ b/src/main/java/de/ellpeck/prettypipes/network/ActiveCraft.java @@ -0,0 +1,77 @@ +package de.ellpeck.prettypipes.network; + +import de.ellpeck.prettypipes.Utility; +import de.ellpeck.prettypipes.misc.ItemEquality; +import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.common.util.INBTSerializable; +import org.jetbrains.annotations.UnknownNullability; + +import java.util.ArrayList; +import java.util.List; + +public class ActiveCraft implements INBTSerializable { + + public List travelingIngredients = new ArrayList<>(); + public List ingredientsToRequest; + public BlockPos resultDestPipe; + 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 ingredientsToRequest, BlockPos resultDestPipe, ItemStack resultStackRemain) { + this.ingredientsToRequest = ingredientsToRequest; + this.resultDestPipe = resultDestPipe; + this.resultStackRemain = resultStackRemain; + } + + public ActiveCraft(HolderLookup.Provider provider, CompoundTag tag) { + this.deserializeNBT(provider, tag); + } + + @Override + public @UnknownNullability CompoundTag serializeNBT(HolderLookup.Provider provider) { + var ret = new CompoundTag(); + 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()); + ret.put("result_stack_remain", this.resultStackRemain.saveOptional(provider)); + ret.putBoolean("in_progress", this.inProgress); + ret.putBoolean("canceled", this.canceled); + return ret; + } + + @Override + public void deserializeNBT(HolderLookup.Provider provider, CompoundTag nbt) { + 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")); + this.resultStackRemain = ItemStack.parseOptional(provider, nbt.getCompound("result_stack_remain")); + this.inProgress = nbt.getBoolean("in_progress"); + this.canceled = nbt.getBoolean("canceled"); + } + + public ItemStack getTravelingIngredient(ItemStack stack, ItemEquality... equalityTypes) { + for (var traveling : this.travelingIngredients) { + if (ItemEquality.compareItems(stack, traveling, equalityTypes)) + return traveling; + } + return ItemStack.EMPTY; + } + + public boolean markCanceledOrResolve(PipeNetwork network) { + if (this.inProgress) { + this.canceled = true; + return false; + } else { + for (var lock : this.ingredientsToRequest) + network.resolveNetworkLock(lock); + return true; + } + } + +} diff --git a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java index 31fb23a..8a90589 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java +++ b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java @@ -26,6 +26,7 @@ import net.neoforged.neoforge.items.IItemHandler; import net.neoforged.neoforge.network.PacketDistributor; import org.apache.commons.lang3.tuple.Pair; +import org.apache.commons.lang3.tuple.Triple; import org.jgrapht.ListenableGraph; import org.jgrapht.alg.shortestpath.DijkstraShortestPath; import org.jgrapht.event.GraphEdgeChangeEvent; @@ -213,21 +214,58 @@ public ItemStack requestItem(BlockPos destPipe, BlockPos destInventory, ItemStac return remain; } // check craftable items - return this.requestCraftedItem(destPipe, null, remain, new Stack<>(), equalityTypes); + return this.requestCraftedItem(destPipe, null, remain, new Stack<>(), equalityTypes).getLeft(); } - public ItemStack requestCraftedItem(BlockPos destPipe, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain, ItemEquality... equalityTypes) { + public Triple, ItemStack, Collection> requestLocksAndCrafts(BlockPos destPipe, Collection locations, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain, ItemEquality... equalityTypes) { + List requests = new ArrayList<>(); + var remain = stack.copy(); + // check for existing items + for (var location : locations) { + var amount = location.getItemAmount(this.level, stack, equalityTypes); + if (amount <= 0) + continue; + amount -= this.getLockedAmount(location.getPos(), stack, null, equalityTypes); + if (amount > 0) { + if (remain.getCount() < amount) + amount = remain.getCount(); + remain.shrink(amount); + while (amount > 0) { + var copy = stack.copy(); + copy.setCount(Math.min(stack.getMaxStackSize(), amount)); + var lock = new NetworkLock(location, copy); + this.createNetworkLock(lock); + requests.add(lock); + amount -= copy.getCount(); + } + if (remain.isEmpty()) + break; + } + } + if (!remain.isEmpty()) { + // check for craftable items + var started = this.requestCraftedItem(destPipe, unavailableConsumer, remain, dependencyChain, equalityTypes); + return Triple.of(requests, started.getLeft(), started.getRight()); + } else { + return Triple.of(requests, remain, List.of()); + } + } + + public Pair> requestCraftedItem(BlockPos destPipe, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain, ItemEquality... equalityTypes) { + var crafts = new ArrayList(); for (var craftable : this.getAllCraftables(destPipe)) { if (!ItemEquality.compareItems(stack, craftable.getRight(), equalityTypes)) continue; var pipe = this.getPipe(craftable.getLeft()); if (pipe == null) continue; - stack = pipe.craft(destPipe, unavailableConsumer, stack, dependencyChain); + var started = pipe.craft(destPipe, unavailableConsumer, stack, dependencyChain); + stack = started.getLeft(); + crafts.addAll(started.getRight()); if (stack.isEmpty()) break; } - return stack; + return Pair.of(stack, crafts); } public ItemStack requestExistingItem(NetworkLocation location, BlockPos destPipe, BlockPos destInventory, NetworkLock ignoredLock, ItemStack stack, ItemEquality... equalityTypes) { diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlockEntity.java b/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlockEntity.java index e7aa24a..bf502b5 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlockEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlockEntity.java @@ -5,10 +5,9 @@ import de.ellpeck.prettypipes.Utility; import de.ellpeck.prettypipes.items.IModule; import de.ellpeck.prettypipes.misc.ItemFilter; -import de.ellpeck.prettypipes.network.NetworkLock; +import de.ellpeck.prettypipes.network.ActiveCraft; import de.ellpeck.prettypipes.network.PipeNetwork; import de.ellpeck.prettypipes.pipe.containers.MainPipeContainer; -import de.ellpeck.prettypipes.pipe.modules.craft.CraftingModuleItem; import de.ellpeck.prettypipes.pressurizer.PressurizerBlockEntity; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -42,7 +41,6 @@ import net.neoforged.neoforge.items.ItemHandlerHelper; import net.neoforged.neoforge.items.ItemStackHandler; import org.apache.commons.lang3.tuple.Pair; -import org.apache.commons.lang3.tuple.Triple; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -72,7 +70,7 @@ protected void onContentsChanged(int slot) { PipeBlockEntity.this.setChanged(); } }; - public final List> activeCrafts = new ArrayList<>(); + public final List> activeCrafts = new ArrayList<>(); public PressurizerBlockEntity pressurizer; public BlockState cover; public int moduleDropCheck; @@ -120,7 +118,7 @@ public void loadAdditional(CompoundTag compound, HolderLookup.Provider provider) 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 CraftingModuleItem.ActiveCraft(provider, tag.getCompound("data")))); + this.activeCrafts.add(Pair.of(tag.getInt("module_slot"), new ActiveCraft(provider, tag.getCompound("data")))); } super.loadAdditional(compound, provider); } @@ -296,15 +294,18 @@ public int getCraftableAmount(Consumer unavailableConsumer, ItemStack return total; } - public ItemStack craft(BlockPos destPipe, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain) { + public Pair> craft(BlockPos destPipe, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain) { + var crafts = new ArrayList(); var modules = this.streamModules().iterator(); while (modules.hasNext()) { var module = modules.next(); - stack = module.getRight().craft(module.getLeft(), this, destPipe, unavailableConsumer, stack, dependencyChain); + var started = module.getRight().craft(module.getLeft(), this, destPipe, unavailableConsumer, stack, dependencyChain); + stack = started.getLeft(); + crafts.addAll(started.getRight()); if (stack.isEmpty()) break; } - return stack; + return Pair.of(stack, crafts); } public IItemHandler getItemHandler(Direction dir) { 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 9697c0f..43c1a16 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 @@ -7,9 +7,9 @@ import de.ellpeck.prettypipes.items.IModule; import de.ellpeck.prettypipes.items.ModuleItem; import de.ellpeck.prettypipes.items.ModuleTier; -import de.ellpeck.prettypipes.misc.EquatableItemStack; import de.ellpeck.prettypipes.misc.ItemEquality; import de.ellpeck.prettypipes.misc.ItemFilter; +import de.ellpeck.prettypipes.network.ActiveCraft; import de.ellpeck.prettypipes.network.NetworkLock; import de.ellpeck.prettypipes.network.PipeNetwork; import de.ellpeck.prettypipes.pipe.PipeBlockEntity; @@ -18,21 +18,15 @@ import de.ellpeck.prettypipes.terminal.ItemTerminalBlockEntity; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.core.HolderLookup; import net.minecraft.core.component.DataComponentType; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; import net.minecraft.util.Mth; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.neoforged.neoforge.common.util.INBTSerializable; import net.neoforged.neoforge.items.IItemHandler; import net.neoforged.neoforge.items.ItemHandlerHelper; import net.neoforged.neoforge.items.ItemStackHandler; import org.apache.commons.lang3.tuple.Pair; -import org.apache.commons.lang3.tuple.Triple; -import org.jetbrains.annotations.UnknownNullability; import java.util.*; import java.util.function.Consumer; @@ -174,11 +168,11 @@ public int getCraftableAmount(ItemStack module, PipeBlockEntity tile, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain) { + public Pair> craft(ItemStack module, PipeBlockEntity tile, BlockPos destPipe, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain) { // check if we can craft the required amount of items var craftableAmount = this.getCraftableAmount(module, tile, unavailableConsumer, stack, dependencyChain); if (craftableAmount <= 0) - return stack; + return Pair.of(stack, List.of()); var slot = tile.getModuleSlot(module); var network = PipeNetwork.get(tile.getLevel()); @@ -192,6 +186,7 @@ public ItemStack craft(ItemStack module, PipeBlockEntity tile, BlockPos destPipe var toCraft = Math.min(craftableCrafts, requiredCrafts); var locks = new ArrayList(); + var crafts = new ArrayList(); var contents = module.get(Contents.TYPE); // if we're ensuring item order, all items for a single recipe should be sent in order first before starting on the next one! for (var c = contents.ensureItemOrder ? toCraft : 1; c > 0; c--) { @@ -202,8 +197,9 @@ public ItemStack craft(ItemStack module, PipeBlockEntity tile, BlockPos destPipe var copy = in.copy(); if (!contents.ensureItemOrder) copy.setCount(in.getCount() * toCraft); - var ret = ItemTerminalBlockEntity.requestItemLater(tile.getLevel(), tile.getBlockPos(), items, unavailableConsumer, copy, CraftingModuleItem.addDependency(dependencyChain, module), equalityTypes); + var ret = network.requestLocksAndCrafts(tile.getBlockPos(), items, unavailableConsumer, copy, CraftingModuleItem.addDependency(dependencyChain, module), equalityTypes); locks.addAll(ret.getLeft()); + crafts.addAll(ret.getRight()); } } @@ -212,10 +208,11 @@ public ItemStack craft(ItemStack module, PipeBlockEntity tile, BlockPos destPipe var result = stack.copy(); result.shrink(remain.getCount()); - var activeCraft = new ActiveCraft(locks, new ArrayList<>(), destPipe, result); + var activeCraft = new ActiveCraft(locks, destPipe, result); tile.activeCrafts.add(Pair.of(slot, activeCraft)); + crafts.add(activeCraft); - return remain; + return Pair.of(remain, crafts); } @Override @@ -277,68 +274,4 @@ public record Contents(ItemStackHandler input, ItemStackHandler output, boolean } - public static class ActiveCraft implements INBTSerializable { - - public List ingredientsToRequest; - public List travelingIngredients; - public BlockPos resultDestPipe; - 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 ingredientsToRequest, List travelingIngredients, BlockPos resultDestPipe, ItemStack resultStackRemain) { - this.ingredientsToRequest = ingredientsToRequest; - this.travelingIngredients = travelingIngredients; - this.resultDestPipe = resultDestPipe; - this.resultStackRemain = resultStackRemain; - } - - public ActiveCraft(HolderLookup.Provider provider, CompoundTag tag) { - this.deserializeNBT(provider, tag); - } - - @Override - public @UnknownNullability CompoundTag serializeNBT(HolderLookup.Provider provider) { - var ret = new CompoundTag(); - 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()); - ret.put("result_stack_remain", this.resultStackRemain.saveOptional(provider)); - ret.putBoolean("in_progress", this.inProgress); - ret.putBoolean("canceled", this.canceled); - return ret; - } - - @Override - public void deserializeNBT(HolderLookup.Provider provider, CompoundTag nbt) { - 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")); - this.resultStackRemain = ItemStack.parseOptional(provider, nbt.getCompound("result_stack_remain")); - this.inProgress = nbt.getBoolean("in_progress"); - this.canceled = nbt.getBoolean("canceled"); - } - - public ItemStack getTravelingIngredient(ItemStack stack, ItemEquality... equalityTypes) { - for (var traveling : this.travelingIngredients) { - if (ItemEquality.compareItems(stack, traveling, equalityTypes)) - return traveling; - } - return ItemStack.EMPTY; - } - - public boolean markCanceledOrResolve(PipeNetwork network) { - if (this.inProgress) { - this.canceled = true; - return false; - } else { - for (var lock : this.ingredientsToRequest) - network.resolveNetworkLock(lock); - return true; - } - } - - } - } diff --git a/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalBlockEntity.java b/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalBlockEntity.java index cb9bba4..3d43b8a 100644 --- a/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalBlockEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/terminal/ItemTerminalBlockEntity.java @@ -5,10 +5,7 @@ import de.ellpeck.prettypipes.Utility; import de.ellpeck.prettypipes.misc.EquatableItemStack; import de.ellpeck.prettypipes.misc.ItemEquality; -import de.ellpeck.prettypipes.network.NetworkItem; -import de.ellpeck.prettypipes.network.NetworkLocation; -import de.ellpeck.prettypipes.network.NetworkLock; -import de.ellpeck.prettypipes.network.PipeNetwork; +import de.ellpeck.prettypipes.network.*; import de.ellpeck.prettypipes.packets.PacketNetworkItems; import de.ellpeck.prettypipes.pipe.ConnectionType; import de.ellpeck.prettypipes.pipe.IPipeConnectable; @@ -35,6 +32,7 @@ import net.neoforged.neoforge.items.ItemHandlerHelper; import net.neoforged.neoforge.items.ItemStackHandler; import org.apache.commons.lang3.tuple.Pair; +import org.apache.commons.lang3.tuple.Triple; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -172,9 +170,10 @@ public void requestItem(Player player, ItemStack stack, int componentsHash) { public int requestItemImpl(ItemStack stack, Consumer unavailableConsumer) { var item = this.networkItems.get(new EquatableItemStack(stack, ItemEquality.NBT)); Collection locations = item == null ? Collections.emptyList() : item.getLocations(); - var ret = ItemTerminalBlockEntity.requestItemLater(this.level, this.getConnectedPipe().getBlockPos(), locations, unavailableConsumer, stack, new Stack<>(), ItemEquality.NBT); + var network = PipeNetwork.get(this.level); + var ret = network.requestLocksAndCrafts(this.getConnectedPipe().getBlockPos(), locations, unavailableConsumer, stack, new Stack<>(), ItemEquality.NBT); this.existingRequests.addAll(ret.getLeft()); - return stack.getCount() - ret.getRight().getCount(); + return stack.getCount() - ret.getMiddle().getCount(); } public Player[] getLookingPlayers() { @@ -269,38 +268,6 @@ public boolean allowsModules(BlockPos pipePos, Direction direction) { return true; } - public static Pair, ItemStack> requestItemLater(Level world, BlockPos destPipe, Collection locations, Consumer unavailableConsumer, ItemStack stack, Stack dependencyChain, ItemEquality... equalityTypes) { - List requests = new ArrayList<>(); - var remain = stack.copy(); - var network = PipeNetwork.get(world); - // check for existing items - for (var location : locations) { - var amount = location.getItemAmount(world, stack, equalityTypes); - if (amount <= 0) - continue; - amount -= network.getLockedAmount(location.getPos(), stack, null, equalityTypes); - if (amount > 0) { - if (remain.getCount() < amount) - amount = remain.getCount(); - remain.shrink(amount); - while (amount > 0) { - var copy = stack.copy(); - copy.setCount(Math.min(stack.getMaxStackSize(), amount)); - var lock = new NetworkLock(location, copy); - network.createNetworkLock(lock); - requests.add(lock); - amount -= copy.getCount(); - } - if (remain.isEmpty()) - break; - } - } - // check for craftable items - if (!remain.isEmpty()) - remain = network.requestCraftedItem(destPipe, unavailableConsumer, remain, dependencyChain, equalityTypes); - return Pair.of(requests, remain); - } - public static Consumer onItemUnavailable(Player player, boolean ignore) { return s -> { if (ignore)