I think we finally fixed recursive dependency issues

This commit is contained in:
Ell 2021-02-06 00:26:27 +01:00
parent 240c82c612
commit 007d08efa0
8 changed files with 34 additions and 31 deletions

View file

@ -104,9 +104,12 @@ dependencies {
compileOnly fg.deobf("mezz.jei:jei-1.16.2:7.3.2.25:api") compileOnly fg.deobf("mezz.jei:jei-1.16.2:7.3.2.25:api")
runtimeOnly fg.deobf("mezz.jei:jei-1.16.2:7.3.2.25") runtimeOnly fg.deobf("mezz.jei:jei-1.16.2:7.3.2.25")
// to test the rf requiring stuff // to test the rf requiring and crafting stuff
runtimeOnly fg.deobf("curse.maven:powah:3057732") runtimeOnly fg.deobf("curse.maven:powah-352656:3057732")
runtimeOnly fg.deobf("curse.maven:lollipop:3057731") runtimeOnly fg.deobf("curse.maven:lollipop-347954:3057731")
runtimeOnly fg.deobf("curse.maven:mcjtylib-233105:3131241")
runtimeOnly fg.deobf("curse.maven:rftools-base-326041:3140147")
runtimeOnly fg.deobf("curse.maven:rftools-utility-342466:3152948")
} }
// Example for how to get properties into the manifest for reading by the runtime.. // Example for how to get properties into the manifest for reading by the runtime..

View file

@ -36,9 +36,9 @@ public interface IModule {
List<ItemStack> getAllCraftables(ItemStack module, PipeTileEntity tile); List<ItemStack> getAllCraftables(ItemStack module, PipeTileEntity tile);
int getCraftableAmount(ItemStack module, PipeTileEntity tile, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<IModule> dependencyChain); int getCraftableAmount(ItemStack module, PipeTileEntity tile, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<ItemStack> dependencyChain);
ItemStack craft(ItemStack module, PipeTileEntity tile, BlockPos destPipe, Consumer<ItemStack> unavailableConsumer, ItemStack stack); ItemStack craft(ItemStack module, PipeTileEntity tile, BlockPos destPipe, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<ItemStack> dependencyChain);
Integer getCustomNextNode(ItemStack module, PipeTileEntity tile, List<BlockPos> nodes, int index); Integer getCustomNextNode(ItemStack module, PipeTileEntity tile, List<BlockPos> nodes, int index);
} }

View file

@ -85,12 +85,12 @@ public abstract class ModuleItem extends Item implements IModule {
} }
@Override @Override
public int getCraftableAmount(ItemStack module, PipeTileEntity tile, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<IModule> dependencyChain) { public int getCraftableAmount(ItemStack module, PipeTileEntity tile, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<ItemStack> dependencyChain) {
return 0; return 0;
} }
@Override @Override
public ItemStack craft(ItemStack module, PipeTileEntity tile, BlockPos destPipe, Consumer<ItemStack> unavailableConsumer, ItemStack stack) { public ItemStack craft(ItemStack module, PipeTileEntity tile, BlockPos destPipe, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<ItemStack> dependencyChain) {
return stack; return stack;
} }

View file

@ -6,8 +6,6 @@ import com.google.common.collect.Streams;
import de.ellpeck.prettypipes.PrettyPipes; import de.ellpeck.prettypipes.PrettyPipes;
import de.ellpeck.prettypipes.Registry; import de.ellpeck.prettypipes.Registry;
import de.ellpeck.prettypipes.Utility; import de.ellpeck.prettypipes.Utility;
import de.ellpeck.prettypipes.items.IModule;
import de.ellpeck.prettypipes.items.ModuleItem;
import de.ellpeck.prettypipes.misc.ItemEqualityType; import de.ellpeck.prettypipes.misc.ItemEqualityType;
import de.ellpeck.prettypipes.packets.PacketHandler; import de.ellpeck.prettypipes.packets.PacketHandler;
import de.ellpeck.prettypipes.packets.PacketItemEnterPipe; import de.ellpeck.prettypipes.packets.PacketItemEnterPipe;
@ -196,17 +194,17 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphL
return remain; return remain;
} }
// check craftable items // check craftable items
return this.requestCraftedItem(destPipe, null, remain, equalityTypes); return this.requestCraftedItem(destPipe, null, remain, new Stack<>(), equalityTypes);
} }
public ItemStack requestCraftedItem(BlockPos destPipe, Consumer<ItemStack> unavailableConsumer, ItemStack stack, ItemEqualityType... equalityTypes) { public ItemStack requestCraftedItem(BlockPos destPipe, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<ItemStack> dependencyChain, ItemEqualityType... equalityTypes) {
for (Pair<BlockPos, ItemStack> craftable : this.getAllCraftables(destPipe)) { for (Pair<BlockPos, ItemStack> craftable : this.getAllCraftables(destPipe)) {
if (!ItemEqualityType.compareItems(stack, craftable.getRight(), equalityTypes)) if (!ItemEqualityType.compareItems(stack, craftable.getRight(), equalityTypes))
continue; continue;
PipeTileEntity pipe = this.getPipe(craftable.getLeft()); PipeTileEntity pipe = this.getPipe(craftable.getLeft());
if (pipe == null) if (pipe == null)
continue; continue;
stack = pipe.craft(destPipe, unavailableConsumer, stack); stack = pipe.craft(destPipe, unavailableConsumer, stack, dependencyChain);
if (stack.isEmpty()) if (stack.isEmpty())
break; break;
} }
@ -301,7 +299,7 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphL
return craftables; return craftables;
} }
public int getCraftableAmount(BlockPos node, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<IModule> dependencyChain, ItemEqualityType... equalityTypes) { public int getCraftableAmount(BlockPos node, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<ItemStack> dependencyChain, ItemEqualityType... equalityTypes) {
int total = 0; int total = 0;
for (Pair<BlockPos, ItemStack> pair : this.getAllCraftables(node)) { for (Pair<BlockPos, ItemStack> pair : this.getAllCraftables(node)) {
if (!ItemEqualityType.compareItems(pair.getRight(), stack, equalityTypes)) if (!ItemEqualityType.compareItems(pair.getRight(), stack, equalityTypes))

View file

@ -4,7 +4,7 @@ import de.ellpeck.prettypipes.PrettyPipes;
import de.ellpeck.prettypipes.Registry; import de.ellpeck.prettypipes.Registry;
import de.ellpeck.prettypipes.Utility; import de.ellpeck.prettypipes.Utility;
import de.ellpeck.prettypipes.items.IModule; import de.ellpeck.prettypipes.items.IModule;
import de.ellpeck.prettypipes.items.ModuleItem; import de.ellpeck.prettypipes.misc.ItemEqualityType;
import de.ellpeck.prettypipes.network.NetworkLock; import de.ellpeck.prettypipes.network.NetworkLock;
import de.ellpeck.prettypipes.network.PipeNetwork; import de.ellpeck.prettypipes.network.PipeNetwork;
import de.ellpeck.prettypipes.pipe.containers.MainPipeContainer; import de.ellpeck.prettypipes.pipe.containers.MainPipeContainer;
@ -307,13 +307,13 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public int getCraftableAmount(Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<IModule> dependencyChain) { public int getCraftableAmount(Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<ItemStack> dependencyChain) {
int total = 0; int total = 0;
Iterator<Pair<ItemStack, IModule>> modules = this.streamModules().iterator(); Iterator<Pair<ItemStack, IModule>> modules = this.streamModules().iterator();
while (modules.hasNext()) { while (modules.hasNext()) {
Pair<ItemStack, IModule> module = modules.next(); Pair<ItemStack, IModule> module = modules.next();
// make sure we don't factor in recursive dependencies like ingot -> block -> ingot etc. // make sure we don't factor in recursive dependencies like ingot -> block -> ingot etc.
if (!dependencyChain.contains(module.getRight())) { if (dependencyChain.stream().noneMatch(d -> ItemEqualityType.compareItems(module.getLeft(), d, ItemEqualityType.NBT))) {
int amount = module.getRight().getCraftableAmount(module.getLeft(), this, unavailableConsumer, stack, dependencyChain); int amount = module.getRight().getCraftableAmount(module.getLeft(), this, unavailableConsumer, stack, dependencyChain);
if (amount > 0) if (amount > 0)
total += amount; total += amount;
@ -322,11 +322,11 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
return total; return total;
} }
public ItemStack craft(BlockPos destPipe, Consumer<ItemStack> unavailableConsumer, ItemStack stack) { public ItemStack craft(BlockPos destPipe, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<ItemStack> dependencyChain) {
Iterator<Pair<ItemStack, IModule>> modules = this.streamModules().iterator(); Iterator<Pair<ItemStack, IModule>> modules = this.streamModules().iterator();
while (modules.hasNext()) { while (modules.hasNext()) {
Pair<ItemStack, IModule> module = modules.next(); Pair<ItemStack, IModule> module = modules.next();
stack = module.getRight().craft(module.getLeft(), this, destPipe, unavailableConsumer, stack); stack = module.getRight().craft(module.getLeft(), this, destPipe, unavailableConsumer, stack, dependencyChain);
if (stack.isEmpty()) if (stack.isEmpty())
break; break;
} }

View file

@ -137,7 +137,7 @@ public class CraftingModuleItem extends ModuleItem {
} }
@Override @Override
public int getCraftableAmount(ItemStack module, PipeTileEntity tile, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<IModule> dependencyChain) { public int getCraftableAmount(ItemStack module, PipeTileEntity tile, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<ItemStack> dependencyChain) {
PipeNetwork network = PipeNetwork.get(tile.getWorld()); PipeNetwork network = PipeNetwork.get(tile.getWorld());
List<NetworkLocation> items = network.getOrderedNetworkItems(tile.getPos()); List<NetworkLocation> items = network.getOrderedNetworkItems(tile.getPos());
ItemEqualityType[] equalityTypes = ItemFilter.getEqualityTypes(tile); ItemEqualityType[] equalityTypes = ItemFilter.getEqualityTypes(tile);
@ -148,12 +148,8 @@ public class CraftingModuleItem extends ModuleItem {
for (int i = 0; i < output.getSlots(); i++) { for (int i = 0; i < output.getSlots(); i++) {
ItemStack out = output.getStackInSlot(i); ItemStack out = output.getStackInSlot(i);
if (!out.isEmpty() && ItemEqualityType.compareItems(out, stack, equalityTypes)) { if (!out.isEmpty() && ItemEqualityType.compareItems(out, stack, equalityTypes)) {
// we copy the dependency chain, because we want to pass down the dependencies for this output only
Stack<IModule> deps = (Stack<IModule>) dependencyChain.clone();
// we can craft this item *in general*, so add us to the dependency chain
deps.push(this);
// figure out how many crafting operations we can actually do with the input items we have in the network // figure out how many crafting operations we can actually do with the input items we have in the network
int availableCrafts = CraftingTerminalTileEntity.getAvailableCrafts(tile, input.getSlots(), input::getStackInSlot, k -> true, s -> items, unavailableConsumer, deps, equalityTypes); int availableCrafts = CraftingTerminalTileEntity.getAvailableCrafts(tile, input.getSlots(), input::getStackInSlot, k -> true, s -> items, unavailableConsumer, addDependency(dependencyChain, module), equalityTypes);
if (availableCrafts > 0) if (availableCrafts > 0)
craftable += out.getCount() * availableCrafts; craftable += out.getCount() * availableCrafts;
} }
@ -162,9 +158,9 @@ public class CraftingModuleItem extends ModuleItem {
} }
@Override @Override
public ItemStack craft(ItemStack module, PipeTileEntity tile, BlockPos destPipe, Consumer<ItemStack> unavailableConsumer, ItemStack stack) { public ItemStack craft(ItemStack module, PipeTileEntity tile, BlockPos destPipe, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<ItemStack> dependencyChain) {
// check if we can craft the required amount of items // check if we can craft the required amount of items
int craftableAmount = this.getCraftableAmount(module, tile, unavailableConsumer, stack, new Stack<>()); int craftableAmount = this.getCraftableAmount(module, tile, unavailableConsumer, stack, dependencyChain);
if (craftableAmount <= 0) if (craftableAmount <= 0)
return stack; return stack;
@ -183,7 +179,7 @@ public class CraftingModuleItem extends ModuleItem {
continue; continue;
ItemStack copy = in.copy(); ItemStack copy = in.copy();
copy.setCount(in.getCount() * toCraft); copy.setCount(in.getCount() * toCraft);
Pair<List<NetworkLock>, ItemStack> ret = ItemTerminalTileEntity.requestItemLater(tile.getWorld(), tile.getPos(), items, unavailableConsumer, copy, equalityTypes); Pair<List<NetworkLock>, ItemStack> ret = ItemTerminalTileEntity.requestItemLater(tile.getWorld(), tile.getPos(), items, unavailableConsumer, copy, addDependency(dependencyChain, module), equalityTypes);
tile.craftIngredientRequests.addAll(ret.getLeft()); tile.craftIngredientRequests.addAll(ret.getLeft());
} }
@ -229,4 +225,10 @@ public class CraftingModuleItem extends ModuleItem {
} }
return resultAmount; return resultAmount;
} }
private static Stack<ItemStack> addDependency(Stack<ItemStack> deps, ItemStack module) {
deps = (Stack<ItemStack>) deps.clone();
deps.push(module);
return deps;
}
} }

View file

@ -196,7 +196,7 @@ public class CraftingTerminalTileEntity extends ItemTerminalTileEntity {
return remain; return remain;
} }
public static int getAvailableCrafts(PipeTileEntity tile, int slots, Function<Integer, ItemStack> inputFunction, Predicate<Integer> isGhost, Function<EquatableItemStack, Collection<NetworkLocation>> locationsFunction, Consumer<ItemStack> unavailableConsumer, Stack<IModule> dependencyChain, ItemEqualityType... equalityTypes) { public static int getAvailableCrafts(PipeTileEntity tile, int slots, Function<Integer, ItemStack> inputFunction, Predicate<Integer> isGhost, Function<EquatableItemStack, Collection<NetworkLocation>> locationsFunction, Consumer<ItemStack> unavailableConsumer, Stack<ItemStack> dependencyChain, ItemEqualityType... equalityTypes) {
PipeNetwork network = PipeNetwork.get(tile.getWorld()); PipeNetwork network = PipeNetwork.get(tile.getWorld());
// the highest amount we can craft with the items we have // the highest amount we can craft with the items we have
int lowestAvailable = Integer.MAX_VALUE; int lowestAvailable = Integer.MAX_VALUE;

View file

@ -158,7 +158,7 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine
public int requestItemImpl(ItemStack stack, Consumer<ItemStack> unavailableConsumer) { public int requestItemImpl(ItemStack stack, Consumer<ItemStack> unavailableConsumer) {
NetworkItem item = this.networkItems.get(new EquatableItemStack(stack, ItemEqualityType.NBT)); NetworkItem item = this.networkItems.get(new EquatableItemStack(stack, ItemEqualityType.NBT));
Collection<NetworkLocation> locations = item == null ? Collections.emptyList() : item.getLocations(); Collection<NetworkLocation> locations = item == null ? Collections.emptyList() : item.getLocations();
Pair<List<NetworkLock>, ItemStack> ret = requestItemLater(this.world, this.getConnectedPipe().getPos(), locations, unavailableConsumer, stack, ItemEqualityType.NBT); Pair<List<NetworkLock>, ItemStack> ret = requestItemLater(this.world, this.getConnectedPipe().getPos(), locations, unavailableConsumer, stack, new Stack<>(), ItemEqualityType.NBT);
this.existingRequests.addAll(ret.getLeft()); this.existingRequests.addAll(ret.getLeft());
return stack.getCount() - ret.getRight().getCount(); return stack.getCount() - ret.getRight().getCount();
} }
@ -269,7 +269,7 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine
return true; return true;
} }
public static Pair<List<NetworkLock>, ItemStack> requestItemLater(World world, BlockPos destPipe, Collection<NetworkLocation> locations, Consumer<ItemStack> unavailableConsumer, ItemStack stack, ItemEqualityType... equalityTypes) { public static Pair<List<NetworkLock>, ItemStack> requestItemLater(World world, BlockPos destPipe, Collection<NetworkLocation> locations, Consumer<ItemStack> unavailableConsumer, ItemStack stack, Stack<ItemStack> dependencyChain, ItemEqualityType... equalityTypes) {
List<NetworkLock> requests = new ArrayList<>(); List<NetworkLock> requests = new ArrayList<>();
ItemStack remain = stack.copy(); ItemStack remain = stack.copy();
PipeNetwork network = PipeNetwork.get(world); PipeNetwork network = PipeNetwork.get(world);
@ -297,7 +297,7 @@ public class ItemTerminalTileEntity extends TileEntity implements INamedContaine
} }
// check for craftable items // check for craftable items
if (!remain.isEmpty()) if (!remain.isEmpty())
remain = network.requestCraftedItem(destPipe, unavailableConsumer, remain, equalityTypes); remain = network.requestCraftedItem(destPipe, unavailableConsumer, remain, dependencyChain, equalityTypes);
return Pair.of(requests, remain); return Pair.of(requests, remain);
} }