From 423ece1ff4a05580ab8255559f10a025028677a8 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sun, 14 Jun 2026 00:55:58 -0700 Subject: [PATCH 001/101] move to proper package mass deletion fix last few references make MultiPredicate respect type improve MultiPredicate debug name implement MultiPredicate rename testing methods add helper methods to PatternState clean up PredicateContext implement rework improve rework merger predicate errors together start work on rework add useful methods to BlockInfo --- .../api/multiblock/PatternPredicate.java | 219 ------- .../api/multiblock/PredicateContext.java | 64 ++ .../gtceu/api/multiblock/Predicates.java | 592 +++++++++++++----- .../api/multiblock/error/PatternError.java | 8 +- .../error/SinglePredicateError.java | 27 +- .../api/multiblock/pattern/BlockPattern.java | 42 +- .../ExpandableMultiblockPatternBuilder.java | 4 +- .../multiblock/pattern/ExpandablePattern.java | 21 +- .../pattern/MultiblockPatternBuilder.java | 21 +- .../api/multiblock/pattern/PatternState.java | 10 + .../multiblock/predicates/BasePredicate.java | 305 ++++++--- .../multiblock/predicates/MultiPredicate.java | 164 +++++ .../predicates/PredicateBlockTag.java | 42 -- .../predicates/PredicateBlocks.java | 60 -- .../predicates/PredicateFluidTag.java | 40 -- .../predicates/PredicateFluids.java | 47 -- .../predicates/PredicatePartAbility.java | 65 -- .../predicates/PredicateStates.java | 50 -- .../gtceu/api/multiblock/util/BlockInfo.java | 18 + .../common/data/machines/GCYMMachines.java | 9 +- .../common/data/machines/GTMachineUtils.java | 47 +- .../common/data/machines/GTMultiMachines.java | 8 +- .../item/behavior/TerminalBehavior.java | 8 + .../electric/ActiveTransformerMachine.java | 4 +- .../electric/CentralMonitorMachine.java | 8 +- .../multiblock/electric/CleanroomMachine.java | 61 +- .../primitive/CharcoalPileIgniterMachine.java | 16 +- .../widgets/MultiblockPreviewWidget.java | 38 +- 28 files changed, 1103 insertions(+), 895 deletions(-) delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/PatternPredicate.java create mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java create mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateBlockTag.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateBlocks.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateFluidTag.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateFluids.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicatePartAbility.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateStates.java diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PatternPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PatternPredicate.java deleted file mode 100644 index e4bd6d3e9e1..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PatternPredicate.java +++ /dev/null @@ -1,219 +0,0 @@ -package com.gregtechceu.gtceu.api.multiblock; - -import com.gregtechceu.gtceu.api.multiblock.error.PatternError; -import com.gregtechceu.gtceu.api.multiblock.error.SimplePatternError; -import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; - -import net.minecraft.network.chat.Component; - -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import lombok.Getter; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - -public class PatternPredicate { - - public static PatternPredicate ANY = new PatternPredicate("Any", currentBlockInfo -> null, null); - public static PatternPredicate AIR = new PatternPredicate("Air", - currentBlockInfo -> currentBlockInfo.retrieveCurrentBlockState().isAir() ? null : - new SimplePatternError(currentBlockInfo.getBlockPos(), Collections.emptyList()), - Collections.singletonList(BlockInfo.EMPTY)); - private static final Comparator predicateComparator = Comparator.comparingInt(p -> p.priority); - public List subPredicates = new ArrayList<>(); - @Getter - protected boolean isController; - protected boolean hasAir = false; - @Getter - protected boolean isSingle = true; - - public PatternPredicate() {} - - public PatternPredicate(PatternPredicate predicate) { - subPredicates.addAll(predicate.subPredicates); - isController = predicate.isController; - hasAir = predicate.hasAir; - isSingle = predicate.isSingle; - } - - /** - * @param debugName the debug name - * @param predicate the testing function for if the current block information is valid - * @param candidates the valid list of BlockInfos that this traceability predicate allows - */ - public PatternPredicate(String debugName, Function predicate, - @Nullable List candidates) { - subPredicates.add(new BasePredicate(debugName, predicate, candidates)); - } - - /** - * - * @param predicate the testing function for if the current block information is valid - * @param candidates the valid list of BlockInfos that this traceability predicate allows - */ - public PatternPredicate(Function predicate, - @Nullable List candidates) { - this("Unknown", predicate, candidates); - } - - public PatternPredicate(Function predicate) { - this(predicate, null); - } - - public PatternPredicate(BasePredicate basePredicate) { - subPredicates.add(basePredicate); - } - - /** - * Mark it as the controller of this multi. Normally you won't call it yourself. Use plz. - */ - public PatternPredicate setController() { - isController = true; - return this; - } - - public boolean hasAir() { - return hasAir; - } - - /** - * Add tooltips for candidates. They are shown in JEI Pages. - */ - public PatternPredicate addTooltips(Component... tips) { - if (tips.length > 0) { - List tooltips = Arrays.stream(tips).toList(); - subPredicates.forEach(predicate -> { - if (predicate.tooltips == null) { - predicate.tooltips = new ArrayList<>(); - } - predicate.tooltips.addAll(tooltips); - }); - } - return this; - } - - public List> getCandidates() { - return subPredicates.stream() - .map(BasePredicate::getCandidates) - .collect(Collectors.toList()); - } - - /** - * Set the minimum number of candidate blocks. - */ - public PatternPredicate setMinGlobalLimited(int min) { - subPredicates.forEach(p -> p.minCount = min); - return this; - } - - public PatternPredicate setMinGlobalLimited(int min, int previewCount) { - return this.setMinGlobalLimited(min).setPreviewCount(previewCount); - } - - /** - * Set the maximum number of candidate blocks. - */ - public PatternPredicate setMaxGlobalLimited(int max) { - subPredicates.forEach(p -> p.maxCount = max); - return this; - } - - public PatternPredicate setMaxGlobalLimited(int max, int previewCount) { - return this.setMaxGlobalLimited(max).setPreviewCount(previewCount); - } - - /** - * Set the minimum number of candidate blocks for each slice layer. - */ - public PatternPredicate setMinLayerLimited(int min) { - subPredicates.forEach(p -> p.minSliceCount = min); - return this; - } - - public PatternPredicate setMinLayerLimited(int min, int previewCount) { - return this.setMinLayerLimited(min).setPreviewCount(previewCount); - } - - /** - * Set the maximum number of candidate blocks for each slice layer. - */ - public PatternPredicate setMaxLayerLimited(int max) { - subPredicates.forEach(p -> p.maxSliceCount = max); - return this; - } - - public PatternPredicate setMaxLayerLimited(int max, int previewCount) { - return this.setMaxLayerLimited(max).setPreviewCount(previewCount); - } - - /** - * Sets the Minimum and Maximum limit to the passed value - * - * @param limit The Maximum and Minimum limit - */ - public PatternPredicate setExactLimit(int limit) { - return this.setMinGlobalLimited(limit).setMaxGlobalLimited(limit); - } - - /** - * Set the number of it appears in JEI pages. It only affects JEI preview. (The specific number) - */ - public PatternPredicate setPreviewCount(int count) { - subPredicates.forEach(p -> p.previewCount = count); - return this; - } - - public PatternPredicate setPriority(int priority) { - subPredicates.forEach(p -> p.priority = priority); - return this; - } - - /** - * Set renderMask. - */ - public PatternPredicate disableRenderFormed() { - subPredicates.forEach(p -> p.disableRenderFormed = true); - return this; - } - - public PatternPredicate setNBTParser(String nbtParser) { - subPredicates.forEach(p -> p.nbtParser = nbtParser); - return this; - } - - public List test(CurrentBlockInfo currBlock, Object2IntMap globalCache, - @Nullable Object2IntMap layerCache) { - List lastErrors = new ArrayList<>(); - for (BasePredicate p : subPredicates) { - PatternError error = p.testLimited(currBlock, globalCache, layerCache); - if (error == null) return List.of(); - lastErrors.add(error); - } - return lastErrors; - } - - public PatternPredicate or(@Nullable PatternPredicate other) { - if (other != null) { - PatternPredicate newPredicate = new PatternPredicate(this); - newPredicate.hasAir = newPredicate.hasAir || this == AIR || other == AIR; - newPredicate.subPredicates.addAll(other.subPredicates); - newPredicate.subPredicates.sort(predicateComparator); - return newPredicate; - } - return this; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (!(obj instanceof PatternPredicate pred)) return false; - - return this.hasAir == pred.hasAir && - this.isController == pred.isController && - this.subPredicates.equals(pred.subPredicates); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java new file mode 100644 index 00000000000..611b01a3216 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -0,0 +1,64 @@ +package com.gregtechceu.gtceu.api.multiblock; + +import com.gregtechceu.gtceu.api.multiblock.error.PatternError; +import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.function.Consumer; + +public record PredicateContext(CurrentBlockInfo blockInfo, + Consumer errorConsumer, + Object2IntMap globalCache, + @Nullable Object2IntMap layerCache) { + + /// accepts a pattern error + /// @return false + public boolean error(PatternError error) { + this.errorConsumer.accept(error); + return false; + } + + /// @return the current Level + public Level level() { + return Objects.requireNonNull(blockInfo.getLevel()); + } + + /// @return the current Block State + public BlockState state() { + return this.blockInfo.retrieveCurrentBlockState(); + } + + /// @return the current Fluid + public Fluid fluid() { + return fluidState().getType(); + } + + /// @return the current Fluid State + public FluidState fluidState() { + return state().getFluidState(); + } + + /// @return the current block pos (immutable) + public BlockPos pos() { + return this.blockInfo.getPos().immutable(); + } + + public @Nullable BlockEntity blockEntity() { + return this.blockInfo.retrieveCurrentBlockEntity(); + } + + public static PredicateContext of(CurrentBlockInfo blockInfo, Consumer errorConsumer, + Object2IntMap cache, + @Nullable Object2IntMap layerCache) { + return new PredicateContext(blockInfo, errorConsumer, cache, layerCache); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 0ff93cae4bb..1774e57c013 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -13,16 +13,17 @@ import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; import com.gregtechceu.gtceu.api.machine.multiblock.PartAbility; import com.gregtechceu.gtceu.api.multiblock.error.BlockMatchingError; +import com.gregtechceu.gtceu.api.multiblock.error.PartAbilityError; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.error.PlaceholderError; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; -import com.gregtechceu.gtceu.api.multiblock.predicates.*; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.pipenet.IPipeNode; import com.gregtechceu.gtceu.api.recipe.GTRecipeType; import com.gregtechceu.gtceu.common.data.GTMaterialBlocks; import com.gregtechceu.gtceu.config.ConfigHolder; - +import com.tterrag.registrate.util.entry.RegistryEntry; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.tags.TagKey; @@ -30,15 +31,16 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; - -import com.tterrag.registrate.util.entry.RegistryEntry; -import dev.latvian.mods.rhino.util.HideFromJS; +import net.minecraft.world.level.material.FluidState; +import net.minecraftforge.registries.ForgeRegistries; import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.Validate; import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.function.Function; -import java.util.stream.Stream; +import java.util.function.Predicate; +import java.util.function.Supplier; public class Predicates { @@ -48,111 +50,349 @@ public class Predicates { */ public static final PlaceholderError PLACEHOLDER = new PlaceholderError(BlockPos.ZERO, Collections.emptyList()); - public static PatternPredicate controller(MultiblockMachineDefinition def) { + public static BasePredicate controller(MultiblockMachineDefinition def) { return controller(blocks(def.getBlock())); } - public static PatternPredicate controller(PatternPredicate predicate) { - return predicate.setController(); + public static BasePredicate controller(BasePredicate predicate) { + return new BasePredicate() { + + @Override + public boolean test(PredicateContext ctx) { + return predicate.test(ctx); + } + + @Override + public List computeCandidates() { + return predicate.computeCandidates(); + } + + @Override + public String getDebugName() { + return "Controller{" + predicate + "}"; + } + + @Override + public boolean isController() { + return true; + } + }; } - public static PatternPredicate states(BlockState... allowedStates) { - var candidates = new ArrayList(); + public static BasePredicate states(@Nullable String debugName, BlockState... allowedStates) { + List states = new ArrayList<>(); for (BlockState state : allowedStates) { - candidates.add(state); + states.add(state); if (state.getBlock() instanceof ActiveBlock block) { - candidates.add(block.changeActive(state, !block.isActive(state))); + states.add(block.changeActive(state, !block.isActive(state))); } } - return new PatternPredicate(new PredicateStates(candidates.toArray(BlockState[]::new))); + return new BasePredicate() { + + @Override + public boolean testInternal(PredicateContext ctx) { + return states.contains(ctx.state()) || ctx.error(PLACEHOLDER); + } + + @Override + public List computeCandidates() { + return states.stream().map(BlockInfo::fromBlockState).toList(); + } + + @Override + public String getDebugName() { + if (debugName == null) { + return "States{" + states.size() + "}"; + } else { + return "States#" + debugName + "{" + states.size() + "}"; + + } + } + }; } - @HideFromJS - public static PatternPredicate blocks(String debugName, Block... blocks) { - return new PatternPredicate(new PredicateBlocks(debugName, blocks)); + public static BasePredicate blocks(Block block) { + return new BasePredicate() { + + @Override + public boolean testInternal(PredicateContext ctx) { + return ctx.state().is(block) || ctx.error(new BlockMatchingError(ctx.pos(), List.of(block))); + } + + @Override + public List computeCandidates() { + return List.of(BlockInfo.fromBlock(block)); + } + + @Override + public String getDebugName() { + return block.toString(); + } + }; } - public static PatternPredicate blocks(Block... blocks) { - return new PatternPredicate(new PredicateBlocks(blocks)); + public static BasePredicate blocks(Block... blocks) { + return blocks(null, blocks); } - /* - * public static PatternPredicate blocks(IMachineBlock... blocks) { - * return new PatternPredicate( - * new PredicateBlocks(Arrays.stream(blocks).map(IMachineBlock::self).toArray(Block[]::new))); - * } - */ + public static BasePredicate blocks(@Nullable String debugName, Block... blocks) { + return new BasePredicate() { + + private final List blockList = Arrays.asList(blocks); + + @Override + public boolean testInternal(PredicateContext ctx) { + return blockList.contains(ctx.state().getBlock()) || + ctx.error(new BlockMatchingError(ctx.pos(), this.blockList)); + } - public static PatternPredicate machines(@Nullable MachineDefinition... definitions) { - return blocks(Arrays.stream(definitions).filter(Objects::nonNull).map(MachineDefinition::get) - .toArray(MetaMachineBlock[]::new)); + @Override + public List computeCandidates() { + return blockList.stream() + .map(BlockInfo::fromBlock) + .toList(); + } + + @Override + public String getDebugName() { + if (debugName == null) { + return "Blocks{" + blockList.size() + "}"; + } else { + return "Blocks#" + debugName + "{" + blockList.size() + "}"; + } + } + }; } - public static PatternPredicate blockTag(TagKey tag) { - return new PatternPredicate(new PredicateBlockTag(tag)); + public static BasePredicate machines(MachineDefinition... definitions) { + Validate.noNullElements(definitions, "MachineDefinition array has null element at index %s"); + return blocks(Arrays.stream(definitions).map(MachineDefinition::get).toArray(MetaMachineBlock[]::new)); } - public static PatternPredicate fluids(Fluid... fluids) { - return new PatternPredicate(new PredicateFluids(fluids)); + public static BasePredicate blockTag(TagKey tag) { + return new BasePredicate() { + + @Override + public boolean testInternal(PredicateContext ctx) { + return ctx.state().is(tag) || ctx.error(PLACEHOLDER); + } + + @Override + public List computeCandidates() { + return Objects.requireNonNull(ForgeRegistries.BLOCKS.tags()) + .getTag(tag) + .stream() + .map(BlockInfo::fromBlock) + .toList(); + } + + @Override + public String getDebugName() { + return "BlockTag{" + tag.location() + "}"; + } + }; } - public static PatternPredicate fluidTag(TagKey tag) { - return new PatternPredicate(new PredicateFluidTag(tag)); + public static BasePredicate fluids(Fluid... fluids) { + return new BasePredicate() { + + final List fluidList = Arrays.asList(fluids); + + @Override + public boolean testInternal(PredicateContext ctx) { + return fluidList.contains(ctx.fluid()) || ctx.error(PLACEHOLDER); + } + + @Override + public List computeCandidates() { + return fluidList.stream() + .map(Fluid::defaultFluidState) + .map(FluidState::createLegacyBlock) + .map(BlockInfo::fromBlockState) + .toList(); + } + + @Override + public String getDebugName() { + return "Fluids{" + fluidList.size() + "}"; + } + }; } - public static PatternPredicate custom(Function predicate, - @Nullable List candidates) { - return new PatternPredicate(predicate, candidates); + public static BasePredicate fluidTag(TagKey tag) { + return new BasePredicate() { + @Override + public boolean testInternal(PredicateContext ctx) { + return ctx.fluidState().is(tag) || ctx.error(PLACEHOLDER); + } + + @Override + public List computeCandidates() { + return Objects.requireNonNull(ForgeRegistries.FLUIDS.tags()) + .getTag(tag).stream() + .map(BlockInfo::fromFluid) + .toList(); + } + + @Override + public String getDebugName() { + return "Fluids{" + tag.location() + "}"; + } + }; } - public static PatternPredicate any() { - return PatternPredicate.ANY; + public static BasePredicate customFunction(Function predicate, + @Nullable List candidates) { + return customPredicate(ctx -> { + PatternError error = predicate.apply(ctx.blockInfo()); + return error == null || ctx.error(error); + }, candidates); } - public static PatternPredicate air() { - return PatternPredicate.AIR; + public static BasePredicate customPredicate(Predicate predicate, + @Nullable List candidates) { + return new BasePredicate() { + @Override + public boolean testInternal(PredicateContext ctx) { + return predicate.test(ctx); + } + + @Override + public List computeCandidates() { + return Optional.ofNullable(candidates).orElse(Collections.emptyList()); + } + + @Override + public String getDebugName() { + return "Custom"; + } + }; } - public static PatternPredicate abilities(PartAbility... abilities) { - StringJoiner sb = new StringJoiner("-"); - for (PartAbility ability : abilities) { - sb.add(ability.getName()); - } - String debugName = sb.toString(); + public static BasePredicate any() { + return BasePredicate.ANY; + } - PatternPredicate predicate = new PatternPredicate(); - for (var ability : abilities) { - predicate.subPredicates.add(new PredicatePartAbility(debugName, ability)); - } - return predicate; + public static BasePredicate air() { + return BasePredicate.AIR; } - public static PatternPredicate ability(PartAbility ability, int... tiers) { - StringJoiner sb = new StringJoiner("-"); - for (int tier : tiers) { - sb.add(GTValues.VN[tier]); - } - String debugName = ability.getName() + sb; + public static BasePredicate abilities(PartAbility ability) { + return new BasePredicate() { + + final Collection blockList = ability.getAllBlocks(); + + @Override + public boolean testInternal(PredicateContext ctx) { + return blockList.contains(ctx.state().getBlock()) || ctx.error(new PartAbilityError(ctx.pos(), ability)); + } + + @Override + public List computeCandidates() { + return blockList.stream() + .map(BlockInfo::fromBlock) + .toList(); + } + + @Override + public String getDebugName() { + return "Ability{" + ability.getName() + "}"; + } + }; + } + + public static BasePredicate abilities(PartAbility... abilities) { + return new BasePredicate() { + + final List abilityList = List.of(abilities); + final String debugName = computeDebugName(); + + @Override + public boolean testInternal(PredicateContext ctx) { + List errors = new ArrayList<>(); + for (PartAbility ability : this.abilityList) { + if (ability.getAllBlocks().contains(ctx.state().getBlock())) { + return true; + } else { + errors.add(new PartAbilityError(ctx.pos(), ability)); + } + } + errors.forEach(ctx::error); + return false; + } + + @Override + public List computeCandidates() { + return this.abilityList.stream() + .flatMap(ability -> ability.getAllBlocks().stream()) + .map(BlockInfo::fromBlock) + .toList(); + } + + private String computeDebugName() { + StringJoiner sb = new StringJoiner(", "); + for (PartAbility ability : this.abilityList) { + sb.add(ability.getName()); + } + return sb.toString(); + } + + @Override + public String getDebugName() { + return "Abilities{" + debugName + "}"; + } + }; + } + + public static BasePredicate ability(PartAbility ability, int... tiers) { + return new BasePredicate() { + + final Collection blockList = ability.getBlocks(tiers); + final String debugName = computeDebugName(); + + @Override + public boolean testInternal(PredicateContext ctx) { + return blockList.contains(ctx.state().getBlock()) || ctx.error(new PartAbilityError(ctx.pos(), ability)); + } + + @Override + public List computeCandidates() { + return blockList.stream() + .map(BlockInfo::fromBlock) + .toList(); + } + + private String computeDebugName() { + StringJoiner sb = new StringJoiner("-"); + for (int tier : tiers) { + sb.add(GTValues.VN[tier]); + } + return ability.getName() + sb; + } - return new PatternPredicate(new PredicatePartAbility(debugName, ability, tiers)); + @Override + public String getDebugName() { + return "Ability{" + debugName + "}"; + } + }; } - public static PatternPredicate autoAbilities(GTRecipeType... recipeType) { + public static BasePredicate autoAbilities(GTRecipeType... recipeType) { return autoAbilities(recipeType, true, true, true, true, true, true); } - public static PatternPredicate autoAbilities(GTRecipeType[] recipeType, + public static BasePredicate autoAbilities(GTRecipeType[] recipeType, boolean checkEnergyIn, boolean checkEnergyOut, boolean checkItemIn, boolean checkItemOut, boolean checkFluidIn, boolean checkFluidOut) { - PatternPredicate predicate = new PatternPredicate(); + List predicates = new ArrayList<>(); if (checkEnergyIn) { for (var type : recipeType) { if (type.getMaxInputs(EURecipeCapability.CAP) > 0) { - predicate = predicate.or(abilities(PartAbility.INPUT_ENERGY).setMinGlobalLimited(1) - .setMaxGlobalLimited(2).setPreviewCount(1) - .setPriority(1)); + predicates.add(abilities(PartAbility.INPUT_ENERGY) + .setMinCount(1).setMaxCount(2) + .setPreviewCount(1).setPriority(1)); break; } } @@ -160,9 +400,9 @@ public static PatternPredicate autoAbilities(GTRecipeType[] recipeType, if (checkEnergyOut) { for (var type : recipeType) { if (type.getMaxOutputs(EURecipeCapability.CAP) > 0) { - predicate = predicate.or(abilities(PartAbility.OUTPUT_ENERGY).setMinGlobalLimited(1) - .setMaxGlobalLimited(2).setPreviewCount(1) - .setPriority(1)); + predicates.add(abilities(PartAbility.OUTPUT_ENERGY) + .setMinCount(1).setMaxCount(2) + .setPreviewCount(1).setPriority(1)); break; } } @@ -170,8 +410,8 @@ public static PatternPredicate autoAbilities(GTRecipeType[] recipeType, if (checkItemIn) { for (var type : recipeType) { if (type.getMaxInputs(ItemRecipeCapability.CAP) > 0) { - predicate = predicate.or(abilities(PartAbility.IMPORT_ITEMS).setPreviewCount(1) - .setPriority(2)); + predicates.add(abilities(PartAbility.IMPORT_ITEMS) + .setPreviewCount(1).setPriority(2)); break; } } @@ -179,8 +419,8 @@ public static PatternPredicate autoAbilities(GTRecipeType[] recipeType, if (checkItemOut) { for (var type : recipeType) { if (type.getMaxOutputs(ItemRecipeCapability.CAP) > 0) { - predicate = predicate.or(abilities(PartAbility.EXPORT_ITEMS).setPreviewCount(1) - .setPriority(2)); + predicates.add(abilities(PartAbility.EXPORT_ITEMS) + .setPreviewCount(1).setPriority(2)); break; } } @@ -188,8 +428,8 @@ public static PatternPredicate autoAbilities(GTRecipeType[] recipeType, if (checkFluidIn) { for (var type : recipeType) { if (type.getMaxInputs(FluidRecipeCapability.CAP) > 0) { - predicate = predicate.or(abilities(PartAbility.IMPORT_FLUIDS).setPreviewCount(1) - .setPriority(3)); + predicates.add(abilities(PartAbility.IMPORT_FLUIDS) + .setPreviewCount(1).setPriority(3)); break; } } @@ -197,88 +437,140 @@ public static PatternPredicate autoAbilities(GTRecipeType[] recipeType, if (checkFluidOut) { for (var type : recipeType) { if (type.getMaxOutputs(FluidRecipeCapability.CAP) > 0) { - predicate = predicate.or(abilities(PartAbility.EXPORT_FLUIDS).setPreviewCount(1) - .setPriority(3)); + predicates.add(abilities(PartAbility.EXPORT_FLUIDS) + .setPreviewCount(1).setPriority(3)); break; } } } - return predicate; + return BasePredicate.or("AutoAbilities", predicates); } - public static PatternPredicate autoAbilities(boolean checkMaintenance, boolean checkMuffler, + public static BasePredicate autoAbilities(boolean checkMaintenance, boolean checkMuffler, boolean checkParallel) { - PatternPredicate predicate = new PatternPredicate(); + List predicates = new ArrayList<>(); if (checkMaintenance) { - predicate = predicate.or(abilities(PartAbility.MAINTENANCE) - .setMinGlobalLimited(ConfigHolder.INSTANCE.machines.enableMaintenance ? 1 : 0) - .setMaxGlobalLimited(1) + predicates.add(abilities(PartAbility.MAINTENANCE) + .setMinCount(ConfigHolder.INSTANCE.machines.enableMaintenance ? 1 : 0) + .setMaxCount(1) .setPriority(1)); } if (checkMuffler) { - predicate = predicate.or(abilities(PartAbility.MUFFLER) + predicates.add(abilities(PartAbility.MUFFLER) .setExactLimit(1) .setPriority(2)); } if (checkParallel) { - predicate = predicate.or(abilities(PartAbility.PARALLEL_HATCH) - .setMaxGlobalLimited(1) + predicates.add(abilities(PartAbility.PARALLEL_HATCH) + .setMaxCount(1) .setPreviewCount(1) .setPriority(3)); } - return predicate; + return BasePredicate.or("AutoAbilities", predicates); } - public static PatternPredicate heatingCoils() { - return new PatternPredicate("Heating Coils", worldState -> { - var blockState = worldState.getBlockState(); - for (var entry : GTCEuAPI.HEATING_COILS.entrySet()) { - if (blockState.is(entry.getValue().get())) { - return null; + public static BasePredicate heatingCoils() { + return new BasePredicate() {{ + addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")); + setPriority(0); + } + + private List getCoils() { + return GTCEuAPI.HEATING_COILS.values() + .stream() + .map(Supplier::get) + .map(Block.class::cast) + .toList(); + } + + @Override + public boolean testInternal(PredicateContext ctx) { + var blockState = ctx.state(); + List coils = this.getCoils(); + for (var blockCoil : coils) { + if (blockState.is(blockCoil)) { + return true; + } } + return ctx.error(new BlockMatchingError(ctx.pos(), coils)); } - return new BlockMatchingError(worldState.getBlockPos(), GTCEuAPI.HEATING_COILS.values().stream() - .map(coilBlockSupplier -> (Block) coilBlockSupplier.get()).toList()); - }, GTCEuAPI.HEATING_COILS.entrySet().stream() - // sort to make autogenerated jei previews not pick random coils each game load - .sorted(Comparator.comparingInt(e -> e.getKey().getTier())) - .map(e -> new BlockInfo(e.getValue().get())) - .toList()) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")) - .setPriority(0); + + @Override + public List computeCandidates() { + return GTCEuAPI.HEATING_COILS.entrySet().stream() + // sort to make autogenerated jei previews not pick random coils each game load + .sorted(Comparator.comparingInt(e -> e.getKey().getTier())) + .map(Map.Entry::getValue) + .map(Supplier::get) + .map(BlockInfo::fromBlock) + .toList(); + } + + @Override + public String getDebugName() { + return "HeatingCoils"; + } + }; } - public static PatternPredicate cleanroomFilters() { - return new PatternPredicate("Cleanroom Filters", worldState -> { - var blockState = worldState.getBlockState(); - for (var entry : GTCEuAPI.CLEANROOM_FILTERS.entrySet()) { - if (blockState.is(entry.getValue().get())) { - return null; + public static BasePredicate cleanroomFilters() { + return new BasePredicate() {{ + addTooltips(Component.translatable("gtceu.multiblock.pattern.cleanroom")); + } + @Override + public boolean testInternal(PredicateContext ctx) { + var blockState = ctx.state(); + for (var entry : GTCEuAPI.CLEANROOM_FILTERS.entrySet()) { + if (blockState.is(entry.getValue().get())) { + return true; + } } + return ctx.error(PLACEHOLDER); + } + + @Override + public List computeCandidates() { + return GTCEuAPI.CLEANROOM_FILTERS.entrySet().stream() + .sorted(Comparator.comparingInt(e -> e.getKey().getCleanroomType().getTier())) + .map(e -> new BlockInfo(e.getValue().get())) + .toList(); + } + + @Override + public String getDebugName() { + return "CleanroomFilters"; } - return new BlockMatchingError(worldState.getBlockPos(), - GTCEuAPI.CLEANROOM_FILTERS.entrySet().stream().map(e -> e.getValue().get()).toList()); - }, GTCEuAPI.CLEANROOM_FILTERS.entrySet().stream() - .sorted(Comparator.comparingInt(e -> e.getKey().getCleanroomType().getTier())) - .map(e -> new BlockInfo(e.getValue().get())) - .toList()) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.filters")); + }; } - public static PatternPredicate powerSubstationBatteries() { - return new PatternPredicate("PSS Batteries", worldState -> { - var state = worldState.getBlockState(); - for (var entry : GTCEuAPI.PSS_BATTERIES.entrySet()) { - if (state.is(entry.getValue().get())) { - return null; + public static BasePredicate powerSubstationBatteries() { + return new BasePredicate() {{ + addTooltips(Component.translatable("gtceu.multiblock.pattern.error.batteries")); + } + @Override + public boolean testInternal(PredicateContext ctx) { + var state = ctx.state(); + for (var entry : GTCEuAPI.PSS_BATTERIES.entrySet()) { + if (state.is(entry.getValue().get())) { + return true; + } } + return ctx.error(PLACEHOLDER); + } + + @Override + public List computeCandidates() { + return GTCEuAPI.PSS_BATTERIES.entrySet().stream() + .sorted(Comparator.comparingInt(e -> e.getKey().getTier())) + .map(e -> new BlockInfo(e.getValue().get().defaultBlockState(), null)) + .toList(); } - return Predicates.PLACEHOLDER; - }, GTCEuAPI.PSS_BATTERIES.entrySet().stream() - .sorted(Comparator.comparingInt(e -> e.getKey().getTier())) - .map(e -> new BlockInfo(e.getValue().get().defaultBlockState())) - .toList()) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.batteries")); + + @Override + public String getDebugName() { + return "PSSBatteries"; + } + }; /* * return new TraceabilityPredicate(blockWorldState -> { @@ -306,24 +598,13 @@ public static PatternPredicate powerSubstationBatteries() { */ } - public static @Nullable PatternPredicate dataHatchPredicate() { + public static @Nullable BasePredicate dataHatchPredicate() { // if research is enabled, require the data hatch, otherwise use a grate instead if (ConfigHolder.INSTANCE.machines.enableResearch) { // TODO xor predicate matching :) - return new PatternPredicate(state -> { - Block block = state.retrieveCurrentBlockState().getBlock(); - if (PartAbility.DATA_ACCESS.isApplicable(block) || - PartAbility.OPTICAL_DATA_RECEPTION.isApplicable(block)) { - return null; - } - List blocks = new ArrayList<>( - List.of(PartAbility.DATA_ACCESS.getAllBlocks().toArray(new Block[0]))); - blocks.addAll(PartAbility.OPTICAL_DATA_RECEPTION.getAllBlocks()); - return new BlockMatchingError(state.getBlockPos(), blocks); - }, Stream - .concat(PartAbility.DATA_ACCESS.getAllBlocks().stream(), - PartAbility.OPTICAL_DATA_RECEPTION.getAllBlocks().stream()) - .map(BlockInfo::fromBlock).toList()).setExactLimit(1); + return abilities(PartAbility.DATA_ACCESS, PartAbility.OPTICAL_DATA_RECEPTION) + .setExactLimit(1) + .setPriority(1); } return null; } @@ -331,7 +612,7 @@ public static PatternPredicate powerSubstationBatteries() { /** * Use this predicate for Frames in your Multiblock. Allows for Framed Pipes as well as normal Frame blocks. */ - public static PatternPredicate frames(Material... frameMaterials) { + public static BasePredicate frames(Material... frameMaterials) { var frameBlocks = Arrays.stream(frameMaterials) .map(m -> GTMaterialBlocks.MATERIAL_BLOCKS.get(TagPrefix.frameGt, m)) .filter(Objects::nonNull) @@ -339,13 +620,26 @@ public static PatternPredicate frames(Material... frameMaterials) { .map(RegistryEntry::get) .toArray(Block[]::new); return blocks(frameBlocks) - .or(new PatternPredicate(blockWorldState -> { - BlockEntity tileEntity = blockWorldState.getBlockEntity(); - if (!(tileEntity instanceof IPipeNode pipeNode)) { - return Predicates.PLACEHOLDER; + .or(new BasePredicate() { + @Override + public boolean testInternal(PredicateContext ctx) { + BlockEntity tileEntity = ctx.blockEntity(); + if (!(tileEntity instanceof IPipeNode pipeNode)) { + return ctx.error(PLACEHOLDER); + } + return ArrayUtils.contains(frameMaterials, pipeNode.getFrameMaterial()) || + ctx.error(PLACEHOLDER); + } + + @Override + public List computeCandidates() { + return Arrays.stream(frameBlocks).map(BlockInfo::fromBlock).toList(); + } + + @Override + public String getDebugName() { + return "FramedPipes"; } - return ArrayUtils.contains(frameMaterials, pipeNode.getFrameMaterial()) ? null : - Predicates.PLACEHOLDER; - }, Arrays.stream(frameBlocks).map(BlockInfo::fromBlock).toList())); + }); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java index 170beb040a6..615ea89a5d8 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java @@ -1,6 +1,5 @@ package com.gregtechceu.gtceu.api.multiblock.error; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.registry.GTRegistries; @@ -30,9 +29,10 @@ public PatternError(@Nullable BlockPos pos, List> candidates) { this.candidates = candidates; } - public PatternError(@Nullable BlockPos pos, PatternPredicate predicate) { - this(pos, predicate.getCandidates()); - } + // TODO FIX +// public PatternError(@Nullable BlockPos pos, PatternPredicate predicate) { +// this(pos, predicate.getCandidates()); +// } public PatternError(@Nullable BlockPos pos, BasePredicate failingPredicate) { this(pos, Collections.singletonList(failingPredicate.getCandidates())); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/SinglePredicateError.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/SinglePredicateError.java index 29a21e20d43..075e1ae6bf2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/SinglePredicateError.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/SinglePredicateError.java @@ -42,9 +42,14 @@ public class SinglePredicateError extends PatternError { public final int predMaxLayerCount; public final String debugName; - public SinglePredicateError(BasePredicate failingPredicate, ErrorType type, int actualCount) { - this(type, actualCount, failingPredicate.minCount, failingPredicate.maxCount, failingPredicate.minSliceCount, - failingPredicate.maxSliceCount, failingPredicate.getPredicateName(), + public SinglePredicateError(BasePredicate failingPredicate, + ErrorType type, int actualCount) { + this(type, actualCount, + failingPredicate.getMinCount(), + failingPredicate.getMaxCount(), + failingPredicate.getMinSliceCount(), + failingPredicate.getMaxSliceCount(), + failingPredicate.toString(), failingPredicate.getCandidates()); } @@ -95,6 +100,22 @@ public PatternErrorUI getPatternErrorUIModifier() { }; } + public static SinglePredicateError maxCount(BasePredicate failingPredicate, int actualCount) { + return new SinglePredicateError(failingPredicate, ErrorType.MAX_COUNT, actualCount); + } + + public static SinglePredicateError minCount(BasePredicate failingPredicate, int actualCount) { + return new SinglePredicateError(failingPredicate, ErrorType.MIN_COUNT, actualCount); + } + + public static SinglePredicateError maxLayerCount(BasePredicate failingPredicate, int actualCount) { + return new SinglePredicateError(failingPredicate, ErrorType.MAX_LAYER_COUNT, actualCount); + } + + public static SinglePredicateError minLayerCount(BasePredicate failingPredicate, int actualCount) { + return new SinglePredicateError(failingPredicate, ErrorType.MIN_LAYER_COUNT, actualCount); + } + @Getter public enum ErrorType implements StringRepresentable { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 0443a0349fc..375dbcca50d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -1,10 +1,9 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; -import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; @@ -19,8 +18,8 @@ import lombok.Getter; import org.jetbrains.annotations.Nullable; -import java.util.List; -import java.util.Objects; +import java.util.*; +import java.util.function.BiPredicate; public class BlockPattern implements IBlockPattern { @@ -39,12 +38,12 @@ public class BlockPattern implements IBlockPattern { @Getter protected final SliceStrategy sliceStrategy; @Getter - protected final Char2ObjectMap predicates; + protected final Char2ObjectMap predicates; public BlockPattern(PatternSlice[] slices, SliceStrategy sliceStrategy, int[] dimensions, RelativeDirection[] directions, @Nullable OriginOffset offset, @Nullable OriginOffset anchorOffset, - Char2ObjectMap predicates, + Char2ObjectMap predicates, char centerChar) { this.slices = slices; this.sliceStrategy = sliceStrategy; @@ -148,9 +147,9 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c patternState.globalCount.clear(); patternState.layerCount.clear(); // Make sure every prerdicate with a minvalue is checked - for (PatternPredicate predicate : predicates.values()) { - for (BasePredicate basePredicate : predicate.subPredicates) { - if (basePredicate.minCount > 0) { + for (BasePredicate predicate : predicates.values()) { + for (BasePredicate basePredicate : predicate.expand()) { + if (basePredicate.getMinCount() > 0) { patternState.globalCount.putIfAbsent(basePredicate, 0); } } @@ -170,10 +169,9 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c if (!sliceStrategy.check(patternState, isFlipped)) return false; for (Object2IntMap.Entry entry : patternState.globalCount.object2IntEntrySet()) { - if (entry.getIntValue() < entry.getKey().minCount) { - patternState - .setError(new SinglePredicateError(entry.getKey(), SinglePredicateError.ErrorType.MIN_COUNT, - entry.getIntValue())); + if (entry.getIntValue() < entry.getKey().getMinCount()) { + patternState.setError(SinglePredicateError + .minCount(entry.getKey(), entry.getIntValue())); return false; } } @@ -214,18 +212,19 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p for (int stringIdx = 0; stringIdx < dimensions[1]; stringIdx++) { for (int charIdx = 0; charIdx < dimensions[2]; charIdx++) { patternState.currentBlockInfo.setCurrentPos(charPos); - PatternPredicate pred = predicates.get(slice.charAt(stringIdx, charIdx)); + BasePredicate pred = predicates.get(slice.charAt(stringIdx, charIdx)); - if (!pred.equals(PatternPredicate.ANY)) { + if (!pred.isAny()) { BlockEntity blockEntity = patternState.currentBlockInfo.retrieveCurrentBlockEntity(); BlockState state = patternState.currentBlockInfo.retrieveCurrentBlockState(); patternState.cache.put(charPos.asLong(), new BlockInfo(state, blockEntity)); } - List errors = pred.test(patternState.currentBlockInfo, patternState.globalCount, - patternState.layerCount); - if (!errors.isEmpty()) { - patternState.setErrors(errors); + + List res = new ArrayList<>(); + boolean passed = pred.test(patternState.toContext(res::add)); + if (!passed) { + patternState.setErrors(res); return false; } @@ -237,10 +236,9 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p } for (Object2IntMap.Entry entry : patternState.layerCount.object2IntEntrySet()) { - if (entry.getIntValue() < entry.getKey().minSliceCount) { + if (entry.getIntValue() < entry.getKey().getMinSliceCount()) { patternState.setError( - new SinglePredicateError(entry.getKey(), SinglePredicateError.ErrorType.MIN_LAYER_COUNT, - entry.getIntValue())); + SinglePredicateError.minLayerCount(entry.getKey(), entry.getIntValue())); return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandableMultiblockPatternBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandableMultiblockPatternBuilder.java index 9617bb8545b..a7e68a609e6 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandableMultiblockPatternBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandableMultiblockPatternBuilder.java @@ -1,6 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import net.minecraft.core.BlockPos; @@ -21,7 +21,7 @@ public class ExpandableMultiblockPatternBuilder { @Setter protected @Nullable ExpandablePattern.BoundsConstraintProvider constraintProvider; @Setter - protected @Nullable BiFunction, PatternPredicate> predicateProvider; + protected @Nullable BiFunction, BasePredicate> predicateProvider; protected final RelativeDirection[] directions = new RelativeDirection[3]; private ExpandableMultiblockPatternBuilder(RelativeDirection aisleDir, RelativeDirection stringDir, diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index 2953e9c2f46..de2d0a26526 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -1,8 +1,8 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; @@ -46,7 +46,7 @@ public interface BoundsConstraintProvider { @Setter protected @Nullable BoundsConstraintProvider boundsConstraints = null; @Getter - protected final BiFunction, PatternPredicate> predicateProvider; + protected final BiFunction, BasePredicate> predicateProvider; @Getter protected final OriginOffset offset = new OriginOffset(); @@ -54,7 +54,7 @@ public interface BoundsConstraintProvider { protected final RelativeDirection[] directions; public ExpandablePattern(BoundsProvider boundsProvider, - BiFunction, PatternPredicate> predicateProvider, + BiFunction, BasePredicate> predicateProvider, RelativeDirection[] directions) { this.boundsProvider = boundsProvider; this.predicateProvider = predicateProvider; @@ -155,7 +155,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c // aisle count, y is str count, and z is char count. for (var pos : BlockPos.betweenClosed(negCorner, posCorner)) { BlockPos.MutableBlockPos mPos = pos.mutable(); - PatternPredicate pred = predicateProvider.apply(mPos, bounds); + BasePredicate pred = predicateProvider.apply(mPos, bounds); // this basically reshuffles the coordinates into absolute form from relative form mPos.set(BlockPos.ZERO).move(absolutes[0], pos.getX()).move(absolutes[1], pos.getY()).move(absolutes[2], @@ -164,23 +164,24 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c mPos = mPos.offset(translation).mutable(); patternState.currentBlockInfo.setCurrentPos(mPos); - if (!pred.equals(PatternPredicate.ANY)) { + if (!pred.isAny()) { BlockState state = patternState.currentBlockInfo.retrieveCurrentBlockState(); BlockEntity blockEntity = patternState.currentBlockInfo.retrieveCurrentBlockEntity(); patternState.cache.put(mPos.asLong(), new BlockInfo(state, blockEntity)); } - List res = pred.test(patternState.currentBlockInfo, patternState.globalCount, null); - if (!res.isEmpty()) { + List res = new ArrayList<>(); + boolean passed = pred.test(patternState.noLayer(res::add)); + if (!passed) { patternState.setErrors(res); return false; } } for (var entry : patternState.globalCount.object2IntEntrySet()) { - if (entry.getIntValue() < entry.getKey().minCount) { - patternState.setError(new SinglePredicateError(entry.getKey(), - SinglePredicateError.ErrorType.MIN_COUNT, entry.getIntValue())); + if (entry.getIntValue() < entry.getKey().getMinCount()) { + patternState.setError(SinglePredicateError.minCount(entry.getKey(), + entry.getIntValue())); return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java index 65bf2024cb1..3985bda10bf 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.google.common.base.Joiner; @@ -51,7 +51,7 @@ public class MultiblockPatternBuilder { private final List slices = new ArrayList<>(); - private final Char2ObjectMap<@Nullable PatternPredicate> symbolMap = new Char2ObjectOpenHashMap<>(); + private final Char2ObjectMap<@Nullable BasePredicate> symbolMap = new Char2ObjectOpenHashMap<>(); private final RelativeDirection[] directions = new RelativeDirection[3]; @@ -62,7 +62,7 @@ private MultiblockPatternBuilder(RelativeDirection sliceDir, RelativeDirection s directions[2] = charDir; RelativeDirection.validateFacingsArray(directions); // todo is this wanted? - this.symbolMap.put(' ', PatternPredicate.ANY); + this.symbolMap.put(' ', BasePredicate.ANY); } public MultiblockPatternBuilder sliceRepeatable(int minRepeats, int maxRepeats, String... slice) { @@ -124,7 +124,7 @@ public static MultiblockPatternBuilder start(RelativeDirection sliceDir, Relativ return new MultiblockPatternBuilder(sliceDir, stringDir, charDir); } - public MultiblockPatternBuilder where(char symbol, PatternPredicate predicate) { + public MultiblockPatternBuilder where(char symbol, BasePredicate predicate) { this.symbolMap.put(symbol, predicate); if (predicate.isController()) centerChar = symbol; return this; @@ -172,20 +172,19 @@ private void checkGlobalConstraints() { for (var entry : symbolMap.char2ObjectEntrySet()) { char symbol = entry.getCharKey(); - PatternPredicate predicate = entry.getValue(); + BasePredicate predicate = entry.getValue(); if (predicate == null) throw new IllegalArgumentException("Predicate for symbol " + symbol + " was null."); - int maxCount = -1; - for (var basePredicate : predicate.subPredicates) { - if (basePredicate.maxCount == -1) { + for (var basePredicate : predicate.expand()) { + if (basePredicate.getMaxCount() == -1) { maxCount = -1; break; } - if (basePredicate.minCount == basePredicate.maxCount) { + if (basePredicate.getMinCount() == basePredicate.getMaxCount()) { if (maxCount == -1) { - maxCount = basePredicate.minCount; + maxCount = basePredicate.getMinCount(); } else { - maxCount += basePredicate.minCount; + maxCount += basePredicate.getMinCount(); } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 9a231cd0a62..96733429c1c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -4,6 +4,7 @@ import com.gregtechceu.gtceu.api.multiblock.MultiblockWorldSavedData; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import net.minecraft.core.BlockPos; @@ -20,6 +21,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.function.Consumer; /* * Contains vital information to an instanced version of a structure pattern. @@ -109,6 +111,14 @@ public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState ne } } + public PredicateContext toContext(Consumer errorConsumer) { + return PredicateContext.of(this.cbi, errorConsumer, this.globalCount, this.layerCount); + } + + public PredicateContext noLayer(Consumer errorConsumer) { + return PredicateContext.of(this.cbi, errorConsumer, this.globalCount, null); + } + @Getter public enum CheckState { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index a39b9623795..24860b7f320 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -1,84 +1,192 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; -import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; -import com.gregtechceu.gtceu.api.mui.MultiblockSchemaInfo; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; -import com.gregtechceu.gtceu.api.multiblock.error.PatternError; +import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; -import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; -import com.gregtechceu.gtceu.client.renderer.PatternPreviewRenderer; -import com.gregtechceu.gtceu.common.item.behavior.TerminalBehavior; import com.gregtechceu.gtceu.data.lang.LangHandler; -import com.gregtechceu.gtceu.integration.recipeviewer.widgets.MultiblockPreviewWidget; - -import net.minecraft.client.Camera; -import net.minecraft.client.renderer.MultiBufferSource; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.client.event.RenderLevelStageEvent; - -import com.mojang.blaze3d.vertex.PoseStack; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import lombok.Getter; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.function.Function; -public class BasePredicate { +@Accessors(chain=true) +public abstract class BasePredicate { + + public static final BasePredicate AIR = new BasePredicate() { - @Getter - public List candidates; - public Function errorPredicate; - public @Nullable List tooltips; - public int priority = 0; - public int minCount = -1; - public int maxCount = -1; - public int minSliceCount = -1; - public int maxSliceCount = -1; - public int previewCount = -1; - public boolean disableRenderFormed = false; - public @Nullable String nbtParser; + @Override + public String getDebugName() { + return "Air"; + } + }; + + public static final BasePredicate ANY = new BasePredicate() { + + @Override + public String getDebugName() { + return "Any"; + } + }; - protected String debugName; + private @Nullable List candidates; + private @Nullable List tooltips; + @Getter @Setter + private int priority = 0; + @Getter @Setter + private int minCount = -1; + @Getter @Setter + private int maxCount = -1; + @Getter @Setter + private int minSliceCount = -1; + @Getter @Setter + private int maxSliceCount = -1; + @Getter @Setter + private int previewCount = -1; + @Getter @Setter + private boolean disableRenderFormed = false; + @Getter @Setter + private @Nullable String nbtParser; // unsure what this does - public BasePredicate() { - this.debugName = "Unknown"; - this.errorPredicate = $ -> null; - this.candidates = Collections.emptyList(); + /// custom testing logic, usually checking if blockstate/entity is correct + public boolean testInternal(PredicateContext ctx) { + return true; + } + + /// computes the candidates for this predicate, called only once + public List computeCandidates() { + return Collections.emptyList(); + } + + public abstract String getDebugName(); + + /// the main testing method + public boolean test(PredicateContext ctx) { + return testInternal(ctx) && testGlobal(ctx) && testLayer(ctx); + } + + /// test against global max count + public boolean testGlobal(PredicateContext ctx) { + ctx.globalCache().merge(this, 1, Integer::sum); + if ((minCount == -1 && maxCount == -1) || ctx.layerCache() == null) return true; + int count = ctx.globalCache().getInt(this); + if (maxCount == -1 || count <= maxCount) return true; + return ctx.error(SinglePredicateError.maxCount(this, count)); + } + + /// test against slice max count + public boolean testLayer(PredicateContext ctx) { + if (ctx.layerCache() == null) return true; + ctx.layerCache().mergeInt(this, 1, Integer::sum); + if ((minSliceCount == -1 && maxSliceCount == -1)) return true; + int count = ctx.layerCache().getInt(this); + if (maxSliceCount == -1 || count <= maxSliceCount) return true; + return ctx.error(SinglePredicateError.maxLayerCount(this, count)); + } + + public boolean isAir() { + return this == AIR; + } + + public boolean isAny() { + return this == ANY; + } + + /// used for tooltips + public boolean hasAir() { + return isAir(); + } + + /// used for tooltips + public boolean isSingle() { + return getCandidates().size() == 1; + } + + public boolean isController() { + return false; + } + + public BasePredicate setMinGlobalLimited(int min) { + return this.setMinCount(min); + } + + public BasePredicate setMinGlobalLimited(int min, int previewCount) { + return this.setMinCount(min).setPreviewCount(previewCount); + } + + public BasePredicate setMaxGlobalLimited(int max) { + return this.setMaxCount(max); + } + + public BasePredicate setMaxGlobalLimited(int max, int previewCount) { + return this.setMaxCount(max).setPreviewCount(previewCount); + } + + public BasePredicate setGlobalMinMax(int min, int max) { + return this.setMinCount(min).setMaxCount(max); + } + + public BasePredicate setMinLayerLimited(int min) { + return this.setMinSliceCount(min); + } + + public BasePredicate setMinLayerLimited(int min, int previewCount) { + return this.setMinSliceCount(min).setPreviewCount(previewCount); + } + + public BasePredicate setMaxLayerLimited(int max) { + return this.setMaxSliceCount(max); + } + + public BasePredicate setMaxLayerLimited(int max, int previewCount) { + return this.setMaxSliceCount(max).setPreviewCount(previewCount); + } + + public BasePredicate setLayerMinMax(int min, int max) { + return this.setMinSliceCount(min).setMaxSliceCount(max); } /** - * @param errorPredicate The predicate function for being a valid block state or tile entity in a pattern - * @param candidates The qualifying blocks or item stacks valid in this predicate based on information from - * either the - * {@link TerminalBehavior#use(Item, Level, Player, InteractionHand) - * Terminal Auto-Builder}, - * {@link PatternPreviewRenderer#draw(PoseStack, MultiBufferSource.BufferSource, Camera, RenderLevelStageEvent.Stage, float) - * In-world Preview} or - * {@link MultiblockPreviewWidget#MultiblockPreviewWidget(MultiblockMachineDefinition, MultiblockSchemaInfo, int, int) - * XEI Preview} + * Sets the Minimum and Maximum limit to the passed value + * + * @param limit The Maximum and Minimum limit */ - public BasePredicate(Function errorPredicate, - @Nullable List candidates) { - this("Unknown", errorPredicate, candidates); + public BasePredicate setExactLimit(int limit) { + return this.setMinCount(limit).setMaxCount(limit); + } + + public BasePredicate disabledRenderFormed() { + return setDisableRenderFormed(true); + } + + public List additionalTooltips() { + if (this.tooltips == null) { + this.tooltips = new ArrayList<>(); + } + return this.tooltips; } - public BasePredicate(String debugName, Function errorPredicate, - @Nullable List candidates) { - this.debugName = debugName; - this.errorPredicate = errorPredicate; - this.candidates = candidates != null ? candidates : Collections.emptyList(); + public BasePredicate addTooltips(Component tooltip) { + this.additionalTooltips().add(tooltip); + return this; + } + + public BasePredicate addTooltips(Component... tooltips) { + Collections.addAll(this.additionalTooltips(), tooltips); + return this; } @OnlyIn(Dist.CLIENT) - public List getTooltips(@Nullable PatternPredicate predicates) { + public List getTooltips(@Nullable BasePredicate predicate) { List result = new ArrayList<>(); if (tooltips != null) { result.addAll(tooltips); @@ -95,58 +203,77 @@ public List getTooltips(@Nullable PatternPredicate predicates) { result.add(LangHandler.getFromMultiLang("gtceu.multiblock.pattern.error.limited", 0, maxCount)); } } - if (predicates == null) return result; - if (predicates.isSingle()) { + if (predicate == null) return result; + if (predicate.isSingle()) { result.add(Component.translatable("gtceu.multiblock.pattern.single")); } - if (predicates.hasAir()) { + if (predicate.hasAir()) { result.add(Component.translatable("gtceu.multiblock.pattern.replaceable_air")); } return result; } - public @Nullable PatternError testRaw(CurrentBlockInfo currBlock) { - return errorPredicate.apply(currBlock); + public List getCandidateStacks() { + return getCandidates().stream() + .filter(BlockInfo::nonAir) + .map(info -> { + if (GTCEu.isClientSide()) { + Level level = Objects.requireNonNull(Minecraft.getInstance().level); + return info.getItemStackForm(level, BlockPos.ZERO); + } + + return info.getItemStackForm(); + }) + .toList(); + } + + public List getCandidates() { + if (candidates == null) { + candidates = computeCandidates(); + } + return candidates; } - public @Nullable PatternError testLimited(CurrentBlockInfo currBlock, - Object2IntMap globalCache, - @Nullable Object2IntMap layerCache) { - PatternError error = testGlobal(currBlock, globalCache, layerCache); - if (error != null) return error; - return testLayer(currBlock, layerCache); + public Optional getFirstCandidate() { + return Optional.of(getCandidates()) + .filter(c -> !c.isEmpty()) + .map(c -> c.get(0)); } - public @Nullable PatternError testGlobal(CurrentBlockInfo currentBlock, - Object2IntMap globalCache, - @Nullable Object2IntMap layerCache) { - PatternError error = errorPredicate.apply(currentBlock); - globalCache.mergeInt(this, (error == null ? 1 : 0), Integer::sum); - if ((minCount == -1 && maxCount == -1) || error != null || layerCache == null) return error; + public List expand() { + return List.of(this); + } - int count = globalCache.getInt(this); - if (maxCount == -1 || count <= maxCount) return null; + @Override + public String toString() { + return "Predicate{" + getDebugName() + "}"; + } - return new SinglePredicateError(this, SinglePredicateError.ErrorType.MAX_COUNT, count); + public BasePredicate or(BasePredicate other) { + return or(this, other); } - public @Nullable PatternError testLayer(CurrentBlockInfo currBlock, - @Nullable Object2IntMap layerCache) { - PatternError error = errorPredicate.apply(currBlock); - if (layerCache == null) return error; + public BasePredicate and(BasePredicate other) { + return and(this, other); + } - layerCache.mergeInt(this, (error == null ? 1 : 0), Integer::sum); - if ((minSliceCount == -1 && maxSliceCount == -1) || error != null) return error; + private static BasePredicate or(BasePredicate a, BasePredicate b) { + return or("OR", List.of(a, b)); + } - if (maxSliceCount != -1 && layerCache.getInt(this) > maxSliceCount) { - return new SinglePredicateError(this, SinglePredicateError.ErrorType.MAX_LAYER_COUNT, - layerCache.getInt(this)); - } + private static BasePredicate and(BasePredicate a, BasePredicate b) { + return and("AND", List.of(a, b)); + } - return null; + public static BasePredicate or(String debugName, List predicates) { + MultiPredicate predicate = new MultiPredicate(debugName); + predicates.forEach(predicate::or); + return predicate; } - public String getPredicateName() { - return debugName; + public static BasePredicate and(String debugName, List predicates) { + MultiPredicate predicate = new MultiPredicate(debugName); + predicates.forEach(predicate::and); + return predicate; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java new file mode 100644 index 00000000000..543c26d5a3d --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -0,0 +1,164 @@ +package com.gregtechceu.gtceu.api.multiblock.predicates; + +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringJoiner; +import java.util.stream.Stream; + +public class MultiPredicate extends BasePredicate { + + private final List predicateList = new ArrayList<>(); + private @Nullable String debugName; + private @Nullable Logic type; + + public MultiPredicate() {} + + public MultiPredicate(String debugName) { + this.debugName = debugName; + } + + @Override + public boolean test(PredicateContext ctx) { + for (BasePredicate predicate : predicateList) { + if (isOr() && predicate.test(ctx)) { + return true; + } else if (isAnd() && !predicate.test(ctx)) { + return false; + } + } + return false; + } + + @Override + public List computeCandidates() { + return predicateList.stream() + .flatMap(p -> p.getCandidates().stream()) + .toList(); + } + + @Override + public List expand() { + return predicateList.stream() + .flatMap(p -> p instanceof MultiPredicate mp ? mp.predicateList.stream() : Stream.of(p)) + .toList(); + } + + @Override + public MultiPredicate setMinCount(int minCount) { + this.predicateList.forEach(p -> p.setMinCount(minCount)); + super.setMinCount(minCount); + return this; + } + + @Override + public MultiPredicate setMaxCount(int maxCount) { + this.predicateList.forEach(p -> p.setMaxCount(maxCount)); + super.setMaxCount(maxCount); + return this; + } + + @Override + public MultiPredicate setMinSliceCount(int minSliceCount) { + this.predicateList.forEach(p -> p.setMinSliceCount(minSliceCount)); + super.setMinSliceCount(minSliceCount); + return this; + } + + @Override + public MultiPredicate setMaxSliceCount(int maxSliceCount) { + this.predicateList.forEach(p -> p.setMaxSliceCount(maxSliceCount)); + super.setMaxSliceCount(maxSliceCount); + return this; + } + + @Override + public MultiPredicate setPreviewCount(int previewCount) { + this.predicateList.forEach(p -> p.setPreviewCount(previewCount)); + super.setPreviewCount(previewCount); + return this; + } + + @Override + public MultiPredicate setDisableRenderFormed(boolean disableRenderFormed) { + this.predicateList.forEach(p -> p.setDisableRenderFormed(disableRenderFormed)); + super.setDisableRenderFormed(disableRenderFormed); + return this; + } + + public boolean isOr() { + return this.type == Logic.OR; + } + + public boolean isAnd() { + return this.type == Logic.AND; + } + + public boolean isValid() { + return this.type != null; + } + + @Override + public MultiPredicate or(BasePredicate other) { + if (!isValid()) { + this.type = Logic.OR; + } + if (!(other instanceof MultiPredicate multi)) { + this.predicateList.add(other); + return this; + } + + if (!isOr()) return multi.or(this); + + if (multi.isOr()) { + this.predicateList.addAll(multi.predicateList); + } else if (multi.isAnd()) { + this.predicateList.add(multi); + } + + return this; + } + + @Override + public MultiPredicate and(BasePredicate other) { + if (!isValid()) { + this.type = Logic.AND; + } + if (!(other instanceof MultiPredicate multi)) { + this.predicateList.add(other); + return this; + } + + if (!isAnd()) return multi.and(this); + + if (multi.isAnd()) { + this.predicateList.addAll(multi.predicateList); + } else if (multi.isOr()) { + this.predicateList.add(multi); + } + + return this; + } + + @Override + public String getDebugName() { + StringBuilder builder = new StringBuilder("Multi"); + if (debugName != null) { + builder.append('#').append(debugName); + } + StringJoiner joiner = new StringJoiner(", "); + this.predicateList.forEach(p -> joiner.add(p.getDebugName())); + return builder.append('{') + .append(joiner) + .append('}') + .toString(); + } + + protected enum Logic { + OR, AND, + XOR // unused + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateBlockTag.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateBlockTag.java deleted file mode 100644 index 26a448e2f39..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateBlockTag.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gregtechceu.gtceu.api.multiblock.predicates; - -import com.gregtechceu.gtceu.api.multiblock.Predicates; -import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; - -import net.minecraft.core.Holder; -import net.minecraft.core.HolderSet; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.tags.TagKey; -import net.minecraft.world.level.block.Block; - -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; - -public class PredicateBlockTag extends BasePredicate { - - public TagKey tag; - - public PredicateBlockTag(TagKey tag) { - this(null, tag); - } - - public PredicateBlockTag(@Nullable String debugName, TagKey tag) { - Objects.requireNonNull(tag, "PredicateBlockTag tag cannot be null"); - this.tag = tag; - - errorPredicate = state -> state.retrieveCurrentBlockState().is(tag) ? null : Predicates.PLACEHOLDER; - candidates = BuiltInRegistries.BLOCK.getTag(tag) - .stream() - .flatMap(HolderSet.Named::stream) - .map(Holder::value) - .map(BlockInfo::fromBlock) - .toList(); - - if (debugName == null) { - this.debugName = tag.registry().location() + "/" + tag.location(); - } else { - this.debugName = debugName; - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateBlocks.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateBlocks.java deleted file mode 100644 index 3f22b008b80..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateBlocks.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.gregtechceu.gtceu.api.multiblock.predicates; - -import com.gregtechceu.gtceu.api.multiblock.error.BlockMatchingError; -import com.gregtechceu.gtceu.api.multiblock.error.PatternError; -import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; - -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.Unmodifiable; - -import java.util.List; -import java.util.StringJoiner; - -public class PredicateBlocks extends BasePredicate { - - public final @Unmodifiable List blocks; - - public PredicateBlocks(Block... blocks) { - this(null, blocks); - } - - public PredicateBlocks(@Nullable String debugName, Block... blocks) { - this(null, List.of(blocks), null); - } - - public PredicateBlocks(@Nullable String debugName, List blocks, @Nullable PatternError error) { - if (blocks.isEmpty()) { - this.blocks = List.of(Blocks.BARRIER); - } else { - this.blocks = blocks; - } - Validate.noNullElements(this.blocks, "Blocks array has null element at index %s"); - - errorPredicate = state -> { - BlockPos pos = state.getPos(); - - return this.blocks.contains(state.retrieveCurrentBlockState().getBlock()) ? null : - (error == null ? new BlockMatchingError(pos, this.blocks) : error); - }; - - candidates = this.blocks.stream() - .map(BlockInfo::fromBlock) - .toList(); - - if (debugName == null) { - StringJoiner sb = new StringJoiner("-"); - for (Block b : blocks) { - sb.add(BuiltInRegistries.BLOCK.getKey(b).getPath()); - } - this.debugName = sb.toString(); - } else { - this.debugName = debugName; - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateFluidTag.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateFluidTag.java deleted file mode 100644 index a40d18ff814..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateFluidTag.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.gregtechceu.gtceu.api.multiblock.predicates; - -import com.gregtechceu.gtceu.api.multiblock.Predicates; -import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; - -import net.minecraft.core.Holder; -import net.minecraft.core.HolderSet; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.tags.TagKey; -import net.minecraft.world.level.material.Fluid; - -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; - -public class PredicateFluidTag extends BasePredicate { - - public TagKey tag; - - public PredicateFluidTag(TagKey tag) { - this(null, tag); - } - - public PredicateFluidTag(@Nullable String debugName, TagKey tag) { - Objects.requireNonNull(tag, "PredicateFluidTag tag cannot be null"); - - this.tag = tag; - - errorPredicate = state -> state.retrieveCurrentBlockState().getFluidState().is(tag) ? null : - Predicates.PLACEHOLDER; - candidates = BuiltInRegistries.FLUID.getTag(tag) - .stream() - .flatMap(HolderSet.Named::stream) - .map(Holder::value) - .map(fluid -> BlockInfo.fromBlockState(fluid.defaultFluidState().createLegacyBlock())) - .toList(); - - this.debugName = Objects.requireNonNullElse(debugName, tag.registry().location() + "/" + tag.location()); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateFluids.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateFluids.java deleted file mode 100644 index adf1f2cd9f3..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateFluids.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.gregtechceu.gtceu.api.multiblock.predicates; - -import com.gregtechceu.gtceu.api.multiblock.Predicates; -import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.Fluids; - -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.StringJoiner; - -public class PredicateFluids extends BasePredicate { - - public final Fluid[] fluids; - - public PredicateFluids(Fluid... fluids) { - this(null, fluids); - } - - public PredicateFluids(@Nullable String debugName, Fluid... fluids) { - Validate.noNullElements(fluids, "Fluids array has null element at index %s"); - - if (fluids.length == 0) this.fluids = new Fluid[] { Fluids.WATER }; - else this.fluids = Arrays.stream(fluids).toArray(Fluid[]::new); - errorPredicate = state -> ArrayUtils.contains(this.fluids, - state.retrieveCurrentBlockState().getFluidState().getType()) ? - null : Predicates.PLACEHOLDER; - candidates = Arrays.stream(this.fluids) - .map(fluid -> BlockInfo.fromBlockState(fluid.defaultFluidState().createLegacyBlock())) - .toList(); - - if (debugName == null) { - StringJoiner sb = new StringJoiner("-"); - for (Fluid f : fluids) { - sb.add(BuiltInRegistries.FLUID.getKey(f).getPath()); - } - this.debugName = sb.toString(); - } else { - this.debugName = debugName; - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicatePartAbility.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicatePartAbility.java deleted file mode 100644 index fe5f941a6de..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicatePartAbility.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.gregtechceu.gtceu.api.multiblock.predicates; - -import com.gregtechceu.gtceu.api.machine.multiblock.PartAbility; -import com.gregtechceu.gtceu.api.multiblock.error.PartAbilityError; -import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; - -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.Unmodifiable; - -import java.util.List; -import java.util.Objects; - -public class PredicatePartAbility extends BasePredicate { - - public final @Unmodifiable List blocks; - public final PartAbility partAbility; - - public PredicatePartAbility(@Nullable String debugName, PartAbility partAbility) { - this.debugName = Objects.requireNonNullElse(debugName, "Unknown Part Ability"); - this.partAbility = partAbility; - if (partAbility.getAllBlocks().isEmpty()) { - this.blocks = List.of(Blocks.BARRIER); - } else { - this.blocks = partAbility.getAllBlocks().stream().toList(); - } - Validate.noNullElements(this.blocks, "Blocks array has null element at index %s"); - - errorPredicate = state -> { - BlockPos pos = state.getPos(); - - return this.blocks.contains(state.retrieveCurrentBlockState().getBlock()) ? null : - new PartAbilityError(pos, partAbility); - }; - - candidates = this.blocks.stream() - .map(BlockInfo::fromBlock) - .toList(); - } - - public PredicatePartAbility(@Nullable String debugName, PartAbility partAbility, int... tiers) { - this.debugName = Objects.requireNonNullElse(debugName, "Unknown Part Ability"); - this.partAbility = partAbility; - if (partAbility.getAllBlocks().isEmpty()) { - this.blocks = List.of(Blocks.BARRIER); - } else { - this.blocks = partAbility.getBlocks(tiers).stream().toList(); - } - Validate.noNullElements(this.blocks, "Blocks array has null element at index %s"); - errorPredicate = state -> { - BlockPos pos = state.getPos(); - - return this.blocks.contains(state.getBlockState().getBlock()) ? null : - new PartAbilityError(pos, partAbility); - }; - - candidates = this.blocks.stream() - .map(BlockInfo::fromBlock) - .toList(); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateStates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateStates.java deleted file mode 100644 index 2ea66e92936..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateStates.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.gregtechceu.gtceu.api.multiblock.predicates; - -import com.gregtechceu.gtceu.api.multiblock.error.BlockMatchingError; -import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; - -import org.apache.commons.lang3.Validate; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.StringJoiner; - -public class PredicateStates extends BasePredicate { - - public final List states; - - public PredicateStates(BlockState[] states) { - this(null, states); - } - - public PredicateStates(@Nullable String debugName, BlockState... states) { - Validate.noNullElements(states, "Blockstate array has null element at index %s"); - - if (states.length == 0) { - this.states = List.of(Blocks.BARRIER.defaultBlockState()); - } else { - this.states = List.of(states); - } - errorPredicate = state -> { - return this.states.contains(state.retrieveCurrentBlockState()) ? null : - new BlockMatchingError(state.getBlockPos(), this.states.stream() - .map(BlockBehaviour.BlockStateBase::getBlock).toList()); - }; - candidates = this.states.stream().map(BlockInfo::fromBlockState).toList(); - - if (debugName == null) { - StringJoiner sb = new StringJoiner("-"); - for (BlockState state : states) { - sb.add(BuiltInRegistries.BLOCK.getKey(state.getBlock()).getPath()); - } - this.debugName = sb.toString(); - } else { - this.debugName = debugName; - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java index 73eedc53704..cdcab886e9a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java @@ -13,6 +13,8 @@ import com.mojang.serialization.Codec; import lombok.Getter; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; import org.jetbrains.annotations.Nullable; import java.util.Objects; @@ -53,6 +55,14 @@ public BlockInfo(BlockState blockState, @Nullable ItemStack itemStack, FAKE_LEVEL.setState(blockState); } + public static BlockInfo fromFluid(Fluid fluid) { + return fromFluidState(fluid.defaultFluidState()); + } + + public static BlockInfo fromFluidState(FluidState fluidState) { + return fromBlockState(fluidState.createLegacyBlock()); + } + public static BlockInfo fromBlockState(BlockState state) { return new BlockInfo(state); } @@ -94,6 +104,14 @@ public void apply(Level level, BlockPos pos) { } } + public boolean isAir() { + return blockState.getBlock() == Blocks.AIR; + } + + public boolean nonAir() { + return !isAir(); + } + @Override public boolean equals(@Nullable Object o) { if (o == null || getClass() != o.getClass()) return false; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java index ea864f72201..129c5cbb6d6 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java @@ -10,14 +10,13 @@ import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.gregtechceu.gtceu.api.machine.property.GTMachineModelProperties; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderHelper; import com.gregtechceu.gtceu.common.data.GTMaterials; import com.gregtechceu.gtceu.common.data.GTRecipeModifiers; import com.gregtechceu.gtceu.common.data.GTRecipeTypes; -import com.gregtechceu.gtceu.common.machine.GTMachineInstanceFactories; import com.gregtechceu.gtceu.common.machine.multiblock.electric.DistillationTowerMachine; import com.gregtechceu.gtceu.common.machine.multiblock.electric.gcym.*; import com.gregtechceu.gtceu.common.machine.multiblock.part.ParallelHatchPartMachine; @@ -595,8 +594,8 @@ public static void init() {} .recipeModifiers(GTRecipeModifiers.PARALLEL_HATCH, OC_NON_PERFECT_SUBTICK, BATCH_MODE) .appearanceBlock(CASING_WATERTIGHT) .pattern(definition -> { - PatternPredicate casingPredicate = blocks(CASING_WATERTIGHT.get()).setMinGlobalLimited(40); - PatternPredicate exportPredicate = abilities(PartAbility.EXPORT_FLUIDS_1X); + BasePredicate casingPredicate = blocks(CASING_WATERTIGHT.get()).setMinGlobalLimited(40); + BasePredicate exportPredicate = abilities(PartAbility.EXPORT_FLUIDS_1X); if (GTCEu.Mods.isAE2Loaded()) exportPredicate = exportPredicate.or(blocks(GTAEMachines.FLUID_EXPORT_HATCH_ME.get())); exportPredicate.setMaxLayerLimited(1); @@ -746,7 +745,7 @@ public static void init() {} .recipeModifiers(GTRecipeModifiers.PARALLEL_HATCH, GTRecipeModifiers::ebfOverclock, BATCH_MODE) .appearanceBlock(CASING_HIGH_TEMPERATURE_SMELTING) .pattern(definition -> { - PatternPredicate casing = blocks(CASING_HIGH_TEMPERATURE_SMELTING.get()).setMinGlobalLimited(360); + BasePredicate casing = blocks(CASING_HIGH_TEMPERATURE_SMELTING.get()).setMinGlobalLimited(360); return MultiblockPatternBuilder.start(FRONT, UP, RIGHT) // spotless:off .slice("##XXXXXXXXX##", "##XXXXXXXXX##", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############") diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 294a8aefa75..d2a2cc4cdbf 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -22,7 +22,7 @@ import com.gregtechceu.gtceu.api.machine.steam.SimpleSteamMachine; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; import com.gregtechceu.gtceu.api.mui.factory.PanelFactory; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.error.PartAbilityError; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; @@ -741,23 +741,36 @@ public static MultiblockMachineDefinition registerLargeTurbine(GTRegistrate regi .register(); } - private static PatternPredicate rotorHolder(int tier) { - return new PatternPredicate(new BasePredicate((worldState) -> { - if (MetaMachine.getMachine(worldState.getLevel(), - worldState.getPos().immutable()) instanceof RotorHolderPartMachine rotorHolder && - worldState.getLevel() - .getBlockState(worldState.getPos().immutable() - .relative(rotorHolder.getFrontFacing())) - .isAir()) { - return null; + private static BasePredicate rotorHolder(int tier) { + return new BasePredicate() {{ + addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")); + addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", VN[tier])); + } + @Override + public boolean testInternal(@NotNull PredicateContext ctx) { + if (MetaMachine.getMachine(ctx.level(), + ctx.pos()) instanceof RotorHolderPartMachine rotorHolder && + ctx.level().getBlockState(ctx.pos() + .relative(rotorHolder.getFrontFacing())) + .isAir()) { + return true; + } + return ctx.error(new PartAbilityError(ctx.pos(), PartAbility.ROTOR_HOLDER)); + } + + @Override + public List computeCandidates() { + return PartAbility.ROTOR_HOLDER.getAllBlocks() + .stream() + .map(BlockInfo::fromBlock) + .toList(); + } + + @Override + public String getDebugName() { + return "RotorHolder"; } - return new PartAbilityError(worldState.getBlockPos(), PartAbility.ROTOR_HOLDER); - }, PartAbility.ROTOR_HOLDER.getAllBlocks().stream() - .map(BlockInfo::fromBlock) - .toList())) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", - VN[tier])); + }; } // Tooltips diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java index 2ad1331b4a8..c870afe30e6 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java @@ -13,7 +13,7 @@ import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.gregtechceu.gtceu.api.machine.property.GTMachineModelProperties; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderHelper; @@ -123,7 +123,7 @@ public class GTMultiMachines { .where('X', blocks(CASING_PRIMITIVE_BRICKS.get())) .where('#', Predicates.air()) .where('&', Predicates.air() - .or(Predicates.custom(bws -> GTUtil.isBlockSnow(bws.retrieveCurrentBlockState()) ? + .or(Predicates.customFunction(bws -> GTUtil.isBlockSnow(bws.retrieveCurrentBlockState()) ? null : Predicates.PLACEHOLDER, null))) .where('Y', Predicates.controller(blocks(definition.getBlock()))) @@ -318,12 +318,12 @@ public class GTMultiMachines { .recipeModifiers(OC_NON_PERFECT_SUBTICK, BATCH_MODE) .appearanceBlock(CASING_STAINLESS_CLEAN) .pattern(definition -> { - PatternPredicate exportPredicate = abilities(PartAbility.EXPORT_FLUIDS_1X); + BasePredicate exportPredicate = abilities(PartAbility.EXPORT_FLUIDS_1X); if (GTCEu.Mods.isAE2Loaded()) { exportPredicate = exportPredicate.or(blocks(GTAEMachines.FLUID_EXPORT_HATCH_ME.get())); } exportPredicate.setMaxLayerLimited(1); - PatternPredicate maint = autoAbilities(true, false, false) + BasePredicate maint = autoAbilities(true, false, false) .setMaxGlobalLimited(1); return MultiblockPatternBuilder.start(UP, BACK, RIGHT) .slice("YSY", "YYY", "YYY") diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/behavior/TerminalBehavior.java b/src/main/java/com/gregtechceu/gtceu/common/item/behavior/TerminalBehavior.java index 949cd3d745e..2d2087d4604 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/behavior/TerminalBehavior.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/behavior/TerminalBehavior.java @@ -6,6 +6,14 @@ import com.gregtechceu.gtceu.api.machine.multiblock.MultiblockControllerMachine; import com.gregtechceu.gtceu.api.mui.IItemUIHolder; import com.gregtechceu.gtceu.api.mui.MultiblockSchemaInfo; +import com.gregtechceu.gtceu.api.multiblock.pattern.BlockPattern; +import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; +import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; +import com.gregtechceu.gtceu.api.multiblock.util.BlockPatternStructureHelper; +import com.gregtechceu.gtceu.api.multiblock.util.ExpandablePatternStructureHelper; +import com.gregtechceu.gtceu.client.mui.schema.MutableSchema; import com.gregtechceu.gtceu.integration.recipeviewer.widgets.MultiblockPreviewWidget; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java index aab66a214c7..59c55c3383d 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java @@ -11,8 +11,8 @@ import com.gregtechceu.gtceu.api.machine.multiblock.part.MultiblockPartMachine; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; import com.gregtechceu.gtceu.api.misc.EnergyContainerList; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.common.mui.GTMultiblockTextUtil; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.utils.FormattingUtil; @@ -157,7 +157,7 @@ public void invalidateStructure(String name) { converterSubscription.unsubscribe(); } - public static PatternPredicate getHatchPredicates() { + public static BasePredicate getHatchPredicates() { return abilities(PartAbility.INPUT_ENERGY).setPreviewCount(1) .or(abilities(PartAbility.OUTPUT_ENERGY).setPreviewCount(2)) .or(abilities(PartAbility.SUBSTATION_INPUT_ENERGY).setPreviewCount(1)) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java index 7162d9165f8..1cf23d54936 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java @@ -10,11 +10,11 @@ import com.gregtechceu.gtceu.api.machine.multiblock.PartAbility; import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.gregtechceu.gtceu.api.misc.EnergyContainerList; -import com.gregtechceu.gtceu.api.multiblock.*; -import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.sync_system.annotations.RerenderOnChanged; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; @@ -62,13 +62,13 @@ public class CentralMonitorMachine extends WorkableElectricMultiblockMachine private @Nullable CurrentBlockInfo patternFindingState; - private static @Nullable PatternPredicate MULTI_PREDICATE = null; + private static @Nullable BasePredicate MULTI_PREDICATE = null; public CentralMonitorMachine(BlockEntityCreationInfo info) { super(info, new CentralMonitorLogic()); } - public static PatternPredicate getMultiPredicate() { + public static BasePredicate getMultiPredicate() { if (MULTI_PREDICATE == null) { MULTI_PREDICATE = Predicates.abilities(PartAbility.INPUT_ENERGY) .setMinGlobalLimited(1).setMaxGlobalLimited(2).setPreviewCount(1) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index e7541b43142..14c2780e09f 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -15,13 +15,14 @@ import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.gregtechceu.gtceu.api.machine.multiblock.part.MultiblockPartMachine; import com.gregtechceu.gtceu.api.misc.EnergyContainerList; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; -import com.gregtechceu.gtceu.api.multiblock.Predicates; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.FilterMatchingError; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandableMultiblockPatternBuilder; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; +import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; @@ -313,17 +314,17 @@ private static boolean isAllFloorBlocks(Level level, BlockPos.MutableBlockPos po public static Function getPattern() { return (definition) -> { - PatternPredicate wallPredicate = states(getCasingState(), getGlassState()).or(getValidFloorBlocks()); - PatternPredicate energyPredicate = autoAbilities(true, false, false).or(abilities(PartAbility.INPUT_ENERGY) + BasePredicate wallPredicate = states(getCasingState(), getGlassState()).or(getValidFloorBlocks()); + BasePredicate energyPredicate = autoAbilities(true, false, false).or(abilities(PartAbility.INPUT_ENERGY) .setMinGlobalLimited(1).setMaxGlobalLimited(3)); - PatternPredicate edgePredicate = wallPredicate.or(energyPredicate); - PatternPredicate facePredicate = wallPredicate.or(energyPredicate) + BasePredicate edgePredicate = wallPredicate.or(energyPredicate); + BasePredicate facePredicate = wallPredicate.or(energyPredicate) .or(doorPredicate().setMaxGlobalLimited(8)) .or(abilities(PartAbility.PASSTHROUGH_HATCH).setMaxGlobalLimited(30)); - PatternPredicate filterPredicate = cleanroomFilters(); - PatternPredicate innerPredicate = innerPredicate(); - PatternPredicate verticalEdgePredicate = edgePredicate.or(blocks(getGlassState().getBlock())); + BasePredicate filterPredicate = cleanroomFilters(); + BasePredicate innerPredicate = innerPredicate(); + BasePredicate verticalEdgePredicate = edgePredicate.or(blocks(getGlassState().getBlock())); return ExpandableMultiblockPatternBuilder .start(RelativeDirection.UP, RelativeDirection.RIGHT, RelativeDirection.FRONT) @@ -468,29 +469,43 @@ protected static BlockState getGlassState() { return GTBlocks.CLEANROOM_GLASS.getDefaultState(); } - protected static PatternPredicate doorPredicate() { - return Predicates.custom( - blockWorldState -> blockWorldState.retrieveCurrentBlockState().getBlock() instanceof DoorBlock ? null : - Predicates.PLACEHOLDER, + protected static BasePredicate doorPredicate() { + return Predicates.customPredicate( + ctx -> ctx.state().getBlock() instanceof DoorBlock || ctx.error(Predicates.PLACEHOLDER), List.of(new BlockInfo(Blocks.IRON_DOOR.defaultBlockState()), new BlockInfo( Blocks.IRON_DOOR.defaultBlockState().setValue(DoorBlock.HALF, DoubleBlockHalf.UPPER)))); } - private static PatternPredicate getValidFloorBlocks() { + private static BasePredicate getValidFloorBlocks() { return Predicates.blockTag(CustomTags.CLEANROOM_FLOORS); } - protected static PatternPredicate innerPredicate() { - return new PatternPredicate(blockWorldState -> { - // all non-GTMachines are allowed inside by default - BlockEntity blockEntity = blockWorldState.getBlockEntity(); - if (blockEntity instanceof MetaMachine machine) { - if (isMachineBanned(machine)) { - return Predicates.PLACEHOLDER; + protected static BasePredicate innerPredicate() { + return new BasePredicate() { + @Override + public boolean testInternal(PredicateContext ctx) { + // all non-GTMachines are allowed inside by default + BlockEntity blockEntity = ctx.blockEntity(); + if (blockEntity instanceof MetaMachine machine) { + if (isMachineBanned(machine)) { + return ctx.error(Predicates.PLACEHOLDER); + } + // todo do this in structure form not in the predicate + // machine.getTraitOptional(CleanroomReceiverTrait.TYPE).ifPresent(cleanroomReceivers::add); } + return true; } - return null; - }, null); + + @Override + public List computeCandidates() { + return List.of(); + } + + @Override + public String getDebugName() { + return "InnerPredicate"; + } + }; } protected static boolean isMachineBanned(MetaMachine machine) { diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java index 1735221646a..70b05564ffa 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java @@ -7,12 +7,13 @@ import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; import com.gregtechceu.gtceu.api.machine.multiblock.WorkableMultiblockMachine; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandableMultiblockPatternBuilder; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; +import com.gregtechceu.gtceu.api.multiblock.pattern.PatternState; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.common.data.GTBlocks; import com.gregtechceu.gtceu.common.item.behavior.LighterBehavior; @@ -116,7 +117,7 @@ public static Function getPattern() return (definition) -> { var floor = Predicates.blocks(Blocks.BRICKS); - var logs = PatternPredicate.AIR.or(logPredicate()); + var logs = BasePredicate.AIR.or(logPredicate()); var walls = wallPredicate(); return ExpandableMultiblockPatternBuilder @@ -138,7 +139,7 @@ public static Function getPattern() if (bp.getY() == -b.get(2) || bp.getY() == b.get(3)) intersects++; if (bp.getZ() == b.get(4) || bp.getZ() == -b.get(5)) intersects++; - if (intersects >= 2) return PatternPredicate.ANY; + if (intersects >= 2) return BasePredicate.ANY; if (intersects == 1) { if (bottomAisle) return floor; @@ -150,9 +151,8 @@ public static Function getPattern() }; } - private static PatternPredicate wallPredicate() { - return new PatternPredicate("Wall Blocks", - multiblockState -> { + private BasePredicate wallPredicate() { + return Predicates.customFunction(multiblockState -> { BlockPos p = multiblockState.getBlockPos(); return multiblockState.getBlockState().is(CustomTags.CHARCOAL_PILE_IGNITER_WALLS) ? null : new PatternStringError(Component.translatable("gtceu.predicate_error.charcoal.walls", @@ -160,8 +160,8 @@ private static PatternPredicate wallPredicate() { }, null); } - private static PatternPredicate logPredicate() { - return new PatternPredicate(multiblockState -> { + private BasePredicate logPredicate() { + return Predicates.customFunction(multiblockState -> { boolean match = multiblockState.getBlockState().is(BlockTags.LOGS_THAT_BURN); return match ? null : new PatternStringError(Component.translatable("gtceu.predicate_error.charcoal.logs")); }, null); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java index 780bbf6f179..c096511eed5 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java @@ -7,7 +7,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.BlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; -import com.gregtechceu.gtceu.api.multiblock.predicates.*; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.client.renderer.PatternPreviewRenderer; import com.gregtechceu.gtceu.common.mui.GTGuiTextures; @@ -140,13 +140,13 @@ public MultiblockPreviewWidget(MultiblockMachineDefinition definition, Multibloc IBlockPattern pattern = multiblockDefinition.getStructurePatterns().get("main").get(); if (pattern instanceof BlockPattern blockPattern) { @SuppressWarnings("DataFlowIssue") // realistically it can't be null here - PatternPredicate predicate = this.multiblockSchemaInfo.getStructureHelper().getPredicateFromPos( + BasePredicate predicate = this.multiblockSchemaInfo.getStructureHelper().getPredicateFromPos( blockPattern, this.selectionInfo.pos(), frontFacing, upFacing, isFlipped); return createSelectedBlockMenu(predicate); } else if (pattern instanceof ExpandablePattern expandablePattern) { @SuppressWarnings("DataFlowIssue") // realistically it can't be null here - PatternPredicate predicate = this.multiblockSchemaInfo.getStructureHelper().getPredicateFromPos( + BasePredicate predicate = this.multiblockSchemaInfo.getStructureHelper().getPredicateFromPos( expandablePattern, this.selectionInfo.pos(), frontFacing, upFacing, isFlipped); return createSelectedBlockMenu(predicate); @@ -240,7 +240,7 @@ public MultiblockPreviewWidget(MultiblockMachineDefinition definition, Multibloc .clientOnlyHandler(partsHandler)))); } - private ContextMenuButton createSelectedBlockMenu(PatternPredicate predicate) { + private ContextMenuButton createSelectedBlockMenu(BasePredicate predicate) { // TODO this can throw invalid state exception when // opening after clicking on a block twice return new ContextMenuButton<>(this.selectionInfo.pos().toString()) @@ -253,14 +253,14 @@ private ContextMenuButton createSelectedBlockMenu(PatternPredicate predicate) .coverChildrenWidth() .collapseDisabledChildren() .childSeparator(Icon.EMPTY_2PX) - .children(predicate.subPredicates, basePredicate -> { - List candidates = basePredicate.candidates; + .children(predicate.expand(), basePredicate -> { + List candidates = basePredicate.getCandidates(); if (candidates.isEmpty()) return new EmptyWidget(); if (candidates.size() > 1) { - return new ContextMenuButton<>(basePredicate.getPredicateName()) + return new ContextMenuButton<>(basePredicate.toString()) .size(16) - .tooltip(r -> r.add(basePredicate.getPredicateName())) + .tooltip(r -> r.add(basePredicate.toString())) .overlay(new ItemDrawable( candidates.get(0).getItemStackForm())) .requiresClick() @@ -290,7 +290,7 @@ private ContextMenuButton createSelectedBlockMenu(PatternPredicate predicate) candidates.get(0)))) .size(16) .tooltip(r -> r.add( - basePredicate.candidates.get(0).getItemStackForm().getHoverName())) + basePredicate.getCandidates().get(0).getItemStackForm().getHoverName())) .overlay(new ItemDrawable( candidates.get(0).getItemStackForm())); } @@ -299,14 +299,14 @@ private ContextMenuButton createSelectedBlockMenu(PatternPredicate predicate) private void createPredicateMenus(Flow predicatesRow, BlockPattern blockPattern) { for (var entry : blockPattern.getPredicates().char2ObjectEntrySet()) { - PatternPredicate predicate = entry.getValue(); + BasePredicate predicate = entry.getValue(); // todo figure out sliders needed for predicate min/max depending on base predicates in the // main predicate - if (predicate.equals(PatternPredicate.ANY) || predicate.equals(PatternPredicate.AIR)) { + if (predicate.isAny() || predicate.isAir()) { continue; } IDrawable overlay; - if (predicate.subPredicates.size() == 1 && predicate.subPredicates.get(0).candidates.size() == 1) { + if (predicate.getCandidates().size() == 1) { continue; } else { overlay = Text.str(String.valueOf(entry.getCharKey())).asIcon().size(8).center(); @@ -328,8 +328,8 @@ private void createPredicateMenus(Flow predicatesRow, BlockPattern blockPattern) .coverChildrenWidth() .collapseDisabledChildren() .childSeparator(Icon.EMPTY_2PX) - .children(predicate.subPredicates, basePredicate -> { - List candidates = basePredicate.candidates; + .children(predicate.expand(), basePredicate -> { + List candidates = basePredicate.getCandidates(); if (candidates.isEmpty()) { return new EmptyWidget(); } else if (candidates.size() > 1) { @@ -341,7 +341,7 @@ private void createPredicateMenus(Flow predicatesRow, BlockPattern blockPattern) candidates.get(0)))) .size(16) .tooltip(r -> r.add( - basePredicate.candidates.get(0).getItemStackForm().getHoverName())) + basePredicate.getCandidates().get(0).getItemStackForm().getHoverName())) .overlay(new ItemDrawable( candidates.get(0).getItemStackForm())); } @@ -350,11 +350,11 @@ private void createPredicateMenus(Flow predicatesRow, BlockPattern blockPattern) } } - private ContextMenuButton createInnerPredicateMenu(PatternPredicate predicate, BasePredicate basePredicate, + private ContextMenuButton createInnerPredicateMenu(BasePredicate predicate, BasePredicate basePredicate, List candidates) { - return new ContextMenuButton<>(basePredicate.getPredicateName()) + return new ContextMenuButton<>(basePredicate.toString()) .size(16) - .tooltip(r -> r.add(basePredicate.getPredicateName())) + .tooltip(r -> r.add(basePredicate.toString())) .overlay(new ItemDrawable( candidates.get(0).getItemStackForm())) .requiresClick() @@ -397,7 +397,7 @@ private void refreshViewWidget() { } /// ==== User Preference UI ====== - private void setPredicateDefaultBlock(PatternPredicate predicate, BasePredicate basePredicate, + private void setPredicateDefaultBlock(BasePredicate predicate, BasePredicate basePredicate, BlockInfo blockInfo) { this.multiblockSchemaInfo.putPredicatePreference(predicate, basePredicate, blockInfo); refreshSchema(); From 269cec3549b4032aec3a4c960c4238d172ca3d8c Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sun, 14 Jun 2026 21:54:30 -0700 Subject: [PATCH 002/101] must return new instances for or/and --- .../multiblock/predicates/MultiPredicate.java | 68 ++++++++++++++----- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 543c26d5a3d..5c2ce3ff9c1 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -2,10 +2,12 @@ import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.StringJoiner; import java.util.stream.Stream; @@ -21,6 +23,11 @@ public MultiPredicate(String debugName) { this.debugName = debugName; } + protected MultiPredicate(List predicates, Logic type) { + this.type = type; + addPredicates(predicates); + } + @Override public boolean test(PredicateContext ctx) { for (BasePredicate predicate : predicateList) { @@ -33,6 +40,16 @@ public boolean test(PredicateContext ctx) { return false; } + protected MultiPredicate addPredicates(List predicates) { + predicates.forEach(this::addPredicates); + return this; + } + + protected MultiPredicate addPredicates(BasePredicate predicate) { + this.predicateList.add(predicate); + return this; + } + @Override public List computeCandidates() { return predicateList.stream() @@ -101,51 +118,68 @@ public boolean isValid() { return this.type != null; } + protected Logic getType() { + return Objects.requireNonNull(type, "null type: " + this); + } + @Override - public MultiPredicate or(BasePredicate other) { - if (!isValid()) { - this.type = Logic.OR; + public boolean hasAir() { + for (BasePredicate predicate : predicateList) { + if (predicate.hasAir()) return true; } + return false; + } + + @Override + @Contract(pure = true) + public MultiPredicate or(BasePredicate other) { + if (!isValid()) this.type = Logic.OR; + + var predicate = new MultiPredicate(this.predicateList, this.getType()); if (!(other instanceof MultiPredicate multi)) { - this.predicateList.add(other); - return this; + return predicate.addPredicates(other); } + if (!multi.isValid()) multi.type = Logic.OR; if (!isOr()) return multi.or(this); if (multi.isOr()) { - this.predicateList.addAll(multi.predicateList); + predicate.addPredicates(multi.predicateList); } else if (multi.isAnd()) { - this.predicateList.add(multi); + predicate.addPredicates(multi); } - return this; + return predicate; } @Override + @Contract(pure = true) public MultiPredicate and(BasePredicate other) { - if (!isValid()) { - this.type = Logic.AND; - } + if (!isValid()) this.type = Logic.AND; + + var predicate = new MultiPredicate(this.predicateList, this.getType()); if (!(other instanceof MultiPredicate multi)) { - this.predicateList.add(other); - return this; + return predicate.addPredicates(other); } + if (!multi.isValid()) multi.type = Logic.AND; if (!isAnd()) return multi.and(this); if (multi.isAnd()) { - this.predicateList.addAll(multi.predicateList); + predicate.addPredicates(multi.predicateList); } else if (multi.isOr()) { - this.predicateList.add(multi); + predicate.addPredicates(multi); } - return this; + return predicate; } @Override public String getDebugName() { - StringBuilder builder = new StringBuilder("Multi"); + StringBuilder builder = new StringBuilder("Multi") + .append('(') + .append(this.type == null ? "INVAlID" : this.type) + .append(')'); if (debugName != null) { builder.append('#').append(debugName); } From fdb416e36d008f8667b7a4aae110c6590eaaedea Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sun, 14 Jun 2026 22:28:56 -0700 Subject: [PATCH 003/101] mark debug name as nullable merge debug names from BasePredicate for or/and --- .../multiblock/predicates/BasePredicate.java | 24 ++++++++++++++++--- .../multiblock/predicates/MultiPredicate.java | 11 +++++---- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 24860b7f320..c09f5db2eaf 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -67,7 +67,7 @@ public List computeCandidates() { return Collections.emptyList(); } - public abstract String getDebugName(); + public abstract @Nullable String getDebugName(); /// the main testing method public boolean test(PredicateContext ctx) { @@ -258,22 +258,40 @@ public BasePredicate and(BasePredicate other) { } private static BasePredicate or(BasePredicate a, BasePredicate b) { + String name1 = a.getDebugName(); + String name2 = b.getDebugName(); + if (name1 != null) { + return or(name2 == null ? name1 : name1 + ", " + name2, List.of(a, b)); + } else if (name2 != null) { + return or(name2, List.of(a, b)); + } return or("OR", List.of(a, b)); } private static BasePredicate and(BasePredicate a, BasePredicate b) { + String name1 = a.getDebugName(); + String name2 = b.getDebugName(); + if (name1 != null) { + return and(name2 == null ? name1 : name1 + ", " + name2, List.of(a, b)); + } else if (name2 != null) { + return and(name2, List.of(a, b)); + } return and("AND", List.of(a, b)); } public static BasePredicate or(String debugName, List predicates) { MultiPredicate predicate = new MultiPredicate(debugName); - predicates.forEach(predicate::or); + for (BasePredicate basePredicate : predicates) { + predicate = predicate.or(basePredicate); + } return predicate; } public static BasePredicate and(String debugName, List predicates) { MultiPredicate predicate = new MultiPredicate(debugName); - predicates.forEach(predicate::and); + for (BasePredicate basePredicate : predicates) { + predicate = predicate.and(basePredicate); + } return predicate; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 5c2ce3ff9c1..00c28fff6a4 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -19,11 +19,12 @@ public class MultiPredicate extends BasePredicate { public MultiPredicate() {} - public MultiPredicate(String debugName) { + public MultiPredicate(@Nullable String debugName) { this.debugName = debugName; } - protected MultiPredicate(List predicates, Logic type) { + protected MultiPredicate(@Nullable String debugName, List predicates, Logic type) { + this(debugName); this.type = type; addPredicates(predicates); } @@ -135,7 +136,7 @@ public boolean hasAir() { public MultiPredicate or(BasePredicate other) { if (!isValid()) this.type = Logic.OR; - var predicate = new MultiPredicate(this.predicateList, this.getType()); + var predicate = new MultiPredicate(this.debugName, this.predicateList, this.getType()); if (!(other instanceof MultiPredicate multi)) { return predicate.addPredicates(other); } @@ -157,7 +158,7 @@ public MultiPredicate or(BasePredicate other) { public MultiPredicate and(BasePredicate other) { if (!isValid()) this.type = Logic.AND; - var predicate = new MultiPredicate(this.predicateList, this.getType()); + var predicate = new MultiPredicate(this.debugName, this.predicateList, this.getType()); if (!(other instanceof MultiPredicate multi)) { return predicate.addPredicates(other); } @@ -175,7 +176,7 @@ public MultiPredicate and(BasePredicate other) { } @Override - public String getDebugName() { + public @Nullable String getDebugName() { StringBuilder builder = new StringBuilder("Multi") .append('(') .append(this.type == null ? "INVAlID" : this.type) From 66e1f9e3a62009380135f9fa90c77a2d83022c04 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Mon, 15 Jun 2026 00:54:10 -0700 Subject: [PATCH 004/101] rename getDebugName() -> getTypeName() add contents method for between curly braces use better constructor for MultiPredicate --- .../gtceu/api/multiblock/Predicates.java | 185 +++++++++++------- .../multiblock/predicates/BasePredicate.java | 38 ++-- .../multiblock/predicates/MultiPredicate.java | 18 +- .../common/data/machines/GTMachineUtils.java | 2 +- .../multiblock/electric/CleanroomMachine.java | 2 +- 5 files changed, 152 insertions(+), 93 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 1774e57c013..2a72df91915 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -25,7 +25,10 @@ import com.gregtechceu.gtceu.config.ConfigHolder; import com.tterrag.registrate.util.entry.RegistryEntry; import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; @@ -64,12 +67,17 @@ public boolean test(PredicateContext ctx) { @Override public List computeCandidates() { - return predicate.computeCandidates(); + return predicate.getCandidates(); } @Override - public String getDebugName() { - return "Controller{" + predicate + "}"; + public String getTypeName() { + return "Controller"; + } + + @Override + protected String getContents() { + return predicate.toString(); } @Override @@ -100,13 +108,15 @@ public List computeCandidates() { } @Override - public String getDebugName() { - if (debugName == null) { - return "States{" + states.size() + "}"; - } else { - return "States#" + debugName + "{" + states.size() + "}"; + public String getTypeName() { + return debugName == null ? "States" : "States#" + debugName; + } - } + @Override + protected String getContents() { + StringJoiner joiner = new StringJoiner(", "); + states.forEach(state -> joiner.add(blockToString(state))); + return joiner.toString(); } }; } @@ -125,12 +135,27 @@ public List computeCandidates() { } @Override - public String getDebugName() { - return block.toString(); + public String getTypeName() { + return "Block"; + } + + @Override + protected String getContents() { + return blockToString(block); } }; } + private static String blockToString(BlockState blockState) { + return blockToString(blockState.getBlock()); + } + + private static String blockToString(Block block) { + return ForgeRegistries.BLOCKS.getDelegate(block) + .map(r -> r.key().location().toString()) + .orElse("unknown"); + } + public static BasePredicate blocks(Block... blocks) { return blocks(null, blocks); } @@ -154,12 +179,15 @@ public List computeCandidates() { } @Override - public String getDebugName() { - if (debugName == null) { - return "Blocks{" + blockList.size() + "}"; - } else { - return "Blocks#" + debugName + "{" + blockList.size() + "}"; - } + public String getTypeName() { + return debugName == null ? "Blocks" : "Blocks#" + debugName; + } + + @Override + protected String getContents() { + StringJoiner joiner = new StringJoiner(", "); + blockList.forEach(block -> joiner.add(block.toString())); + return joiner.toString(); } }; } @@ -187,8 +215,13 @@ public List computeCandidates() { } @Override - public String getDebugName() { - return "BlockTag{" + tag.location() + "}"; + public String getTypeName() { + return "BlockTag"; + } + + @Override + protected String getContents() { + return tag.location().toString(); } }; } @@ -213,8 +246,17 @@ public List computeCandidates() { } @Override - public String getDebugName() { - return "Fluids{" + fluidList.size() + "}"; + public String getTypeName() { + return "Fluids"; + } + + @Override + protected String getContents() { + StringJoiner joiner = new StringJoiner(", "); + fluidList.forEach(fluid -> joiner.add(ForgeRegistries.FLUIDS.getDelegate(fluid) + .map(r -> r.key().location().toString()) + .orElse("unknown"))); + return joiner.toString(); } }; } @@ -235,8 +277,13 @@ public List computeCandidates() { } @Override - public String getDebugName() { - return "Fluids{" + tag.location() + "}"; + public String getTypeName() { + return "FluidTag"; + } + + @Override + protected String getContents() { + return tag.location().toString(); } }; } @@ -263,7 +310,7 @@ public List computeCandidates() { } @Override - public String getDebugName() { + public String getTypeName() { return "Custom"; } }; @@ -295,8 +342,13 @@ public List computeCandidates() { } @Override - public String getDebugName() { - return "Ability{" + ability.getName() + "}"; + public String getTypeName() { + return "AbilityPredicate"; + } + + @Override + protected String getContents() { + return ability.getName(); } }; } @@ -305,19 +357,16 @@ public static BasePredicate abilities(PartAbility... abilities) { return new BasePredicate() { final List abilityList = List.of(abilities); - final String debugName = computeDebugName(); @Override public boolean testInternal(PredicateContext ctx) { - List errors = new ArrayList<>(); for (PartAbility ability : this.abilityList) { if (ability.getAllBlocks().contains(ctx.state().getBlock())) { return true; } else { - errors.add(new PartAbilityError(ctx.pos(), ability)); + ctx.error(new PartAbilityError(ctx.pos(), ability)); } } - errors.forEach(ctx::error); return false; } @@ -329,18 +378,19 @@ public List computeCandidates() { .toList(); } - private String computeDebugName() { + @Override + public String getTypeName() { + return "AbilitiesPredicate"; + } + + @Override + protected String getContents() { StringJoiner sb = new StringJoiner(", "); for (PartAbility ability : this.abilityList) { sb.add(ability.getName()); } return sb.toString(); } - - @Override - public String getDebugName() { - return "Abilities{" + debugName + "}"; - } }; } @@ -348,7 +398,6 @@ public static BasePredicate ability(PartAbility ability, int... tiers) { return new BasePredicate() { final Collection blockList = ability.getBlocks(tiers); - final String debugName = computeDebugName(); @Override public boolean testInternal(PredicateContext ctx) { @@ -362,18 +411,19 @@ public List computeCandidates() { .toList(); } - private String computeDebugName() { + @Override + public String getTypeName() { + return "TieredAbilityPredicate"; + } + + @Override + protected String getContents() { StringJoiner sb = new StringJoiner("-"); for (int tier : tiers) { sb.add(GTValues.VN[tier]); } return ability.getName() + sb; } - - @Override - public String getDebugName() { - return "Ability{" + debugName + "}"; - } }; } @@ -507,7 +557,7 @@ public List computeCandidates() { } @Override - public String getDebugName() { + public String getTypeName() { return "HeatingCoils"; } }; @@ -537,7 +587,7 @@ public List computeCandidates() { } @Override - public String getDebugName() { + public String getTypeName() { return "CleanroomFilters"; } }; @@ -567,7 +617,7 @@ public List computeCandidates() { } @Override - public String getDebugName() { + public String getTypeName() { return "PSSBatteries"; } }; @@ -619,27 +669,30 @@ public static BasePredicate frames(Material... frameMaterials) { .filter(RegistryEntry::isPresent) .map(RegistryEntry::get) .toArray(Block[]::new); - return blocks(frameBlocks) - .or(new BasePredicate() { - @Override - public boolean testInternal(PredicateContext ctx) { - BlockEntity tileEntity = ctx.blockEntity(); - if (!(tileEntity instanceof IPipeNode pipeNode)) { - return ctx.error(PLACEHOLDER); - } - return ArrayUtils.contains(frameMaterials, pipeNode.getFrameMaterial()) || - ctx.error(PLACEHOLDER); - } + return blocks(frameBlocks).or(framedPipes(frameMaterials, frameBlocks)); + } - @Override - public List computeCandidates() { - return Arrays.stream(frameBlocks).map(BlockInfo::fromBlock).toList(); - } + public static BasePredicate framedPipes(Material[] frameMaterials, Block[] frameBlocks) { + return new BasePredicate() { + @Override + public boolean testInternal(PredicateContext ctx) { + BlockEntity tileEntity = ctx.blockEntity(); + if (!(tileEntity instanceof IPipeNode pipeNode)) { + return ctx.error(PLACEHOLDER); + } + return ArrayUtils.contains(frameMaterials, pipeNode.getFrameMaterial()) || + ctx.error(PLACEHOLDER); + } - @Override - public String getDebugName() { - return "FramedPipes"; - } - }); + @Override + public List computeCandidates() { + return Arrays.stream(frameBlocks).map(BlockInfo::fromBlock).toList(); + } + + @Override + public String getTypeName() { + return "FramedPipes"; + } + }; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index c09f5db2eaf..917e3b64c8a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -25,7 +25,7 @@ public abstract class BasePredicate { public static final BasePredicate AIR = new BasePredicate() { @Override - public String getDebugName() { + public String getTypeName() { return "Air"; } }; @@ -33,7 +33,7 @@ public String getDebugName() { public static final BasePredicate ANY = new BasePredicate() { @Override - public String getDebugName() { + public String getTypeName() { return "Any"; } }; @@ -62,12 +62,18 @@ public boolean testInternal(PredicateContext ctx) { return true; } - /// computes the candidates for this predicate, called only once + /// computes the candidates for this predicate, lazily initialized public List computeCandidates() { return Collections.emptyList(); } - public abstract @Nullable String getDebugName(); + /// the type of this predicate + public abstract @Nullable String getTypeName(); + + /// the contents of this predicate + protected String getContents() { + return ""; + } /// the main testing method public boolean test(PredicateContext ctx) { @@ -108,7 +114,7 @@ public boolean hasAir() { /// used for tooltips public boolean isSingle() { - return getCandidates().size() == 1; + return true; } public boolean isController() { @@ -246,7 +252,7 @@ public List expand() { @Override public String toString() { - return "Predicate{" + getDebugName() + "}"; + return getTypeName() + "{" + getContents() + "}"; } public BasePredicate or(BasePredicate other) { @@ -258,8 +264,8 @@ public BasePredicate and(BasePredicate other) { } private static BasePredicate or(BasePredicate a, BasePredicate b) { - String name1 = a.getDebugName(); - String name2 = b.getDebugName(); + String name1 = a.getTypeName(); + String name2 = b.getTypeName(); if (name1 != null) { return or(name2 == null ? name1 : name1 + ", " + name2, List.of(a, b)); } else if (name2 != null) { @@ -269,8 +275,8 @@ private static BasePredicate or(BasePredicate a, BasePredicate b) { } private static BasePredicate and(BasePredicate a, BasePredicate b) { - String name1 = a.getDebugName(); - String name2 = b.getDebugName(); + String name1 = a.getTypeName(); + String name2 = b.getTypeName(); if (name1 != null) { return and(name2 == null ? name1 : name1 + ", " + name2, List.of(a, b)); } else if (name2 != null) { @@ -280,18 +286,10 @@ private static BasePredicate and(BasePredicate a, BasePredicate b) { } public static BasePredicate or(String debugName, List predicates) { - MultiPredicate predicate = new MultiPredicate(debugName); - for (BasePredicate basePredicate : predicates) { - predicate = predicate.or(basePredicate); - } - return predicate; + return new MultiPredicate(debugName, predicates, MultiPredicate.Logic.OR); } public static BasePredicate and(String debugName, List predicates) { - MultiPredicate predicate = new MultiPredicate(debugName); - for (BasePredicate basePredicate : predicates) { - predicate = predicate.and(basePredicate); - } - return predicate; + return new MultiPredicate(debugName, predicates, MultiPredicate.Logic.AND); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 00c28fff6a4..3bff02f26f8 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -14,10 +14,12 @@ public class MultiPredicate extends BasePredicate { private final List predicateList = new ArrayList<>(); - private @Nullable String debugName; + private final @Nullable String debugName; private @Nullable Logic type; - public MultiPredicate() {} + public MultiPredicate() { + this(null); + } public MultiPredicate(@Nullable String debugName) { this.debugName = debugName; @@ -176,7 +178,12 @@ public MultiPredicate and(BasePredicate other) { } @Override - public @Nullable String getDebugName() { + public boolean isSingle() { + return false; + } + + @Override + public @Nullable String getTypeName() { StringBuilder builder = new StringBuilder("Multi") .append('(') .append(this.type == null ? "INVAlID" : this.type) @@ -185,7 +192,7 @@ public MultiPredicate and(BasePredicate other) { builder.append('#').append(debugName); } StringJoiner joiner = new StringJoiner(", "); - this.predicateList.forEach(p -> joiner.add(p.getDebugName())); + this.predicateList.forEach(p -> joiner.add(p.getTypeName())); return builder.append('{') .append(joiner) .append('}') @@ -193,7 +200,8 @@ public MultiPredicate and(BasePredicate other) { } protected enum Logic { - OR, AND, + OR, + AND, XOR // unused } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index d2a2cc4cdbf..896121e5e52 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -767,7 +767,7 @@ public List computeCandidates() { } @Override - public String getDebugName() { + public String getTypeName() { return "RotorHolder"; } }; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index 14c2780e09f..aa06727091e 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -502,7 +502,7 @@ public List computeCandidates() { } @Override - public String getDebugName() { + public String getTypeName() { return "InnerPredicate"; } }; From 7aad4a37fd581879ea7bdf36a215ec2d5d6a7e94 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Mon, 15 Jun 2026 11:13:58 -0700 Subject: [PATCH 005/101] use method fix rebase spotless --- .../gtceu/api/mui/MultiblockSchemaInfo.java | 3 +- .../api/multiblock/PredicateContext.java | 6 +- .../gtceu/api/multiblock/Predicates.java | 56 ++++++++++++------- .../api/multiblock/error/PatternError.java | 6 +- .../api/multiblock/pattern/BlockPattern.java | 4 +- .../multiblock/pattern/ExpandablePattern.java | 3 +- .../api/multiblock/pattern/PatternState.java | 6 +- .../multiblock/predicates/BasePredicate.java | 36 +++++++----- .../multiblock/predicates/MultiPredicate.java | 1 + .../util/AbstractStructureHelper.java | 19 +++---- .../gtceu/api/multiblock/util/BlockInfo.java | 4 +- .../multiblock/util/BlockPatternHelper.java | 35 ++++++------ .../util/ExpandablePatternHelper.java | 15 +++-- .../common/data/machines/GCYMMachines.java | 2 +- .../common/data/machines/GTMachineUtils.java | 14 +++-- .../common/data/machines/GTMultiMachines.java | 2 +- .../item/behavior/TerminalBehavior.java | 8 --- .../electric/CentralMonitorMachine.java | 2 +- .../multiblock/electric/CleanroomMachine.java | 5 +- .../primitive/CharcoalPileIgniterMachine.java | 19 +++---- .../widgets/MultiblockPreviewWidget.java | 4 +- 21 files changed, 134 insertions(+), 116 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java b/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java index a4b296144ef..4598608f302 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java @@ -1,7 +1,6 @@ package com.gregtechceu.gtceu.api.mui; import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; import com.gregtechceu.gtceu.api.multiblock.pattern.BlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; @@ -120,7 +119,7 @@ public void clearUserPreferences() { this.userDimensions.clear(); } - public void putPredicatePreference(PatternPredicate predicate, BasePredicate basePredicate, BlockInfo info) { + public void putPredicatePreference(BasePredicate predicate, BasePredicate basePredicate, BlockInfo info) { this.structureHelper.getBlockPreferences().put(predicate, basePredicate, info); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 611b01a3216..077482031b0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -3,13 +3,15 @@ import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import it.unimi.dsi.fastutil.objects.Object2IntMap; + import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; import org.jetbrains.annotations.Nullable; import java.util.Objects; @@ -20,7 +22,7 @@ public record PredicateContext(CurrentBlockInfo blockInfo, Object2IntMap globalCache, @Nullable Object2IntMap layerCache) { - /// accepts a pattern error + /// accepts a pattern error /// @return false public boolean error(PatternError error) { this.errorConsumer.accept(error); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 2a72df91915..d5c5e6100b2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -23,12 +23,9 @@ import com.gregtechceu.gtceu.api.recipe.GTRecipeType; import com.gregtechceu.gtceu.common.data.GTMaterialBlocks; import com.gregtechceu.gtceu.config.ConfigHolder; -import com.tterrag.registrate.util.entry.RegistryEntry; + import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; @@ -36,6 +33,8 @@ import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; import net.minecraftforge.registries.ForgeRegistries; + +import com.tterrag.registrate.util.entry.RegistryEntry; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.Validate; import org.jetbrains.annotations.Nullable; @@ -87,6 +86,10 @@ public boolean isController() { }; } + public static BasePredicate states(BlockState... allowedStates) { + return states(null, allowedStates); + } + public static BasePredicate states(@Nullable String debugName, BlockState... allowedStates) { List states = new ArrayList<>(); for (BlockState state : allowedStates) { @@ -263,6 +266,7 @@ protected String getContents() { public static BasePredicate fluidTag(TagKey tag) { return new BasePredicate() { + @Override public boolean testInternal(PredicateContext ctx) { return ctx.fluidState().is(tag) || ctx.error(PLACEHOLDER); @@ -299,6 +303,7 @@ public static BasePredicate customFunction(Function predicate, @Nullable List candidates) { return new BasePredicate() { + @Override public boolean testInternal(PredicateContext ctx) { return predicate.test(ctx); @@ -331,7 +336,8 @@ public static BasePredicate abilities(PartAbility ability) { @Override public boolean testInternal(PredicateContext ctx) { - return blockList.contains(ctx.state().getBlock()) || ctx.error(new PartAbilityError(ctx.pos(), ability)); + return blockList.contains(ctx.state().getBlock()) || + ctx.error(new PartAbilityError(ctx.pos(), ability)); } @Override @@ -401,7 +407,8 @@ public static BasePredicate ability(PartAbility ability, int... tiers) { @Override public boolean testInternal(PredicateContext ctx) { - return blockList.contains(ctx.state().getBlock()) || ctx.error(new PartAbilityError(ctx.pos(), ability)); + return blockList.contains(ctx.state().getBlock()) || + ctx.error(new PartAbilityError(ctx.pos(), ability)); } @Override @@ -432,9 +439,9 @@ public static BasePredicate autoAbilities(GTRecipeType... recipeType) { } public static BasePredicate autoAbilities(GTRecipeType[] recipeType, - boolean checkEnergyIn, boolean checkEnergyOut, - boolean checkItemIn, boolean checkItemOut, - boolean checkFluidIn, boolean checkFluidOut) { + boolean checkEnergyIn, boolean checkEnergyOut, + boolean checkItemIn, boolean checkItemOut, + boolean checkFluidIn, boolean checkFluidOut) { List predicates = new ArrayList<>(); if (checkEnergyIn) { @@ -497,7 +504,7 @@ public static BasePredicate autoAbilities(GTRecipeType[] recipeType, } public static BasePredicate autoAbilities(boolean checkMaintenance, boolean checkMuffler, - boolean checkParallel) { + boolean checkParallel) { List predicates = new ArrayList<>(); if (checkMaintenance) { predicates.add(abilities(PartAbility.MAINTENANCE) @@ -520,10 +527,12 @@ public static BasePredicate autoAbilities(boolean checkMaintenance, boolean chec } public static BasePredicate heatingCoils() { - return new BasePredicate() {{ - addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")); - setPriority(0); - } + return new BasePredicate() { + + { + addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")); + setPriority(0); + } private List getCoils() { return GTCEuAPI.HEATING_COILS.values() @@ -564,9 +573,12 @@ public String getTypeName() { } public static BasePredicate cleanroomFilters() { - return new BasePredicate() {{ - addTooltips(Component.translatable("gtceu.multiblock.pattern.cleanroom")); - } + return new BasePredicate() { + + { + addTooltips(Component.translatable("gtceu.multiblock.pattern.cleanroom")); + } + @Override public boolean testInternal(PredicateContext ctx) { var blockState = ctx.state(); @@ -594,9 +606,12 @@ public String getTypeName() { } public static BasePredicate powerSubstationBatteries() { - return new BasePredicate() {{ - addTooltips(Component.translatable("gtceu.multiblock.pattern.error.batteries")); - } + return new BasePredicate() { + + { + addTooltips(Component.translatable("gtceu.multiblock.pattern.error.batteries")); + } + @Override public boolean testInternal(PredicateContext ctx) { var state = ctx.state(); @@ -674,6 +689,7 @@ public static BasePredicate frames(Material... frameMaterials) { public static BasePredicate framedPipes(Material[] frameMaterials, Block[] frameBlocks) { return new BasePredicate() { + @Override public boolean testInternal(PredicateContext ctx) { BlockEntity tileEntity = ctx.blockEntity(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java index 615ea89a5d8..b0777fe42f6 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java @@ -30,9 +30,9 @@ public PatternError(@Nullable BlockPos pos, List> candidates) { } // TODO FIX -// public PatternError(@Nullable BlockPos pos, PatternPredicate predicate) { -// this(pos, predicate.getCandidates()); -// } + // public PatternError(@Nullable BlockPos pos, PatternPredicate predicate) { + // this(pos, predicate.getCandidates()); + // } public PatternError(@Nullable BlockPos pos, BasePredicate failingPredicate) { this(pos, Collections.singletonList(failingPredicate.getCandidates())); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 375dbcca50d..9f186690f4c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -2,8 +2,8 @@ import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; @@ -19,7 +19,6 @@ import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.function.BiPredicate; public class BlockPattern implements IBlockPattern { @@ -220,7 +219,6 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p patternState.cache.put(charPos.asLong(), new BlockInfo(state, blockEntity)); } - List res = new ArrayList<>(); boolean passed = pred.test(patternState.toContext(res::add)); if (!passed) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index de2d0a26526..d54c94c84da 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -2,8 +2,8 @@ import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; @@ -21,6 +21,7 @@ import lombok.Setter; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.List; import java.util.function.BiFunction; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 96733429c1c..522da3f9960 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -2,9 +2,9 @@ import com.gregtechceu.gtceu.api.machine.multiblock.MultiblockControllerMachine; import com.gregtechceu.gtceu.api.multiblock.MultiblockWorldSavedData; +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import net.minecraft.core.BlockPos; @@ -112,11 +112,11 @@ public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState ne } public PredicateContext toContext(Consumer errorConsumer) { - return PredicateContext.of(this.cbi, errorConsumer, this.globalCount, this.layerCount); + return PredicateContext.of(this.currentBlockInfo, errorConsumer, this.globalCount, this.layerCount); } public PredicateContext noLayer(Consumer errorConsumer) { - return PredicateContext.of(this.cbi, errorConsumer, this.globalCount, null); + return PredicateContext.of(this.currentBlockInfo, errorConsumer, this.globalCount, null); } @Getter diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 917e3b64c8a..b81e2eae846 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -1,13 +1,11 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; import com.gregtechceu.gtceu.GTCEu; -import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.data.lang.LangHandler; -import lombok.Getter; -import lombok.Setter; -import lombok.experimental.Accessors; + import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; @@ -15,11 +13,15 @@ import net.minecraft.world.level.Level; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; + +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; import org.jetbrains.annotations.Nullable; import java.util.*; -@Accessors(chain=true) +@Accessors(chain = true) public abstract class BasePredicate { public static final BasePredicate AIR = new BasePredicate() { @@ -40,21 +42,29 @@ public String getTypeName() { private @Nullable List candidates; private @Nullable List tooltips; - @Getter @Setter + @Getter + @Setter private int priority = 0; - @Getter @Setter + @Getter + @Setter private int minCount = -1; - @Getter @Setter + @Getter + @Setter private int maxCount = -1; - @Getter @Setter + @Getter + @Setter private int minSliceCount = -1; - @Getter @Setter + @Getter + @Setter private int maxSliceCount = -1; - @Getter @Setter + @Getter + @Setter private int previewCount = -1; - @Getter @Setter + @Getter + @Setter private boolean disableRenderFormed = false; - @Getter @Setter + @Getter + @Setter private @Nullable String nbtParser; // unsure what this does /// custom testing logic, usually checking if blockstate/entity is correct diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 3bff02f26f8..ba3eb8bbcbe 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -2,6 +2,7 @@ import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; + import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java index 60b97856e3c..075d0ba0d12 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java @@ -2,7 +2,6 @@ import com.gregtechceu.gtceu.api.block.MetaMachineBlock; import com.gregtechceu.gtceu.api.block.property.GTBlockStateProperties; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; @@ -29,9 +28,9 @@ public abstract class AbstractStructureHelper { Direction.EAST, Direction.UP, Direction.DOWN }; @Getter - protected final HashBasedTable blockPreferences = HashBasedTable + protected final HashBasedTable blockPreferences = HashBasedTable .create(); - protected final HashBasedTable minMaxPreferences = HashBasedTable + protected final HashBasedTable minMaxPreferences = HashBasedTable .create(); protected @Nullable Block controllerBlock; @@ -43,7 +42,7 @@ public static AbstractStructureHelper expandable(IntList sliceRepeats) { return new ExpandablePatternHelper(sliceRepeats); } - public Table getMinMaxPreferences() { + public Table getMinMaxPreferences() { return this.minMaxPreferences; } @@ -70,18 +69,18 @@ protected abstract void populateWithUserBlockPreferences(Map resultStructure, IBlockPattern pattern, Direction frontFacing, Direction upFacing, boolean isFlipped); - public abstract PatternPredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, - Direction frontFacing, Direction upFacing, boolean isFlipped); + public abstract BasePredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, + Direction frontFacing, Direction upFacing, boolean isFlipped); - protected int getMinCount(PatternPredicate predicate, BasePredicate basePredicate) { + protected int getMinCount(BasePredicate predicate, BasePredicate basePredicate) { if (!minMaxPreferences.contains(predicate, basePredicate)) - return basePredicate.minCount; + return basePredicate.getMinCount(); return minMaxPreferences.get(predicate, basePredicate).leftInt(); } - protected int getMaxCount(PatternPredicate predicate, BasePredicate basePredicate) { + protected int getMaxCount(BasePredicate predicate, BasePredicate basePredicate) { if (!minMaxPreferences.contains(predicate, basePredicate)) - return basePredicate.maxCount; + return basePredicate.getMaxCount(); return minMaxPreferences.get(predicate, basePredicate).rightInt(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java index cdcab886e9a..f092701ce4c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java @@ -10,11 +10,11 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; import com.mojang.serialization.Codec; import lombok.Getter; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.FluidState; import org.jetbrains.annotations.Nullable; import java.util.Objects; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java index 33599059c91..a599d428aee 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java @@ -1,6 +1,5 @@ package com.gregtechceu.gtceu.api.multiblock.util; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; import com.gregtechceu.gtceu.api.multiblock.pattern.BlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.PatternSlice; @@ -25,8 +24,8 @@ protected BlockPatternHelper(Int2IntMap sliceRepeats) { this.sliceRepeats = sliceRepeats; } - public PatternPredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, - Direction frontFacing, Direction upFacing, boolean isFlipped) { + public BasePredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, + Direction frontFacing, Direction upFacing, boolean isFlipped) { BlockPattern blockPattern = (BlockPattern) pattern; char[][][] flattenedBlockPattern = flattenBlockPattern(blockPattern); char[][][] adjustedBlockPattern = rotateAndFlipPattern(flattenedBlockPattern, blockPattern.getDirections(), @@ -35,7 +34,7 @@ public PatternPredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, if (pos.getX() < 0 || pos.getX() >= dimensions.getX() || pos.getY() < 0 || pos.getY() >= dimensions.getY() || pos.getZ() < 0 || pos.getZ() >= dimensions.getZ()) { - return PatternPredicate.AIR; + return BasePredicate.AIR; } char c = adjustedBlockPattern[pos.getX()][pos.getY()][pos.getZ()]; return blockPattern.getPredicates().get(c); @@ -67,7 +66,7 @@ protected void populateWithUserBlockPreferences(Map resultS dimensions.getX() + "," + dimensions.getY() + "," + dimensions.getZ()); } char c = this.flattenedBlockPattern[pos.getX()][pos.getY()][pos.getZ()]; - PatternPredicate predicate = blockPattern.getPredicates().get(c); + BasePredicate predicate = blockPattern.getPredicates().get(c); if (!isValidCandidate(resultStructure, predicate, pos, blockInfo, sliceDir)) { throw new IllegalStateException("Invalid preference " + blockInfo.getBlockState().getBlock().getName() + " for position " + pos); @@ -109,9 +108,9 @@ protected void populateFromPattern(Map resultStructure, IBl if (resultStructure.containsKey(pos)) continue; char c = this.flattenedBlockPattern[pos.getX()][pos.getY()][pos.getZ()]; - PatternPredicate predicate = blockPattern.getPredicates().get(c); + BasePredicate predicate = blockPattern.getPredicates().get(c); - if (predicate == PatternPredicate.AIR || predicate == PatternPredicate.ANY) { + if (predicate.isAir() || predicate.isAny()) { continue; } @@ -127,17 +126,17 @@ protected void populateFromPattern(Map resultStructure, IBl } } - private boolean tryMinCount(Map resultStructure, PatternPredicate predicate, + private boolean tryMinCount(Map resultStructure, BasePredicate predicate, BlockPos pos, Direction dir, int offset) { - for (BasePredicate basePredicate : predicate.subPredicates) { + for (BasePredicate basePredicate : predicate.expand()) { int minCount = getMinCount(predicate, basePredicate); if (minCount == 0) continue; int totalAlreadyPopulated = countPopulatedGlobal(resultStructure, basePredicate); int layerAlreadyPopulated = countPopulatedInLayer(resultStructure, basePredicate, dir, offset); boolean globalMinUnmet = minCount > 0 && totalAlreadyPopulated < minCount; - boolean layerMinUnmet = basePredicate.minSliceCount > 0 && - layerAlreadyPopulated < basePredicate.minSliceCount; + boolean layerMinUnmet = basePredicate.getMinSliceCount() > 0 && + layerAlreadyPopulated < basePredicate.getMinSliceCount(); if (!globalMinUnmet && !layerMinUnmet) continue; BlockInfo toInsert = blockPreferences.get(predicate, basePredicate); @@ -156,16 +155,16 @@ private boolean tryMinCount(Map resultStructure, PatternPre return false; } - private boolean tryMaxCount(Map resultStructure, PatternPredicate predicate, + private boolean tryMaxCount(Map resultStructure, BasePredicate predicate, BlockPos pos, Direction dir, int offset) { - for (BasePredicate basePredicate : predicate.subPredicates) { + for (BasePredicate basePredicate : predicate.expand()) { int maxCount = getMaxCount(predicate, basePredicate); if (maxCount == 0) continue; int totalAlreadyPopulated = countPopulatedGlobal(resultStructure, basePredicate); int layerAlreadyPopulated = countPopulatedInLayer(resultStructure, basePredicate, dir, offset); if (maxCount != -1 && totalAlreadyPopulated >= maxCount) continue; - if (basePredicate.maxSliceCount != -1 && layerAlreadyPopulated >= basePredicate.maxSliceCount) { + if (basePredicate.getMaxSliceCount() != -1 && layerAlreadyPopulated >= basePredicate.getMaxSliceCount()) { continue; } @@ -185,15 +184,15 @@ private boolean tryMaxCount(Map resultStructure, PatternPre return false; } - private boolean isValidCandidate(Map resultStructure, PatternPredicate predicate, + private boolean isValidCandidate(Map resultStructure, BasePredicate predicate, BlockPos pos, BlockInfo newInfo, Direction sliceDir) { // The slice (layer) this position belongs to. int sliceCoord = getCoordFromDir(pos, sliceDir); // newInfo is valid if there's a basePredicate it qualifies for whose maxCount (global) and maxSliceCount // (this slice) wouldn't be exceeded by placing it here. - for (BasePredicate basePredicate : predicate.subPredicates) { - if (!basePredicate.candidates.contains(newInfo)) continue; + for (BasePredicate basePredicate : predicate.expand()) { + if (!basePredicate.getCandidates().contains(newInfo)) continue; int maxCount = getMaxCount(predicate, basePredicate); if (maxCount == 0) continue; @@ -202,7 +201,7 @@ private boolean isValidCandidate(Map resultStructure, Patte int layerAlreadyPopulated = countPopulatedInLayer(resultStructure, basePredicate, sliceDir, sliceCoord); if (maxCount != -1 && totalAlreadyPopulated >= maxCount) continue; - if (basePredicate.maxSliceCount == -1 || layerAlreadyPopulated < basePredicate.maxSliceCount) { + if (basePredicate.getMaxSliceCount() == -1 || layerAlreadyPopulated < basePredicate.getMaxSliceCount()) { return true; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java index d05aec2709c..b517189d7a6 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java @@ -1,6 +1,5 @@ package com.gregtechceu.gtceu.api.multiblock.util; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; @@ -89,7 +88,7 @@ public void populateFromPattern(Map resultStructure, IBlock // this basically means the x val of the iter is aisle count, y is str count, and z is char count. for (BlockPos pos : betweenClosed(corners.bounds())) { BlockPos.MutableBlockPos mutablePos = pos.mutable(); - PatternPredicate predicate = predicateProvider.apply(mutablePos, userRepeats); + BasePredicate predicate = predicateProvider.apply(mutablePos, userRepeats); // this basically reshuffles the coordinates into absolute form from relative form setFromDirection(mutablePos, absolutes[0], pos.getX()); @@ -108,9 +107,9 @@ public void populateFromPattern(Map resultStructure, IBlock } } - private boolean tryMinCount(Map resultStructure, PatternPredicate predicate, + private boolean tryMinCount(Map resultStructure, BasePredicate predicate, BlockPos pos) { - for (BasePredicate basePredicate : predicate.subPredicates) { + for (BasePredicate basePredicate : predicate.expand()) { int minCount = getMinCount(predicate, basePredicate); if (minCount == 0) continue; @@ -129,9 +128,9 @@ private boolean tryMinCount(Map resultStructure, PatternPre return false; } - private boolean tryMaxCount(Map resultStructure, PatternPredicate predicate, + private boolean tryMaxCount(Map resultStructure, BasePredicate predicate, BlockPos pos) { - for (BasePredicate basePredicate : predicate.subPredicates) { + for (BasePredicate basePredicate : predicate.expand()) { int maxCount = getMaxCount(predicate, basePredicate); if (maxCount == 0) continue; @@ -151,8 +150,8 @@ private boolean tryMaxCount(Map resultStructure, PatternPre } @Override - public PatternPredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, - Direction frontFacing, Direction upFacing, boolean isFlipped) { + public BasePredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, + Direction frontFacing, Direction upFacing, boolean isFlipped) { ExpandablePattern expandablePattern = (ExpandablePattern) pattern; Direction[] absolutes = getCorners(userRepeats, expandablePattern, frontFacing, upFacing, isFlipped) .absolutes(); diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java index 129c5cbb6d6..cf615c8c4b9 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java @@ -10,9 +10,9 @@ import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.gregtechceu.gtceu.api.machine.property.GTMachineModelProperties; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderHelper; import com.gregtechceu.gtceu.common.data.GTMaterials; import com.gregtechceu.gtceu.common.data.GTRecipeModifiers; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 896121e5e52..c02f33a4b4f 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -24,7 +24,6 @@ import com.gregtechceu.gtceu.api.mui.factory.PanelFactory; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.Predicates; -import com.gregtechceu.gtceu.api.multiblock.error.PartAbilityError; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; @@ -742,16 +741,19 @@ public static MultiblockMachineDefinition registerLargeTurbine(GTRegistrate regi } private static BasePredicate rotorHolder(int tier) { - return new BasePredicate() {{ - addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")); - addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", VN[tier])); - } + return new BasePredicate() { + + { + addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")); + addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", VN[tier])); + } + @Override public boolean testInternal(@NotNull PredicateContext ctx) { if (MetaMachine.getMachine(ctx.level(), ctx.pos()) instanceof RotorHolderPartMachine rotorHolder && ctx.level().getBlockState(ctx.pos() - .relative(rotorHolder.getFrontFacing())) + .relative(rotorHolder.getFrontFacing())) .isAir()) { return true; } diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java index c870afe30e6..1e1da5807d1 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java @@ -13,9 +13,9 @@ import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.gregtechceu.gtceu.api.machine.property.GTMachineModelProperties; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderHelper; import com.gregtechceu.gtceu.client.util.TooltipHelper; import com.gregtechceu.gtceu.common.block.BoilerFireboxType; diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/behavior/TerminalBehavior.java b/src/main/java/com/gregtechceu/gtceu/common/item/behavior/TerminalBehavior.java index 2d2087d4604..949cd3d745e 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/behavior/TerminalBehavior.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/behavior/TerminalBehavior.java @@ -6,14 +6,6 @@ import com.gregtechceu.gtceu.api.machine.multiblock.MultiblockControllerMachine; import com.gregtechceu.gtceu.api.mui.IItemUIHolder; import com.gregtechceu.gtceu.api.mui.MultiblockSchemaInfo; -import com.gregtechceu.gtceu.api.multiblock.pattern.BlockPattern; -import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; -import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; -import com.gregtechceu.gtceu.api.multiblock.util.BlockPatternStructureHelper; -import com.gregtechceu.gtceu.api.multiblock.util.ExpandablePatternStructureHelper; -import com.gregtechceu.gtceu.client.mui.schema.MutableSchema; import com.gregtechceu.gtceu.integration.recipeviewer.widgets.MultiblockPreviewWidget; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java index 1cf23d54936..bbfa1836fbe 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java @@ -10,11 +10,11 @@ import com.gregtechceu.gtceu.api.machine.multiblock.PartAbility; import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.gregtechceu.gtceu.api.misc.EnergyContainerList; +import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.sync_system.annotations.RerenderOnChanged; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index aa06727091e..64cb895a24a 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -15,14 +15,14 @@ import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.gregtechceu.gtceu.api.machine.multiblock.part.MultiblockPartMachine; import com.gregtechceu.gtceu.api.misc.EnergyContainerList; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.error.FilterMatchingError; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandableMultiblockPatternBuilder; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; -import com.gregtechceu.gtceu.api.multiblock.Predicates; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; @@ -482,6 +482,7 @@ private static BasePredicate getValidFloorBlocks() { protected static BasePredicate innerPredicate() { return new BasePredicate() { + @Override public boolean testInternal(PredicateContext ctx) { // all non-GTMachines are allowed inside by default diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java index 70b05564ffa..c70859a2288 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java @@ -7,13 +7,12 @@ import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; import com.gregtechceu.gtceu.api.machine.multiblock.WorkableMultiblockMachine; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandableMultiblockPatternBuilder; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; -import com.gregtechceu.gtceu.api.multiblock.pattern.PatternState; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.common.data.GTBlocks; import com.gregtechceu.gtceu.common.item.behavior.LighterBehavior; @@ -151,18 +150,18 @@ public static Function getPattern() }; } - private BasePredicate wallPredicate() { + private static BasePredicate wallPredicate() { return Predicates.customFunction(multiblockState -> { - BlockPos p = multiblockState.getBlockPos(); - return multiblockState.getBlockState().is(CustomTags.CHARCOAL_PILE_IGNITER_WALLS) ? - null : new PatternStringError(Component.translatable("gtceu.predicate_error.charcoal.walls", - p.getX(), p.getY(), p.getZ())); - }, null); + BlockPos p = multiblockState.getBlockPos(); + return multiblockState.retrieveCurrentBlockState().is(CustomTags.CHARCOAL_PILE_IGNITER_WALLS) ? + null : new PatternStringError(Component.translatable("gtceu.predicate_error.charcoal.walls", + p.getX(), p.getY(), p.getZ())); + }, null); } - private BasePredicate logPredicate() { + private static BasePredicate logPredicate() { return Predicates.customFunction(multiblockState -> { - boolean match = multiblockState.getBlockState().is(BlockTags.LOGS_THAT_BURN); + boolean match = multiblockState.retrieveCurrentBlockState().is(BlockTags.LOGS_THAT_BURN); return match ? null : new PatternStringError(Component.translatable("gtceu.predicate_error.charcoal.logs")); }, null); } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java index c096511eed5..b9a0da3f47d 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java @@ -3,7 +3,6 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; import com.gregtechceu.gtceu.api.mui.MultiblockSchemaInfo; -import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; import com.gregtechceu.gtceu.api.multiblock.pattern.BlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; @@ -341,7 +340,8 @@ private void createPredicateMenus(Flow predicatesRow, BlockPattern blockPattern) candidates.get(0)))) .size(16) .tooltip(r -> r.add( - basePredicate.getCandidates().get(0).getItemStackForm().getHoverName())) + basePredicate.getCandidates().get(0).getItemStackForm() + .getHoverName())) .overlay(new ItemDrawable( candidates.get(0).getItemStackForm())); } From aff7f2ca8f009bfbbd6d5368e1d65a2e46e62500 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Tue, 16 Jun 2026 14:24:12 -0700 Subject: [PATCH 006/101] add toString to BlockInfo --- .../com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java index f092701ce4c..ea2af0c9756 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java @@ -112,6 +112,11 @@ public boolean nonAir() { return !isAir(); } + @Override + public String toString() { + return "BlockInfo{" + this.getBlockState() + ", hasBE=" + (this.blockEntity != null) + "}"; + } + @Override public boolean equals(@Nullable Object o) { if (o == null || getClass() != o.getClass()) return false; From acbfa209f589c7d49c2cc06f509c49a8ede5b445 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Tue, 16 Jun 2026 14:26:25 -0700 Subject: [PATCH 007/101] fix MultiPredicate list and sort --- .../multiblock/predicates/BasePredicate.java | 42 +++++++++------- .../multiblock/predicates/MultiPredicate.java | 48 +++++++++++++------ 2 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index b81e2eae846..da80f14d862 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -274,32 +274,42 @@ public BasePredicate and(BasePredicate other) { } private static BasePredicate or(BasePredicate a, BasePredicate b) { - String name1 = a.getTypeName(); - String name2 = b.getTypeName(); - if (name1 != null) { - return or(name2 == null ? name1 : name1 + ", " + name2, List.of(a, b)); - } else if (name2 != null) { - return or(name2, List.of(a, b)); + if (a instanceof MultiPredicate mp) { + return mp.or(b); + } else { + return new MultiPredicate().or(a).or(b); } - return or("OR", List.of(a, b)); +// String name1 = a.getTypeName(); +// String name2 = b.getTypeName(); +// if (name1 != null) { +// return or(name2 == null ? name1 : name1 + ", " + name2, List.of(a, b)); +// } else if (name2 != null) { +// return or(name2, List.of(a, b)); +// } +// return or("OR", List.of(a, b)); } private static BasePredicate and(BasePredicate a, BasePredicate b) { - String name1 = a.getTypeName(); - String name2 = b.getTypeName(); - if (name1 != null) { - return and(name2 == null ? name1 : name1 + ", " + name2, List.of(a, b)); - } else if (name2 != null) { - return and(name2, List.of(a, b)); + if (a instanceof MultiPredicate mp) { + return mp.and(b); + } else { + return new MultiPredicate().and(a).and(b); } - return and("AND", List.of(a, b)); +// String name1 = a.getTypeName(); +// String name2 = b.getTypeName(); +// if (name1 != null) { +// return and(name2 == null ? name1 : name1 + ", " + name2, List.of(a, b)); +// } else if (name2 != null) { +// return and(name2, List.of(a, b)); +// } +// return and("AND", List.of(a, b)); } - public static BasePredicate or(String debugName, List predicates) { + public static BasePredicate or(String debugName, Iterable predicates) { return new MultiPredicate(debugName, predicates, MultiPredicate.Logic.OR); } - public static BasePredicate and(String debugName, List predicates) { + public static BasePredicate and(String debugName, Iterable predicates) { return new MultiPredicate(debugName, predicates, MultiPredicate.Logic.AND); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index ba3eb8bbcbe..a6d4c538920 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -2,19 +2,18 @@ import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.StringJoiner; +import java.util.*; import java.util.stream.Stream; public class MultiPredicate extends BasePredicate { - private final List predicateList = new ArrayList<>(); + private static final Comparator PREDICATE_COMPARATOR = Comparator.comparingInt(BasePredicate::getPriority); + private final List predicateList = new ObjectArrayList<>(); private final @Nullable String debugName; private @Nullable Logic type; @@ -26,10 +25,22 @@ public MultiPredicate(@Nullable String debugName) { this.debugName = debugName; } - protected MultiPredicate(@Nullable String debugName, List predicates, Logic type) { + protected MultiPredicate(@Nullable String debugName, Iterable predicates, Logic type) { this(debugName); this.type = type; - addPredicates(predicates); + for (BasePredicate predicate : predicates) { + if (!(predicate instanceof MultiPredicate multi)) { + addPredicates(predicate); + continue; + } + + if (!multi.isValid() || multi.getType() == this.getType()) { + addPredicates(multi.predicateList); + } else { + addPredicates(multi); + } + } + sorted(); } @Override @@ -44,7 +55,7 @@ public boolean test(PredicateContext ctx) { return false; } - protected MultiPredicate addPredicates(List predicates) { + protected MultiPredicate addPredicates(Collection predicates) { predicates.forEach(this::addPredicates); return this; } @@ -134,6 +145,11 @@ public boolean hasAir() { return false; } + public MultiPredicate sorted() { + this.predicateList.sort(PREDICATE_COMPARATOR); + return this; + } + @Override @Contract(pure = true) public MultiPredicate or(BasePredicate other) { @@ -153,7 +169,7 @@ public MultiPredicate or(BasePredicate other) { predicate.addPredicates(multi); } - return predicate; + return predicate.sorted(); } @Override @@ -175,7 +191,7 @@ public MultiPredicate and(BasePredicate other) { predicate.addPredicates(multi); } - return predicate; + return predicate.sorted(); } @Override @@ -192,12 +208,14 @@ public boolean isSingle() { if (debugName != null) { builder.append('#').append(debugName); } + return builder.toString(); + } + + @Override + protected String getContents() { StringJoiner joiner = new StringJoiner(", "); - this.predicateList.forEach(p -> joiner.add(p.getTypeName())); - return builder.append('{') - .append(joiner) - .append('}') - .toString(); + this.predicateList.forEach(p -> joiner.add(p.toString())); + return joiner.toString(); } protected enum Logic { From 828bd522dc327de409add3cba1dadc044cdc3c8e Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Tue, 16 Jun 2026 22:05:49 -0700 Subject: [PATCH 008/101] cleanup --- .../multiblock/predicates/BasePredicate.java | 24 ++-------- .../multiblock/predicates/MultiPredicate.java | 47 +++++++++++-------- 2 files changed, 32 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index da80f14d862..ab0059cdcff 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -277,39 +277,23 @@ private static BasePredicate or(BasePredicate a, BasePredicate b) { if (a instanceof MultiPredicate mp) { return mp.or(b); } else { - return new MultiPredicate().or(a).or(b); + return or(null, List.of(a, b)); } -// String name1 = a.getTypeName(); -// String name2 = b.getTypeName(); -// if (name1 != null) { -// return or(name2 == null ? name1 : name1 + ", " + name2, List.of(a, b)); -// } else if (name2 != null) { -// return or(name2, List.of(a, b)); -// } -// return or("OR", List.of(a, b)); } private static BasePredicate and(BasePredicate a, BasePredicate b) { if (a instanceof MultiPredicate mp) { return mp.and(b); } else { - return new MultiPredicate().and(a).and(b); + return and(null, List.of(a, b)); } -// String name1 = a.getTypeName(); -// String name2 = b.getTypeName(); -// if (name1 != null) { -// return and(name2 == null ? name1 : name1 + ", " + name2, List.of(a, b)); -// } else if (name2 != null) { -// return and(name2, List.of(a, b)); -// } -// return and("AND", List.of(a, b)); } - public static BasePredicate or(String debugName, Iterable predicates) { + public static BasePredicate or(@Nullable String debugName, Iterable predicates) { return new MultiPredicate(debugName, predicates, MultiPredicate.Logic.OR); } - public static BasePredicate and(String debugName, Iterable predicates) { + public static BasePredicate and(@Nullable String debugName, Iterable predicates) { return new MultiPredicate(debugName, predicates, MultiPredicate.Logic.AND); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index a6d4c538920..b2454ff0630 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -4,7 +4,6 @@ import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -17,10 +16,6 @@ public class MultiPredicate extends BasePredicate { private final @Nullable String debugName; private @Nullable Logic type; - public MultiPredicate() { - this(null); - } - public MultiPredicate(@Nullable String debugName) { this.debugName = debugName; } @@ -45,14 +40,7 @@ protected MultiPredicate(@Nullable String debugName, Iterable pre @Override public boolean test(PredicateContext ctx) { - for (BasePredicate predicate : predicateList) { - if (isOr() && predicate.test(ctx)) { - return true; - } else if (isAnd() && !predicate.test(ctx)) { - return false; - } - } - return false; + return getType().run(ctx, this.predicateList); } protected MultiPredicate addPredicates(Collection predicates) { @@ -145,13 +133,12 @@ public boolean hasAir() { return false; } - public MultiPredicate sorted() { + protected MultiPredicate sorted() { this.predicateList.sort(PREDICATE_COMPARATOR); return this; } @Override - @Contract(pure = true) public MultiPredicate or(BasePredicate other) { if (!isValid()) this.type = Logic.OR; @@ -173,7 +160,6 @@ public MultiPredicate or(BasePredicate other) { } @Override - @Contract(pure = true) public MultiPredicate and(BasePredicate other) { if (!isValid()) this.type = Logic.AND; @@ -219,8 +205,31 @@ protected String getContents() { } protected enum Logic { - OR, - AND, - XOR // unused + OR { + @Override + protected boolean run(PredicateContext ctx, List predicates) { + for (BasePredicate basePredicate : predicates) { + if (basePredicate.test(ctx)) { + return true; + } + } + return false; + } + }, + AND { + @Override + protected boolean run(PredicateContext ctx, List predicates) { + return !OR.run(ctx, predicates); + } + }, + // unused + XOR { + @Override + protected boolean run(PredicateContext ctx, List predicates) { + return true; + } + }; + + protected abstract boolean run(PredicateContext ctx, List predicates); } } From 99a32a0c02ed06d788139160de01e56698ce0f46 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 17 Jun 2026 18:34:49 -0700 Subject: [PATCH 009/101] replace expand with visitor method --- .../api/multiblock/predicates/BasePredicate.java | 13 +++++++++++-- .../api/multiblock/predicates/MultiPredicate.java | 8 +++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index ab0059cdcff..f43390a6909 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.Consumer; @Accessors(chain = true) public abstract class BasePredicate { @@ -40,6 +41,7 @@ public String getTypeName() { } }; + protected static final Comparator PREDICATE_COMPARATOR = Comparator.comparingInt(BasePredicate::getPriority); private @Nullable List candidates; private @Nullable List tooltips; @Getter @@ -256,8 +258,15 @@ public Optional getFirstCandidate() { .map(c -> c.get(0)); } - public List expand() { - return List.of(this); + public void visit(Consumer visitor) { + visitor.accept(this); + } + + public final List expand() { + List result = new ArrayList<>(); + visit(result::add); + result.sort(PREDICATE_COMPARATOR); + return result; } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index b2454ff0630..bc85230a1c3 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -7,11 +7,11 @@ import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.Consumer; import java.util.stream.Stream; public class MultiPredicate extends BasePredicate { - private static final Comparator PREDICATE_COMPARATOR = Comparator.comparingInt(BasePredicate::getPriority); private final List predicateList = new ObjectArrayList<>(); private final @Nullable String debugName; private @Nullable Logic type; @@ -61,10 +61,8 @@ public List computeCandidates() { } @Override - public List expand() { - return predicateList.stream() - .flatMap(p -> p instanceof MultiPredicate mp ? mp.predicateList.stream() : Stream.of(p)) - .toList(); + public void visit(Consumer visitor) { + predicateList.forEach(p -> p.visit(visitor)); } @Override From 725c0cae290c87f58226cb10f59181365b11b3d2 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 17 Jun 2026 20:23:25 -0700 Subject: [PATCH 010/101] wrap unmodifiable --- .../gtceu/api/multiblock/predicates/BasePredicate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index f43390a6909..3a8ebbff837 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -266,7 +266,7 @@ public final List expand() { List result = new ArrayList<>(); visit(result::add); result.sort(PREDICATE_COMPARATOR); - return result; + return Collections.unmodifiableList(result); } @Override From d59496a75c61f66cc91c4fe2eb59d951a7cda6ca Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 17 Jun 2026 20:34:56 -0700 Subject: [PATCH 011/101] fix air predicate --- .../gtceu/api/multiblock/predicates/BasePredicate.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 3a8ebbff837..71ca7ac98d2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -11,6 +11,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -27,6 +28,11 @@ public abstract class BasePredicate { public static final BasePredicate AIR = new BasePredicate() { + @Override + public boolean testInternal(PredicateContext ctx) { + return ctx.state().is(Blocks.AIR); + } + @Override public String getTypeName() { return "Air"; From 2cee1bf8546cd72a92efc0b9479f155cef462652 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 17 Jun 2026 20:51:24 -0700 Subject: [PATCH 012/101] use string builder for type name and contents --- .../gtceu/api/multiblock/Predicates.java | 115 ++++++++++-------- .../multiblock/predicates/BasePredicate.java | 20 +-- .../multiblock/predicates/MultiPredicate.java | 11 +- .../common/data/machines/GTMachineUtils.java | 4 +- .../multiblock/electric/CleanroomMachine.java | 4 +- 5 files changed, 83 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index d5c5e6100b2..031d50a50c8 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -70,13 +70,13 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "Controller"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("Controller"); } @Override - protected String getContents() { - return predicate.toString(); + protected StringBuilder getContents(StringBuilder builder) { + return builder.append(predicate); } @Override @@ -111,15 +111,19 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return debugName == null ? "States" : "States#" + debugName; + public StringBuilder getTypeName(StringBuilder builder) { + builder.append("States"); + if(debugName != null) { + builder.append('#').append(debugName); + } + return builder; } @Override - protected String getContents() { + protected StringBuilder getContents(StringBuilder builder) { StringJoiner joiner = new StringJoiner(", "); states.forEach(state -> joiner.add(blockToString(state))); - return joiner.toString(); + return builder.append(joiner); } }; } @@ -138,13 +142,13 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "Block"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("Block"); } @Override - protected String getContents() { - return blockToString(block); + protected StringBuilder getContents(StringBuilder builder) { + return builder.append(blockToString(block)); } }; } @@ -182,15 +186,19 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return debugName == null ? "Blocks" : "Blocks#" + debugName; + public StringBuilder getTypeName(StringBuilder builder) { + builder.append("Blocks"); + if(debugName != null) { + builder.append('#').append(debugName); + } + return builder; } @Override - protected String getContents() { + protected StringBuilder getContents(StringBuilder builder) { StringJoiner joiner = new StringJoiner(", "); blockList.forEach(block -> joiner.add(block.toString())); - return joiner.toString(); + return builder.append(joiner); } }; } @@ -218,13 +226,13 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "BlockTag"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("BlockTag"); } @Override - protected String getContents() { - return tag.location().toString(); + protected StringBuilder getContents(StringBuilder builder) { + return builder.append(tag.location()); } }; } @@ -249,17 +257,17 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "Fluids"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("Fluids"); } @Override - protected String getContents() { + protected StringBuilder getContents(StringBuilder builder) { StringJoiner joiner = new StringJoiner(", "); fluidList.forEach(fluid -> joiner.add(ForgeRegistries.FLUIDS.getDelegate(fluid) .map(r -> r.key().location().toString()) .orElse("unknown"))); - return joiner.toString(); + return builder.append(joiner); } }; } @@ -281,13 +289,13 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "FluidTag"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("FluidTag"); } @Override - protected String getContents() { - return tag.location().toString(); + protected StringBuilder getContents(StringBuilder builder) { + return builder.append(tag.location()); } }; } @@ -315,8 +323,8 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "Custom"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("Custom"); } }; } @@ -348,13 +356,13 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "AbilityPredicate"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("AbilityPredicate"); } @Override - protected String getContents() { - return ability.getName(); + protected StringBuilder getContents(StringBuilder builder) { + return builder.append(ability.getName()); } }; } @@ -385,17 +393,15 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "AbilitiesPredicate"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("AbilitiesPredicate"); } @Override - protected String getContents() { + protected StringBuilder getContents(StringBuilder builder) { StringJoiner sb = new StringJoiner(", "); - for (PartAbility ability : this.abilityList) { - sb.add(ability.getName()); - } - return sb.toString(); + this.abilityList.forEach(partAbility -> sb.add(partAbility.getName())); + return builder.append(sb); } }; } @@ -419,17 +425,20 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "TieredAbilityPredicate"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("TieredAbilityPredicate"); } @Override - protected String getContents() { + protected StringBuilder getContents(StringBuilder builder) { StringJoiner sb = new StringJoiner("-"); for (int tier : tiers) { sb.add(GTValues.VN[tier]); } - return ability.getName() + sb; + return builder.append(ability.getName()) + .append('[') + .append(sb) + .append(']'); } }; } @@ -566,8 +575,8 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "HeatingCoils"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("HeatingCoils"); } }; } @@ -599,8 +608,8 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "CleanroomFilters"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("CleanroomFilters"); } }; } @@ -632,8 +641,8 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "PSSBatteries"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("PSSBatteries"); } }; @@ -706,8 +715,8 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "FramedPipes"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("FramedPipes"); } }; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 71ca7ac98d2..610c84bd33a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -34,16 +34,16 @@ public boolean testInternal(PredicateContext ctx) { } @Override - public String getTypeName() { - return "Air"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("Air"); } }; public static final BasePredicate ANY = new BasePredicate() { @Override - public String getTypeName() { - return "Any"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("Any"); } }; @@ -86,11 +86,11 @@ public List computeCandidates() { } /// the type of this predicate - public abstract @Nullable String getTypeName(); + public abstract StringBuilder getTypeName(StringBuilder builder); /// the contents of this predicate - protected String getContents() { - return ""; + protected StringBuilder getContents(StringBuilder builder) { + return builder; } /// the main testing method @@ -277,7 +277,11 @@ public final List expand() { @Override public String toString() { - return getTypeName() + "{" + getContents() + "}"; + StringBuilder builder = getTypeName(new StringBuilder()) + .append('{'); + return getContents(builder) + .append('}') + .toString(); } public BasePredicate or(BasePredicate other) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index bc85230a1c3..f1684e8ba45 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -8,7 +8,6 @@ import java.util.*; import java.util.function.Consumer; -import java.util.stream.Stream; public class MultiPredicate extends BasePredicate { @@ -184,22 +183,22 @@ public boolean isSingle() { } @Override - public @Nullable String getTypeName() { - StringBuilder builder = new StringBuilder("Multi") + public StringBuilder getTypeName(StringBuilder builder) { + builder.append("Multi") .append('(') .append(this.type == null ? "INVAlID" : this.type) .append(')'); if (debugName != null) { builder.append('#').append(debugName); } - return builder.toString(); + return builder; } @Override - protected String getContents() { + protected StringBuilder getContents(StringBuilder builder) { StringJoiner joiner = new StringJoiner(", "); this.predicateList.forEach(p -> joiner.add(p.toString())); - return joiner.toString(); + return builder.append(joiner); } protected enum Logic { diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index c02f33a4b4f..9214e7f3cdf 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -769,8 +769,8 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "RotorHolder"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("RotorHolder"); } }; } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index 64cb895a24a..811e2cde440 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -503,8 +503,8 @@ public List computeCandidates() { } @Override - public String getTypeName() { - return "InnerPredicate"; + public StringBuilder getTypeName(StringBuilder builder) { + return builder.append("InnerPredicate"); } }; } From f8fb039da3ce370c40e90f84021cbb1241dcbf2d Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 17 Jun 2026 20:52:25 -0700 Subject: [PATCH 013/101] move methods --- .../multiblock/predicates/BasePredicate.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 610c84bd33a..30ba034fe70 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -75,29 +75,16 @@ public StringBuilder getTypeName(StringBuilder builder) { @Setter private @Nullable String nbtParser; // unsure what this does - /// custom testing logic, usually checking if blockstate/entity is correct - public boolean testInternal(PredicateContext ctx) { - return true; - } - - /// computes the candidates for this predicate, lazily initialized - public List computeCandidates() { - return Collections.emptyList(); - } - - /// the type of this predicate - public abstract StringBuilder getTypeName(StringBuilder builder); - - /// the contents of this predicate - protected StringBuilder getContents(StringBuilder builder) { - return builder; - } - /// the main testing method public boolean test(PredicateContext ctx) { return testInternal(ctx) && testGlobal(ctx) && testLayer(ctx); } + /// custom testing logic, usually checking if blockstate/entity is correct + public boolean testInternal(PredicateContext ctx) { + return true; + } + /// test against global max count public boolean testGlobal(PredicateContext ctx) { ctx.globalCache().merge(this, 1, Integer::sum); @@ -117,6 +104,11 @@ public boolean testLayer(PredicateContext ctx) { return ctx.error(SinglePredicateError.maxLayerCount(this, count)); } + /// computes the candidates for this predicate, lazily initialized + public List computeCandidates() { + return Collections.emptyList(); + } + public boolean isAir() { return this == AIR; } @@ -275,6 +267,14 @@ public final List expand() { return Collections.unmodifiableList(result); } + /// the type of this predicate + public abstract StringBuilder getTypeName(StringBuilder builder); + + /// the contents of this predicate + protected StringBuilder getContents(StringBuilder builder) { + return builder; + } + @Override public String toString() { StringBuilder builder = getTypeName(new StringBuilder()) From c8266a1471f1d6f5dd1d57c6fc47f5b189b58217 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 17 Jun 2026 20:56:48 -0700 Subject: [PATCH 014/101] small work --- .../gtceu/api/multiblock/predicates/BasePredicate.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 30ba034fe70..9aae1304250 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -87,7 +87,7 @@ public boolean testInternal(PredicateContext ctx) { /// test against global max count public boolean testGlobal(PredicateContext ctx) { - ctx.globalCache().merge(this, 1, Integer::sum); + ctx.globalCache().mergeInt(this, 1, Integer::sum); if ((minCount == -1 && maxCount == -1) || ctx.layerCache() == null) return true; int count = ctx.globalCache().getInt(this); if (maxCount == -1 || count <= maxCount) return true; @@ -118,6 +118,8 @@ public boolean isAny() { } /// used for tooltips + /// + /// @return true if this or any sub predicates is air public boolean hasAir() { return isAir(); } @@ -263,7 +265,7 @@ public void visit(Consumer visitor) { public final List expand() { List result = new ArrayList<>(); visit(result::add); - result.sort(PREDICATE_COMPARATOR); + if (result.size() > 1) result.sort(PREDICATE_COMPARATOR); return Collections.unmodifiableList(result); } From 54fc0ef7ff4910199b5c3d220634bdf22ee1337d Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 17 Jun 2026 20:57:21 -0700 Subject: [PATCH 015/101] method rename --- .../gtceu/api/multiblock/Predicates.java | 50 +++++++++---------- .../multiblock/predicates/BasePredicate.java | 12 ++--- .../multiblock/predicates/MultiPredicate.java | 4 +- .../common/data/machines/GTMachineUtils.java | 2 +- .../multiblock/electric/CleanroomMachine.java | 2 +- 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 031d50a50c8..9b1eab6b59c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -70,12 +70,12 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("Controller"); } @Override - protected StringBuilder getContents(StringBuilder builder) { + protected StringBuilder appendContents(StringBuilder builder) { return builder.append(predicate); } @@ -111,7 +111,7 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { builder.append("States"); if(debugName != null) { builder.append('#').append(debugName); @@ -120,7 +120,7 @@ public StringBuilder getTypeName(StringBuilder builder) { } @Override - protected StringBuilder getContents(StringBuilder builder) { + protected StringBuilder appendContents(StringBuilder builder) { StringJoiner joiner = new StringJoiner(", "); states.forEach(state -> joiner.add(blockToString(state))); return builder.append(joiner); @@ -142,12 +142,12 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("Block"); } @Override - protected StringBuilder getContents(StringBuilder builder) { + protected StringBuilder appendContents(StringBuilder builder) { return builder.append(blockToString(block)); } }; @@ -186,7 +186,7 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { builder.append("Blocks"); if(debugName != null) { builder.append('#').append(debugName); @@ -195,7 +195,7 @@ public StringBuilder getTypeName(StringBuilder builder) { } @Override - protected StringBuilder getContents(StringBuilder builder) { + protected StringBuilder appendContents(StringBuilder builder) { StringJoiner joiner = new StringJoiner(", "); blockList.forEach(block -> joiner.add(block.toString())); return builder.append(joiner); @@ -226,12 +226,12 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("BlockTag"); } @Override - protected StringBuilder getContents(StringBuilder builder) { + protected StringBuilder appendContents(StringBuilder builder) { return builder.append(tag.location()); } }; @@ -257,12 +257,12 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("Fluids"); } @Override - protected StringBuilder getContents(StringBuilder builder) { + protected StringBuilder appendContents(StringBuilder builder) { StringJoiner joiner = new StringJoiner(", "); fluidList.forEach(fluid -> joiner.add(ForgeRegistries.FLUIDS.getDelegate(fluid) .map(r -> r.key().location().toString()) @@ -289,12 +289,12 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("FluidTag"); } @Override - protected StringBuilder getContents(StringBuilder builder) { + protected StringBuilder appendContents(StringBuilder builder) { return builder.append(tag.location()); } }; @@ -323,7 +323,7 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("Custom"); } }; @@ -356,12 +356,12 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("AbilityPredicate"); } @Override - protected StringBuilder getContents(StringBuilder builder) { + protected StringBuilder appendContents(StringBuilder builder) { return builder.append(ability.getName()); } }; @@ -393,12 +393,12 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("AbilitiesPredicate"); } @Override - protected StringBuilder getContents(StringBuilder builder) { + protected StringBuilder appendContents(StringBuilder builder) { StringJoiner sb = new StringJoiner(", "); this.abilityList.forEach(partAbility -> sb.add(partAbility.getName())); return builder.append(sb); @@ -425,12 +425,12 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("TieredAbilityPredicate"); } @Override - protected StringBuilder getContents(StringBuilder builder) { + protected StringBuilder appendContents(StringBuilder builder) { StringJoiner sb = new StringJoiner("-"); for (int tier : tiers) { sb.add(GTValues.VN[tier]); @@ -575,7 +575,7 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("HeatingCoils"); } }; @@ -608,7 +608,7 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("CleanroomFilters"); } }; @@ -641,7 +641,7 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("PSSBatteries"); } }; @@ -715,7 +715,7 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("FramedPipes"); } }; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 9aae1304250..6634cce8cb7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -34,7 +34,7 @@ public boolean testInternal(PredicateContext ctx) { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("Air"); } }; @@ -42,7 +42,7 @@ public StringBuilder getTypeName(StringBuilder builder) { public static final BasePredicate ANY = new BasePredicate() { @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("Any"); } }; @@ -270,18 +270,18 @@ public final List expand() { } /// the type of this predicate - public abstract StringBuilder getTypeName(StringBuilder builder); + public abstract StringBuilder appendType(StringBuilder builder); /// the contents of this predicate - protected StringBuilder getContents(StringBuilder builder) { + protected StringBuilder appendContents(StringBuilder builder) { return builder; } @Override public String toString() { - StringBuilder builder = getTypeName(new StringBuilder()) + StringBuilder builder = appendType(new StringBuilder()) .append('{'); - return getContents(builder) + return appendContents(builder) .append('}') .toString(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index f1684e8ba45..a2c3a536592 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -183,7 +183,7 @@ public boolean isSingle() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { builder.append("Multi") .append('(') .append(this.type == null ? "INVAlID" : this.type) @@ -195,7 +195,7 @@ public StringBuilder getTypeName(StringBuilder builder) { } @Override - protected StringBuilder getContents(StringBuilder builder) { + protected StringBuilder appendContents(StringBuilder builder) { StringJoiner joiner = new StringJoiner(", "); this.predicateList.forEach(p -> joiner.add(p.toString())); return builder.append(joiner); diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 9214e7f3cdf..39d01efae7b 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -769,7 +769,7 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("RotorHolder"); } }; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index 811e2cde440..02077e78208 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -503,7 +503,7 @@ public List computeCandidates() { } @Override - public StringBuilder getTypeName(StringBuilder builder) { + public StringBuilder appendType(StringBuilder builder) { return builder.append("InnerPredicate"); } }; From 41dc4fc54dae181580e3685a9e9ed06c9256df2f Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 17 Jun 2026 21:07:44 -0700 Subject: [PATCH 016/101] simplify or/and methods --- .../multiblock/predicates/MultiPredicate.java | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index a2c3a536592..678195ade0b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -135,46 +135,34 @@ protected MultiPredicate sorted() { return this; } + protected MultiPredicate copy() { + return new MultiPredicate(this.debugName, this.predicateList, this.getType()); + } + @Override public MultiPredicate or(BasePredicate other) { if (!isValid()) this.type = Logic.OR; - var predicate = new MultiPredicate(this.debugName, this.predicateList, this.getType()); if (!(other instanceof MultiPredicate multi)) { - return predicate.addPredicates(other); + return this.copy().addPredicates(other).sorted(); } - if (!multi.isValid()) multi.type = Logic.OR; if (!isOr()) return multi.or(this); - if (multi.isOr()) { - predicate.addPredicates(multi.predicateList); - } else if (multi.isAnd()) { - predicate.addPredicates(multi); - } - - return predicate.sorted(); + return combine(this, multi, this.copy()); } @Override public MultiPredicate and(BasePredicate other) { if (!isValid()) this.type = Logic.AND; - var predicate = new MultiPredicate(this.debugName, this.predicateList, this.getType()); if (!(other instanceof MultiPredicate multi)) { - return predicate.addPredicates(other); + return this.copy().addPredicates(other).sorted(); } - if (!multi.isValid()) multi.type = Logic.AND; if (!isAnd()) return multi.and(this); - if (multi.isAnd()) { - predicate.addPredicates(multi.predicateList); - } else if (multi.isOr()) { - predicate.addPredicates(multi); - } - - return predicate.sorted(); + return combine(this, multi, this.copy()); } @Override @@ -201,6 +189,19 @@ protected StringBuilder appendContents(StringBuilder builder) { return builder.append(joiner); } + private static MultiPredicate combine(MultiPredicate a, MultiPredicate b, MultiPredicate dest) { + if (!b.isValid()) { + b.type = a.getType(); + } + if (a.getType() == b.getType()) { + dest.addPredicates(b.predicateList); + } else { + dest.addPredicates(b); + } + + return dest.sorted(); + } + protected enum Logic { OR { @Override From c8c46f046dc13eea52c322c88aa26bab3ce9e7b4 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 18 Jun 2026 19:35:56 -0700 Subject: [PATCH 017/101] make everything go through customPredicate make Custom class --- .../gtceu/api/multiblock/Predicates.java | 570 +++++------------- .../multiblock/predicates/BasePredicate.java | 44 ++ .../multiblock/electric/CleanroomMachine.java | 6 +- 3 files changed, 185 insertions(+), 435 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 9b1eab6b59c..057670ea070 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -31,7 +31,6 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.FluidState; import net.minecraftforge.registries.ForgeRegistries; import com.tterrag.registrate.util.entry.RegistryEntry; @@ -40,9 +39,11 @@ import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; +import java.util.stream.Stream; public class Predicates { @@ -87,7 +88,7 @@ public boolean isController() { } public static BasePredicate states(BlockState... allowedStates) { - return states(null, allowedStates); + return states("States", allowedStates); } public static BasePredicate states(@Nullable String debugName, BlockState... allowedStates) { @@ -98,59 +99,50 @@ public static BasePredicate states(@Nullable String debugName, BlockState... all states.add(block.changeActive(state, !block.isActive(state))); } } - return new BasePredicate() { - - @Override - public boolean testInternal(PredicateContext ctx) { - return states.contains(ctx.state()) || ctx.error(PLACEHOLDER); - } - - @Override - public List computeCandidates() { - return states.stream().map(BlockInfo::fromBlockState).toList(); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - builder.append("States"); - if(debugName != null) { - builder.append('#').append(debugName); - } - return builder; - } - - @Override - protected StringBuilder appendContents(StringBuilder builder) { - StringJoiner joiner = new StringJoiner(", "); - states.forEach(state -> joiner.add(blockToString(state))); - return builder.append(joiner); - } - }; + return customPredicate(debugName, + ctx -> states.contains(ctx.state()) || ctx.error(PLACEHOLDER), + () -> states.stream().map(BlockInfo::fromBlockState), + builder -> { + StringJoiner joiner = new StringJoiner(", "); + states.forEach(state -> joiner.add(blockToString(state))); + builder.append(joiner); + }); } public static BasePredicate blocks(Block block) { - return new BasePredicate() { + return customPredicate("Block", + ctx -> ctx.state().is(block) || ctx.error(new BlockMatchingError(ctx.pos(), List.of(block))), + () -> Stream.of(BlockInfo.fromBlock(block)), + builder -> builder.append(blockToString(block))); + } - @Override - public boolean testInternal(PredicateContext ctx) { - return ctx.state().is(block) || ctx.error(new BlockMatchingError(ctx.pos(), List.of(block))); - } + public static BasePredicate blocks(Block... blocks) { + return blocks("Blocks", blocks); + } - @Override - public List computeCandidates() { - return List.of(BlockInfo.fromBlock(block)); - } + public static BasePredicate blocks(@Nullable String debugName, Block... blocks) { + return blocks(debugName, () -> Arrays.stream(blocks)); + } - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("Block"); - } + public static BasePredicate blocks(@Nullable String debugName, + Supplier> blocks) { + return blocks(debugName, blocks, blocks); + } - @Override - protected StringBuilder appendContents(StringBuilder builder) { - return builder.append(blockToString(block)); - } - }; + public static BasePredicate blocks(@Nullable String debugName, + Supplier> blocks, + Supplier> candidates) { + return customPredicate(debugName, ctx -> { + var blockList = blocks.get().toList(); + for (var block : blockList) { + if (ctx.state().is(block)) return true; + } + return ctx.error(new BlockMatchingError(ctx.pos(), blockList)); + }, () -> candidates.get().map(BlockInfo::fromBlock), builder -> { + StringJoiner joiner = new StringJoiner(", "); + blocks.get().forEach(block -> joiner.add(blockToString(block))); + builder.append(joiner); + }); } private static String blockToString(BlockState blockState) { @@ -160,47 +152,7 @@ private static String blockToString(BlockState blockState) { private static String blockToString(Block block) { return ForgeRegistries.BLOCKS.getDelegate(block) .map(r -> r.key().location().toString()) - .orElse("unknown"); - } - - public static BasePredicate blocks(Block... blocks) { - return blocks(null, blocks); - } - - public static BasePredicate blocks(@Nullable String debugName, Block... blocks) { - return new BasePredicate() { - - private final List blockList = Arrays.asList(blocks); - - @Override - public boolean testInternal(PredicateContext ctx) { - return blockList.contains(ctx.state().getBlock()) || - ctx.error(new BlockMatchingError(ctx.pos(), this.blockList)); - } - - @Override - public List computeCandidates() { - return blockList.stream() - .map(BlockInfo::fromBlock) - .toList(); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - builder.append("Blocks"); - if(debugName != null) { - builder.append('#').append(debugName); - } - return builder; - } - - @Override - protected StringBuilder appendContents(StringBuilder builder) { - StringJoiner joiner = new StringJoiner(", "); - blockList.forEach(block -> joiner.add(block.toString())); - return builder.append(joiner); - } - }; + .orElse("unknown block"); } public static BasePredicate machines(MachineDefinition... definitions) { @@ -209,95 +161,36 @@ public static BasePredicate machines(MachineDefinition... definitions) { } public static BasePredicate blockTag(TagKey tag) { - return new BasePredicate() { - - @Override - public boolean testInternal(PredicateContext ctx) { - return ctx.state().is(tag) || ctx.error(PLACEHOLDER); - } - - @Override - public List computeCandidates() { - return Objects.requireNonNull(ForgeRegistries.BLOCKS.tags()) - .getTag(tag) - .stream() - .map(BlockInfo::fromBlock) - .toList(); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("BlockTag"); - } - - @Override - protected StringBuilder appendContents(StringBuilder builder) { - return builder.append(tag.location()); - } - }; + return customPredicate("BlockTag", + ctx -> ctx.state().is(tag), + () -> Objects.requireNonNull(ForgeRegistries.BLOCKS.tags()) + .getTag(tag).stream() + .map(BlockInfo::fromBlock), + builder -> builder.append(tag.location())); } public static BasePredicate fluids(Fluid... fluids) { - return new BasePredicate() { - - final List fluidList = Arrays.asList(fluids); - - @Override - public boolean testInternal(PredicateContext ctx) { - return fluidList.contains(ctx.fluid()) || ctx.error(PLACEHOLDER); - } - - @Override - public List computeCandidates() { - return fluidList.stream() - .map(Fluid::defaultFluidState) - .map(FluidState::createLegacyBlock) - .map(BlockInfo::fromBlockState) - .toList(); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("Fluids"); - } - - @Override - protected StringBuilder appendContents(StringBuilder builder) { - StringJoiner joiner = new StringJoiner(", "); - fluidList.forEach(fluid -> joiner.add(ForgeRegistries.FLUIDS.getDelegate(fluid) - .map(r -> r.key().location().toString()) - .orElse("unknown"))); - return builder.append(joiner); - } - }; + return customPredicate("Fluids", + ctx -> ArrayUtils.contains(fluids, ctx.fluid()) || ctx.error(PLACEHOLDER), + () -> Arrays.stream(fluids).map(BlockInfo::fromFluid), + builder -> { + StringJoiner joiner = new StringJoiner(", "); + for (Fluid fluid : fluids) { + joiner.add(ForgeRegistries.FLUIDS.getDelegate(fluid) + .map(r -> r.key().location().toString()) + .orElse("unknown")); + } + builder.append(joiner); + }); } public static BasePredicate fluidTag(TagKey tag) { - return new BasePredicate() { - - @Override - public boolean testInternal(PredicateContext ctx) { - return ctx.fluidState().is(tag) || ctx.error(PLACEHOLDER); - } - - @Override - public List computeCandidates() { - return Objects.requireNonNull(ForgeRegistries.FLUIDS.tags()) + return customPredicate("FluidTag", + ctx -> ctx.fluidState().is(tag), + () -> Objects.requireNonNull(ForgeRegistries.FLUIDS.tags()) .getTag(tag).stream() - .map(BlockInfo::fromFluid) - .toList(); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("FluidTag"); - } - - @Override - protected StringBuilder appendContents(StringBuilder builder) { - return builder.append(tag.location()); - } - }; + .map(BlockInfo::fromFluid), + builder -> builder.append(tag.location())); } public static BasePredicate customFunction(Function predicate, @@ -305,28 +198,25 @@ public static BasePredicate customFunction(Function { PatternError error = predicate.apply(ctx.blockInfo()); return error == null || ctx.error(error); - }, candidates); + }, Optional.ofNullable(candidates).orElse(Collections.emptyList())::stream); } public static BasePredicate customPredicate(Predicate predicate, - @Nullable List candidates) { - return new BasePredicate() { - - @Override - public boolean testInternal(PredicateContext ctx) { - return predicate.test(ctx); - } + Supplier> candidates) { + return customPredicate(null, predicate, candidates); + } - @Override - public List computeCandidates() { - return Optional.ofNullable(candidates).orElse(Collections.emptyList()); - } + public static BasePredicate customPredicate(@Nullable String debugName, + Predicate predicate, + Supplier> candidates) { + return customPredicate(debugName, predicate, candidates, null); + } - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("Custom"); - } - }; + public static BasePredicate customPredicate(@Nullable String debugName, + Predicate predicate, + Supplier> candidates, + @Nullable Consumer contents) { + return new BasePredicate.Custom(debugName, predicate, candidates, contents); } public static BasePredicate any() { @@ -338,109 +228,44 @@ public static BasePredicate air() { } public static BasePredicate abilities(PartAbility ability) { - return new BasePredicate() { - - final Collection blockList = ability.getAllBlocks(); - - @Override - public boolean testInternal(PredicateContext ctx) { - return blockList.contains(ctx.state().getBlock()) || - ctx.error(new PartAbilityError(ctx.pos(), ability)); - } - - @Override - public List computeCandidates() { - return blockList.stream() - .map(BlockInfo::fromBlock) - .toList(); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("AbilityPredicate"); - } - - @Override - protected StringBuilder appendContents(StringBuilder builder) { - return builder.append(ability.getName()); - } - }; + return customPredicate("Ability", + ctx -> ability.isApplicable(ctx.state().getBlock()) || + ctx.error(new PartAbilityError(ctx.pos(), ability)), + () -> ability.getAllBlocks().stream().map(BlockInfo::fromBlock), + builder -> builder.append(ability.getName())); } public static BasePredicate abilities(PartAbility... abilities) { - return new BasePredicate() { - - final List abilityList = List.of(abilities); - - @Override - public boolean testInternal(PredicateContext ctx) { - for (PartAbility ability : this.abilityList) { - if (ability.getAllBlocks().contains(ctx.state().getBlock())) { - return true; - } else { + return customPredicate("Abilities", + ctx -> { + for (PartAbility ability : abilities) { + if (ability.isApplicable(ctx.state().getBlock())) { + return true; + } ctx.error(new PartAbilityError(ctx.pos(), ability)); } - } - return false; - } - - @Override - public List computeCandidates() { - return this.abilityList.stream() - .flatMap(ability -> ability.getAllBlocks().stream()) - .map(BlockInfo::fromBlock) - .toList(); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("AbilitiesPredicate"); - } - - @Override - protected StringBuilder appendContents(StringBuilder builder) { - StringJoiner sb = new StringJoiner(", "); - this.abilityList.forEach(partAbility -> sb.add(partAbility.getName())); - return builder.append(sb); - } - }; + return false; + }, + () -> Arrays.stream(abilities) + .flatMap(a -> a.getAllBlocks().stream()) + .map(BlockInfo::fromBlock), + builder -> { + StringJoiner sb = new StringJoiner(", "); + for (PartAbility ability : abilities) { + sb.add(ability.getName()); + } + builder.append(sb); + }); } public static BasePredicate ability(PartAbility ability, int... tiers) { - return new BasePredicate() { - - final Collection blockList = ability.getBlocks(tiers); - - @Override - public boolean testInternal(PredicateContext ctx) { - return blockList.contains(ctx.state().getBlock()) || - ctx.error(new PartAbilityError(ctx.pos(), ability)); - } - - @Override - public List computeCandidates() { - return blockList.stream() - .map(BlockInfo::fromBlock) - .toList(); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("TieredAbilityPredicate"); - } - - @Override - protected StringBuilder appendContents(StringBuilder builder) { - StringJoiner sb = new StringJoiner("-"); - for (int tier : tiers) { - sb.add(GTValues.VN[tier]); - } - return builder.append(ability.getName()) - .append('[') - .append(sb) - .append(']'); - } - }; + StringJoiner sb = new StringJoiner("-"); + for (int tier : tiers) { + sb.add(GTValues.VN[tier]); + } + return customPredicate("Ability[" + sb + "]", + ctx -> ability.isApplicable(ctx.state().getBlock()) || ctx.error(new PartAbilityError(ctx.pos(), ability)), + () -> ability.getBlocks(tiers).stream().map(BlockInfo::fromBlock)); } public static BasePredicate autoAbilities(GTRecipeType... recipeType) { @@ -536,140 +361,32 @@ public static BasePredicate autoAbilities(boolean checkMaintenance, boolean chec } public static BasePredicate heatingCoils() { - return new BasePredicate() { - - { - addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")); - setPriority(0); - } - - private List getCoils() { - return GTCEuAPI.HEATING_COILS.values() - .stream() - .map(Supplier::get) - .map(Block.class::cast) - .toList(); - } - - @Override - public boolean testInternal(PredicateContext ctx) { - var blockState = ctx.state(); - List coils = this.getCoils(); - for (var blockCoil : coils) { - if (blockState.is(blockCoil)) { - return true; - } - } - return ctx.error(new BlockMatchingError(ctx.pos(), coils)); - } - - @Override - public List computeCandidates() { - return GTCEuAPI.HEATING_COILS.entrySet().stream() - // sort to make autogenerated jei previews not pick random coils each game load - .sorted(Comparator.comparingInt(e -> e.getKey().getTier())) - .map(Map.Entry::getValue) - .map(Supplier::get) - .map(BlockInfo::fromBlock) - .toList(); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("HeatingCoils"); - } - }; + return blocks("HeatingCoils", + () -> GTCEuAPI.HEATING_COILS.values().stream().map(Supplier::get)) + .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")) + .setPriority(0); } public static BasePredicate cleanroomFilters() { - return new BasePredicate() { - - { - addTooltips(Component.translatable("gtceu.multiblock.pattern.cleanroom")); - } - - @Override - public boolean testInternal(PredicateContext ctx) { - var blockState = ctx.state(); - for (var entry : GTCEuAPI.CLEANROOM_FILTERS.entrySet()) { - if (blockState.is(entry.getValue().get())) { - return true; - } - } - return ctx.error(PLACEHOLDER); - } - - @Override - public List computeCandidates() { - return GTCEuAPI.CLEANROOM_FILTERS.entrySet().stream() + return blocks("CleanroomFilters", + () -> GTCEuAPI.CLEANROOM_FILTERS.values() + .stream().map(Supplier::get), + () -> GTCEuAPI.CLEANROOM_FILTERS.entrySet() + .stream() .sorted(Comparator.comparingInt(e -> e.getKey().getCleanroomType().getTier())) - .map(e -> new BlockInfo(e.getValue().get())) - .toList(); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("CleanroomFilters"); - } - }; + .map(entry -> entry.getValue().get())) + .addTooltips(Component.translatable("gtceu.multiblock.pattern.cleanroom")); } public static BasePredicate powerSubstationBatteries() { - return new BasePredicate() { - - { - addTooltips(Component.translatable("gtceu.multiblock.pattern.error.batteries")); - } - - @Override - public boolean testInternal(PredicateContext ctx) { - var state = ctx.state(); - for (var entry : GTCEuAPI.PSS_BATTERIES.entrySet()) { - if (state.is(entry.getValue().get())) { - return true; - } - } - return ctx.error(PLACEHOLDER); - } - - @Override - public List computeCandidates() { - return GTCEuAPI.PSS_BATTERIES.entrySet().stream() + return blocks("PSS-Batteries", + () -> GTCEuAPI.PSS_BATTERIES.values() + .stream().map(Supplier::get), + () -> GTCEuAPI.PSS_BATTERIES.entrySet() + .stream() .sorted(Comparator.comparingInt(e -> e.getKey().getTier())) - .map(e -> new BlockInfo(e.getValue().get().defaultBlockState(), null)) - .toList(); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("PSSBatteries"); - } - }; - - /* - * return new TraceabilityPredicate(blockWorldState -> { - * BlockState state = blockWorldState.getBlockState(); - * for (Map.Entry> entry : GTCEuAPI.PSS_BATTERIES.entrySet()) { - * if (state.is(entry.getValue().get())) { - * IBatteryData battery = entry.getKey(); - * // Allow unfilled batteries in the structure, but do not add them to match context. - * // This lets you use empty batteries as "filler slots" for convenience if desired. - * if (battery.getTier() != -1 && battery.getCapacity() > 0) { - * String key = PMC_BATTERY_HEADER + battery.getBatteryName(); - * PowerSubstationMachine.BatteryMatchWrapper wrapper = blockWorldState.getMatchContext().get(key); - * if (wrapper == null) wrapper = new PowerSubstationMachine.BatteryMatchWrapper(battery); - * blockWorldState.getMatchContext().set(key, wrapper.increment()); - * } - * return true; - * } - * } - * return false; - * }, () -> GTCEuAPI.PSS_BATTERIES.entrySet().stream() - * .sorted(Comparator.comparingInt(entry -> entry.getKey().getTier())) - * .map(entry -> new BlockInfo(entry.getValue().get().defaultBlockState(), null)) - * .toArray(BlockInfo[]::new)) - * .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.batteries")); - */ + .map(e -> e.getValue().get())) + .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.batteries")); } public static @Nullable BasePredicate dataHatchPredicate() { @@ -680,6 +397,7 @@ public StringBuilder appendType(StringBuilder builder) { .setExactLimit(1) .setPriority(1); } + // this really should not be null return null; } @@ -689,35 +407,21 @@ public StringBuilder appendType(StringBuilder builder) { public static BasePredicate frames(Material... frameMaterials) { var frameBlocks = Arrays.stream(frameMaterials) .map(m -> GTMaterialBlocks.MATERIAL_BLOCKS.get(TagPrefix.frameGt, m)) - .filter(Objects::nonNull) - .filter(RegistryEntry::isPresent) + .filter(obj -> Objects.nonNull(obj) && obj.isPresent()) .map(RegistryEntry::get) .toArray(Block[]::new); - return blocks(frameBlocks).or(framedPipes(frameMaterials, frameBlocks)); + return blocks("Frames", frameBlocks) + .or(framedPipes(frameMaterials, frameBlocks)); } public static BasePredicate framedPipes(Material[] frameMaterials, Block[] frameBlocks) { - return new BasePredicate() { - - @Override - public boolean testInternal(PredicateContext ctx) { - BlockEntity tileEntity = ctx.blockEntity(); - if (!(tileEntity instanceof IPipeNode pipeNode)) { - return ctx.error(PLACEHOLDER); - } - return ArrayUtils.contains(frameMaterials, pipeNode.getFrameMaterial()) || - ctx.error(PLACEHOLDER); - } - - @Override - public List computeCandidates() { - return Arrays.stream(frameBlocks).map(BlockInfo::fromBlock).toList(); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("FramedPipes"); + return customPredicate("FramedPipes", ctx -> { + BlockEntity tileEntity = ctx.blockEntity(); + if (!(tileEntity instanceof IPipeNode pipeNode)) { + return ctx.error(PLACEHOLDER); } - }; + return ArrayUtils.contains(frameMaterials, pipeNode.getFrameMaterial()) || + ctx.error(PLACEHOLDER); + }, () -> Arrays.stream(frameBlocks).map(BlockInfo::fromBlock)); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 6634cce8cb7..4f1a99a9fb4 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -22,6 +22,9 @@ import java.util.*; import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.stream.Stream; @Accessors(chain = true) public abstract class BasePredicate { @@ -317,4 +320,45 @@ public static BasePredicate or(@Nullable String debugName, Iterable predicates) { return new MultiPredicate(debugName, predicates, MultiPredicate.Logic.AND); } + + public static class Custom extends BasePredicate { + @Nullable + private final String debugName; + private final Predicate predicate; + private final Supplier> candidates; + private Consumer contents = b -> {}; + + public Custom(@Nullable String debugName, + Predicate predicate, + Supplier> candidates, + @Nullable Consumer contents) { + this.debugName = debugName; + this.predicate = predicate; + this.candidates = candidates; + if (contents != null) { + this.contents = contents; + } + } + + @Override + public boolean testInternal(PredicateContext ctx) { + return this.predicate.test(ctx); + } + + @Override + public List computeCandidates() { + return this.candidates.get().toList(); + } + + @Override + public StringBuilder appendType(StringBuilder builder) { + return builder.append(debugName != null ? debugName : "Custom"); + } + + @Override + protected StringBuilder appendContents(StringBuilder builder) { + contents.accept(builder); + return builder; + } + } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index 02077e78208..460ccf76fd3 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -74,6 +74,7 @@ import java.util.*; import java.util.function.Function; +import java.util.stream.Stream; import javax.annotation.ParametersAreNonnullByDefault; @@ -472,8 +473,9 @@ protected static BlockState getGlassState() { protected static BasePredicate doorPredicate() { return Predicates.customPredicate( ctx -> ctx.state().getBlock() instanceof DoorBlock || ctx.error(Predicates.PLACEHOLDER), - List.of(new BlockInfo(Blocks.IRON_DOOR.defaultBlockState()), new BlockInfo( - Blocks.IRON_DOOR.defaultBlockState().setValue(DoorBlock.HALF, DoubleBlockHalf.UPPER)))); + () -> Stream.of(new BlockInfo(Blocks.IRON_DOOR.defaultBlockState()), + new BlockInfo(Blocks.IRON_DOOR.defaultBlockState() + .setValue(DoorBlock.HALF, DoubleBlockHalf.UPPER)))); } private static BasePredicate getValidFloorBlocks() { From 719142393d7223e0cdbbaafc56f744bfbc9abecd Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 18 Jun 2026 19:43:37 -0700 Subject: [PATCH 018/101] add and use simple type name --- .../gtceu/api/multiblock/predicates/BasePredicate.java | 4 ++++ .../recipeviewer/widgets/MultiblockPreviewWidget.java | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 4f1a99a9fb4..3454fd69ea6 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -272,6 +272,10 @@ public final List expand() { return Collections.unmodifiableList(result); } + public String getTypeName() { + return appendType(new StringBuilder()).toString(); + } + /// the type of this predicate public abstract StringBuilder appendType(StringBuilder builder); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java index b9a0da3f47d..4a18baa6724 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java @@ -257,9 +257,9 @@ private ContextMenuButton createSelectedBlockMenu(BasePredicate predicate) { if (candidates.isEmpty()) return new EmptyWidget(); if (candidates.size() > 1) { - return new ContextMenuButton<>(basePredicate.toString()) + return new ContextMenuButton<>(basePredicate.getTypeName()) .size(16) - .tooltip(r -> r.add(basePredicate.toString())) + .tooltip(r -> r.add(basePredicate.getTypeName())) .overlay(new ItemDrawable( candidates.get(0).getItemStackForm())) .requiresClick() @@ -354,7 +354,7 @@ private ContextMenuButton createInnerPredicateMenu(BasePredicate predicate, B List candidates) { return new ContextMenuButton<>(basePredicate.toString()) .size(16) - .tooltip(r -> r.add(basePredicate.toString())) + .tooltip(r -> r.add(basePredicate.getTypeName())) .overlay(new ItemDrawable( candidates.get(0).getItemStackForm())) .requiresClick() From 82759f77b747c5728694cf516a23aee2abb1ed5b Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Mon, 22 Jun 2026 17:00:30 -0700 Subject: [PATCH 019/101] use custom predicate for rotor holder spotless --- .../gtceu/api/multiblock/Predicates.java | 27 +++++------ .../multiblock/predicates/BasePredicate.java | 4 +- .../multiblock/predicates/MultiPredicate.java | 6 ++- .../common/data/machines/GTMachineUtils.java | 45 ++++++------------- 4 files changed, 35 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 057670ea070..75a70c375f6 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -133,16 +133,16 @@ public static BasePredicate blocks(@Nullable String debugName, Supplier> blocks, Supplier> candidates) { return customPredicate(debugName, ctx -> { - var blockList = blocks.get().toList(); - for (var block : blockList) { - if (ctx.state().is(block)) return true; - } - return ctx.error(new BlockMatchingError(ctx.pos(), blockList)); - }, () -> candidates.get().map(BlockInfo::fromBlock), builder -> { - StringJoiner joiner = new StringJoiner(", "); - blocks.get().forEach(block -> joiner.add(blockToString(block))); - builder.append(joiner); - }); + var blockList = blocks.get().toList(); + for (var block : blockList) { + if (ctx.state().is(block)) return true; + } + return ctx.error(new BlockMatchingError(ctx.pos(), blockList)); + }, () -> candidates.get().map(BlockInfo::fromBlock), builder -> { + StringJoiner joiner = new StringJoiner(", "); + blocks.get().forEach(block -> joiner.add(blockToString(block))); + builder.append(joiner); + }); } private static String blockToString(BlockState blockState) { @@ -247,8 +247,8 @@ public static BasePredicate abilities(PartAbility... abilities) { return false; }, () -> Arrays.stream(abilities) - .flatMap(a -> a.getAllBlocks().stream()) - .map(BlockInfo::fromBlock), + .flatMap(a -> a.getAllBlocks().stream()) + .map(BlockInfo::fromBlock), builder -> { StringJoiner sb = new StringJoiner(", "); for (PartAbility ability : abilities) { @@ -264,7 +264,8 @@ public static BasePredicate ability(PartAbility ability, int... tiers) { sb.add(GTValues.VN[tier]); } return customPredicate("Ability[" + sb + "]", - ctx -> ability.isApplicable(ctx.state().getBlock()) || ctx.error(new PartAbilityError(ctx.pos(), ability)), + ctx -> ability.isApplicable(ctx.state().getBlock()) || + ctx.error(new PartAbilityError(ctx.pos(), ability)), () -> ability.getBlocks(tiers).stream().map(BlockInfo::fromBlock)); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 3454fd69ea6..5853a071a5b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -50,7 +50,8 @@ public StringBuilder appendType(StringBuilder builder) { } }; - protected static final Comparator PREDICATE_COMPARATOR = Comparator.comparingInt(BasePredicate::getPriority); + protected static final Comparator PREDICATE_COMPARATOR = Comparator + .comparingInt(BasePredicate::getPriority); private @Nullable List candidates; private @Nullable List tooltips; @Getter @@ -326,6 +327,7 @@ public static BasePredicate and(@Nullable String debugName, Iterable predicate; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 678195ade0b..f6dad0b22af 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -2,8 +2,8 @@ import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -203,7 +203,9 @@ private static MultiPredicate combine(MultiPredicate a, MultiPredicate b, MultiP } protected enum Logic { + OR { + @Override protected boolean run(PredicateContext ctx, List predicates) { for (BasePredicate basePredicate : predicates) { @@ -215,6 +217,7 @@ protected boolean run(PredicateContext ctx, List predicates) { } }, AND { + @Override protected boolean run(PredicateContext ctx, List predicates) { return !OR.run(ctx, predicates); @@ -222,6 +225,7 @@ protected boolean run(PredicateContext ctx, List predicates) { }, // unused XOR { + @Override protected boolean run(PredicateContext ctx, List predicates) { return true; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 39d01efae7b..308b96b2a05 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -22,7 +22,6 @@ import com.gregtechceu.gtceu.api.machine.steam.SimpleSteamMachine; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; import com.gregtechceu.gtceu.api.mui.factory.PanelFactory; -import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; @@ -741,38 +740,20 @@ public static MultiblockMachineDefinition registerLargeTurbine(GTRegistrate regi } private static BasePredicate rotorHolder(int tier) { - return new BasePredicate() { - - { - addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")); - addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", VN[tier])); - } - - @Override - public boolean testInternal(@NotNull PredicateContext ctx) { - if (MetaMachine.getMachine(ctx.level(), - ctx.pos()) instanceof RotorHolderPartMachine rotorHolder && - ctx.level().getBlockState(ctx.pos() - .relative(rotorHolder.getFrontFacing())) - .isAir()) { - return true; - } - return ctx.error(new PartAbilityError(ctx.pos(), PartAbility.ROTOR_HOLDER)); - } - - @Override - public List computeCandidates() { - return PartAbility.ROTOR_HOLDER.getAllBlocks() - .stream() - .map(BlockInfo::fromBlock) - .toList(); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("RotorHolder"); + return Predicates.customPredicate("RotorHolder", ctx -> { + if (MetaMachine.getMachine(ctx.level(), + ctx.pos()) instanceof RotorHolderPartMachine rotorHolder && + ctx.level().getBlockState(ctx.pos() + .relative(rotorHolder.getFrontFacing())) + .isAir()) { + return true; } - }; + return ctx.error(new PartAbilityError(ctx.pos(), PartAbility.ROTOR_HOLDER)); + }, () -> PartAbility.ROTOR_HOLDER.getAllBlocks() + .stream() + .map(BlockInfo::fromBlock)) + .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")) + .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", VN[tier])); } // Tooltips From 0306828198efb9dfcf1451e7e4c833ce53b14725 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 26 Jun 2026 14:52:41 -0700 Subject: [PATCH 020/101] delete unused tooltips --- .../gtceu/api/multiblock/Predicates.java | 8 ++-- .../multiblock/predicates/BasePredicate.java | 47 +------------------ 2 files changed, 6 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 75a70c375f6..0cc4862b7dc 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -364,7 +364,7 @@ public static BasePredicate autoAbilities(boolean checkMaintenance, boolean chec public static BasePredicate heatingCoils() { return blocks("HeatingCoils", () -> GTCEuAPI.HEATING_COILS.values().stream().map(Supplier::get)) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")) +// .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")) .setPriority(0); } @@ -376,7 +376,8 @@ public static BasePredicate cleanroomFilters() { .stream() .sorted(Comparator.comparingInt(e -> e.getKey().getCleanroomType().getTier())) .map(entry -> entry.getValue().get())) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.cleanroom")); +// .addTooltips(Component.translatable("gtceu.multiblock.pattern.cleanroom")) + ; } public static BasePredicate powerSubstationBatteries() { @@ -387,7 +388,8 @@ public static BasePredicate powerSubstationBatteries() { .stream() .sorted(Comparator.comparingInt(e -> e.getKey().getTier())) .map(e -> e.getValue().get())) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.batteries")); +// .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.batteries")) + ; } public static @Nullable BasePredicate dataHatchPredicate() { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 5853a071a5b..88fe4ca892d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -53,7 +53,7 @@ public StringBuilder appendType(StringBuilder builder) { protected static final Comparator PREDICATE_COMPARATOR = Comparator .comparingInt(BasePredicate::getPriority); private @Nullable List candidates; - private @Nullable List tooltips; + @Getter @Setter private int priority = 0; @@ -190,51 +190,6 @@ public BasePredicate disabledRenderFormed() { return setDisableRenderFormed(true); } - public List additionalTooltips() { - if (this.tooltips == null) { - this.tooltips = new ArrayList<>(); - } - return this.tooltips; - } - - public BasePredicate addTooltips(Component tooltip) { - this.additionalTooltips().add(tooltip); - return this; - } - - public BasePredicate addTooltips(Component... tooltips) { - Collections.addAll(this.additionalTooltips(), tooltips); - return this; - } - - @OnlyIn(Dist.CLIENT) - public List getTooltips(@Nullable BasePredicate predicate) { - List result = new ArrayList<>(); - if (tooltips != null) { - result.addAll(tooltips); - } - if (minCount == maxCount && maxCount != -1) { - result.add(Component.translatable("gtceu.multiblock.pattern.error.limited_exact", minCount)); - } else if (minCount != maxCount && minCount != -1 && maxCount != -1) { - result.add(Component.translatable("gtceu.multiblock.pattern.error.limited_within", minCount, maxCount)); - } else { - if (minCount != -1) { - result.add(LangHandler.getFromMultiLang("gtceu.multiblock.pattern.error.limited", 1, minCount)); - } - if (maxCount != -1) { - result.add(LangHandler.getFromMultiLang("gtceu.multiblock.pattern.error.limited", 0, maxCount)); - } - } - if (predicate == null) return result; - if (predicate.isSingle()) { - result.add(Component.translatable("gtceu.multiblock.pattern.single")); - } - if (predicate.hasAir()) { - result.add(Component.translatable("gtceu.multiblock.pattern.replaceable_air")); - } - return result; - } - public List getCandidateStacks() { return getCandidates().stream() .filter(BlockInfo::nonAir) From 69f08abf49502c70de8ae3706fcc6150cd92c43d Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 26 Jun 2026 15:52:21 -0700 Subject: [PATCH 021/101] move test layer/global methods out to MultiPredicate replace custom with anonymous class move methods around improve MultiPredicate constructors allow MultiPredicates with a single predicate to function pre-calculate hasAir --- .../gtceu/api/multiblock/Predicates.java | 2 +- .../multiblock/predicates/BasePredicate.java | 182 +++++++----------- .../multiblock/predicates/MultiPredicate.java | 117 ++++++----- 3 files changed, 125 insertions(+), 176 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 0cc4862b7dc..73081dee333 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -216,7 +216,7 @@ public static BasePredicate customPredicate(@Nullable String debugName, Predicate predicate, Supplier> candidates, @Nullable Consumer contents) { - return new BasePredicate.Custom(debugName, predicate, candidates, contents); + return BasePredicate.create(debugName, predicate, candidates.get(), contents); } public static BasePredicate any() { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 88fe4ca892d..b3517132368 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -2,18 +2,13 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; -import com.gregtechceu.gtceu.data.lang.LangHandler; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import lombok.Getter; import lombok.Setter; @@ -23,94 +18,89 @@ import java.util.*; import java.util.function.Consumer; import java.util.function.Predicate; -import java.util.function.Supplier; import java.util.stream.Stream; @Accessors(chain = true) public abstract class BasePredicate { - public static final BasePredicate AIR = new BasePredicate() { + public static final BasePredicate AIR = create("Air", ctx -> ctx.state().is(Blocks.AIR)); - @Override - public boolean testInternal(PredicateContext ctx) { - return ctx.state().is(Blocks.AIR); - } - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("Air"); - } - }; - - public static final BasePredicate ANY = new BasePredicate() { - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("Any"); - } - }; + public static final BasePredicate ANY = create("Any", ctx -> true); protected static final Comparator PREDICATE_COMPARATOR = Comparator .comparingInt(BasePredicate::getPriority); + private @Nullable List candidates; @Getter @Setter - private int priority = 0; + protected int priority = 0; @Getter @Setter - private int minCount = -1; + protected int minCount = -1; @Getter @Setter - private int maxCount = -1; + protected int maxCount = -1; @Getter @Setter - private int minSliceCount = -1; + protected int minSliceCount = -1; @Getter @Setter - private int maxSliceCount = -1; + protected int maxSliceCount = -1; @Getter @Setter - private int previewCount = -1; + protected int previewCount = -1; @Getter @Setter - private boolean disableRenderFormed = false; + protected boolean disableRenderFormed = false; @Getter @Setter private @Nullable String nbtParser; // unsure what this does /// the main testing method public boolean test(PredicateContext ctx) { - return testInternal(ctx) && testGlobal(ctx) && testLayer(ctx); + return true; } - /// custom testing logic, usually checking if blockstate/entity is correct - public boolean testInternal(PredicateContext ctx) { + /// method called after all blocks have been iterated, used for checking min values + public boolean postTest(PredicateContext ctx) { return true; } - /// test against global max count - public boolean testGlobal(PredicateContext ctx) { - ctx.globalCache().mergeInt(this, 1, Integer::sum); - if ((minCount == -1 && maxCount == -1) || ctx.layerCache() == null) return true; - int count = ctx.globalCache().getInt(this); - if (maxCount == -1 || count <= maxCount) return true; - return ctx.error(SinglePredicateError.maxCount(this, count)); + /// computes the candidates for this predicate, lazily initialized + public List computeCandidates() { + return Collections.emptyList(); } - /// test against slice max count - public boolean testLayer(PredicateContext ctx) { - if (ctx.layerCache() == null) return true; - ctx.layerCache().mergeInt(this, 1, Integer::sum); - if ((minSliceCount == -1 && maxSliceCount == -1)) return true; - int count = ctx.layerCache().getInt(this); - if (maxSliceCount == -1 || count <= maxSliceCount) return true; - return ctx.error(SinglePredicateError.maxLayerCount(this, count)); + public List getCandidates(int index) { + return getCandidates(); } - /// computes the candidates for this predicate, lazily initialized - public List computeCandidates() { - return Collections.emptyList(); + public List getCandidates() { + if (candidates == null) { + candidates = computeCandidates(); + } + return candidates; + } + + public List getCandidateStacks() { + return getCandidates().stream() + .filter(BlockInfo::nonAir) + .map(info -> { + if (GTCEu.isClientSide()) { + Level level = Objects.requireNonNull(Minecraft.getInstance().level); + return info.getItemStackForm(level, BlockPos.ZERO); + } + + return info.getItemStackForm(); + }) + .toList(); + } + + public Optional getFirstCandidate() { + return Optional.of(getCandidates()) + .filter(c -> !c.isEmpty()) + .map(c -> c.get(0)); } public boolean isAir() { @@ -190,33 +180,6 @@ public BasePredicate disabledRenderFormed() { return setDisableRenderFormed(true); } - public List getCandidateStacks() { - return getCandidates().stream() - .filter(BlockInfo::nonAir) - .map(info -> { - if (GTCEu.isClientSide()) { - Level level = Objects.requireNonNull(Minecraft.getInstance().level); - return info.getItemStackForm(level, BlockPos.ZERO); - } - - return info.getItemStackForm(); - }) - .toList(); - } - - public List getCandidates() { - if (candidates == null) { - candidates = computeCandidates(); - } - return candidates; - } - - public Optional getFirstCandidate() { - return Optional.of(getCandidates()) - .filter(c -> !c.isEmpty()) - .map(c -> c.get(0)); - } - public void visit(Consumer visitor) { visitor.accept(this); } @@ -281,45 +244,36 @@ public static BasePredicate and(@Nullable String debugName, Iterable predicate) { + return create(debugName, predicate, Stream.empty(), null); + } - @Nullable - private final String debugName; - private final Predicate predicate; - private final Supplier> candidates; - private Consumer contents = b -> {}; + public static BasePredicate create(@Nullable String debugName, Predicate predicate, + Stream candidates, @Nullable Consumer contents) { + return new BasePredicate() { - public Custom(@Nullable String debugName, - Predicate predicate, - Supplier> candidates, - @Nullable Consumer contents) { - this.debugName = debugName; - this.predicate = predicate; - this.candidates = candidates; - if (contents != null) { - this.contents = contents; + @Override + public boolean test(PredicateContext ctx) { + return predicate.test(ctx); } - } - - @Override - public boolean testInternal(PredicateContext ctx) { - return this.predicate.test(ctx); - } - @Override - public List computeCandidates() { - return this.candidates.get().toList(); - } + @Override + public List computeCandidates() { + return candidates.toList(); + } - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append(debugName != null ? debugName : "Custom"); - } + @Override + public StringBuilder appendType(StringBuilder builder) { + return builder.append(Objects.requireNonNullElse(debugName, "Predicate")); + } - @Override - protected StringBuilder appendContents(StringBuilder builder) { - contents.accept(builder); - return builder; - } + @Override + protected StringBuilder appendContents(StringBuilder builder) { + if (contents != null) { + contents.accept(builder); + } + return builder; + } + }; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index f6dad0b22af..0e59f0dd820 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -8,40 +9,73 @@ import java.util.*; import java.util.function.Consumer; +import java.util.function.Predicate; public class MultiPredicate extends BasePredicate { private final List predicateList = new ObjectArrayList<>(); - private final @Nullable String debugName; + private final List> indexedCandidates; + private final String debugName; private @Nullable Logic type; + private boolean hasAir = false; public MultiPredicate(@Nullable String debugName) { - this.debugName = debugName; + this.debugName = debugName == null ? "MultiPredicate" : debugName; + this.indexedCandidates = Collections.emptyList(); } protected MultiPredicate(@Nullable String debugName, Iterable predicates, Logic type) { - this(debugName); + this.debugName = debugName == null ? "MultiPredicate" : debugName; this.type = type; + List> indexedCandidates = new ArrayList<>(); for (BasePredicate predicate : predicates) { + this.hasAir |= predicate.hasAir(); if (!(predicate instanceof MultiPredicate multi)) { addPredicates(predicate); - continue; - } - - if (!multi.isValid() || multi.getType() == this.getType()) { - addPredicates(multi.predicateList); + indexedCandidates.add(predicate.getCandidates()); + } else if (!multi.sameType(this)) { + addPredicates(predicate); + indexedCandidates.add(predicate.getCandidates()); } else { - addPredicates(multi); + addPredicates(multi.predicateList); + multi.predicateList.forEach(p -> indexedCandidates.add(p.getCandidates())); } } + this.indexedCandidates = Collections.unmodifiableList(indexedCandidates); sorted(); } @Override public boolean test(PredicateContext ctx) { + return testInternal(ctx) && testGlobalMax(ctx) && testSliceMax(ctx); + } + + /// custom testing logic, usually checking if blockstate/entity is correct + private boolean testInternal(PredicateContext ctx) { + if (this.predicateList.isEmpty()) return true; + if (isSingle()) return this.predicateList.get(0).test(ctx); return getType().run(ctx, this.predicateList); } + /// test against global max count + private boolean testGlobalMax(PredicateContext ctx) { + ctx.globalCache().mergeInt(this, 1, Integer::sum); + if ((minCount == -1 && maxCount == -1) || ctx.layerCache() == null) return true; + int count = ctx.globalCache().getInt(this); + if (maxCount == -1 || count <= maxCount) return true; + return ctx.error(SinglePredicateError.maxCount(this, count)); + } + + /// test against slice max count + private boolean testSliceMax(PredicateContext ctx) { + if (ctx.layerCache() == null) return true; + ctx.layerCache().mergeInt(this, 1, Integer::sum); + if ((minSliceCount == -1 && maxSliceCount == -1)) return true; + int count = ctx.layerCache().getInt(this); + if (maxSliceCount == -1 || count <= maxSliceCount) return true; + return ctx.error(SinglePredicateError.maxLayerCount(this, count)); + } + protected MultiPredicate addPredicates(Collection predicates) { predicates.forEach(this::addPredicates); return this; @@ -60,50 +94,13 @@ public List computeCandidates() { } @Override - public void visit(Consumer visitor) { - predicateList.forEach(p -> p.visit(visitor)); - } - - @Override - public MultiPredicate setMinCount(int minCount) { - this.predicateList.forEach(p -> p.setMinCount(minCount)); - super.setMinCount(minCount); - return this; - } - - @Override - public MultiPredicate setMaxCount(int maxCount) { - this.predicateList.forEach(p -> p.setMaxCount(maxCount)); - super.setMaxCount(maxCount); - return this; - } - - @Override - public MultiPredicate setMinSliceCount(int minSliceCount) { - this.predicateList.forEach(p -> p.setMinSliceCount(minSliceCount)); - super.setMinSliceCount(minSliceCount); - return this; - } - - @Override - public MultiPredicate setMaxSliceCount(int maxSliceCount) { - this.predicateList.forEach(p -> p.setMaxSliceCount(maxSliceCount)); - super.setMaxSliceCount(maxSliceCount); - return this; - } - - @Override - public MultiPredicate setPreviewCount(int previewCount) { - this.predicateList.forEach(p -> p.setPreviewCount(previewCount)); - super.setPreviewCount(previewCount); - return this; + public List getCandidates(int index) { + return this.indexedCandidates.get(index); } @Override - public MultiPredicate setDisableRenderFormed(boolean disableRenderFormed) { - this.predicateList.forEach(p -> p.setDisableRenderFormed(disableRenderFormed)); - super.setDisableRenderFormed(disableRenderFormed); - return this; + public void visit(Consumer visitor) { + predicateList.forEach(p -> p.visit(visitor)); } public boolean isOr() { @@ -115,19 +112,20 @@ public boolean isAnd() { } public boolean isValid() { - return this.type != null; + return isSingle() || this.type != null; } protected Logic getType() { return Objects.requireNonNull(type, "null type: " + this); } + protected boolean sameType(MultiPredicate other) { + return this.type == other.type; + } + @Override public boolean hasAir() { - for (BasePredicate predicate : predicateList) { - if (predicate.hasAir()) return true; - } - return false; + return this.hasAir; } protected MultiPredicate sorted() { @@ -167,18 +165,15 @@ public MultiPredicate and(BasePredicate other) { @Override public boolean isSingle() { - return false; + return this.predicateList.size() == 1; } @Override public StringBuilder appendType(StringBuilder builder) { - builder.append("Multi") + builder.append(debugName) .append('(') - .append(this.type == null ? "INVAlID" : this.type) + .append(isValid() ? isSingle() ? "SINGLE" : this.type : "INVAlID") .append(')'); - if (debugName != null) { - builder.append('#').append(debugName); - } return builder; } From 6fe2f93a66a54df5f80256f6ec9ae2917ee4115d Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:06:32 -0700 Subject: [PATCH 022/101] refactor string and type name use stream instead of stream supplier comment out tooltips --- .../gtceu/api/multiblock/Predicates.java | 39 +++++++++---------- .../multiblock/predicates/BasePredicate.java | 27 +++++-------- .../multiblock/predicates/MultiPredicate.java | 16 ++++---- .../common/data/machines/GTMachineUtils.java | 15 ++++--- .../multiblock/electric/CleanroomMachine.java | 36 ++++++----------- 5 files changed, 56 insertions(+), 77 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 73081dee333..09beaebf8f9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -25,7 +25,6 @@ import com.gregtechceu.gtceu.config.ConfigHolder; import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; import net.minecraft.tags.TagKey; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; @@ -71,13 +70,13 @@ public List computeCandidates() { } @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("Controller"); + public String getTypeName() { + return "Controller"; } @Override - protected StringBuilder appendContents(StringBuilder builder) { - return builder.append(predicate); + protected void appendContents(StringBuilder builder) { + builder.append(predicate); } @Override @@ -101,7 +100,7 @@ public static BasePredicate states(@Nullable String debugName, BlockState... all } return customPredicate(debugName, ctx -> states.contains(ctx.state()) || ctx.error(PLACEHOLDER), - () -> states.stream().map(BlockInfo::fromBlockState), + states.stream().map(BlockInfo::fromBlockState), builder -> { StringJoiner joiner = new StringJoiner(", "); states.forEach(state -> joiner.add(blockToString(state))); @@ -112,7 +111,7 @@ public static BasePredicate states(@Nullable String debugName, BlockState... all public static BasePredicate blocks(Block block) { return customPredicate("Block", ctx -> ctx.state().is(block) || ctx.error(new BlockMatchingError(ctx.pos(), List.of(block))), - () -> Stream.of(BlockInfo.fromBlock(block)), + Stream.of(BlockInfo.fromBlock(block)), builder -> builder.append(blockToString(block))); } @@ -138,7 +137,7 @@ public static BasePredicate blocks(@Nullable String debugName, if (ctx.state().is(block)) return true; } return ctx.error(new BlockMatchingError(ctx.pos(), blockList)); - }, () -> candidates.get().map(BlockInfo::fromBlock), builder -> { + }, candidates.get().map(BlockInfo::fromBlock), builder -> { StringJoiner joiner = new StringJoiner(", "); blocks.get().forEach(block -> joiner.add(blockToString(block))); builder.append(joiner); @@ -163,7 +162,7 @@ public static BasePredicate machines(MachineDefinition... definitions) { public static BasePredicate blockTag(TagKey tag) { return customPredicate("BlockTag", ctx -> ctx.state().is(tag), - () -> Objects.requireNonNull(ForgeRegistries.BLOCKS.tags()) + Objects.requireNonNull(ForgeRegistries.BLOCKS.tags()) .getTag(tag).stream() .map(BlockInfo::fromBlock), builder -> builder.append(tag.location())); @@ -172,7 +171,7 @@ public static BasePredicate blockTag(TagKey tag) { public static BasePredicate fluids(Fluid... fluids) { return customPredicate("Fluids", ctx -> ArrayUtils.contains(fluids, ctx.fluid()) || ctx.error(PLACEHOLDER), - () -> Arrays.stream(fluids).map(BlockInfo::fromFluid), + Arrays.stream(fluids).map(BlockInfo::fromFluid), builder -> { StringJoiner joiner = new StringJoiner(", "); for (Fluid fluid : fluids) { @@ -187,7 +186,7 @@ public static BasePredicate fluids(Fluid... fluids) { public static BasePredicate fluidTag(TagKey tag) { return customPredicate("FluidTag", ctx -> ctx.fluidState().is(tag), - () -> Objects.requireNonNull(ForgeRegistries.FLUIDS.tags()) + Objects.requireNonNull(ForgeRegistries.FLUIDS.tags()) .getTag(tag).stream() .map(BlockInfo::fromFluid), builder -> builder.append(tag.location())); @@ -198,25 +197,25 @@ public static BasePredicate customFunction(Function { PatternError error = predicate.apply(ctx.blockInfo()); return error == null || ctx.error(error); - }, Optional.ofNullable(candidates).orElse(Collections.emptyList())::stream); + }, Objects.>requireNonNullElse(candidates, Collections.emptyList()).stream()); } public static BasePredicate customPredicate(Predicate predicate, - Supplier> candidates) { + Stream candidates) { return customPredicate(null, predicate, candidates); } public static BasePredicate customPredicate(@Nullable String debugName, Predicate predicate, - Supplier> candidates) { + Stream candidates) { return customPredicate(debugName, predicate, candidates, null); } public static BasePredicate customPredicate(@Nullable String debugName, Predicate predicate, - Supplier> candidates, + Stream candidates, @Nullable Consumer contents) { - return BasePredicate.create(debugName, predicate, candidates.get(), contents); + return BasePredicate.create(debugName, predicate, candidates, contents); } public static BasePredicate any() { @@ -231,7 +230,7 @@ public static BasePredicate abilities(PartAbility ability) { return customPredicate("Ability", ctx -> ability.isApplicable(ctx.state().getBlock()) || ctx.error(new PartAbilityError(ctx.pos(), ability)), - () -> ability.getAllBlocks().stream().map(BlockInfo::fromBlock), + ability.getAllBlocks().stream().map(BlockInfo::fromBlock), builder -> builder.append(ability.getName())); } @@ -246,7 +245,7 @@ public static BasePredicate abilities(PartAbility... abilities) { } return false; }, - () -> Arrays.stream(abilities) + Arrays.stream(abilities) .flatMap(a -> a.getAllBlocks().stream()) .map(BlockInfo::fromBlock), builder -> { @@ -266,7 +265,7 @@ public static BasePredicate ability(PartAbility ability, int... tiers) { return customPredicate("Ability[" + sb + "]", ctx -> ability.isApplicable(ctx.state().getBlock()) || ctx.error(new PartAbilityError(ctx.pos(), ability)), - () -> ability.getBlocks(tiers).stream().map(BlockInfo::fromBlock)); + ability.getBlocks(tiers).stream().map(BlockInfo::fromBlock)); } public static BasePredicate autoAbilities(GTRecipeType... recipeType) { @@ -425,6 +424,6 @@ public static BasePredicate framedPipes(Material[] frameMaterials, Block[] frame } return ArrayUtils.contains(frameMaterials, pipeNode.getFrameMaterial()) || ctx.error(PLACEHOLDER); - }, () -> Arrays.stream(frameBlocks).map(BlockInfo::fromBlock)); + }, Arrays.stream(frameBlocks).map(BlockInfo::fromBlock)); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index b3517132368..1e2b50a8aa6 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -191,25 +191,19 @@ public final List expand() { return Collections.unmodifiableList(result); } - public String getTypeName() { - return appendType(new StringBuilder()).toString(); - } - /// the type of this predicate - public abstract StringBuilder appendType(StringBuilder builder); + public abstract String getTypeName(); /// the contents of this predicate - protected StringBuilder appendContents(StringBuilder builder) { - return builder; - } + protected void appendContents(StringBuilder builder) {} @Override public String toString() { - StringBuilder builder = appendType(new StringBuilder()) - .append('{'); - return appendContents(builder) - .append('}') - .toString(); + StringBuilder builder = new StringBuilder(getTypeName()); + builder.append('{'); + appendContents(builder); + builder.append('}'); + return builder.toString(); } public BasePredicate or(BasePredicate other) { @@ -263,16 +257,15 @@ public List computeCandidates() { } @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append(Objects.requireNonNullElse(debugName, "Predicate")); + public String getTypeName() { + return Objects.requireNonNullElse(debugName, "Predicate"); } @Override - protected StringBuilder appendContents(StringBuilder builder) { + protected void appendContents(StringBuilder builder) { if (contents != null) { contents.accept(builder); } - return builder; } }; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 0e59f0dd820..35830652514 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -9,7 +9,6 @@ import java.util.*; import java.util.function.Consumer; -import java.util.function.Predicate; public class MultiPredicate extends BasePredicate { @@ -169,19 +168,18 @@ public boolean isSingle() { } @Override - public StringBuilder appendType(StringBuilder builder) { - builder.append(debugName) - .append('(') - .append(isValid() ? isSingle() ? "SINGLE" : this.type : "INVAlID") - .append(')'); - return builder; + public String getTypeName() { + return debugName + + '(' + + (isValid() ? isSingle() ? "SINGLE" : this.type : "INVAlID") + + ')'; } @Override - protected StringBuilder appendContents(StringBuilder builder) { + protected void appendContents(StringBuilder builder) { StringJoiner joiner = new StringJoiner(", "); this.predicateList.forEach(p -> joiner.add(p.toString())); - return builder.append(joiner); + builder.append(joiner); } private static MultiPredicate combine(MultiPredicate a, MultiPredicate b, MultiPredicate dest) { diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 308b96b2a05..322be0acfa5 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -670,11 +670,13 @@ public static MultiblockMachineDefinition registerLargeCombustionEngine(GTRegist IntStream.of(ULV, LV, MV, HV, EV, IV, LuV, ZPM, UV, UHV) .filter(t -> t >= tier) .toArray()) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", - GTValues.VN[tier]))) +// .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", +// GTValues.VN[tier])) + ) .where('A', blocks(intake.get()) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_1"))) +// .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_1")) + ) .where('Y', controller(blocks(definition.getBlock()))) .build()) .recoveryItems( @@ -749,11 +751,12 @@ private static BasePredicate rotorHolder(int tier) { return true; } return ctx.error(new PartAbilityError(ctx.pos(), PartAbility.ROTOR_HOLDER)); - }, () -> PartAbility.ROTOR_HOLDER.getAllBlocks() + }, PartAbility.ROTOR_HOLDER.getAllBlocks() .stream() .map(BlockInfo::fromBlock)) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", VN[tier])); +// .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")) +// .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", VN[tier])) + ; } // Tooltips diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index 460ccf76fd3..4965848ec0e 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -473,7 +473,7 @@ protected static BlockState getGlassState() { protected static BasePredicate doorPredicate() { return Predicates.customPredicate( ctx -> ctx.state().getBlock() instanceof DoorBlock || ctx.error(Predicates.PLACEHOLDER), - () -> Stream.of(new BlockInfo(Blocks.IRON_DOOR.defaultBlockState()), + Stream.of(new BlockInfo(Blocks.IRON_DOOR.defaultBlockState()), new BlockInfo(Blocks.IRON_DOOR.defaultBlockState() .setValue(DoorBlock.HALF, DoubleBlockHalf.UPPER)))); } @@ -483,32 +483,18 @@ private static BasePredicate getValidFloorBlocks() { } protected static BasePredicate innerPredicate() { - return new BasePredicate() { - - @Override - public boolean testInternal(PredicateContext ctx) { - // all non-GTMachines are allowed inside by default - BlockEntity blockEntity = ctx.blockEntity(); - if (blockEntity instanceof MetaMachine machine) { - if (isMachineBanned(machine)) { - return ctx.error(Predicates.PLACEHOLDER); - } - // todo do this in structure form not in the predicate - // machine.getTraitOptional(CleanroomReceiverTrait.TYPE).ifPresent(cleanroomReceivers::add); + return BasePredicate.create("InnerPredicate", ctx -> { + // all non-GTMachines are allowed inside by default + BlockEntity blockEntity = ctx.blockEntity(); + if (blockEntity instanceof MetaMachine machine) { + if (isMachineBanned(machine)) { + return ctx.error(Predicates.PLACEHOLDER); } - return true; - } - - @Override - public List computeCandidates() { - return List.of(); + // todo do this in structure form not in the predicate + // machine.getTraitOptional(CleanroomReceiverTrait.TYPE).ifPresent(cleanroomReceivers::add); } - - @Override - public StringBuilder appendType(StringBuilder builder) { - return builder.append("InnerPredicate"); - } - }; + return true; + }); } protected static boolean isMachineBanned(MetaMachine machine) { From 6fb876ffd2f08586385c86832fc7d2aff945a57c Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:09:15 -0700 Subject: [PATCH 023/101] implement xor spotless --- .../gregtechceu/gtceu/api/multiblock/Predicates.java | 10 +++++----- .../api/multiblock/predicates/MultiPredicate.java | 9 +++++++-- .../gtceu/common/data/machines/GTMachineUtils.java | 12 ++++++------ .../multiblock/electric/CleanroomMachine.java | 1 - 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 09beaebf8f9..1fe9dea9fb7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -363,7 +363,7 @@ public static BasePredicate autoAbilities(boolean checkMaintenance, boolean chec public static BasePredicate heatingCoils() { return blocks("HeatingCoils", () -> GTCEuAPI.HEATING_COILS.values().stream().map(Supplier::get)) -// .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")) + // .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")) .setPriority(0); } @@ -375,8 +375,8 @@ public static BasePredicate cleanroomFilters() { .stream() .sorted(Comparator.comparingInt(e -> e.getKey().getCleanroomType().getTier())) .map(entry -> entry.getValue().get())) -// .addTooltips(Component.translatable("gtceu.multiblock.pattern.cleanroom")) - ; + // .addTooltips(Component.translatable("gtceu.multiblock.pattern.cleanroom")) + ; } public static BasePredicate powerSubstationBatteries() { @@ -387,8 +387,8 @@ public static BasePredicate powerSubstationBatteries() { .stream() .sorted(Comparator.comparingInt(e -> e.getKey().getTier())) .map(e -> e.getValue().get())) -// .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.batteries")) - ; + // .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.batteries")) + ; } public static @Nullable BasePredicate dataHatchPredicate() { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 35830652514..a9356404588 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -216,12 +216,17 @@ protected boolean run(PredicateContext ctx, List predicates) { return !OR.run(ctx, predicates); } }, - // unused XOR { @Override protected boolean run(PredicateContext ctx, List predicates) { - return true; + int passed = 0; + for (BasePredicate basePredicate : predicates) { + if (basePredicate.test(ctx)) { + if (++passed > 1) return false; + } + } + return passed == 1; } }; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 322be0acfa5..7fffc09eaee 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -670,12 +670,12 @@ public static MultiblockMachineDefinition registerLargeCombustionEngine(GTRegist IntStream.of(ULV, LV, MV, HV, EV, IV, LuV, ZPM, UV, UHV) .filter(t -> t >= tier) .toArray()) -// .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", -// GTValues.VN[tier])) + // .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", + // GTValues.VN[tier])) ) .where('A', blocks(intake.get()) -// .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_1")) + // .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_1")) ) .where('Y', controller(blocks(definition.getBlock()))) .build()) @@ -754,9 +754,9 @@ private static BasePredicate rotorHolder(int tier) { }, PartAbility.ROTOR_HOLDER.getAllBlocks() .stream() .map(BlockInfo::fromBlock)) -// .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")) -// .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", VN[tier])) - ; + // .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")) + // .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", VN[tier])) + ; } // Tooltips diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index 4965848ec0e..221357788f1 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -15,7 +15,6 @@ import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.gregtechceu.gtceu.api.machine.multiblock.part.MultiblockPartMachine; import com.gregtechceu.gtceu.api.misc.EnergyContainerList; -import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.error.FilterMatchingError; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; From 8d42abd27c591859d6645aba9437a9ddc81fd14f Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:20:26 -0700 Subject: [PATCH 024/101] pull out is single check for is valid make logic nonnull make has air final --- .../multiblock/predicates/MultiPredicate.java | 32 ++++++------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index a9356404588..58e75400da7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -15,20 +15,16 @@ public class MultiPredicate extends BasePredicate { private final List predicateList = new ObjectArrayList<>(); private final List> indexedCandidates; private final String debugName; - private @Nullable Logic type; - private boolean hasAir = false; - - public MultiPredicate(@Nullable String debugName) { - this.debugName = debugName == null ? "MultiPredicate" : debugName; - this.indexedCandidates = Collections.emptyList(); - } + private final Logic type; + private final boolean hasAir; protected MultiPredicate(@Nullable String debugName, Iterable predicates, Logic type) { this.debugName = debugName == null ? "MultiPredicate" : debugName; this.type = type; + boolean hasAir = false; List> indexedCandidates = new ArrayList<>(); for (BasePredicate predicate : predicates) { - this.hasAir |= predicate.hasAir(); + hasAir |= predicate.hasAir(); if (!(predicate instanceof MultiPredicate multi)) { addPredicates(predicate); indexedCandidates.add(predicate.getCandidates()); @@ -41,6 +37,7 @@ protected MultiPredicate(@Nullable String debugName, Iterable pre } } this.indexedCandidates = Collections.unmodifiableList(indexedCandidates); + this.hasAir = hasAir; sorted(); } @@ -110,10 +107,6 @@ public boolean isAnd() { return this.type == Logic.AND; } - public boolean isValid() { - return isSingle() || this.type != null; - } - protected Logic getType() { return Objects.requireNonNull(type, "null type: " + this); } @@ -138,8 +131,6 @@ protected MultiPredicate copy() { @Override public MultiPredicate or(BasePredicate other) { - if (!isValid()) this.type = Logic.OR; - if (!(other instanceof MultiPredicate multi)) { return this.copy().addPredicates(other).sorted(); } @@ -151,8 +142,6 @@ public MultiPredicate or(BasePredicate other) { @Override public MultiPredicate and(BasePredicate other) { - if (!isValid()) this.type = Logic.AND; - if (!(other instanceof MultiPredicate multi)) { return this.copy().addPredicates(other).sorted(); } @@ -169,10 +158,7 @@ public boolean isSingle() { @Override public String getTypeName() { - return debugName + - '(' + - (isValid() ? isSingle() ? "SINGLE" : this.type : "INVAlID") + - ')'; + return debugName + '(' + (isSingle() ? "SINGLE" : this.type) + ')'; } @Override @@ -182,10 +168,10 @@ protected void appendContents(StringBuilder builder) { builder.append(joiner); } + /// @param a will have type set + /// @param b will have type set + /// @param dest output predicate private static MultiPredicate combine(MultiPredicate a, MultiPredicate b, MultiPredicate dest) { - if (!b.isValid()) { - b.type = a.getType(); - } if (a.getType() == b.getType()) { dest.addPredicates(b.predicateList); } else { From 39a671b8492ffd8641b65ae5bc1c637064853bbe Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:23:14 -0700 Subject: [PATCH 025/101] fully implement xor --- .../api/multiblock/predicates/BasePredicate.java | 16 ++++++++++++++++ .../multiblock/predicates/MultiPredicate.java | 15 +++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 1e2b50a8aa6..09d6769f019 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -214,6 +214,10 @@ public BasePredicate and(BasePredicate other) { return and(this, other); } + public BasePredicate xor(BasePredicate other) { + return xor(this, other); + } + private static BasePredicate or(BasePredicate a, BasePredicate b) { if (a instanceof MultiPredicate mp) { return mp.or(b); @@ -230,6 +234,14 @@ private static BasePredicate and(BasePredicate a, BasePredicate b) { } } + private static BasePredicate xor(BasePredicate a, BasePredicate b) { + if (a instanceof MultiPredicate mp) { + return mp.xor(b); + } else { + return and(null, List.of(a, b)); + } + } + public static BasePredicate or(@Nullable String debugName, Iterable predicates) { return new MultiPredicate(debugName, predicates, MultiPredicate.Logic.OR); } @@ -238,6 +250,10 @@ public static BasePredicate and(@Nullable String debugName, Iterable predicates) { + return new MultiPredicate(debugName, predicates, MultiPredicate.Logic.XOR); + } + public static BasePredicate create(@Nullable String debugName, Predicate predicate) { return create(debugName, predicate, Stream.empty(), null); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 58e75400da7..6c2ec5c69cb 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -107,6 +107,10 @@ public boolean isAnd() { return this.type == Logic.AND; } + public boolean isXor() { + return this.type == Logic.XOR; + } + protected Logic getType() { return Objects.requireNonNull(type, "null type: " + this); } @@ -151,6 +155,17 @@ public MultiPredicate and(BasePredicate other) { return combine(this, multi, this.copy()); } + @Override + public BasePredicate xor(BasePredicate other) { + if (!(other instanceof MultiPredicate multi)) { + return this.copy().addPredicates(other).sorted(); + } + + if (!isXor()) return multi.xor(this); + + return combine(this, multi, this.copy()); + } + @Override public boolean isSingle() { return this.predicateList.size() == 1; From 55b44f77a87caa11c9276b5c61a4c94ea0e5ff12 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 26 Jun 2026 22:42:42 -0700 Subject: [PATCH 026/101] move test global/slice max back into BasePredicate simplified indexed candidate list use logic to simplify combining add method to get inner predicate add simplify method add test global/slice min to BasePredicate fix wrong method in xor MultiPredicate no longer works with a single predicate simplified predicate cannot be simplified further --- .../multiblock/predicates/BasePredicate.java | 135 ++++++++++++++--- .../multiblock/predicates/MultiPredicate.java | 136 ++++++++---------- 2 files changed, 172 insertions(+), 99 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 09d6769f019..df72956bbe9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -2,6 +2,7 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import net.minecraft.client.Minecraft; @@ -62,20 +63,58 @@ public boolean test(PredicateContext ctx) { return true; } + /// test against global max count + protected boolean testGlobalMax(PredicateContext ctx) { + ctx.globalCache().mergeInt(this, 1, Integer::sum); + if ((minCount == -1 && maxCount == -1) || ctx.layerCache() == null) return true; + int count = ctx.globalCache().getInt(this); + if (maxCount == -1 || count <= maxCount) return true; + return ctx.error(SinglePredicateError.maxCount(this, count)); + } + + /// test against slice max count + protected boolean testSliceMax(PredicateContext ctx) { + if (ctx.layerCache() == null) return true; + ctx.layerCache().mergeInt(this, 1, Integer::sum); + if ((minSliceCount == -1 && maxSliceCount == -1)) return true; + int count = ctx.layerCache().getInt(this); + if (maxSliceCount == -1 || count <= maxSliceCount) return true; + return ctx.error(SinglePredicateError.maxLayerCount(this, count)); + } + /// method called after all blocks have been iterated, used for checking min values public boolean postTest(PredicateContext ctx) { return true; } - /// computes the candidates for this predicate, lazily initialized - public List computeCandidates() { - return Collections.emptyList(); + /// test against global max count + protected boolean testGlobalMin(PredicateContext ctx) { + ctx.globalCache().mergeInt(this, 1, Integer::sum); + if ((minCount == -1 && maxCount == -1) || ctx.layerCache() == null) return true; + int count = ctx.globalCache().getInt(this); + if (maxCount == -1 || count <= maxCount) return true; + return ctx.error(SinglePredicateError.maxCount(this, count)); } - public List getCandidates(int index) { - return getCandidates(); + /// test against slice max count + protected boolean testSliceMin(PredicateContext ctx) { + if (ctx.layerCache() == null) return true; + ctx.layerCache().mergeInt(this, 1, Integer::sum); + if ((minSliceCount == -1 && maxSliceCount == -1)) return true; + int count = ctx.layerCache().getInt(this); + if (maxSliceCount == -1 || count <= maxSliceCount) return true; + return ctx.error(SinglePredicateError.maxLayerCount(this, count)); } + /// returns the internal predicate + public abstract Predicate getPredicate(); + + /// computes the candidates for this predicate + public List computeCandidates() { + return Collections.emptyList(); + } + + /// @return the candidate blocks for this predicate, may be empty, lazily initialized public List getCandidates() { if (candidates == null) { candidates = computeCandidates(); @@ -83,6 +122,11 @@ public List getCandidates() { return candidates; } + /// @return a list of candidates from a predicate at {@code index} + public List getCandidates(int index) { + return getCandidates(); + } + public List getCandidateStacks() { return getCandidates().stream() .filter(BlockInfo::nonAir) @@ -180,10 +224,12 @@ public BasePredicate disabledRenderFormed() { return setDisableRenderFormed(true); } + /// visits every predicate public void visit(Consumer visitor) { visitor.accept(this); } + /// @return a flat list of all predicates public final List expand() { List result = new ArrayList<>(); visit(result::add); @@ -191,6 +237,16 @@ public final List expand() { return Collections.unmodifiableList(result); } + protected boolean isSimplified() { + return false; + } + + /// simplify this predicate to just the internal predicate + public final BasePredicate simplify() { + if (isSimplified()) return this; + return simplify(getTypeName(), getPredicate(), getCandidates(), this::appendContents); + } + /// the type of this predicate public abstract String getTypeName(); @@ -206,6 +262,7 @@ public String toString() { return builder.toString(); } + // === instance methods === public BasePredicate or(BasePredicate other) { return or(this, other); } @@ -218,30 +275,20 @@ public BasePredicate xor(BasePredicate other) { return xor(this, other); } + // === private static helpers === private static BasePredicate or(BasePredicate a, BasePredicate b) { - if (a instanceof MultiPredicate mp) { - return mp.or(b); - } else { - return or(null, List.of(a, b)); - } + return or(null, List.of(a, b)); } private static BasePredicate and(BasePredicate a, BasePredicate b) { - if (a instanceof MultiPredicate mp) { - return mp.and(b); - } else { - return and(null, List.of(a, b)); - } + return and(null, List.of(a, b)); } private static BasePredicate xor(BasePredicate a, BasePredicate b) { - if (a instanceof MultiPredicate mp) { - return mp.xor(b); - } else { - return and(null, List.of(a, b)); - } + return xor(null, List.of(a, b)); } + // === public static helpers === public static BasePredicate or(@Nullable String debugName, Iterable predicates) { return new MultiPredicate(debugName, predicates, MultiPredicate.Logic.OR); } @@ -258,10 +305,15 @@ public static BasePredicate create(@Nullable String debugName, Predicate predicate, - Stream candidates, @Nullable Consumer contents) { + private static BasePredicate simplify(String debugName, Predicate predicate, + List candidateList, Consumer contents) { return new BasePredicate() { + @Override + public String getTypeName() { + return debugName + "(Simplified)"; + } + @Override public boolean test(PredicateContext ctx) { return predicate.test(ctx); @@ -269,7 +321,44 @@ public boolean test(PredicateContext ctx) { @Override public List computeCandidates() { - return candidates.toList(); + return candidateList; + } + + @Override + public Predicate getPredicate() { + return predicate; + } + + @Override + protected void appendContents(StringBuilder builder) { + contents.accept(builder); + } + + @Override + protected boolean isSimplified() { + return true; + } + }; + } + + // this uses stream for lazy initialization + public static BasePredicate create(@Nullable String debugName, Predicate predicate, + Stream candidateStream, @Nullable Consumer contents) { + return new BasePredicate() { + + @Override + public boolean test(PredicateContext ctx) { + return predicate.test(ctx) && testGlobalMax(ctx) && testSliceMax(ctx); + } + + @Override + public Predicate getPredicate() { + return predicate; + } + + @Override + public List computeCandidates() { + return candidateStream.toList(); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 6c2ec5c69cb..0530d782c08 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -1,20 +1,22 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import lombok.AccessLevel; +import lombok.Getter; import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.function.Consumer; +import java.util.function.Predicate; -public class MultiPredicate extends BasePredicate { +public class MultiPredicate extends BasePredicate implements Iterable { private final List predicateList = new ObjectArrayList<>(); - private final List> indexedCandidates; private final String debugName; + @Getter(AccessLevel.PROTECTED) private final Logic type; private final boolean hasAir; @@ -22,21 +24,14 @@ protected MultiPredicate(@Nullable String debugName, Iterable pre this.debugName = debugName == null ? "MultiPredicate" : debugName; this.type = type; boolean hasAir = false; - List> indexedCandidates = new ArrayList<>(); for (BasePredicate predicate : predicates) { hasAir |= predicate.hasAir(); - if (!(predicate instanceof MultiPredicate multi)) { - addPredicates(predicate); - indexedCandidates.add(predicate.getCandidates()); - } else if (!multi.sameType(this)) { - addPredicates(predicate); - indexedCandidates.add(predicate.getCandidates()); + if (!(predicate instanceof MultiPredicate multi) || !multi.sameType(this)) { + addPredicate(predicate.simplify()); } else { - addPredicates(multi.predicateList); - multi.predicateList.forEach(p -> indexedCandidates.add(p.getCandidates())); + addPredicates(multi); } } - this.indexedCandidates = Collections.unmodifiableList(indexedCandidates); this.hasAir = hasAir; sorted(); } @@ -48,36 +43,22 @@ public boolean test(PredicateContext ctx) { /// custom testing logic, usually checking if blockstate/entity is correct private boolean testInternal(PredicateContext ctx) { - if (this.predicateList.isEmpty()) return true; - if (isSingle()) return this.predicateList.get(0).test(ctx); return getType().run(ctx, this.predicateList); } - /// test against global max count - private boolean testGlobalMax(PredicateContext ctx) { - ctx.globalCache().mergeInt(this, 1, Integer::sum); - if ((minCount == -1 && maxCount == -1) || ctx.layerCache() == null) return true; - int count = ctx.globalCache().getInt(this); - if (maxCount == -1 || count <= maxCount) return true; - return ctx.error(SinglePredicateError.maxCount(this, count)); - } - - /// test against slice max count - private boolean testSliceMax(PredicateContext ctx) { - if (ctx.layerCache() == null) return true; - ctx.layerCache().mergeInt(this, 1, Integer::sum); - if ((minSliceCount == -1 && maxSliceCount == -1)) return true; - int count = ctx.layerCache().getInt(this); - if (maxSliceCount == -1 || count <= maxSliceCount) return true; - return ctx.error(SinglePredicateError.maxLayerCount(this, count)); + @Override + public Predicate getPredicate() { + // should a nested multi predicate respect its own global/slice max? + // precedent would say no + return this::testInternal; } - protected MultiPredicate addPredicates(Collection predicates) { - predicates.forEach(this::addPredicates); + protected MultiPredicate addPredicates(Iterable predicates) { + predicates.forEach(this::addPredicate); return this; } - protected MultiPredicate addPredicates(BasePredicate predicate) { + protected MultiPredicate addPredicate(BasePredicate predicate) { this.predicateList.add(predicate); return this; } @@ -91,7 +72,7 @@ public List computeCandidates() { @Override public List getCandidates(int index) { - return this.indexedCandidates.get(index); + return this.predicateList.get(index).getCandidates(); } @Override @@ -111,10 +92,6 @@ public boolean isXor() { return this.type == Logic.XOR; } - protected Logic getType() { - return Objects.requireNonNull(type, "null type: " + this); - } - protected boolean sameType(MultiPredicate other) { return this.type == other.type; } @@ -134,46 +111,28 @@ protected MultiPredicate copy() { } @Override - public MultiPredicate or(BasePredicate other) { - if (!(other instanceof MultiPredicate multi)) { - return this.copy().addPredicates(other).sorted(); - } - - if (!isOr()) return multi.or(this); - - return combine(this, multi, this.copy()); + public BasePredicate or(BasePredicate other) { + return Logic.OR.combine(this, other); } @Override - public MultiPredicate and(BasePredicate other) { - if (!(other instanceof MultiPredicate multi)) { - return this.copy().addPredicates(other).sorted(); - } - - if (!isAnd()) return multi.and(this); - - return combine(this, multi, this.copy()); + public BasePredicate and(BasePredicate other) { + return Logic.AND.combine(this, other); } @Override public BasePredicate xor(BasePredicate other) { - if (!(other instanceof MultiPredicate multi)) { - return this.copy().addPredicates(other).sorted(); - } - - if (!isXor()) return multi.xor(this); - - return combine(this, multi, this.copy()); + return Logic.XOR.combine(this, other); } @Override public boolean isSingle() { - return this.predicateList.size() == 1; + return false; } @Override public String getTypeName() { - return debugName + '(' + (isSingle() ? "SINGLE" : this.type) + ')'; + return debugName + '(' + this.type + ')'; } @Override @@ -183,17 +142,9 @@ protected void appendContents(StringBuilder builder) { builder.append(joiner); } - /// @param a will have type set - /// @param b will have type set - /// @param dest output predicate - private static MultiPredicate combine(MultiPredicate a, MultiPredicate b, MultiPredicate dest) { - if (a.getType() == b.getType()) { - dest.addPredicates(b.predicateList); - } else { - dest.addPredicates(b); - } - - return dest.sorted(); + @Override + public Iterator iterator() { + return this.predicateList.iterator(); } protected enum Logic { @@ -209,6 +160,7 @@ protected boolean run(PredicateContext ctx, List predicates) { } return false; } + }, AND { @@ -216,6 +168,7 @@ protected boolean run(PredicateContext ctx, List predicates) { protected boolean run(PredicateContext ctx, List predicates) { return !OR.run(ctx, predicates); } + }, XOR { @@ -229,8 +182,39 @@ protected boolean run(PredicateContext ctx, List predicates) { } return passed == 1; } + }; protected abstract boolean run(PredicateContext ctx, List predicates); + + /// @param a will have type set + /// @param b may or may not be a multi predicate + /// @return copy of {@code a} with {@code b} added + protected BasePredicate combine(MultiPredicate a, BasePredicate b) { + if (!(b instanceof MultiPredicate multi)) { + // b is not a multi predicate, simply add it + return a.copy().addPredicate(b.simplify()).sorted(); + } + + if (a.getType() != this && multi.getType() != this) { + // if neither predicate is of this type, make new multi predicate of this type + return new MultiPredicate(null, List.of(a, b), this); + } else if (a.getType() != this) { + // b must be of this type, flip operation to add a to b + return this.combine(multi, a); + } + + // a must be of this type, b may or may not + var dest = a.copy(); + if (a.getType() == multi.getType()) { + // add all inner predicates + dest.addPredicates(multi); + } else { + // add multi predicate as a simplified predicate + dest.addPredicate(multi.simplify()); + } + + return dest.sorted(); + } } } From 02465227b4c602ad63bd1bec36ff30d5a0fb6add Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 27 Jun 2026 00:03:48 -0700 Subject: [PATCH 027/101] move global/layer min check to base predicate remove simplification methods improve logic run method comment out tooltip call --- .../api/multiblock/pattern/BlockPattern.java | 18 +++-- .../multiblock/predicates/BasePredicate.java | 73 ++----------------- .../multiblock/predicates/MultiPredicate.java | 44 +++++------ .../common/data/machines/GTMultiMachines.java | 3 +- 4 files changed, 41 insertions(+), 97 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 9f186690f4c..31663bf75ab 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -167,10 +167,11 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c sliceStrategy.start(controllerPos, frontFacing, upwardsFacing); if (!sliceStrategy.check(patternState, isFlipped)) return false; + // global min check for (Object2IntMap.Entry entry : patternState.globalCount.object2IntEntrySet()) { - if (entry.getIntValue() < entry.getKey().getMinCount()) { - patternState.setError(SinglePredicateError - .minCount(entry.getKey(), entry.getIntValue())); + List res = new ArrayList<>(); + if (!entry.getKey().testGlobalMin(patternState.toContext(res::add))) { + patternState.setErrors(res); return false; } } @@ -220,8 +221,8 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p } List res = new ArrayList<>(); - boolean passed = pred.test(patternState.toContext(res::add)); - if (!passed) { + // internal predicate check, global/slice max checks + if (!pred.test(patternState.toContext(res::add))) { patternState.setErrors(res); return false; } @@ -233,10 +234,11 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p charPos.set(stringStart); } + // slice min check for (Object2IntMap.Entry entry : patternState.layerCount.object2IntEntrySet()) { - if (entry.getIntValue() < entry.getKey().getMinSliceCount()) { - patternState.setError( - SinglePredicateError.minLayerCount(entry.getKey(), entry.getIntValue())); + List res = new ArrayList<>(); + if (!entry.getKey().testSliceMin(patternState.toContext(res::add))) { + patternState.setErrors(res); return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index df72956bbe9..ee67cddf08d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -82,33 +82,23 @@ protected boolean testSliceMax(PredicateContext ctx) { return ctx.error(SinglePredicateError.maxLayerCount(this, count)); } - /// method called after all blocks have been iterated, used for checking min values - public boolean postTest(PredicateContext ctx) { - return true; - } - /// test against global max count - protected boolean testGlobalMin(PredicateContext ctx) { - ctx.globalCache().mergeInt(this, 1, Integer::sum); + public boolean testGlobalMin(PredicateContext ctx) { if ((minCount == -1 && maxCount == -1) || ctx.layerCache() == null) return true; int count = ctx.globalCache().getInt(this); - if (maxCount == -1 || count <= maxCount) return true; - return ctx.error(SinglePredicateError.maxCount(this, count)); + if (minCount == -1 || count >= minCount) return true; + return ctx.error(SinglePredicateError.minCount(this, count)); } /// test against slice max count - protected boolean testSliceMin(PredicateContext ctx) { + public boolean testSliceMin(PredicateContext ctx) { if (ctx.layerCache() == null) return true; - ctx.layerCache().mergeInt(this, 1, Integer::sum); if ((minSliceCount == -1 && maxSliceCount == -1)) return true; int count = ctx.layerCache().getInt(this); - if (maxSliceCount == -1 || count <= maxSliceCount) return true; - return ctx.error(SinglePredicateError.maxLayerCount(this, count)); + if (minSliceCount == -1 || count >= minSliceCount) return true; + return ctx.error(SinglePredicateError.minLayerCount(this, count)); } - /// returns the internal predicate - public abstract Predicate getPredicate(); - /// computes the candidates for this predicate public List computeCandidates() { return Collections.emptyList(); @@ -237,16 +227,6 @@ public final List expand() { return Collections.unmodifiableList(result); } - protected boolean isSimplified() { - return false; - } - - /// simplify this predicate to just the internal predicate - public final BasePredicate simplify() { - if (isSimplified()) return this; - return simplify(getTypeName(), getPredicate(), getCandidates(), this::appendContents); - } - /// the type of this predicate public abstract String getTypeName(); @@ -305,42 +285,6 @@ public static BasePredicate create(@Nullable String debugName, Predicate predicate, - List candidateList, Consumer contents) { - return new BasePredicate() { - - @Override - public String getTypeName() { - return debugName + "(Simplified)"; - } - - @Override - public boolean test(PredicateContext ctx) { - return predicate.test(ctx); - } - - @Override - public List computeCandidates() { - return candidateList; - } - - @Override - public Predicate getPredicate() { - return predicate; - } - - @Override - protected void appendContents(StringBuilder builder) { - contents.accept(builder); - } - - @Override - protected boolean isSimplified() { - return true; - } - }; - } - // this uses stream for lazy initialization public static BasePredicate create(@Nullable String debugName, Predicate predicate, Stream candidateStream, @Nullable Consumer contents) { @@ -351,11 +295,6 @@ public boolean test(PredicateContext ctx) { return predicate.test(ctx) && testGlobalMax(ctx) && testSliceMax(ctx); } - @Override - public Predicate getPredicate() { - return predicate; - } - @Override public List computeCandidates() { return candidateStream.toList(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 0530d782c08..e48f0d17f78 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -7,10 +7,11 @@ import lombok.AccessLevel; import lombok.Getter; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; import java.util.*; +import java.util.function.BiPredicate; import java.util.function.Consumer; -import java.util.function.Predicate; public class MultiPredicate extends BasePredicate implements Iterable { @@ -27,7 +28,7 @@ protected MultiPredicate(@Nullable String debugName, Iterable pre for (BasePredicate predicate : predicates) { hasAir |= predicate.hasAir(); if (!(predicate instanceof MultiPredicate multi) || !multi.sameType(this)) { - addPredicate(predicate.simplify()); + addPredicate(predicate); } else { addPredicates(multi); } @@ -43,14 +44,17 @@ public boolean test(PredicateContext ctx) { /// custom testing logic, usually checking if blockstate/entity is correct private boolean testInternal(PredicateContext ctx) { - return getType().run(ctx, this.predicateList); + return getType().run(ctx, this.predicateList, BasePredicate::test); } @Override - public Predicate getPredicate() { - // should a nested multi predicate respect its own global/slice max? - // precedent would say no - return this::testInternal; + public boolean testGlobalMin(PredicateContext ctx) { + return getType().run(ctx, this.predicateList, BasePredicate::testGlobalMin); + } + + @Override + public boolean testSliceMin(PredicateContext ctx) { + return getType().run(ctx, this.predicateList, BasePredicate::testSliceMin); } protected MultiPredicate addPredicates(Iterable predicates) { @@ -152,40 +156,38 @@ protected enum Logic { OR { @Override - protected boolean run(PredicateContext ctx, List predicates) { + protected boolean run(PredicateContext ctx, List predicates, BiPredicate extractor) { for (BasePredicate basePredicate : predicates) { - if (basePredicate.test(ctx)) { + if (extractor.test(basePredicate, ctx)) { return true; } } return false; } - }, - AND { + }, AND { @Override - protected boolean run(PredicateContext ctx, List predicates) { - return !OR.run(ctx, predicates); + protected boolean run(PredicateContext ctx, List predicates, BiPredicate extractor) { + return !OR.run(ctx, predicates, extractor); } - }, - XOR { + }, XOR { @Override - protected boolean run(PredicateContext ctx, List predicates) { + protected boolean run(PredicateContext ctx, List predicates, BiPredicate extractor) { int passed = 0; for (BasePredicate basePredicate : predicates) { - if (basePredicate.test(ctx)) { + if (extractor.test(basePredicate, ctx)) { if (++passed > 1) return false; } } return passed == 1; } - }; - protected abstract boolean run(PredicateContext ctx, List predicates); + protected abstract boolean run(PredicateContext ctx, List predicates, + BiPredicate extractor); /// @param a will have type set /// @param b may or may not be a multi predicate @@ -193,7 +195,7 @@ protected boolean run(PredicateContext ctx, List predicates) { protected BasePredicate combine(MultiPredicate a, BasePredicate b) { if (!(b instanceof MultiPredicate multi)) { // b is not a multi predicate, simply add it - return a.copy().addPredicate(b.simplify()).sorted(); + return a.copy().addPredicate(b).sorted(); } if (a.getType() != this && multi.getType() != this) { @@ -211,7 +213,7 @@ protected BasePredicate combine(MultiPredicate a, BasePredicate b) { dest.addPredicates(multi); } else { // add multi predicate as a simplified predicate - dest.addPredicate(multi.simplify()); + dest.addPredicate(multi); } return dest.sorted(); diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java index 1e1da5807d1..871dd2252b4 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java @@ -389,7 +389,8 @@ public class GTMultiMachines { Predicates.abilities(PartAbility.IMPORT_FLUIDS_1X).setMaxGlobalLimited(4))) .where('O', Predicates.abilities(PartAbility.EXPORT_ITEMS) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.location_end"))) +// .addTooltips(Component.translatable("gtceu.multiblock.pattern.location_end")) + ) .where('Y', blocks(CASING_STEEL_SOLID.get()).or(Predicates.abilities(PartAbility.INPUT_ENERGY) .setMinGlobalLimited(1).setMaxGlobalLimited(2))) From 97d82b2fcae5828479c5b31e4a25a084c2cdfdd5 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 27 Jun 2026 00:18:46 -0700 Subject: [PATCH 028/101] remove more stream suppliers --- .../gtceu/api/multiblock/Predicates.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 1fe9dea9fb7..3e7ffc28f39 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -120,26 +120,26 @@ public static BasePredicate blocks(Block... blocks) { } public static BasePredicate blocks(@Nullable String debugName, Block... blocks) { - return blocks(debugName, () -> Arrays.stream(blocks)); + return blocks(debugName, Arrays.stream(blocks)); } public static BasePredicate blocks(@Nullable String debugName, - Supplier> blocks) { - return blocks(debugName, blocks, blocks); + Stream blocks) { + List blockList = blocks.toList(); + return blocks(debugName, blockList, blockList.stream()); } public static BasePredicate blocks(@Nullable String debugName, - Supplier> blocks, - Supplier> candidates) { + List blocks, + Stream candidates) { return customPredicate(debugName, ctx -> { - var blockList = blocks.get().toList(); - for (var block : blockList) { + for (var block : blocks) { if (ctx.state().is(block)) return true; } - return ctx.error(new BlockMatchingError(ctx.pos(), blockList)); - }, candidates.get().map(BlockInfo::fromBlock), builder -> { + return ctx.error(new BlockMatchingError(ctx.pos(), blocks)); + }, candidates.map(BlockInfo::fromBlock), builder -> { StringJoiner joiner = new StringJoiner(", "); - blocks.get().forEach(block -> joiner.add(blockToString(block))); + blocks.forEach(block -> joiner.add(blockToString(block))); builder.append(joiner); }); } @@ -362,16 +362,16 @@ public static BasePredicate autoAbilities(boolean checkMaintenance, boolean chec public static BasePredicate heatingCoils() { return blocks("HeatingCoils", - () -> GTCEuAPI.HEATING_COILS.values().stream().map(Supplier::get)) + GTCEuAPI.HEATING_COILS.values().stream().map(Supplier::get)) // .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")) .setPriority(0); } public static BasePredicate cleanroomFilters() { return blocks("CleanroomFilters", - () -> GTCEuAPI.CLEANROOM_FILTERS.values() - .stream().map(Supplier::get), - () -> GTCEuAPI.CLEANROOM_FILTERS.entrySet() + GTCEuAPI.CLEANROOM_FILTERS.values() + .stream().map(Supplier::get).toList(), + GTCEuAPI.CLEANROOM_FILTERS.entrySet() .stream() .sorted(Comparator.comparingInt(e -> e.getKey().getCleanroomType().getTier())) .map(entry -> entry.getValue().get())) @@ -381,9 +381,9 @@ public static BasePredicate cleanroomFilters() { public static BasePredicate powerSubstationBatteries() { return blocks("PSS-Batteries", - () -> GTCEuAPI.PSS_BATTERIES.values() - .stream().map(Supplier::get), - () -> GTCEuAPI.PSS_BATTERIES.entrySet() + GTCEuAPI.PSS_BATTERIES.values() + .stream().map(Supplier::get).map(Block.class::cast).toList(), + GTCEuAPI.PSS_BATTERIES.entrySet() .stream() .sorted(Comparator.comparingInt(e -> e.getKey().getTier())) .map(e -> e.getValue().get())) From be7ea83c2df7bfbff5fdd3d692036c8a46945077 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 27 Jun 2026 14:42:29 -0700 Subject: [PATCH 029/101] list -> iterable make isController mutable --- .../gtceu/api/multiblock/Predicates.java | 28 +------------------ .../multiblock/predicates/BasePredicate.java | 13 ++++++--- .../multiblock/predicates/MultiPredicate.java | 25 ++++++++++------- 3 files changed, 25 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 3e7ffc28f39..ec1f5f3154d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -57,33 +57,7 @@ public static BasePredicate controller(MultiblockMachineDefinition def) { } public static BasePredicate controller(BasePredicate predicate) { - return new BasePredicate() { - - @Override - public boolean test(PredicateContext ctx) { - return predicate.test(ctx); - } - - @Override - public List computeCandidates() { - return predicate.getCandidates(); - } - - @Override - public String getTypeName() { - return "Controller"; - } - - @Override - protected void appendContents(StringBuilder builder) { - builder.append(predicate); - } - - @Override - public boolean isController() { - return true; - } - }; + return predicate.setController(true); } public static BasePredicate states(BlockState... allowedStates) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index ee67cddf08d..f4d50818829 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -33,6 +33,9 @@ public abstract class BasePredicate { private @Nullable List candidates; + @Getter + @Setter + private boolean isController = false; @Getter @Setter protected int priority = 0; @@ -157,10 +160,6 @@ public boolean isSingle() { return true; } - public boolean isController() { - return false; - } - public BasePredicate setMinGlobalLimited(int min) { return this.setMinCount(min); } @@ -214,6 +213,11 @@ public BasePredicate disabledRenderFormed() { return setDisableRenderFormed(true); } + /// @return a non-flattened list of predicates + public List getInnerPredicates() { + return List.of(this); + } + /// visits every predicate public void visit(Consumer visitor) { visitor.accept(this); @@ -236,6 +240,7 @@ protected void appendContents(StringBuilder builder) {} @Override public String toString() { StringBuilder builder = new StringBuilder(getTypeName()); + if (isController()) builder.append("[Controller]"); builder.append('{'); appendContents(builder); builder.append('}'); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index e48f0d17f78..938ab24298b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -44,17 +44,17 @@ public boolean test(PredicateContext ctx) { /// custom testing logic, usually checking if blockstate/entity is correct private boolean testInternal(PredicateContext ctx) { - return getType().run(ctx, this.predicateList, BasePredicate::test); + return getType().run(ctx, this, BasePredicate::test); } @Override public boolean testGlobalMin(PredicateContext ctx) { - return getType().run(ctx, this.predicateList, BasePredicate::testGlobalMin); + return getType().run(ctx, this, BasePredicate::testGlobalMin); } @Override public boolean testSliceMin(PredicateContext ctx) { - return getType().run(ctx, this.predicateList, BasePredicate::testSliceMin); + return getType().run(ctx, this, BasePredicate::testSliceMin); } protected MultiPredicate addPredicates(Iterable predicates) { @@ -79,9 +79,14 @@ public List getCandidates(int index) { return this.predicateList.get(index).getCandidates(); } + @Override + public List getInnerPredicates() { + return this.predicateList; + } + @Override public void visit(Consumer visitor) { - predicateList.forEach(p -> p.visit(visitor)); + this.forEach(p -> p.visit(visitor)); } public boolean isOr() { @@ -111,7 +116,7 @@ protected MultiPredicate sorted() { } protected MultiPredicate copy() { - return new MultiPredicate(this.debugName, this.predicateList, this.getType()); + return new MultiPredicate(this.debugName, this, this.getType()); } @Override @@ -142,7 +147,7 @@ public String getTypeName() { @Override protected void appendContents(StringBuilder builder) { StringJoiner joiner = new StringJoiner(", "); - this.predicateList.forEach(p -> joiner.add(p.toString())); + this.forEach(p -> joiner.add(p.toString())); builder.append(joiner); } @@ -156,7 +161,7 @@ protected enum Logic { OR { @Override - protected boolean run(PredicateContext ctx, List predicates, BiPredicate extractor) { + protected boolean run(PredicateContext ctx, Iterable predicates, BiPredicate extractor) { for (BasePredicate basePredicate : predicates) { if (extractor.test(basePredicate, ctx)) { return true; @@ -168,14 +173,14 @@ protected boolean run(PredicateContext ctx, List predicates, BiPr }, AND { @Override - protected boolean run(PredicateContext ctx, List predicates, BiPredicate extractor) { + protected boolean run(PredicateContext ctx, Iterable predicates, BiPredicate extractor) { return !OR.run(ctx, predicates, extractor); } }, XOR { @Override - protected boolean run(PredicateContext ctx, List predicates, BiPredicate extractor) { + protected boolean run(PredicateContext ctx, Iterable predicates, BiPredicate extractor) { int passed = 0; for (BasePredicate basePredicate : predicates) { if (extractor.test(basePredicate, ctx)) { @@ -186,7 +191,7 @@ protected boolean run(PredicateContext ctx, List predicates, BiPr } }; - protected abstract boolean run(PredicateContext ctx, List predicates, + protected abstract boolean run(PredicateContext ctx, Iterable predicates, BiPredicate extractor); /// @param a will have type set From 938b931f7dc96024463cecec28d3ea960106d3f7 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 27 Jun 2026 14:45:00 -0700 Subject: [PATCH 030/101] clean up or/and/xor methods --- .../multiblock/predicates/BasePredicate.java | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index f4d50818829..744d343183c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -249,28 +249,15 @@ public String toString() { // === instance methods === public BasePredicate or(BasePredicate other) { - return or(this, other); + return or(null, List.of(this, other)); } public BasePredicate and(BasePredicate other) { - return and(this, other); + return and(null, List.of(this, other)); } public BasePredicate xor(BasePredicate other) { - return xor(this, other); - } - - // === private static helpers === - private static BasePredicate or(BasePredicate a, BasePredicate b) { - return or(null, List.of(a, b)); - } - - private static BasePredicate and(BasePredicate a, BasePredicate b) { - return and(null, List.of(a, b)); - } - - private static BasePredicate xor(BasePredicate a, BasePredicate b) { - return xor(null, List.of(a, b)); + return xor(null, List.of(this, other)); } // === public static helpers === From 3f102dcb4257a784df9e43c357c52c4345630433 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Tue, 30 Jun 2026 00:42:00 -0700 Subject: [PATCH 031/101] give PredicateContext list instead of consumer reference --- .../api/multiblock/PredicateContext.java | 40 +++++++++++++++---- .../api/multiblock/pattern/BlockPattern.java | 20 +++++----- .../multiblock/pattern/ExpandablePattern.java | 9 ++--- .../api/multiblock/pattern/PatternState.java | 9 ++--- 4 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 077482031b0..e44d6e4045a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -14,21 +14,37 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Objects; -import java.util.function.Consumer; -public record PredicateContext(CurrentBlockInfo blockInfo, - Consumer errorConsumer, - Object2IntMap globalCache, - @Nullable Object2IntMap layerCache) { +public final class PredicateContext { + private final CurrentBlockInfo blockInfo; + private final List errors = new ArrayList<>(); + private final Object2IntMap globalCache; + private final @Nullable Object2IntMap layerCache; + + public PredicateContext(CurrentBlockInfo blockInfo, + Object2IntMap globalCache, + @Nullable Object2IntMap layerCache) { + this.blockInfo = blockInfo; + this.globalCache = globalCache; + this.layerCache = layerCache; + } /// accepts a pattern error + /// /// @return false public boolean error(PatternError error) { - this.errorConsumer.accept(error); + this.errors.add(error); return false; } + public List getErrors() { + return Collections.unmodifiableList(errors); + } + /// @return the current Level public Level level() { return Objects.requireNonNull(blockInfo.getLevel()); @@ -58,9 +74,17 @@ public BlockPos pos() { return this.blockInfo.retrieveCurrentBlockEntity(); } - public static PredicateContext of(CurrentBlockInfo blockInfo, Consumer errorConsumer, + public static PredicateContext of(CurrentBlockInfo blockInfo, Object2IntMap cache, @Nullable Object2IntMap layerCache) { - return new PredicateContext(blockInfo, errorConsumer, cache, layerCache); + return new PredicateContext(blockInfo, cache, layerCache); + } + + public Object2IntMap globalCache() { + return globalCache; + } + + public @Nullable Object2IntMap layerCache() { + return layerCache; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 31663bf75ab..459b3fab002 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -1,8 +1,8 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; -import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; @@ -169,9 +169,9 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c // global min check for (Object2IntMap.Entry entry : patternState.globalCount.object2IntEntrySet()) { - List res = new ArrayList<>(); - if (!entry.getKey().testGlobalMin(patternState.toContext(res::add))) { - patternState.setErrors(res); + PredicateContext ctx = patternState.toContext(); + if (!entry.getKey().testGlobalMin(ctx)) { + patternState.setErrors(ctx.getErrors()); return false; } } @@ -220,10 +220,10 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p patternState.cache.put(charPos.asLong(), new BlockInfo(state, blockEntity)); } - List res = new ArrayList<>(); + PredicateContext ctx = patternState.toContext(); // internal predicate check, global/slice max checks - if (!pred.test(patternState.toContext(res::add))) { - patternState.setErrors(res); + if (!pred.test(ctx)) { + patternState.setErrors(ctx.getErrors()); return false; } @@ -236,9 +236,9 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // slice min check for (Object2IntMap.Entry entry : patternState.layerCount.object2IntEntrySet()) { - List res = new ArrayList<>(); - if (!entry.getKey().testSliceMin(patternState.toContext(res::add))) { - patternState.setErrors(res); + PredicateContext ctx = patternState.toContext(); + if (!entry.getKey().testSliceMin(ctx)) { + patternState.setErrors(ctx.getErrors()); return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index d54c94c84da..6c83d37d216 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; @@ -16,7 +17,6 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.ints.IntList; -import it.unimi.dsi.fastutil.longs.*; import lombok.Getter; import lombok.Setter; import org.jetbrains.annotations.Nullable; @@ -171,10 +171,9 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c patternState.cache.put(mPos.asLong(), new BlockInfo(state, blockEntity)); } - List res = new ArrayList<>(); - boolean passed = pred.test(patternState.noLayer(res::add)); - if (!passed) { - patternState.setErrors(res); + PredicateContext ctx = patternState.noLayer(); + if (!pred.test(ctx)) { + patternState.setErrors(ctx.getErrors()); return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 522da3f9960..3e8e3dd1d15 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -21,7 +21,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; -import java.util.function.Consumer; /* * Contains vital information to an instanced version of a structure pattern. @@ -111,12 +110,12 @@ public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState ne } } - public PredicateContext toContext(Consumer errorConsumer) { - return PredicateContext.of(this.currentBlockInfo, errorConsumer, this.globalCount, this.layerCount); + public PredicateContext toContext() { + return PredicateContext.of(this.currentBlockInfo, this.globalCount, this.layerCount); } - public PredicateContext noLayer(Consumer errorConsumer) { - return PredicateContext.of(this.currentBlockInfo, errorConsumer, this.globalCount, null); + public PredicateContext noLayer() { + return PredicateContext.of(this.currentBlockInfo, this.globalCount, null); } @Getter From 23582cf23b16a9bb2c0ece748a1e2e94a63e5dd8 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Tue, 30 Jun 2026 01:20:17 -0700 Subject: [PATCH 032/101] unsure if this is cooking move test global/slice min/max to PredicateContext --- .../api/multiblock/PredicateContext.java | 43 +++++++++++++++++++ .../api/multiblock/pattern/BlockPattern.java | 39 +++++++++++------ .../multiblock/predicates/BasePredicate.java | 42 ++++++++---------- .../multiblock/predicates/MultiPredicate.java | 20 ++++----- 4 files changed, 96 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index e44d6e4045a..eb3c97681e7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; +import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; @@ -87,4 +88,46 @@ public Object2IntMap globalCache() { public @Nullable Object2IntMap layerCache() { return layerCache; } + + /// test against global max count + public boolean testGlobalMax(BasePredicate predicate) { + if (predicate.skipGlobalTest() || layerCache() == null) return true; + int count = incrementGlobalCount(predicate); + if (predicate.testGlobalMax(count)) return true; + return error(SinglePredicateError.maxCount(predicate, count)); + } + + /// test against slice max count + public boolean testSliceMax(BasePredicate predicate) { + if (predicate.skipSliceTest() || layerCache() == null) return true; + int count = incrementSliceCount(predicate); + if (predicate.testSliceMax(count)) return true; + return error(SinglePredicateError.maxLayerCount(predicate, count)); + } + + private int incrementGlobalCount(BasePredicate predicate) { + globalCache().mergeInt(predicate, 1, Integer::sum); + return globalCache().getInt(predicate); + } + + private int incrementSliceCount(BasePredicate predicate) { + Objects.requireNonNull(layerCache()).mergeInt(predicate, 1, Integer::sum); + return layerCache().getInt(predicate); + } + + /// test against global min count + public boolean testGlobalMin(BasePredicate predicate) { + if (predicate.skipGlobalTest() || layerCache() == null) return true; + int count = globalCache().getInt(predicate); + if (predicate.testGlobalMin(count)) return true; + return error(SinglePredicateError.minCount(predicate, count)); + } + + /// test against slice min count + public boolean testSliceMin(BasePredicate predicate) { + if (predicate.skipSliceTest() || layerCache() == null) return true; + int count = layerCache().getInt(predicate); + if (predicate.testSliceMin(count)) return true; + return error(SinglePredicateError.minLayerCount(predicate, count)); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 459b3fab002..07797dafeff 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -163,18 +163,25 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c BlockPos.MutableBlockPos controllerPos = centerPos.mutable(); + // handle slices sliceStrategy.setPattern(this); sliceStrategy.start(controllerPos, frontFacing, upwardsFacing); if (!sliceStrategy.check(patternState, isFlipped)) return false; // global min check - for (Object2IntMap.Entry entry : patternState.globalCount.object2IntEntrySet()) { - PredicateContext ctx = patternState.toContext(); - if (!entry.getKey().testGlobalMin(ctx)) { + PredicateContext ctx = patternState.toContext(); + for (BasePredicate predicate : predicates.values()) { + if (ctx.testGlobalMin(predicate)) { patternState.setErrors(ctx.getErrors()); return false; } } +// for (Object2IntMap.Entry entry : patternState.globalCount.object2IntEntrySet()) { +// if (!entry.getKey().testGlobalMin(ctx)) { +// patternState.setErrors(ctx.getErrors()); +// return false; +// } +// } patternState.setError(null); return true; @@ -207,27 +214,29 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p BlockPos.MutableBlockPos charPos = sliceStart.mutable(); PatternSlice slice = slices[sliceIndex]; + // theoretically, predicates could track their own current layer/global count patternState.layerCount.clear(); + PredicateContext ctx = patternState.toContext(); for (int stringIdx = 0; stringIdx < dimensions[1]; stringIdx++) { for (int charIdx = 0; charIdx < dimensions[2]; charIdx++) { patternState.currentBlockInfo.setCurrentPos(charPos); BasePredicate pred = predicates.get(slice.charAt(stringIdx, charIdx)); if (!pred.isAny()) { - BlockEntity blockEntity = patternState.currentBlockInfo.retrieveCurrentBlockEntity(); - BlockState state = patternState.currentBlockInfo.retrieveCurrentBlockState(); + BlockEntity blockEntity = ctx.blockEntity(); + BlockState state = ctx.state(); patternState.cache.put(charPos.asLong(), new BlockInfo(state, blockEntity)); } - PredicateContext ctx = patternState.toContext(); // internal predicate check, global/slice max checks - if (!pred.test(ctx)) { + if (pred.test(ctx) && ctx.testGlobalMax(pred) && ctx.testSliceMax(pred)) { + charPos.move(absoluteChar); + // continue... + } else { patternState.setErrors(ctx.getErrors()); return false; } - - charPos.move(absoluteChar); } stringStart.move(absoluteString); @@ -235,13 +244,17 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p } // slice min check - for (Object2IntMap.Entry entry : patternState.layerCount.object2IntEntrySet()) { - PredicateContext ctx = patternState.toContext(); - if (!entry.getKey().testSliceMin(ctx)) { + for (BasePredicate predicate : predicates.values()) { + if (ctx.testSliceMin(predicate)) { patternState.setErrors(ctx.getErrors()); - return false; } } +// for (Object2IntMap.Entry entry : patternState.layerCount.object2IntEntrySet()) { +// if (!entry.getKey().testSliceMin(ctx)) { +// patternState.setErrors(ctx.getErrors()); +// return false; +// } +// } return true; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 744d343183c..0412c0c8747 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -67,39 +67,31 @@ public boolean test(PredicateContext ctx) { } /// test against global max count - protected boolean testGlobalMax(PredicateContext ctx) { - ctx.globalCache().mergeInt(this, 1, Integer::sum); - if ((minCount == -1 && maxCount == -1) || ctx.layerCache() == null) return true; - int count = ctx.globalCache().getInt(this); - if (maxCount == -1 || count <= maxCount) return true; - return ctx.error(SinglePredicateError.maxCount(this, count)); + public boolean testGlobalMax(int count) { + return maxCount == -1 || count <= maxCount; } /// test against slice max count - protected boolean testSliceMax(PredicateContext ctx) { - if (ctx.layerCache() == null) return true; - ctx.layerCache().mergeInt(this, 1, Integer::sum); - if ((minSliceCount == -1 && maxSliceCount == -1)) return true; - int count = ctx.layerCache().getInt(this); - if (maxSliceCount == -1 || count <= maxSliceCount) return true; - return ctx.error(SinglePredicateError.maxLayerCount(this, count)); + public boolean testSliceMax(int count) { + return maxSliceCount == -1 || count <= maxSliceCount; } /// test against global max count - public boolean testGlobalMin(PredicateContext ctx) { - if ((minCount == -1 && maxCount == -1) || ctx.layerCache() == null) return true; - int count = ctx.globalCache().getInt(this); - if (minCount == -1 || count >= minCount) return true; - return ctx.error(SinglePredicateError.minCount(this, count)); + public boolean testGlobalMin(int count) { + return minCount == -1 || count >= minCount; } /// test against slice max count - public boolean testSliceMin(PredicateContext ctx) { - if (ctx.layerCache() == null) return true; - if ((minSliceCount == -1 && maxSliceCount == -1)) return true; - int count = ctx.layerCache().getInt(this); - if (minSliceCount == -1 || count >= minSliceCount) return true; - return ctx.error(SinglePredicateError.minLayerCount(this, count)); + public boolean testSliceMin(int count) { + return minSliceCount == -1 || count >= minSliceCount; + } + + public boolean skipGlobalTest() { + return minCount == -1 && maxCount == -1; + } + + public boolean skipSliceTest() { + return minSliceCount == -1 && maxSliceCount == -1; } /// computes the candidates for this predicate @@ -284,7 +276,7 @@ public static BasePredicate create(@Nullable String debugName, Predicate pre @Override public boolean test(PredicateContext ctx) { - return testInternal(ctx) && testGlobalMax(ctx) && testSliceMax(ctx); + return testInternal(ctx); } /// custom testing logic, usually checking if blockstate/entity is correct @@ -47,15 +47,15 @@ private boolean testInternal(PredicateContext ctx) { return getType().run(ctx, this, BasePredicate::test); } - @Override - public boolean testGlobalMin(PredicateContext ctx) { - return getType().run(ctx, this, BasePredicate::testGlobalMin); - } - - @Override - public boolean testSliceMin(PredicateContext ctx) { - return getType().run(ctx, this, BasePredicate::testSliceMin); - } +// @Override +// public boolean testGlobalMin(PredicateContext ctx) { +// return getType().run(ctx, this, BasePredicate::testGlobalMin); +// } +// +// @Override +// public boolean testSliceMin(PredicateContext ctx) { +// return getType().run(ctx, this, BasePredicate::testSliceMin); +// } protected MultiPredicate addPredicates(Iterable predicates) { predicates.forEach(this::addPredicate); From 015a9b695cb686f4c83ef70eeb6ae68a8fa2970f Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 3 Jul 2026 04:31:50 -0700 Subject: [PATCH 033/101] change basically everything --- .../gtceu/api/mui/MultiblockSchemaInfo.java | 3 +- .../api/multiblock/PredicateContext.java | 40 +- .../gtceu/api/multiblock/Predicates.java | 130 +++--- .../api/multiblock/pattern/BlockPattern.java | 40 +- .../ExpandableMultiblockPatternBuilder.java | 4 +- .../multiblock/pattern/ExpandablePattern.java | 10 +- .../pattern/MultiblockPatternBuilder.java | 9 +- .../multiblock/predicates/BasePredicate.java | 179 ++------ .../multiblock/predicates/MultiPredicate.java | 411 +++++++++++++----- .../util/AbstractStructureHelper.java | 15 +- .../multiblock/util/BlockPatternHelper.java | 21 +- .../util/ExpandablePatternHelper.java | 15 +- .../common/data/machines/GCYMMachines.java | 8 +- .../common/data/machines/GTMachineUtils.java | 6 +- .../common/data/machines/GTMultiMachines.java | 10 +- .../electric/ActiveTransformerMachine.java | 4 +- .../electric/CentralMonitorMachine.java | 6 +- .../multiblock/electric/CleanroomMachine.java | 21 +- .../primitive/CharcoalPileIgniterMachine.java | 5 +- .../widgets/MultiblockPreviewWidget.java | 17 +- 20 files changed, 506 insertions(+), 448 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java b/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java index 4598608f302..54d8dfd56f8 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java @@ -5,6 +5,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.AbstractStructureHelper; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.client.mui.schema.MutableSchema; @@ -119,7 +120,7 @@ public void clearUserPreferences() { this.userDimensions.clear(); } - public void putPredicatePreference(BasePredicate predicate, BasePredicate basePredicate, BlockInfo info) { + public void putPredicatePreference(MultiPredicate predicate, BasePredicate basePredicate, BlockInfo info) { this.structureHelper.getBlockPreferences().put(predicate, basePredicate, info); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index eb3c97681e7..e38a9525597 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -1,7 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; -import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; @@ -13,6 +12,7 @@ import net.minecraft.world.level.material.FluidState; import it.unimi.dsi.fastutil.objects.Object2IntMap; +import lombok.Getter; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -21,6 +21,8 @@ import java.util.Objects; public final class PredicateContext { + + @Getter private final CurrentBlockInfo blockInfo; private final List errors = new ArrayList<>(); private final Object2IntMap globalCache; @@ -89,45 +91,13 @@ public Object2IntMap globalCache() { return layerCache; } - /// test against global max count - public boolean testGlobalMax(BasePredicate predicate) { - if (predicate.skipGlobalTest() || layerCache() == null) return true; - int count = incrementGlobalCount(predicate); - if (predicate.testGlobalMax(count)) return true; - return error(SinglePredicateError.maxCount(predicate, count)); - } - - /// test against slice max count - public boolean testSliceMax(BasePredicate predicate) { - if (predicate.skipSliceTest() || layerCache() == null) return true; - int count = incrementSliceCount(predicate); - if (predicate.testSliceMax(count)) return true; - return error(SinglePredicateError.maxLayerCount(predicate, count)); - } - - private int incrementGlobalCount(BasePredicate predicate) { + public int incrementGlobalCount(BasePredicate predicate) { globalCache().mergeInt(predicate, 1, Integer::sum); return globalCache().getInt(predicate); } - private int incrementSliceCount(BasePredicate predicate) { + public int incrementSliceCount(BasePredicate predicate) { Objects.requireNonNull(layerCache()).mergeInt(predicate, 1, Integer::sum); return layerCache().getInt(predicate); } - - /// test against global min count - public boolean testGlobalMin(BasePredicate predicate) { - if (predicate.skipGlobalTest() || layerCache() == null) return true; - int count = globalCache().getInt(predicate); - if (predicate.testGlobalMin(count)) return true; - return error(SinglePredicateError.minCount(predicate, count)); - } - - /// test against slice min count - public boolean testSliceMin(BasePredicate predicate) { - if (predicate.skipSliceTest() || layerCache() == null) return true; - int count = layerCache().getInt(predicate); - if (predicate.testSliceMin(count)) return true; - return error(SinglePredicateError.minLayerCount(predicate, count)); - } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index ec1f5f3154d..246cf016241 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -18,6 +18,7 @@ import com.gregtechceu.gtceu.api.multiblock.error.PlaceholderError; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.pipenet.IPipeNode; import com.gregtechceu.gtceu.api.recipe.GTRecipeType; @@ -52,19 +53,20 @@ public class Predicates { */ public static final PlaceholderError PLACEHOLDER = new PlaceholderError(BlockPos.ZERO, Collections.emptyList()); - public static BasePredicate controller(MultiblockMachineDefinition def) { - return controller(blocks(def.getBlock())); + public static MultiPredicate controller(MultiblockMachineDefinition def) { + return blocks(def.getBlock()).setController(true); } - public static BasePredicate controller(BasePredicate predicate) { + @Deprecated + public static MultiPredicate controller(MultiPredicate predicate) { return predicate.setController(true); } - public static BasePredicate states(BlockState... allowedStates) { + public static MultiPredicate states(BlockState... allowedStates) { return states("States", allowedStates); } - public static BasePredicate states(@Nullable String debugName, BlockState... allowedStates) { + public static MultiPredicate states(@Nullable String debugName, BlockState... allowedStates) { List states = new ArrayList<>(); for (BlockState state : allowedStates) { states.add(state); @@ -82,30 +84,30 @@ public static BasePredicate states(@Nullable String debugName, BlockState... all }); } - public static BasePredicate blocks(Block block) { + public static MultiPredicate blocks(Block block) { return customPredicate("Block", ctx -> ctx.state().is(block) || ctx.error(new BlockMatchingError(ctx.pos(), List.of(block))), Stream.of(BlockInfo.fromBlock(block)), builder -> builder.append(blockToString(block))); } - public static BasePredicate blocks(Block... blocks) { + public static MultiPredicate blocks(Block... blocks) { return blocks("Blocks", blocks); } - public static BasePredicate blocks(@Nullable String debugName, Block... blocks) { + public static MultiPredicate blocks(@Nullable String debugName, Block... blocks) { return blocks(debugName, Arrays.stream(blocks)); } - public static BasePredicate blocks(@Nullable String debugName, - Stream blocks) { + public static MultiPredicate blocks(@Nullable String debugName, + Stream blocks) { List blockList = blocks.toList(); return blocks(debugName, blockList, blockList.stream()); } - public static BasePredicate blocks(@Nullable String debugName, - List blocks, - Stream candidates) { + public static MultiPredicate blocks(@Nullable String debugName, + List blocks, + Stream candidates) { return customPredicate(debugName, ctx -> { for (var block : blocks) { if (ctx.state().is(block)) return true; @@ -128,12 +130,12 @@ private static String blockToString(Block block) { .orElse("unknown block"); } - public static BasePredicate machines(MachineDefinition... definitions) { + public static MultiPredicate machines(MachineDefinition... definitions) { Validate.noNullElements(definitions, "MachineDefinition array has null element at index %s"); return blocks(Arrays.stream(definitions).map(MachineDefinition::get).toArray(MetaMachineBlock[]::new)); } - public static BasePredicate blockTag(TagKey tag) { + public static MultiPredicate blockTag(TagKey tag) { return customPredicate("BlockTag", ctx -> ctx.state().is(tag), Objects.requireNonNull(ForgeRegistries.BLOCKS.tags()) @@ -142,7 +144,7 @@ public static BasePredicate blockTag(TagKey tag) { builder -> builder.append(tag.location())); } - public static BasePredicate fluids(Fluid... fluids) { + public static MultiPredicate fluids(Fluid... fluids) { return customPredicate("Fluids", ctx -> ArrayUtils.contains(fluids, ctx.fluid()) || ctx.error(PLACEHOLDER), Arrays.stream(fluids).map(BlockInfo::fromFluid), @@ -157,7 +159,7 @@ public static BasePredicate fluids(Fluid... fluids) { }); } - public static BasePredicate fluidTag(TagKey tag) { + public static MultiPredicate fluidTag(TagKey tag) { return customPredicate("FluidTag", ctx -> ctx.fluidState().is(tag), Objects.requireNonNull(ForgeRegistries.FLUIDS.tags()) @@ -166,41 +168,42 @@ public static BasePredicate fluidTag(TagKey tag) { builder -> builder.append(tag.location())); } - public static BasePredicate customFunction(Function predicate, - @Nullable List candidates) { + @Deprecated + public static MultiPredicate customFunction(Function predicate, + @Nullable List candidates) { return customPredicate(ctx -> { - PatternError error = predicate.apply(ctx.blockInfo()); + PatternError error = predicate.apply(ctx.getBlockInfo()); return error == null || ctx.error(error); }, Objects.>requireNonNullElse(candidates, Collections.emptyList()).stream()); } - public static BasePredicate customPredicate(Predicate predicate, - Stream candidates) { + public static MultiPredicate customPredicate(Predicate predicate, + Stream candidates) { return customPredicate(null, predicate, candidates); } - public static BasePredicate customPredicate(@Nullable String debugName, - Predicate predicate, - Stream candidates) { + public static MultiPredicate customPredicate(@Nullable String debugName, + Predicate predicate, + Stream candidates) { return customPredicate(debugName, predicate, candidates, null); } - public static BasePredicate customPredicate(@Nullable String debugName, - Predicate predicate, - Stream candidates, - @Nullable Consumer contents) { + public static MultiPredicate customPredicate(@Nullable String debugName, + Predicate predicate, + Stream candidates, + @Nullable Consumer contents) { return BasePredicate.create(debugName, predicate, candidates, contents); } - public static BasePredicate any() { + public static MultiPredicate any() { return BasePredicate.ANY; } - public static BasePredicate air() { + public static MultiPredicate air() { return BasePredicate.AIR; } - public static BasePredicate abilities(PartAbility ability) { + public static MultiPredicate abilities(PartAbility ability) { return customPredicate("Ability", ctx -> ability.isApplicable(ctx.state().getBlock()) || ctx.error(new PartAbilityError(ctx.pos(), ability)), @@ -208,7 +211,7 @@ public static BasePredicate abilities(PartAbility ability) { builder -> builder.append(ability.getName())); } - public static BasePredicate abilities(PartAbility... abilities) { + public static MultiPredicate abilities(PartAbility... abilities) { return customPredicate("Abilities", ctx -> { for (PartAbility ability : abilities) { @@ -231,7 +234,7 @@ public static BasePredicate abilities(PartAbility... abilities) { }); } - public static BasePredicate ability(PartAbility ability, int... tiers) { + public static MultiPredicate ability(PartAbility ability, int... tiers) { StringJoiner sb = new StringJoiner("-"); for (int tier : tiers) { sb.add(GTValues.VN[tier]); @@ -242,20 +245,19 @@ public static BasePredicate ability(PartAbility ability, int... tiers) { ability.getBlocks(tiers).stream().map(BlockInfo::fromBlock)); } - public static BasePredicate autoAbilities(GTRecipeType... recipeType) { + public static MultiPredicate autoAbilities(GTRecipeType... recipeType) { return autoAbilities(recipeType, true, true, true, true, true, true); } - public static BasePredicate autoAbilities(GTRecipeType[] recipeType, - boolean checkEnergyIn, boolean checkEnergyOut, - boolean checkItemIn, boolean checkItemOut, - boolean checkFluidIn, boolean checkFluidOut) { - List predicates = new ArrayList<>(); - + public static MultiPredicate autoAbilities(GTRecipeType[] recipeType, + boolean checkEnergyIn, boolean checkEnergyOut, + boolean checkItemIn, boolean checkItemOut, + boolean checkFluidIn, boolean checkFluidOut) { + MultiPredicate predicate = new MultiPredicate(); if (checkEnergyIn) { for (var type : recipeType) { if (type.getMaxInputs(EURecipeCapability.CAP) > 0) { - predicates.add(abilities(PartAbility.INPUT_ENERGY) + predicate = predicate.or(abilities(PartAbility.INPUT_ENERGY) .setMinCount(1).setMaxCount(2) .setPreviewCount(1).setPriority(1)); break; @@ -265,7 +267,7 @@ public static BasePredicate autoAbilities(GTRecipeType[] recipeType, if (checkEnergyOut) { for (var type : recipeType) { if (type.getMaxOutputs(EURecipeCapability.CAP) > 0) { - predicates.add(abilities(PartAbility.OUTPUT_ENERGY) + predicate = predicate.or(abilities(PartAbility.OUTPUT_ENERGY) .setMinCount(1).setMaxCount(2) .setPreviewCount(1).setPriority(1)); break; @@ -275,7 +277,7 @@ public static BasePredicate autoAbilities(GTRecipeType[] recipeType, if (checkItemIn) { for (var type : recipeType) { if (type.getMaxInputs(ItemRecipeCapability.CAP) > 0) { - predicates.add(abilities(PartAbility.IMPORT_ITEMS) + predicate = predicate.or(abilities(PartAbility.IMPORT_ITEMS) .setPreviewCount(1).setPriority(2)); break; } @@ -284,7 +286,7 @@ public static BasePredicate autoAbilities(GTRecipeType[] recipeType, if (checkItemOut) { for (var type : recipeType) { if (type.getMaxOutputs(ItemRecipeCapability.CAP) > 0) { - predicates.add(abilities(PartAbility.EXPORT_ITEMS) + predicate = predicate.or(abilities(PartAbility.EXPORT_ITEMS) .setPreviewCount(1).setPriority(2)); break; } @@ -293,7 +295,7 @@ public static BasePredicate autoAbilities(GTRecipeType[] recipeType, if (checkFluidIn) { for (var type : recipeType) { if (type.getMaxInputs(FluidRecipeCapability.CAP) > 0) { - predicates.add(abilities(PartAbility.IMPORT_FLUIDS) + predicate = predicate.or(abilities(PartAbility.IMPORT_FLUIDS) .setPreviewCount(1).setPriority(3)); break; } @@ -302,46 +304,46 @@ public static BasePredicate autoAbilities(GTRecipeType[] recipeType, if (checkFluidOut) { for (var type : recipeType) { if (type.getMaxOutputs(FluidRecipeCapability.CAP) > 0) { - predicates.add(abilities(PartAbility.EXPORT_FLUIDS) + predicate = predicate.or(abilities(PartAbility.EXPORT_FLUIDS) .setPreviewCount(1).setPriority(3)); break; } } } - return BasePredicate.or("AutoAbilities", predicates); + return predicate; } - public static BasePredicate autoAbilities(boolean checkMaintenance, boolean checkMuffler, - boolean checkParallel) { - List predicates = new ArrayList<>(); + public static MultiPredicate autoAbilities(boolean checkMaintenance, boolean checkMuffler, + boolean checkParallel) { + MultiPredicate predicate = new MultiPredicate(); if (checkMaintenance) { - predicates.add(abilities(PartAbility.MAINTENANCE) + predicate = predicate.or(abilities(PartAbility.MAINTENANCE) .setMinCount(ConfigHolder.INSTANCE.machines.enableMaintenance ? 1 : 0) .setMaxCount(1) .setPriority(1)); } if (checkMuffler) { - predicates.add(abilities(PartAbility.MUFFLER) + predicate = predicate.or(abilities(PartAbility.MUFFLER) .setExactLimit(1) .setPriority(2)); } if (checkParallel) { - predicates.add(abilities(PartAbility.PARALLEL_HATCH) + predicate = predicate.or(abilities(PartAbility.PARALLEL_HATCH) .setMaxCount(1) .setPreviewCount(1) .setPriority(3)); } - return BasePredicate.or("AutoAbilities", predicates); + return predicate; } - public static BasePredicate heatingCoils() { + public static MultiPredicate heatingCoils() { return blocks("HeatingCoils", GTCEuAPI.HEATING_COILS.values().stream().map(Supplier::get)) // .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")) .setPriority(0); } - public static BasePredicate cleanroomFilters() { + public static MultiPredicate cleanroomFilters() { return blocks("CleanroomFilters", GTCEuAPI.CLEANROOM_FILTERS.values() .stream().map(Supplier::get).toList(), @@ -353,7 +355,7 @@ public static BasePredicate cleanroomFilters() { ; } - public static BasePredicate powerSubstationBatteries() { + public static MultiPredicate powerSubstationBatteries() { return blocks("PSS-Batteries", GTCEuAPI.PSS_BATTERIES.values() .stream().map(Supplier::get).map(Block.class::cast).toList(), @@ -365,13 +367,17 @@ public static BasePredicate powerSubstationBatteries() { ; } - public static @Nullable BasePredicate dataHatchPredicate() { + public static @Nullable MultiPredicate dataHatchPredicate() { // if research is enabled, require the data hatch, otherwise use a grate instead if (ConfigHolder.INSTANCE.machines.enableResearch) { // TODO xor predicate matching :) - return abilities(PartAbility.DATA_ACCESS, PartAbility.OPTICAL_DATA_RECEPTION) + return abilities(PartAbility.DATA_ACCESS) + .xor(abilities(PartAbility.OPTICAL_DATA_RECEPTION)) .setExactLimit(1) .setPriority(1); + // return abilities(PartAbility.DATA_ACCESS, PartAbility.OPTICAL_DATA_RECEPTION) + // .setExactLimit(1) + // .setPriority(1); } // this really should not be null return null; @@ -380,7 +386,7 @@ public static BasePredicate powerSubstationBatteries() { /** * Use this predicate for Frames in your Multiblock. Allows for Framed Pipes as well as normal Frame blocks. */ - public static BasePredicate frames(Material... frameMaterials) { + public static MultiPredicate frames(Material... frameMaterials) { var frameBlocks = Arrays.stream(frameMaterials) .map(m -> GTMaterialBlocks.MATERIAL_BLOCKS.get(TagPrefix.frameGt, m)) .filter(obj -> Objects.nonNull(obj) && obj.isPresent()) @@ -390,7 +396,7 @@ public static BasePredicate frames(Material... frameMaterials) { .or(framedPipes(frameMaterials, frameBlocks)); } - public static BasePredicate framedPipes(Material[] frameMaterials, Block[] frameBlocks) { + public static MultiPredicate framedPipes(Material[] frameMaterials, Block[] frameBlocks) { return customPredicate("FramedPipes", ctx -> { BlockEntity tileEntity = ctx.blockEntity(); if (!(tileEntity instanceof IPipeNode pipeNode)) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 07797dafeff..34842e6f7e3 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -2,8 +2,7 @@ import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.PatternError; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; @@ -14,7 +13,6 @@ import net.minecraft.world.level.block.state.BlockState; import it.unimi.dsi.fastutil.chars.Char2ObjectMap; -import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.Getter; import org.jetbrains.annotations.Nullable; @@ -37,12 +35,12 @@ public class BlockPattern implements IBlockPattern { @Getter protected final SliceStrategy sliceStrategy; @Getter - protected final Char2ObjectMap predicates; + protected final Char2ObjectMap predicates; public BlockPattern(PatternSlice[] slices, SliceStrategy sliceStrategy, int[] dimensions, RelativeDirection[] directions, @Nullable OriginOffset offset, @Nullable OriginOffset anchorOffset, - Char2ObjectMap predicates, + Char2ObjectMap predicates, char centerChar) { this.slices = slices; this.sliceStrategy = sliceStrategy; @@ -145,14 +143,6 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c patternState.globalCount.clear(); patternState.layerCount.clear(); - // Make sure every prerdicate with a minvalue is checked - for (BasePredicate predicate : predicates.values()) { - for (BasePredicate basePredicate : predicate.expand()) { - if (basePredicate.getMinCount() > 0) { - patternState.globalCount.putIfAbsent(basePredicate, 0); - } - } - } // only try to clear the cache for structure checking mapping when checking the structure for unflipped // maybe switch to a multiblock state value instead? if (!isFlipped) { @@ -170,18 +160,12 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c // global min check PredicateContext ctx = patternState.toContext(); - for (BasePredicate predicate : predicates.values()) { - if (ctx.testGlobalMin(predicate)) { + for (MultiPredicate predicate : predicates.values()) { + if (!predicate.testGlobalMin(ctx)) { patternState.setErrors(ctx.getErrors()); return false; } } -// for (Object2IntMap.Entry entry : patternState.globalCount.object2IntEntrySet()) { -// if (!entry.getKey().testGlobalMin(ctx)) { -// patternState.setErrors(ctx.getErrors()); -// return false; -// } -// } patternState.setError(null); return true; @@ -221,7 +205,7 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p for (int stringIdx = 0; stringIdx < dimensions[1]; stringIdx++) { for (int charIdx = 0; charIdx < dimensions[2]; charIdx++) { patternState.currentBlockInfo.setCurrentPos(charPos); - BasePredicate pred = predicates.get(slice.charAt(stringIdx, charIdx)); + MultiPredicate pred = predicates.get(slice.charAt(stringIdx, charIdx)); if (!pred.isAny()) { BlockEntity blockEntity = ctx.blockEntity(); @@ -230,7 +214,7 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p } // internal predicate check, global/slice max checks - if (pred.test(ctx) && ctx.testGlobalMax(pred) && ctx.testSliceMax(pred)) { + if (pred.test(ctx)) { charPos.move(absoluteChar); // continue... } else { @@ -244,17 +228,11 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p } // slice min check - for (BasePredicate predicate : predicates.values()) { - if (ctx.testSliceMin(predicate)) { + for (MultiPredicate predicate : predicates.values()) { + if (!predicate.testSliceMin(ctx)) { patternState.setErrors(ctx.getErrors()); } } -// for (Object2IntMap.Entry entry : patternState.layerCount.object2IntEntrySet()) { -// if (!entry.getKey().testSliceMin(ctx)) { -// patternState.setErrors(ctx.getErrors()); -// return false; -// } -// } return true; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandableMultiblockPatternBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandableMultiblockPatternBuilder.java index a7e68a609e6..de05d5519fd 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandableMultiblockPatternBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandableMultiblockPatternBuilder.java @@ -1,6 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import net.minecraft.core.BlockPos; @@ -21,7 +21,7 @@ public class ExpandableMultiblockPatternBuilder { @Setter protected @Nullable ExpandablePattern.BoundsConstraintProvider constraintProvider; @Setter - protected @Nullable BiFunction, BasePredicate> predicateProvider; + protected @Nullable BiFunction, MultiPredicate> predicateProvider; protected final RelativeDirection[] directions = new RelativeDirection[3]; private ExpandableMultiblockPatternBuilder(RelativeDirection aisleDir, RelativeDirection stringDir, diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index 6c83d37d216..052e8e84243 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -2,9 +2,8 @@ import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; @@ -21,7 +20,6 @@ import lombok.Setter; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.List; import java.util.function.BiFunction; @@ -47,7 +45,7 @@ public interface BoundsConstraintProvider { @Setter protected @Nullable BoundsConstraintProvider boundsConstraints = null; @Getter - protected final BiFunction, BasePredicate> predicateProvider; + protected final BiFunction, MultiPredicate> predicateProvider; @Getter protected final OriginOffset offset = new OriginOffset(); @@ -55,7 +53,7 @@ public interface BoundsConstraintProvider { protected final RelativeDirection[] directions; public ExpandablePattern(BoundsProvider boundsProvider, - BiFunction, BasePredicate> predicateProvider, + BiFunction, MultiPredicate> predicateProvider, RelativeDirection[] directions) { this.boundsProvider = boundsProvider; this.predicateProvider = predicateProvider; @@ -156,7 +154,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c // aisle count, y is str count, and z is char count. for (var pos : BlockPos.betweenClosed(negCorner, posCorner)) { BlockPos.MutableBlockPos mPos = pos.mutable(); - BasePredicate pred = predicateProvider.apply(mPos, bounds); + MultiPredicate pred = predicateProvider.apply(mPos, bounds); // this basically reshuffles the coordinates into absolute form from relative form mPos.set(BlockPos.ZERO).move(absolutes[0], pos.getX()).move(absolutes[1], pos.getY()).move(absolutes[2], diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java index 3985bda10bf..2acb3a76a6f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java @@ -2,6 +2,7 @@ import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.google.common.base.Joiner; @@ -51,7 +52,7 @@ public class MultiblockPatternBuilder { private final List slices = new ArrayList<>(); - private final Char2ObjectMap<@Nullable BasePredicate> symbolMap = new Char2ObjectOpenHashMap<>(); + private final Char2ObjectMap<@Nullable MultiPredicate> symbolMap = new Char2ObjectOpenHashMap<>(); private final RelativeDirection[] directions = new RelativeDirection[3]; @@ -124,7 +125,7 @@ public static MultiblockPatternBuilder start(RelativeDirection sliceDir, Relativ return new MultiblockPatternBuilder(sliceDir, stringDir, charDir); } - public MultiblockPatternBuilder where(char symbol, BasePredicate predicate) { + public MultiblockPatternBuilder where(char symbol, MultiPredicate predicate) { this.symbolMap.put(symbol, predicate); if (predicate.isController()) centerChar = symbol; return this; @@ -172,10 +173,10 @@ private void checkGlobalConstraints() { for (var entry : symbolMap.char2ObjectEntrySet()) { char symbol = entry.getCharKey(); - BasePredicate predicate = entry.getValue(); + MultiPredicate predicate = entry.getValue(); if (predicate == null) throw new IllegalArgumentException("Predicate for symbol " + symbol + " was null."); int maxCount = -1; - for (var basePredicate : predicate.expand()) { + for (var basePredicate : predicate) { if (basePredicate.getMaxCount() == -1) { maxCount = -1; break; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 0412c0c8747..41b65bb0c41 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -13,7 +13,6 @@ import lombok.Getter; import lombok.Setter; -import lombok.experimental.Accessors; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -21,12 +20,11 @@ import java.util.function.Predicate; import java.util.stream.Stream; -@Accessors(chain = true) public abstract class BasePredicate { - public static final BasePredicate AIR = create("Air", ctx -> ctx.state().is(Blocks.AIR)); + public static final MultiPredicate AIR = create("Air", ctx -> ctx.state().is(Blocks.AIR)); - public static final BasePredicate ANY = create("Any", ctx -> true); + public static final MultiPredicate ANY = create("Any", ctx -> true); protected static final Comparator PREDICATE_COMPARATOR = Comparator .comparingInt(BasePredicate::getPriority); @@ -62,18 +60,43 @@ public abstract class BasePredicate { private @Nullable String nbtParser; // unsure what this does /// the main testing method - public boolean test(PredicateContext ctx) { - return true; + public abstract boolean test(PredicateContext ctx); + + /// test with internal function and global/slice max + public boolean testLimited(PredicateContext ctx) { + return test(ctx) && testGlobalMax(ctx) && testSliceMax(ctx); + } + + /// test against global max count + public boolean testGlobalMax(PredicateContext ctx) { + if (skipGlobalTest()) return true; + int count = ctx.incrementGlobalCount(this); + if (maxCount == -1 || count <= maxCount) return true; + return ctx.error(SinglePredicateError.maxCount(this, count)); + } + + /// test against slice max count + public boolean testSliceMax(PredicateContext ctx) { + if (skipSliceTest() || ctx.layerCache() == null) return true; + int count = ctx.incrementSliceCount(this); + if (maxSliceCount == -1 || count <= maxSliceCount) return true; + return ctx.error(SinglePredicateError.maxLayerCount(this, count)); } /// test against global max count - public boolean testGlobalMax(int count) { - return maxCount == -1 || count <= maxCount; + public boolean testGlobalMin(PredicateContext ctx) { + if (skipGlobalTest()) return true; + int count = ctx.globalCache().getInt(this); + if (maxCount == -1 || count <= maxCount) return true; + return ctx.error(SinglePredicateError.minCount(this, count)); } /// test against slice max count - public boolean testSliceMax(int count) { - return maxSliceCount == -1 || count <= maxSliceCount; + public boolean testSliceMin(PredicateContext ctx) { + if (skipSliceTest() || ctx.layerCache() == null) return true; + int count = ctx.layerCache().getInt(this); + if (maxSliceCount == -1 || count <= maxSliceCount) return true; + return ctx.error(SinglePredicateError.minLayerCount(this, count)); } /// test against global max count @@ -95,9 +118,7 @@ public boolean skipSliceTest() { } /// computes the candidates for this predicate - public List computeCandidates() { - return Collections.emptyList(); - } + public abstract List computeCandidates(); /// @return the candidate blocks for this predicate, may be empty, lazily initialized public List getCandidates() { @@ -107,11 +128,6 @@ public List getCandidates() { return candidates; } - /// @return a list of candidates from a predicate at {@code index} - public List getCandidates(int index) { - return getCandidates(); - } - public List getCandidateStacks() { return getCandidates().stream() .filter(BlockInfo::nonAir) @@ -132,97 +148,6 @@ public Optional getFirstCandidate() { .map(c -> c.get(0)); } - public boolean isAir() { - return this == AIR; - } - - public boolean isAny() { - return this == ANY; - } - - /// used for tooltips - /// - /// @return true if this or any sub predicates is air - public boolean hasAir() { - return isAir(); - } - - /// used for tooltips - public boolean isSingle() { - return true; - } - - public BasePredicate setMinGlobalLimited(int min) { - return this.setMinCount(min); - } - - public BasePredicate setMinGlobalLimited(int min, int previewCount) { - return this.setMinCount(min).setPreviewCount(previewCount); - } - - public BasePredicate setMaxGlobalLimited(int max) { - return this.setMaxCount(max); - } - - public BasePredicate setMaxGlobalLimited(int max, int previewCount) { - return this.setMaxCount(max).setPreviewCount(previewCount); - } - - public BasePredicate setGlobalMinMax(int min, int max) { - return this.setMinCount(min).setMaxCount(max); - } - - public BasePredicate setMinLayerLimited(int min) { - return this.setMinSliceCount(min); - } - - public BasePredicate setMinLayerLimited(int min, int previewCount) { - return this.setMinSliceCount(min).setPreviewCount(previewCount); - } - - public BasePredicate setMaxLayerLimited(int max) { - return this.setMaxSliceCount(max); - } - - public BasePredicate setMaxLayerLimited(int max, int previewCount) { - return this.setMaxSliceCount(max).setPreviewCount(previewCount); - } - - public BasePredicate setLayerMinMax(int min, int max) { - return this.setMinSliceCount(min).setMaxSliceCount(max); - } - - /** - * Sets the Minimum and Maximum limit to the passed value - * - * @param limit The Maximum and Minimum limit - */ - public BasePredicate setExactLimit(int limit) { - return this.setMinCount(limit).setMaxCount(limit); - } - - public BasePredicate disabledRenderFormed() { - return setDisableRenderFormed(true); - } - - /// @return a non-flattened list of predicates - public List getInnerPredicates() { - return List.of(this); - } - - /// visits every predicate - public void visit(Consumer visitor) { - visitor.accept(this); - } - - /// @return a flat list of all predicates - public final List expand() { - List result = new ArrayList<>(); - visit(result::add); - if (result.size() > 1) result.sort(PREDICATE_COMPARATOR); - return Collections.unmodifiableList(result); - } - /// the type of this predicate public abstract String getTypeName(); @@ -232,47 +157,20 @@ protected void appendContents(StringBuilder builder) {} @Override public String toString() { StringBuilder builder = new StringBuilder(getTypeName()); - if (isController()) builder.append("[Controller]"); builder.append('{'); appendContents(builder); builder.append('}'); return builder.toString(); } - // === instance methods === - public BasePredicate or(BasePredicate other) { - return or(null, List.of(this, other)); - } - - public BasePredicate and(BasePredicate other) { - return and(null, List.of(this, other)); - } - - public BasePredicate xor(BasePredicate other) { - return xor(null, List.of(this, other)); - } - - // === public static helpers === - public static BasePredicate or(@Nullable String debugName, Iterable predicates) { - return new MultiPredicate(debugName, predicates, MultiPredicate.Logic.OR); - } - - public static BasePredicate and(@Nullable String debugName, Iterable predicates) { - return new MultiPredicate(debugName, predicates, MultiPredicate.Logic.AND); - } - - public static BasePredicate xor(@Nullable String debugName, Iterable predicates) { - return new MultiPredicate(debugName, predicates, MultiPredicate.Logic.XOR); - } - - public static BasePredicate create(@Nullable String debugName, Predicate predicate) { + public static MultiPredicate create(@Nullable String debugName, Predicate predicate) { return create(debugName, predicate, Stream.empty(), null); } // this uses stream for lazy initialization - public static BasePredicate create(@Nullable String debugName, Predicate predicate, - Stream candidateStream, @Nullable Consumer contents) { - return new BasePredicate() { + public static MultiPredicate create(@Nullable String debugName, Predicate predicate, + Stream candidateStream, @Nullable Consumer contents) { + BasePredicate basePredicate = new BasePredicate() { @Override public boolean test(PredicateContext ctx) { @@ -296,5 +194,6 @@ protected void appendContents(StringBuilder builder) { } } }; + return new MultiPredicate(basePredicate); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 7c29d72f85a..1b78ffce612 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -1,61 +1,63 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import lombok.AccessLevel; import lombok.Getter; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.UnknownNullability; import java.util.*; -import java.util.function.BiPredicate; -import java.util.function.Consumer; -public class MultiPredicate extends BasePredicate implements Iterable { +public class MultiPredicate implements Iterable { + private static final String UNINITIALIZED = "__UNINITIALIZED__"; private final List predicateList = new ObjectArrayList<>(); - private final String debugName; - @Getter(AccessLevel.PROTECTED) - private final Logic type; + private @Nullable final String debugName; + private @Nullable final Logic type; private final boolean hasAir; + @Getter + private boolean controller; - protected MultiPredicate(@Nullable String debugName, Iterable predicates, Logic type) { - this.debugName = debugName == null ? "MultiPredicate" : debugName; + public MultiPredicate() { + this.debugName = UNINITIALIZED; + this.type = null; + this.hasAir = false; + } + + private MultiPredicate(@Nullable String debugName, Logic type, boolean hasAir) { + this.debugName = debugName; this.type = type; - boolean hasAir = false; - for (BasePredicate predicate : predicates) { - hasAir |= predicate.hasAir(); - if (!(predicate instanceof MultiPredicate multi) || !multi.sameType(this)) { - addPredicate(predicate); - } else { - addPredicates(multi); - } - } this.hasAir = hasAir; - sorted(); } - @Override + protected MultiPredicate(BasePredicate singleton) { + this.debugName = null; + this.type = null; + this.hasAir = false; + addPredicate(singleton); + } + + @ApiStatus.Internal + public boolean isUninitialized() { + return UNINITIALIZED.equals(debugName); + } + public boolean test(PredicateContext ctx) { - return testInternal(ctx); + return getType().run(ctx, this); } - /// custom testing logic, usually checking if blockstate/entity is correct - private boolean testInternal(PredicateContext ctx) { - return getType().run(ctx, this, BasePredicate::test); + /// test against global min count + public boolean testGlobalMin(PredicateContext ctx) { + return getType().testGlobalMin(ctx, this); } -// @Override -// public boolean testGlobalMin(PredicateContext ctx) { -// return getType().run(ctx, this, BasePredicate::testGlobalMin); -// } -// -// @Override -// public boolean testSliceMin(PredicateContext ctx) { -// return getType().run(ctx, this, BasePredicate::testSliceMin); -// } + /// test against slice min count + public boolean testSliceMin(PredicateContext ctx) { + return getType().testSliceMin(ctx, this); + } protected MultiPredicate addPredicates(Iterable predicates) { predicates.forEach(this::addPredicate); @@ -67,28 +69,12 @@ protected MultiPredicate addPredicate(BasePredicate predicate) { return this; } - @Override - public List computeCandidates() { - return predicateList.stream() - .flatMap(p -> p.getCandidates().stream()) + public List> getCandidates() { + return this.predicateList.stream() + .map(BasePredicate::getCandidates) .toList(); } - @Override - public List getCandidates(int index) { - return this.predicateList.get(index).getCandidates(); - } - - @Override - public List getInnerPredicates() { - return this.predicateList; - } - - @Override - public void visit(Consumer visitor) { - this.forEach(p -> p.visit(visitor)); - } - public boolean isOr() { return this.type == Logic.OR; } @@ -105,123 +91,336 @@ protected boolean sameType(MultiPredicate other) { return this.type == other.type; } - @Override + public boolean hasType() { + return this.type != null; + } + + public boolean isValid() { + return isSingle() || hasType(); + } + + public boolean isAny() { + return this == BasePredicate.ANY; + } + + public boolean isAir() { + return this == BasePredicate.AIR; + } + public boolean hasAir() { - return this.hasAir; + return this.isAir() || this.hasAir; } - protected MultiPredicate sorted() { - this.predicateList.sort(PREDICATE_COMPARATOR); + protected BasePredicate compact() { + return new BasePredicate() { + + @Override + public boolean test(PredicateContext ctx) { + return getType().run(ctx, MultiPredicate.this); + } + + @Override + public boolean testGlobalMin(PredicateContext ctx) { + return getType().testGlobalMin(ctx, MultiPredicate.this); + } + + @Override + public boolean testSliceMin(PredicateContext ctx) { + return getType().testSliceMin(ctx, MultiPredicate.this); + } + + @Override + public List computeCandidates() { + return MultiPredicate.this.getCandidates() + .stream() + .flatMap(Collection::stream) + .toList(); + } + + @Override + public String getTypeName() { + return MultiPredicate.this.getTypeName(); + } + + @Override + protected void appendContents(StringBuilder builder) { + MultiPredicate.this.appendContents(builder); + } + }; + } + + public MultiPredicate setMinGlobalLimited(int min) { + return this.setMinCount(min); + } + + public MultiPredicate setMinGlobalLimited(int min, int previewCount) { + return this.setMinCount(min).setPreviewCount(previewCount); + } + + public MultiPredicate setMinCount(int min) { + this.forEach(p -> p.setMinCount(min)); return this; } - protected MultiPredicate copy() { - return new MultiPredicate(this.debugName, this, this.getType()); + public MultiPredicate setMaxGlobalLimited(int max) { + return this.setMaxCount(max); } - @Override - public BasePredicate or(BasePredicate other) { + public MultiPredicate setMaxGlobalLimited(int max, int previewCount) { + return this.setMaxCount(max).setPreviewCount(previewCount); + } + + public MultiPredicate setMaxCount(int max) { + this.forEach(p -> p.setMaxCount(max)); + return this; + } + + public MultiPredicate setGlobalMinMax(int min, int max) { + return this.setMinCount(min).setMaxCount(max); + } + + public MultiPredicate setMinLayerLimited(int min) { + return this.setMinSliceCount(min); + } + + public MultiPredicate setMinLayerLimited(int min, int previewCount) { + return this.setMinSliceCount(min).setPreviewCount(previewCount); + } + + public MultiPredicate setMinSliceCount(int min) { + this.forEach(p -> p.setMinSliceCount(min)); + return this; + } + + public MultiPredicate setMaxLayerLimited(int max) { + return this.setMaxSliceCount(max); + } + + public MultiPredicate setMaxLayerLimited(int max, int previewCount) { + return this.setMaxSliceCount(max).setPreviewCount(previewCount); + } + + public MultiPredicate setMaxSliceCount(int max) { + this.forEach(p -> p.setMaxSliceCount(max)); + return this; + } + + public MultiPredicate setPreviewCount(int previewCount) { + this.forEach(p -> p.setPreviewCount(previewCount)); + return this; + } + + public MultiPredicate setLayerMinMax(int min, int max) { + return this.setMinSliceCount(min).setMaxSliceCount(max); + } + + /** + * Sets the Minimum and Maximum limit to the passed value + * + * @param limit The Maximum and Minimum limit + */ + public MultiPredicate setExactLimit(int limit) { + return this.setMinCount(limit).setMaxCount(limit); + } + + public MultiPredicate disabledRenderFormed() { + return setDisableRenderFormed(true); + } + + private MultiPredicate setDisableRenderFormed(boolean disable) { + this.forEach(p -> p.setDisableRenderFormed(disable)); + return this; + } + + protected MultiPredicate sorted() { + this.predicateList.sort(BasePredicate.PREDICATE_COMPARATOR); + return this; + } + + public MultiPredicate or(MultiPredicate other) { return Logic.OR.combine(this, other); } - @Override - public BasePredicate and(BasePredicate other) { + public MultiPredicate and(MultiPredicate other) { return Logic.AND.combine(this, other); } - @Override - public BasePredicate xor(BasePredicate other) { + public MultiPredicate xor(MultiPredicate other) { return Logic.XOR.combine(this, other); } - @Override public boolean isSingle() { - return false; + return this.predicateList.size() == 1; } - @Override public String getTypeName() { - return debugName + '(' + this.type + ')'; + if (isSingle()) return "SINGLETON"; + StringBuilder builder = new StringBuilder().append(this.type); + if (this.debugName != null) builder.append("#").append(this.debugName); + return builder.toString(); } - @Override protected void appendContents(StringBuilder builder) { StringJoiner joiner = new StringJoiner(", "); this.forEach(p -> joiner.add(p.toString())); builder.append(joiner); } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(getTypeName()); + if (isController()) builder.append("[Controller]"); + builder.append('{'); + appendContents(builder); + builder.append('}'); + return builder.toString(); + } + @Override public Iterator iterator() { return this.predicateList.iterator(); } + protected Logic getType() { + if (isSingle()) return Logic.OR; + return Objects.requireNonNull(this.type, "type == null"); + } + + public MultiPredicate setController(boolean controller) { + this.controller = controller; + return this; + } + + public MultiPredicate setPriority(int priority) { + this.forEach(p -> p.setPriority(priority)); + return this; + } + protected enum Logic { - OR { + OR, + AND { @Override - protected boolean run(PredicateContext ctx, Iterable predicates, BiPredicate extractor) { - for (BasePredicate basePredicate : predicates) { - if (extractor.test(basePredicate, ctx)) { - return true; - } - } - return false; + protected boolean run(PredicateContext ctx, MultiPredicate predicates) { + return !super.run(ctx, predicates); } - }, AND { + @Override + public boolean testGlobalMin(PredicateContext ctx, MultiPredicate predicates) { + return !super.testGlobalMin(ctx, predicates); + } @Override - protected boolean run(PredicateContext ctx, Iterable predicates, BiPredicate extractor) { - return !OR.run(ctx, predicates, extractor); + public boolean testSliceMin(PredicateContext ctx, MultiPredicate predicates) { + return !super.testSliceMin(ctx, predicates); } - }, XOR { + // override test slice/global min? + }, + XOR { @Override - protected boolean run(PredicateContext ctx, Iterable predicates, BiPredicate extractor) { + protected boolean run(PredicateContext ctx, MultiPredicate predicates) { int passed = 0; for (BasePredicate basePredicate : predicates) { - if (extractor.test(basePredicate, ctx)) { + if (basePredicate.testLimited(ctx)) { if (++passed > 1) return false; } } return passed == 1; } - }; - protected abstract boolean run(PredicateContext ctx, Iterable predicates, - BiPredicate extractor); + @Override + public boolean testGlobalMin(PredicateContext ctx, MultiPredicate predicates) { + int skipped = 0; + int passed = 0; + for (BasePredicate predicate : predicates) { + if (predicate.getMinCount() == -1) { + skipped++; + continue; + } + int count = ctx.globalCache().getInt(predicate); + if (predicate.testGlobalMin(count)) { + if (++passed > 1) { + // TODO special xor error + return ctx.error(SinglePredicateError.minCount(predicate, count)); + } + } else { + return ctx.error(SinglePredicateError.minCount(predicate, count)); + } + } + if (skipped == predicates.predicateList.size()) return true; + return passed == 1; + } + + @Override + public boolean testSliceMin(PredicateContext ctx, MultiPredicate predicates) { + if (ctx.layerCache() == null) return true; + int skipped = 0; + int passed = 0; + for (BasePredicate predicate : predicates) { + if (predicate.getMinCount() == -1) { + skipped++; + continue; + } + int count = ctx.layerCache().getInt(predicate); + if (predicate.testGlobalMin(count)) { + if (++passed > 1) { + // TODO special xor error + return ctx.error(SinglePredicateError.minCount(predicate, count)); + } + } else { + return ctx.error(SinglePredicateError.minCount(predicate, count)); + } + } + if (skipped == predicates.predicateList.size()) return true; + return passed == 1; + } + }; /// @param a will have type set /// @param b may or may not be a multi predicate /// @return copy of {@code a} with {@code b} added - protected BasePredicate combine(MultiPredicate a, BasePredicate b) { - if (!(b instanceof MultiPredicate multi)) { - // b is not a multi predicate, simply add it - return a.copy().addPredicate(b).sorted(); + protected MultiPredicate combine(MultiPredicate a, @Nullable MultiPredicate b) { + if (b == null) return a; // b really should not be null in the first place + if (a.isUninitialized()) return b; + var ret = new MultiPredicate("Multi", this, a.hasAir() || b.hasAir()); + appendPredicate(a, ret); + appendPredicate(b, ret); + return ret.sorted(); + } + + private void appendPredicate(MultiPredicate source, MultiPredicate dest) { + if (source.type == null && source.isSingle()) { + dest.addPredicate(source.predicateList.get(0)); + } else if (source.type != this) { + dest.addPredicate(source.compact()); + } else { + dest.addPredicates(source); } + } - if (a.getType() != this && multi.getType() != this) { - // if neither predicate is of this type, make new multi predicate of this type - return new MultiPredicate(null, List.of(a, b), this); - } else if (a.getType() != this) { - // b must be of this type, flip operation to add a to b - return this.combine(multi, a); + protected boolean run(PredicateContext ctx, MultiPredicate predicates) { + for (BasePredicate basePredicate : predicates) { + if (basePredicate.testLimited(ctx)) return true; } + return false; + } - // a must be of this type, b may or may not - var dest = a.copy(); - if (a.getType() == multi.getType()) { - // add all inner predicates - dest.addPredicates(multi); - } else { - // add multi predicate as a simplified predicate - dest.addPredicate(multi); + public boolean testGlobalMin(PredicateContext ctx, MultiPredicate predicates) { + for (BasePredicate predicate : predicates) { + if (predicate.testGlobalMin(ctx)) return true; } + return false; + } - return dest.sorted(); + public boolean testSliceMin(PredicateContext ctx, MultiPredicate predicates) { + if (ctx.layerCache() == null) return true; + for (BasePredicate predicate : predicates) { + if (predicate.testSliceMin(ctx)) return true; + } + return false; } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java index 075d0ba0d12..5c7befa8336 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java @@ -4,6 +4,7 @@ import com.gregtechceu.gtceu.api.block.property.GTBlockStateProperties; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -28,9 +29,9 @@ public abstract class AbstractStructureHelper { Direction.EAST, Direction.UP, Direction.DOWN }; @Getter - protected final HashBasedTable blockPreferences = HashBasedTable + protected final HashBasedTable blockPreferences = HashBasedTable .create(); - protected final HashBasedTable minMaxPreferences = HashBasedTable + protected final HashBasedTable minMaxPreferences = HashBasedTable .create(); protected @Nullable Block controllerBlock; @@ -42,7 +43,7 @@ public static AbstractStructureHelper expandable(IntList sliceRepeats) { return new ExpandablePatternHelper(sliceRepeats); } - public Table getMinMaxPreferences() { + public Table getMinMaxPreferences() { return this.minMaxPreferences; } @@ -69,16 +70,16 @@ protected abstract void populateWithUserBlockPreferences(Map resultStructure, IBlockPattern pattern, Direction frontFacing, Direction upFacing, boolean isFlipped); - public abstract BasePredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, - Direction frontFacing, Direction upFacing, boolean isFlipped); + public abstract MultiPredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, + Direction frontFacing, Direction upFacing, boolean isFlipped); - protected int getMinCount(BasePredicate predicate, BasePredicate basePredicate) { + protected int getMinCount(MultiPredicate predicate, BasePredicate basePredicate) { if (!minMaxPreferences.contains(predicate, basePredicate)) return basePredicate.getMinCount(); return minMaxPreferences.get(predicate, basePredicate).leftInt(); } - protected int getMaxCount(BasePredicate predicate, BasePredicate basePredicate) { + protected int getMaxCount(MultiPredicate predicate, BasePredicate basePredicate) { if (!minMaxPreferences.contains(predicate, basePredicate)) return basePredicate.getMaxCount(); return minMaxPreferences.get(predicate, basePredicate).rightInt(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java index a599d428aee..6eed8a1b615 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java @@ -4,6 +4,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.PatternSlice; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -24,8 +25,8 @@ protected BlockPatternHelper(Int2IntMap sliceRepeats) { this.sliceRepeats = sliceRepeats; } - public BasePredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, - Direction frontFacing, Direction upFacing, boolean isFlipped) { + public MultiPredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, + Direction frontFacing, Direction upFacing, boolean isFlipped) { BlockPattern blockPattern = (BlockPattern) pattern; char[][][] flattenedBlockPattern = flattenBlockPattern(blockPattern); char[][][] adjustedBlockPattern = rotateAndFlipPattern(flattenedBlockPattern, blockPattern.getDirections(), @@ -66,7 +67,7 @@ protected void populateWithUserBlockPreferences(Map resultS dimensions.getX() + "," + dimensions.getY() + "," + dimensions.getZ()); } char c = this.flattenedBlockPattern[pos.getX()][pos.getY()][pos.getZ()]; - BasePredicate predicate = blockPattern.getPredicates().get(c); + MultiPredicate predicate = blockPattern.getPredicates().get(c); if (!isValidCandidate(resultStructure, predicate, pos, blockInfo, sliceDir)) { throw new IllegalStateException("Invalid preference " + blockInfo.getBlockState().getBlock().getName() + " for position " + pos); @@ -108,7 +109,7 @@ protected void populateFromPattern(Map resultStructure, IBl if (resultStructure.containsKey(pos)) continue; char c = this.flattenedBlockPattern[pos.getX()][pos.getY()][pos.getZ()]; - BasePredicate predicate = blockPattern.getPredicates().get(c); + MultiPredicate predicate = blockPattern.getPredicates().get(c); if (predicate.isAir() || predicate.isAny()) { continue; @@ -126,9 +127,9 @@ protected void populateFromPattern(Map resultStructure, IBl } } - private boolean tryMinCount(Map resultStructure, BasePredicate predicate, + private boolean tryMinCount(Map resultStructure, MultiPredicate predicate, BlockPos pos, Direction dir, int offset) { - for (BasePredicate basePredicate : predicate.expand()) { + for (BasePredicate basePredicate : predicate) { int minCount = getMinCount(predicate, basePredicate); if (minCount == 0) continue; @@ -155,9 +156,9 @@ private boolean tryMinCount(Map resultStructure, BasePredic return false; } - private boolean tryMaxCount(Map resultStructure, BasePredicate predicate, + private boolean tryMaxCount(Map resultStructure, MultiPredicate predicate, BlockPos pos, Direction dir, int offset) { - for (BasePredicate basePredicate : predicate.expand()) { + for (BasePredicate basePredicate : predicate) { int maxCount = getMaxCount(predicate, basePredicate); if (maxCount == 0) continue; @@ -184,14 +185,14 @@ private boolean tryMaxCount(Map resultStructure, BasePredic return false; } - private boolean isValidCandidate(Map resultStructure, BasePredicate predicate, + private boolean isValidCandidate(Map resultStructure, MultiPredicate predicate, BlockPos pos, BlockInfo newInfo, Direction sliceDir) { // The slice (layer) this position belongs to. int sliceCoord = getCoordFromDir(pos, sliceDir); // newInfo is valid if there's a basePredicate it qualifies for whose maxCount (global) and maxSliceCount // (this slice) wouldn't be exceeded by placing it here. - for (BasePredicate basePredicate : predicate.expand()) { + for (BasePredicate basePredicate : predicate) { if (!basePredicate.getCandidates().contains(newInfo)) continue; int maxCount = getMaxCount(predicate, basePredicate); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java index b517189d7a6..abf4bea2d7b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java @@ -3,6 +3,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -88,7 +89,7 @@ public void populateFromPattern(Map resultStructure, IBlock // this basically means the x val of the iter is aisle count, y is str count, and z is char count. for (BlockPos pos : betweenClosed(corners.bounds())) { BlockPos.MutableBlockPos mutablePos = pos.mutable(); - BasePredicate predicate = predicateProvider.apply(mutablePos, userRepeats); + MultiPredicate predicate = predicateProvider.apply(mutablePos, userRepeats); // this basically reshuffles the coordinates into absolute form from relative form setFromDirection(mutablePos, absolutes[0], pos.getX()); @@ -107,9 +108,9 @@ public void populateFromPattern(Map resultStructure, IBlock } } - private boolean tryMinCount(Map resultStructure, BasePredicate predicate, + private boolean tryMinCount(Map resultStructure, MultiPredicate predicate, BlockPos pos) { - for (BasePredicate basePredicate : predicate.expand()) { + for (BasePredicate basePredicate : predicate) { int minCount = getMinCount(predicate, basePredicate); if (minCount == 0) continue; @@ -128,9 +129,9 @@ private boolean tryMinCount(Map resultStructure, BasePredic return false; } - private boolean tryMaxCount(Map resultStructure, BasePredicate predicate, + private boolean tryMaxCount(Map resultStructure, MultiPredicate predicate, BlockPos pos) { - for (BasePredicate basePredicate : predicate.expand()) { + for (BasePredicate basePredicate : predicate) { int maxCount = getMaxCount(predicate, basePredicate); if (maxCount == 0) continue; @@ -150,8 +151,8 @@ private boolean tryMaxCount(Map resultStructure, BasePredic } @Override - public BasePredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, - Direction frontFacing, Direction upFacing, boolean isFlipped) { + public MultiPredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, + Direction frontFacing, Direction upFacing, boolean isFlipped) { ExpandablePattern expandablePattern = (ExpandablePattern) pattern; Direction[] absolutes = getCorners(userRepeats, expandablePattern, frontFacing, upFacing, isFlipped) .absolutes(); diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java index cf615c8c4b9..7fab1ece5e5 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java @@ -12,7 +12,7 @@ import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderHelper; import com.gregtechceu.gtceu.common.data.GTMaterials; import com.gregtechceu.gtceu.common.data.GTRecipeModifiers; @@ -594,8 +594,8 @@ public static void init() {} .recipeModifiers(GTRecipeModifiers.PARALLEL_HATCH, OC_NON_PERFECT_SUBTICK, BATCH_MODE) .appearanceBlock(CASING_WATERTIGHT) .pattern(definition -> { - BasePredicate casingPredicate = blocks(CASING_WATERTIGHT.get()).setMinGlobalLimited(40); - BasePredicate exportPredicate = abilities(PartAbility.EXPORT_FLUIDS_1X); + MultiPredicate casingPredicate = blocks(CASING_WATERTIGHT.get()).setMinGlobalLimited(40); + MultiPredicate exportPredicate = abilities(PartAbility.EXPORT_FLUIDS_1X); if (GTCEu.Mods.isAE2Loaded()) exportPredicate = exportPredicate.or(blocks(GTAEMachines.FLUID_EXPORT_HATCH_ME.get())); exportPredicate.setMaxLayerLimited(1); @@ -745,7 +745,7 @@ public static void init() {} .recipeModifiers(GTRecipeModifiers.PARALLEL_HATCH, GTRecipeModifiers::ebfOverclock, BATCH_MODE) .appearanceBlock(CASING_HIGH_TEMPERATURE_SMELTING) .pattern(definition -> { - BasePredicate casing = blocks(CASING_HIGH_TEMPERATURE_SMELTING.get()).setMinGlobalLimited(360); + MultiPredicate casing = blocks(CASING_HIGH_TEMPERATURE_SMELTING.get()).setMinGlobalLimited(360); return MultiblockPatternBuilder.start(FRONT, UP, RIGHT) // spotless:off .slice("##XXXXXXXXX##", "##XXXXXXXXX##", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############", "#############") diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 7fffc09eaee..3d7a6d038cd 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -24,7 +24,7 @@ import com.gregtechceu.gtceu.api.mui.factory.PanelFactory; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.recipe.GTRecipeType; @@ -601,7 +601,7 @@ public static MultiblockMachineDefinition registerLargeBoiler(GTRegistrate regis controller.getBlockPos().below().getY() == part.getBlockPos().getY() ? fireBox.get().defaultBlockState() : casing.get().defaultBlockState()) .pattern((definition) -> { - PatternPredicate fireboxPred = blocks(ALL_FIREBOXES.get(firebox).get()).setMinGlobalLimited(3) + MultiPredicate fireboxPred = blocks(ALL_FIREBOXES.get(firebox).get()).setMinGlobalLimited(3) .or(Predicates.abilities(PartAbility.IMPORT_FLUIDS).setMinGlobalLimited(1) .setPreviewCount(1)) .or(Predicates.abilities(PartAbility.IMPORT_ITEMS).setMaxGlobalLimited(1) @@ -741,7 +741,7 @@ public static MultiblockMachineDefinition registerLargeTurbine(GTRegistrate regi .register(); } - private static BasePredicate rotorHolder(int tier) { + private static MultiPredicate rotorHolder(int tier) { return Predicates.customPredicate("RotorHolder", ctx -> { if (MetaMachine.getMachine(ctx.level(), ctx.pos()) instanceof RotorHolderPartMachine rotorHolder && diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java index 871dd2252b4..f94af9ad8ab 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java @@ -15,7 +15,7 @@ import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderHelper; import com.gregtechceu.gtceu.client.util.TooltipHelper; import com.gregtechceu.gtceu.common.block.BoilerFireboxType; @@ -318,12 +318,12 @@ public class GTMultiMachines { .recipeModifiers(OC_NON_PERFECT_SUBTICK, BATCH_MODE) .appearanceBlock(CASING_STAINLESS_CLEAN) .pattern(definition -> { - BasePredicate exportPredicate = abilities(PartAbility.EXPORT_FLUIDS_1X); + MultiPredicate exportPredicate = abilities(PartAbility.EXPORT_FLUIDS_1X); if (GTCEu.Mods.isAE2Loaded()) { exportPredicate = exportPredicate.or(blocks(GTAEMachines.FLUID_EXPORT_HATCH_ME.get())); } exportPredicate.setMaxLayerLimited(1); - BasePredicate maint = autoAbilities(true, false, false) + MultiPredicate maint = autoAbilities(true, false, false) .setMaxGlobalLimited(1); return MultiblockPatternBuilder.start(UP, BACK, RIGHT) .slice("YSY", "YYY", "YYY") @@ -389,7 +389,7 @@ public class GTMultiMachines { Predicates.abilities(PartAbility.IMPORT_FLUIDS_1X).setMaxGlobalLimited(4))) .where('O', Predicates.abilities(PartAbility.EXPORT_ITEMS) -// .addTooltips(Component.translatable("gtceu.multiblock.pattern.location_end")) + // .addTooltips(Component.translatable("gtceu.multiblock.pattern.location_end")) ) .where('Y', blocks(CASING_STEEL_SOLID.get()).or(Predicates.abilities(PartAbility.INPUT_ENERGY) @@ -399,7 +399,7 @@ public class GTMultiMachines { .where('A', blocks(CASING_ASSEMBLY_CONTROL.get())) .where('R', blocks(CASING_LAMINATED_GLASS.get())) .where('T', blocks(CASING_ASSEMBLY_LINE.get())) - .where('D', blocks(CASING_GRATE.get()).or(dataHatchPredicate())) + .where('D', blocks(CASING_GRATE.get()).and(dataHatchPredicate())) .where('#', Predicates.any()) .build()) .partSorter(AssemblyLineMachine::partSorter) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java index 59c55c3383d..5e324db8a66 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java @@ -12,7 +12,7 @@ import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; import com.gregtechceu.gtceu.api.misc.EnergyContainerList; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.common.mui.GTMultiblockTextUtil; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.utils.FormattingUtil; @@ -157,7 +157,7 @@ public void invalidateStructure(String name) { converterSubscription.unsubscribe(); } - public static BasePredicate getHatchPredicates() { + public static MultiPredicate getHatchPredicates() { return abilities(PartAbility.INPUT_ENERGY).setPreviewCount(1) .or(abilities(PartAbility.OUTPUT_ENERGY).setPreviewCount(2)) .or(abilities(PartAbility.SUBSTATION_INPUT_ENERGY).setPreviewCount(1)) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java index bbfa1836fbe..d3d94de4a1a 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java @@ -14,7 +14,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.sync_system.annotations.RerenderOnChanged; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; @@ -62,13 +62,13 @@ public class CentralMonitorMachine extends WorkableElectricMultiblockMachine private @Nullable CurrentBlockInfo patternFindingState; - private static @Nullable BasePredicate MULTI_PREDICATE = null; + private static @Nullable MultiPredicate MULTI_PREDICATE = null; public CentralMonitorMachine(BlockEntityCreationInfo info) { super(info, new CentralMonitorLogic()); } - public static BasePredicate getMultiPredicate() { + public static MultiPredicate getMultiPredicate() { if (MULTI_PREDICATE == null) { MULTI_PREDICATE = Predicates.abilities(PartAbility.INPUT_ENERGY) .setMinGlobalLimited(1).setMaxGlobalLimited(2).setPreviewCount(1) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index 221357788f1..e82ce82f63b 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -22,6 +22,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; @@ -314,17 +315,17 @@ private static boolean isAllFloorBlocks(Level level, BlockPos.MutableBlockPos po public static Function getPattern() { return (definition) -> { - BasePredicate wallPredicate = states(getCasingState(), getGlassState()).or(getValidFloorBlocks()); - BasePredicate energyPredicate = autoAbilities(true, false, false).or(abilities(PartAbility.INPUT_ENERGY) + MultiPredicate wallPredicate = states(getCasingState(), getGlassState()).or(getValidFloorBlocks()); + MultiPredicate energyPredicate = autoAbilities(true, false, false).or(abilities(PartAbility.INPUT_ENERGY) .setMinGlobalLimited(1).setMaxGlobalLimited(3)); - BasePredicate edgePredicate = wallPredicate.or(energyPredicate); - BasePredicate facePredicate = wallPredicate.or(energyPredicate) + MultiPredicate edgePredicate = wallPredicate.or(energyPredicate); + MultiPredicate facePredicate = wallPredicate.or(energyPredicate) .or(doorPredicate().setMaxGlobalLimited(8)) .or(abilities(PartAbility.PASSTHROUGH_HATCH).setMaxGlobalLimited(30)); - BasePredicate filterPredicate = cleanroomFilters(); - BasePredicate innerPredicate = innerPredicate(); - BasePredicate verticalEdgePredicate = edgePredicate.or(blocks(getGlassState().getBlock())); + MultiPredicate filterPredicate = cleanroomFilters(); + MultiPredicate innerPredicate = innerPredicate(); + MultiPredicate verticalEdgePredicate = edgePredicate.or(blocks(getGlassState().getBlock())); return ExpandableMultiblockPatternBuilder .start(RelativeDirection.UP, RelativeDirection.RIGHT, RelativeDirection.FRONT) @@ -469,7 +470,7 @@ protected static BlockState getGlassState() { return GTBlocks.CLEANROOM_GLASS.getDefaultState(); } - protected static BasePredicate doorPredicate() { + protected static MultiPredicate doorPredicate() { return Predicates.customPredicate( ctx -> ctx.state().getBlock() instanceof DoorBlock || ctx.error(Predicates.PLACEHOLDER), Stream.of(new BlockInfo(Blocks.IRON_DOOR.defaultBlockState()), @@ -477,11 +478,11 @@ protected static BasePredicate doorPredicate() { .setValue(DoorBlock.HALF, DoubleBlockHalf.UPPER)))); } - private static BasePredicate getValidFloorBlocks() { + private static MultiPredicate getValidFloorBlocks() { return Predicates.blockTag(CustomTags.CLEANROOM_FLOORS); } - protected static BasePredicate innerPredicate() { + protected static MultiPredicate innerPredicate() { return BasePredicate.create("InnerPredicate", ctx -> { // all non-GTMachines are allowed inside by default BlockEntity blockEntity = ctx.blockEntity(); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java index c70859a2288..36f737572d7 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java @@ -13,6 +13,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.common.data.GTBlocks; import com.gregtechceu.gtceu.common.item.behavior.LighterBehavior; @@ -150,7 +151,7 @@ public static Function getPattern() }; } - private static BasePredicate wallPredicate() { + private static MultiPredicate wallPredicate() { return Predicates.customFunction(multiblockState -> { BlockPos p = multiblockState.getBlockPos(); return multiblockState.retrieveCurrentBlockState().is(CustomTags.CHARCOAL_PILE_IGNITER_WALLS) ? @@ -159,7 +160,7 @@ private static BasePredicate wallPredicate() { }, null); } - private static BasePredicate logPredicate() { + private static MultiPredicate logPredicate() { return Predicates.customFunction(multiblockState -> { boolean match = multiblockState.retrieveCurrentBlockState().is(BlockTags.LOGS_THAT_BURN); return match ? null : new PatternStringError(Component.translatable("gtceu.predicate_error.charcoal.logs")); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java index 4a18baa6724..fdac4154d30 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java @@ -7,6 +7,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.client.renderer.PatternPreviewRenderer; import com.gregtechceu.gtceu.common.mui.GTGuiTextures; @@ -139,13 +140,13 @@ public MultiblockPreviewWidget(MultiblockMachineDefinition definition, Multibloc IBlockPattern pattern = multiblockDefinition.getStructurePatterns().get("main").get(); if (pattern instanceof BlockPattern blockPattern) { @SuppressWarnings("DataFlowIssue") // realistically it can't be null here - BasePredicate predicate = this.multiblockSchemaInfo.getStructureHelper().getPredicateFromPos( + MultiPredicate predicate = this.multiblockSchemaInfo.getStructureHelper().getPredicateFromPos( blockPattern, this.selectionInfo.pos(), frontFacing, upFacing, isFlipped); return createSelectedBlockMenu(predicate); } else if (pattern instanceof ExpandablePattern expandablePattern) { @SuppressWarnings("DataFlowIssue") // realistically it can't be null here - BasePredicate predicate = this.multiblockSchemaInfo.getStructureHelper().getPredicateFromPos( + MultiPredicate predicate = this.multiblockSchemaInfo.getStructureHelper().getPredicateFromPos( expandablePattern, this.selectionInfo.pos(), frontFacing, upFacing, isFlipped); return createSelectedBlockMenu(predicate); @@ -239,7 +240,7 @@ public MultiblockPreviewWidget(MultiblockMachineDefinition definition, Multibloc .clientOnlyHandler(partsHandler)))); } - private ContextMenuButton createSelectedBlockMenu(BasePredicate predicate) { + private ContextMenuButton createSelectedBlockMenu(MultiPredicate predicate) { // TODO this can throw invalid state exception when // opening after clicking on a block twice return new ContextMenuButton<>(this.selectionInfo.pos().toString()) @@ -252,7 +253,7 @@ private ContextMenuButton createSelectedBlockMenu(BasePredicate predicate) { .coverChildrenWidth() .collapseDisabledChildren() .childSeparator(Icon.EMPTY_2PX) - .children(predicate.expand(), basePredicate -> { + .children(predicate, basePredicate -> { List candidates = basePredicate.getCandidates(); if (candidates.isEmpty()) return new EmptyWidget(); @@ -298,7 +299,7 @@ private ContextMenuButton createSelectedBlockMenu(BasePredicate predicate) { private void createPredicateMenus(Flow predicatesRow, BlockPattern blockPattern) { for (var entry : blockPattern.getPredicates().char2ObjectEntrySet()) { - BasePredicate predicate = entry.getValue(); + MultiPredicate predicate = entry.getValue(); // todo figure out sliders needed for predicate min/max depending on base predicates in the // main predicate if (predicate.isAny() || predicate.isAir()) { @@ -327,7 +328,7 @@ private void createPredicateMenus(Flow predicatesRow, BlockPattern blockPattern) .coverChildrenWidth() .collapseDisabledChildren() .childSeparator(Icon.EMPTY_2PX) - .children(predicate.expand(), basePredicate -> { + .children(predicate, basePredicate -> { List candidates = basePredicate.getCandidates(); if (candidates.isEmpty()) { return new EmptyWidget(); @@ -350,7 +351,7 @@ private void createPredicateMenus(Flow predicatesRow, BlockPattern blockPattern) } } - private ContextMenuButton createInnerPredicateMenu(BasePredicate predicate, BasePredicate basePredicate, + private ContextMenuButton createInnerPredicateMenu(MultiPredicate predicate, BasePredicate basePredicate, List candidates) { return new ContextMenuButton<>(basePredicate.toString()) .size(16) @@ -397,7 +398,7 @@ private void refreshViewWidget() { } /// ==== User Preference UI ====== - private void setPredicateDefaultBlock(BasePredicate predicate, BasePredicate basePredicate, + private void setPredicateDefaultBlock(MultiPredicate predicate, BasePredicate basePredicate, BlockInfo blockInfo) { this.multiblockSchemaInfo.putPredicatePreference(predicate, basePredicate, blockInfo); refreshSchema(); From dd2e2a3eb5f88b8a57677b35ab865cb6a17ecbb5 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 3 Jul 2026 21:26:34 -0700 Subject: [PATCH 034/101] woah that's a lot more changes add empty predicate unused failure reason BlockPattern notes improve MultiPredicate constructors extra helper methods is PredicateContext --- .../api/multiblock/PredicateContext.java | 20 ++ .../gtceu/api/multiblock/Predicates.java | 4 +- .../api/multiblock/pattern/BlockPattern.java | 2 + .../multiblock/predicates/BasePredicate.java | 70 ++---- .../multiblock/predicates/MultiPredicate.java | 210 +++++++++--------- 5 files changed, 156 insertions(+), 150 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index e38a9525597..c00ff6f00f4 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -13,6 +13,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.Getter; +import lombok.Setter; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -27,6 +28,9 @@ public final class PredicateContext { private final List errors = new ArrayList<>(); private final Object2IntMap globalCache; private final @Nullable Object2IntMap layerCache; + @Getter + @Setter + private FailureReason failureReason; public PredicateContext(CurrentBlockInfo blockInfo, Object2IntMap globalCache, @@ -100,4 +104,20 @@ public int incrementSliceCount(BasePredicate predicate) { Objects.requireNonNull(layerCache()).mergeInt(predicate, 1, Integer::sum); return layerCache().getInt(predicate); } + + public int getGlobalCount(BasePredicate predicate) { + return globalCache().getInt(predicate); + } + + public int getSliceCount(BasePredicate predicate) { + return Objects.requireNonNull(layerCache()).getInt(predicate); + } + + public enum FailureReason { + INTERNAL, + GLOBAL_MAX, + GLOBAL_MIN, + SLICE_MAX, + SLICE_MIN; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 246cf016241..a5f94f363af 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -253,7 +253,7 @@ public static MultiPredicate autoAbilities(GTRecipeType[] recipeType, boolean checkEnergyIn, boolean checkEnergyOut, boolean checkItemIn, boolean checkItemOut, boolean checkFluidIn, boolean checkFluidOut) { - MultiPredicate predicate = new MultiPredicate(); + MultiPredicate predicate = MultiPredicate.empty(); if (checkEnergyIn) { for (var type : recipeType) { if (type.getMaxInputs(EURecipeCapability.CAP) > 0) { @@ -315,7 +315,7 @@ public static MultiPredicate autoAbilities(GTRecipeType[] recipeType, public static MultiPredicate autoAbilities(boolean checkMaintenance, boolean checkMuffler, boolean checkParallel) { - MultiPredicate predicate = new MultiPredicate(); + MultiPredicate predicate = MultiPredicate.empty(); if (checkMaintenance) { predicate = predicate.or(abilities(PartAbility.MAINTENANCE) .setMinCount(ConfigHolder.INSTANCE.machines.enableMaintenance ? 1 : 0) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 34842e6f7e3..554c2ba46bc 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -123,6 +123,7 @@ public void checkPatternFastAt(Level level, PatternState patternState, BlockPos } if (allowsFlip) { + // this overwrites any previous errors valid = checkPatternAt(level, patternState, centerPos, frontFacing, upwardsFacing, true); } if (!valid) { @@ -214,6 +215,7 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p } // internal predicate check, global/slice max checks + // if all internal predicates pass, but global/slice max/min checks fail, then do not flip if (pred.test(ctx)) { charPos.move(absoluteChar); // continue... diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 41b65bb0c41..ef0f452ccdb 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -26,14 +26,8 @@ public abstract class BasePredicate { public static final MultiPredicate ANY = create("Any", ctx -> true); - protected static final Comparator PREDICATE_COMPARATOR = Comparator - .comparingInt(BasePredicate::getPriority); - private @Nullable List candidates; - @Getter - @Setter - private boolean isController = false; @Getter @Setter protected int priority = 0; @@ -69,52 +63,54 @@ public boolean testLimited(PredicateContext ctx) { /// test against global max count public boolean testGlobalMax(PredicateContext ctx) { - if (skipGlobalTest()) return true; + if (getMaxCount() == -1) return true; int count = ctx.incrementGlobalCount(this); - if (maxCount == -1 || count <= maxCount) return true; + if (testGlobalMax(count)) return true; return ctx.error(SinglePredicateError.maxCount(this, count)); } /// test against slice max count public boolean testSliceMax(PredicateContext ctx) { - if (skipSliceTest() || ctx.layerCache() == null) return true; + if (getMaxSliceCount() == -1 || ctx.layerCache() == null) return true; int count = ctx.incrementSliceCount(this); - if (maxSliceCount == -1 || count <= maxSliceCount) return true; + if (testSliceMax(count)) return true; return ctx.error(SinglePredicateError.maxLayerCount(this, count)); } - /// test against global max count + /// test against global min count public boolean testGlobalMin(PredicateContext ctx) { - if (skipGlobalTest()) return true; - int count = ctx.globalCache().getInt(this); - if (maxCount == -1 || count <= maxCount) return true; + if (getMinCount() == -1) return true; + int count = ctx.getGlobalCount(this); + if (testGlobalMin(count)) return true; return ctx.error(SinglePredicateError.minCount(this, count)); } - /// test against slice max count + /// test against slice min count public boolean testSliceMin(PredicateContext ctx) { - if (skipSliceTest() || ctx.layerCache() == null) return true; - int count = ctx.layerCache().getInt(this); - if (maxSliceCount == -1 || count <= maxSliceCount) return true; + if (getMinSliceCount() == -1 || ctx.layerCache() == null) return true; + int count = ctx.getSliceCount(this); + if (testSliceMin(count)) return true; return ctx.error(SinglePredicateError.minLayerCount(this, count)); } - /// test against global max count + /// simple test against global min count public boolean testGlobalMin(int count) { return minCount == -1 || count >= minCount; } - /// test against slice max count + /// simple test against slice min count public boolean testSliceMin(int count) { return minSliceCount == -1 || count >= minSliceCount; } - public boolean skipGlobalTest() { - return minCount == -1 && maxCount == -1; + /// simple test against global max count + public boolean testGlobalMax(int count) { + return maxCount == -1 || count <= maxCount; } - public boolean skipSliceTest() { - return minSliceCount == -1 && maxSliceCount == -1; + /// simple test against slice max count + public boolean testSliceMax(int count) { + return maxSliceCount == -1 || count <= maxSliceCount; } /// computes the candidates for this predicate @@ -170,30 +166,6 @@ public static MultiPredicate create(@Nullable String debugName, Predicate predicate, Stream candidateStream, @Nullable Consumer contents) { - BasePredicate basePredicate = new BasePredicate() { - - @Override - public boolean test(PredicateContext ctx) { - return predicate.test(ctx); - } - - @Override - public List computeCandidates() { - return candidateStream.toList(); - } - - @Override - public String getTypeName() { - return Objects.requireNonNullElse(debugName, "Predicate"); - } - - @Override - protected void appendContents(StringBuilder builder) { - if (contents != null) { - contents.accept(builder); - } - } - }; - return new MultiPredicate(basePredicate); + return new MultiPredicate(debugName, predicate, candidateStream, contents); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 1b78ffce612..5cea831d697 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; @@ -10,51 +11,83 @@ import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; public class MultiPredicate implements Iterable { - private static final String UNINITIALIZED = "__UNINITIALIZED__"; + private static final Comparator PREDICATE_COMPARATOR = Comparator + .comparingInt(BasePredicate::getPriority); + private static final MultiPredicate EMPTY = new MultiPredicate(); + private final List predicateList = new ObjectArrayList<>(); - private @Nullable final String debugName; - private @Nullable final Logic type; + @Getter(lombok.AccessLevel.PROTECTED) + private final Logic type; private final boolean hasAir; @Getter private boolean controller; - public MultiPredicate() { - this.debugName = UNINITIALIZED; - this.type = null; - this.hasAir = false; + MultiPredicate(@Nullable String debugName, Predicate predicate, + Stream candidateStream, @Nullable Consumer contents) { + this(new BasePredicate() { + + @Override + public boolean test(PredicateContext ctx) { + return predicate.test(ctx); + } + + @Override + public List computeCandidates() { + return candidateStream.toList(); + } + + @Override + public String getTypeName() { + return Objects.requireNonNullElse(debugName, "Predicate"); + } + + @Override + protected void appendContents(StringBuilder builder) { + if (contents != null) { + contents.accept(builder); + } + } + }); } - private MultiPredicate(@Nullable String debugName, Logic type, boolean hasAir) { - this.debugName = debugName; + private MultiPredicate(Logic type, boolean hasAir) { this.type = type; this.hasAir = hasAir; } - protected MultiPredicate(BasePredicate singleton) { - this.debugName = null; - this.type = null; - this.hasAir = false; + private MultiPredicate(BasePredicate singleton) { + this(); addPredicate(singleton); } + private MultiPredicate() { + this.type = Logic.SINGLE; + this.hasAir = false; + } + @ApiStatus.Internal - public boolean isUninitialized() { - return UNINITIALIZED.equals(debugName); + public boolean isEmpty() { + return this == EMPTY; } + /// delegates to {@link #type} to run {@link BasePredicate#testLimited(PredicateContext)} public boolean test(PredicateContext ctx) { return getType().run(ctx, this); } - /// test against global min count + /// delegates to {@link #type} to test against global min count public boolean testGlobalMin(PredicateContext ctx) { return getType().testGlobalMin(ctx, this); } - /// test against slice min count + /// delegates to {@link #type} to test against slice min count public boolean testSliceMin(PredicateContext ctx) { return getType().testSliceMin(ctx, this); } @@ -91,14 +124,6 @@ protected boolean sameType(MultiPredicate other) { return this.type == other.type; } - public boolean hasType() { - return this.type != null; - } - - public boolean isValid() { - return isSingle() || hasType(); - } - public boolean isAny() { return this == BasePredicate.ANY; } @@ -114,24 +139,29 @@ public boolean hasAir() { protected BasePredicate compact() { return new BasePredicate() { + private MultiPredicate getParent() { + return MultiPredicate.this; + } + @Override public boolean test(PredicateContext ctx) { - return getType().run(ctx, MultiPredicate.this); + // this also tests global/slice max, but with no respect to logic type + return getParent().test(ctx); } @Override public boolean testGlobalMin(PredicateContext ctx) { - return getType().testGlobalMin(ctx, MultiPredicate.this); + return getParent().testGlobalMin(ctx); } @Override public boolean testSliceMin(PredicateContext ctx) { - return getType().testSliceMin(ctx, MultiPredicate.this); + return getParent().testSliceMin(ctx); } @Override public List computeCandidates() { - return MultiPredicate.this.getCandidates() + return getParent().getCandidates() .stream() .flatMap(Collection::stream) .toList(); @@ -139,12 +169,12 @@ public List computeCandidates() { @Override public String getTypeName() { - return MultiPredicate.this.getTypeName(); + return getParent().getTypeName(); } @Override protected void appendContents(StringBuilder builder) { - MultiPredicate.this.appendContents(builder); + getParent().appendContents(builder); } }; } @@ -220,7 +250,7 @@ public MultiPredicate setLayerMinMax(int min, int max) { * @param limit The Maximum and Minimum limit */ public MultiPredicate setExactLimit(int limit) { - return this.setMinCount(limit).setMaxCount(limit); + return this.setGlobalMinMax(limit, limit); } public MultiPredicate disabledRenderFormed() { @@ -233,7 +263,7 @@ private MultiPredicate setDisableRenderFormed(boolean disable) { } protected MultiPredicate sorted() { - this.predicateList.sort(BasePredicate.PREDICATE_COMPARATOR); + this.predicateList.sort(PREDICATE_COMPARATOR); return this; } @@ -250,14 +280,11 @@ public MultiPredicate xor(MultiPredicate other) { } public boolean isSingle() { - return this.predicateList.size() == 1; + return getType() == Logic.SINGLE; } public String getTypeName() { - if (isSingle()) return "SINGLETON"; - StringBuilder builder = new StringBuilder().append(this.type); - if (this.debugName != null) builder.append("#").append(this.debugName); - return builder.toString(); + return String.valueOf(this.type); } protected void appendContents(StringBuilder builder) { @@ -281,11 +308,6 @@ public Iterator iterator() { return this.predicateList.iterator(); } - protected Logic getType() { - if (isSingle()) return Logic.OR; - return Objects.requireNonNull(this.type, "type == null"); - } - public MultiPredicate setController(boolean controller) { this.controller = controller; return this; @@ -296,103 +318,93 @@ public MultiPredicate setPriority(int priority) { return this; } + public static MultiPredicate empty() { + return EMPTY; + } + protected enum Logic { + SINGLE, OR, AND { - @Override - protected boolean run(PredicateContext ctx, MultiPredicate predicates) { - return !super.run(ctx, predicates); - } - @Override public boolean testGlobalMin(PredicateContext ctx, MultiPredicate predicates) { - return !super.testGlobalMin(ctx, predicates); + for (BasePredicate predicate : predicates) { + if (!predicate.testGlobalMin(ctx)) return false; + } + return true; } @Override public boolean testSliceMin(PredicateContext ctx, MultiPredicate predicates) { - return !super.testSliceMin(ctx, predicates); + for (BasePredicate predicate : predicates) { + if (!predicate.testSliceMin(ctx)) return false; + } + return true; } - - // override test slice/global min? }, XOR { - @Override - protected boolean run(PredicateContext ctx, MultiPredicate predicates) { - int passed = 0; - for (BasePredicate basePredicate : predicates) { - if (basePredicate.testLimited(ctx)) { - if (++passed > 1) return false; - } - } - return passed == 1; - } - @Override public boolean testGlobalMin(PredicateContext ctx, MultiPredicate predicates) { - int skipped = 0; - int passed = 0; - for (BasePredicate predicate : predicates) { - if (predicate.getMinCount() == -1) { - skipped++; - continue; - } - int count = ctx.globalCache().getInt(predicate); - if (predicate.testGlobalMin(count)) { - if (++passed > 1) { - // TODO special xor error - return ctx.error(SinglePredicateError.minCount(predicate, count)); - } - } else { - return ctx.error(SinglePredicateError.minCount(predicate, count)); - } - } - if (skipped == predicates.predicateList.size()) return true; - return passed == 1; + return test(ctx, predicates, + p -> p.getMinCount() == -1, + p -> p.testGlobalMin(ctx.getGlobalCount(p)), + p -> SinglePredicateError.minCount(p, ctx.getGlobalCount(p))); } @Override public boolean testSliceMin(PredicateContext ctx, MultiPredicate predicates) { - if (ctx.layerCache() == null) return true; - int skipped = 0; - int passed = 0; + return ctx.layerCache() == null || test(ctx, predicates, + p -> p.getMinSliceCount() == -1, + p -> p.testSliceMin(ctx.getSliceCount(p)), + p -> SinglePredicateError.minLayerCount(p, ctx.getSliceCount(p))); + } + + private boolean test(PredicateContext ctx, MultiPredicate predicates, + Predicate skip, + Predicate tester, + Function errorFunction) { + int skipped = 0, passed = 0, size = predicates.predicateList.size(); for (BasePredicate predicate : predicates) { - if (predicate.getMinCount() == -1) { - skipped++; - continue; + if (skip.test(predicate)) { + if (++skipped == size) { + return true; + } else { + continue; + } } - int count = ctx.layerCache().getInt(predicate); - if (predicate.testGlobalMin(count)) { + if (tester.test(predicate)) { if (++passed > 1) { // TODO special xor error - return ctx.error(SinglePredicateError.minCount(predicate, count)); + return ctx.error(errorFunction.apply(predicate)); } - } else { - return ctx.error(SinglePredicateError.minCount(predicate, count)); } } - if (skipped == predicates.predicateList.size()) return true; - return passed == 1; + if (passed == 0) { + // todo special xor error + predicates.forEach(p -> ctx.error(errorFunction.apply(p))); + return false; + } + return true; } }; /// @param a will have type set /// @param b may or may not be a multi predicate - /// @return copy of {@code a} with {@code b} added + /// @return copy of {@code a} combined with {@code b} protected MultiPredicate combine(MultiPredicate a, @Nullable MultiPredicate b) { if (b == null) return a; // b really should not be null in the first place - if (a.isUninitialized()) return b; - var ret = new MultiPredicate("Multi", this, a.hasAir() || b.hasAir()); + if (a.isEmpty()) return b; + var ret = new MultiPredicate(this, a.hasAir() || b.hasAir()); appendPredicate(a, ret); appendPredicate(b, ret); return ret.sorted(); } private void appendPredicate(MultiPredicate source, MultiPredicate dest) { - if (source.type == null && source.isSingle()) { + if (source.isSingle()) { dest.addPredicate(source.predicateList.get(0)); } else if (source.type != this) { dest.addPredicate(source.compact()); From e89dabb1d5aedd355e8bbd9121b64356ac9ae6c9 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 3 Jul 2026 22:15:58 -0700 Subject: [PATCH 035/101] use new error methods in PredicateContext --- .../api/multiblock/PredicateContext.java | 38 ++++++++++++++++++- .../gtceu/api/multiblock/Predicates.java | 21 +++++----- .../multiblock/predicates/BasePredicate.java | 12 ++---- .../multiblock/predicates/MultiPredicate.java | 20 +++++----- .../common/data/machines/GTMachineUtils.java | 2 +- .../multiblock/electric/CleanroomMachine.java | 4 +- 6 files changed, 62 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index c00ff6f00f4..6d7482c2785 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -1,11 +1,16 @@ package com.gregtechceu.gtceu.api.multiblock; +import com.gregtechceu.gtceu.api.machine.multiblock.PartAbility; +import com.gregtechceu.gtceu.api.multiblock.error.BlockMatchingError; +import com.gregtechceu.gtceu.api.multiblock.error.PartAbilityError; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; +import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; @@ -30,7 +35,7 @@ public final class PredicateContext { private final @Nullable Object2IntMap layerCache; @Getter @Setter - private FailureReason failureReason; + private FailureReason lastFailureReason; public PredicateContext(CurrentBlockInfo blockInfo, Object2IntMap globalCache, @@ -43,11 +48,40 @@ public PredicateContext(CurrentBlockInfo blockInfo, /// accepts a pattern error /// /// @return false - public boolean error(PatternError error) { + private boolean error(PatternError error) { this.errors.add(error); return false; } + public boolean abilityError(PartAbility ability) { + return internalError(new PartAbilityError(pos(), ability)); + } + + public boolean blockMatchingError(List blocks) { + return internalError(new BlockMatchingError(pos(), blocks)); + } + + public boolean internalError(PatternError error) { + this.lastFailureReason = FailureReason.INTERNAL; + return error(error); + } + + public boolean globalError(BasePredicate predicate, boolean min) { + this.lastFailureReason = min ? FailureReason.GLOBAL_MIN : FailureReason.GLOBAL_MAX; + SinglePredicateError error = min + ? SinglePredicateError.minCount(predicate, getGlobalCount(predicate)) + : SinglePredicateError.maxCount(predicate, getGlobalCount(predicate)); + return error(error); + } + + public boolean sliceError(BasePredicate predicate, boolean min) { + this.lastFailureReason = min ? FailureReason.SLICE_MIN : FailureReason.SLICE_MAX; + SinglePredicateError error = min + ? SinglePredicateError.minLayerCount(predicate, getSliceCount(predicate)) + : SinglePredicateError.maxLayerCount(predicate, getSliceCount(predicate)); + return error(error); + } + public List getErrors() { return Collections.unmodifiableList(errors); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index a5f94f363af..a7ba5f0b45a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -75,7 +75,7 @@ public static MultiPredicate states(@Nullable String debugName, BlockState... al } } return customPredicate(debugName, - ctx -> states.contains(ctx.state()) || ctx.error(PLACEHOLDER), + ctx -> states.contains(ctx.state()) || ctx.internalError(PLACEHOLDER), states.stream().map(BlockInfo::fromBlockState), builder -> { StringJoiner joiner = new StringJoiner(", "); @@ -86,7 +86,7 @@ public static MultiPredicate states(@Nullable String debugName, BlockState... al public static MultiPredicate blocks(Block block) { return customPredicate("Block", - ctx -> ctx.state().is(block) || ctx.error(new BlockMatchingError(ctx.pos(), List.of(block))), + ctx -> ctx.state().is(block) || ctx.blockMatchingError(List.of(block)), Stream.of(BlockInfo.fromBlock(block)), builder -> builder.append(blockToString(block))); } @@ -112,7 +112,7 @@ public static MultiPredicate blocks(@Nullable String debugName, for (var block : blocks) { if (ctx.state().is(block)) return true; } - return ctx.error(new BlockMatchingError(ctx.pos(), blocks)); + return ctx.blockMatchingError(blocks); }, candidates.map(BlockInfo::fromBlock), builder -> { StringJoiner joiner = new StringJoiner(", "); blocks.forEach(block -> joiner.add(blockToString(block))); @@ -146,7 +146,7 @@ public static MultiPredicate blockTag(TagKey tag) { public static MultiPredicate fluids(Fluid... fluids) { return customPredicate("Fluids", - ctx -> ArrayUtils.contains(fluids, ctx.fluid()) || ctx.error(PLACEHOLDER), + ctx -> ArrayUtils.contains(fluids, ctx.fluid()) || ctx.internalError(PLACEHOLDER), Arrays.stream(fluids).map(BlockInfo::fromFluid), builder -> { StringJoiner joiner = new StringJoiner(", "); @@ -173,7 +173,7 @@ public static MultiPredicate customFunction(Function candidates) { return customPredicate(ctx -> { PatternError error = predicate.apply(ctx.getBlockInfo()); - return error == null || ctx.error(error); + return error == null || ctx.internalError(error); }, Objects.>requireNonNullElse(candidates, Collections.emptyList()).stream()); } @@ -205,8 +205,7 @@ public static MultiPredicate air() { public static MultiPredicate abilities(PartAbility ability) { return customPredicate("Ability", - ctx -> ability.isApplicable(ctx.state().getBlock()) || - ctx.error(new PartAbilityError(ctx.pos(), ability)), + ctx -> ability.isApplicable(ctx.state().getBlock()) || ctx.abilityError(ability), ability.getAllBlocks().stream().map(BlockInfo::fromBlock), builder -> builder.append(ability.getName())); } @@ -218,7 +217,7 @@ public static MultiPredicate abilities(PartAbility... abilities) { if (ability.isApplicable(ctx.state().getBlock())) { return true; } - ctx.error(new PartAbilityError(ctx.pos(), ability)); + ctx.abilityError(ability); } return false; }, @@ -241,7 +240,7 @@ public static MultiPredicate ability(PartAbility ability, int... tiers) { } return customPredicate("Ability[" + sb + "]", ctx -> ability.isApplicable(ctx.state().getBlock()) || - ctx.error(new PartAbilityError(ctx.pos(), ability)), + ctx.abilityError(ability), ability.getBlocks(tiers).stream().map(BlockInfo::fromBlock)); } @@ -400,10 +399,10 @@ public static MultiPredicate framedPipes(Material[] frameMaterials, Block[] fram return customPredicate("FramedPipes", ctx -> { BlockEntity tileEntity = ctx.blockEntity(); if (!(tileEntity instanceof IPipeNode pipeNode)) { - return ctx.error(PLACEHOLDER); + return ctx.internalError(PLACEHOLDER); } return ArrayUtils.contains(frameMaterials, pipeNode.getFrameMaterial()) || - ctx.error(PLACEHOLDER); + ctx.internalError(PLACEHOLDER); }, Arrays.stream(frameBlocks).map(BlockInfo::fromBlock)); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index ef0f452ccdb..5cb05e2263e 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -65,32 +65,28 @@ public boolean testLimited(PredicateContext ctx) { public boolean testGlobalMax(PredicateContext ctx) { if (getMaxCount() == -1) return true; int count = ctx.incrementGlobalCount(this); - if (testGlobalMax(count)) return true; - return ctx.error(SinglePredicateError.maxCount(this, count)); + return testGlobalMax(count) || ctx.globalError(this, false); } /// test against slice max count public boolean testSliceMax(PredicateContext ctx) { if (getMaxSliceCount() == -1 || ctx.layerCache() == null) return true; int count = ctx.incrementSliceCount(this); - if (testSliceMax(count)) return true; - return ctx.error(SinglePredicateError.maxLayerCount(this, count)); + return testSliceMax(count) || ctx.sliceError(this, false); } /// test against global min count public boolean testGlobalMin(PredicateContext ctx) { if (getMinCount() == -1) return true; int count = ctx.getGlobalCount(this); - if (testGlobalMin(count)) return true; - return ctx.error(SinglePredicateError.minCount(this, count)); + return testGlobalMin(count) || ctx.globalError(this, true); } /// test against slice min count public boolean testSliceMin(PredicateContext ctx) { if (getMinSliceCount() == -1 || ctx.layerCache() == null) return true; int count = ctx.getSliceCount(this); - if (testSliceMin(count)) return true; - return ctx.error(SinglePredicateError.minLayerCount(this, count)); + return testSliceMin(count) || ctx.globalError(this, true); } /// simple test against global min count diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 5cea831d697..d7473ab3e60 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -1,8 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.PatternError; -import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -12,7 +10,6 @@ import java.util.*; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @@ -348,24 +345,24 @@ public boolean testSliceMin(PredicateContext ctx, MultiPredicate predicates) { @Override public boolean testGlobalMin(PredicateContext ctx, MultiPredicate predicates) { - return test(ctx, predicates, + return test(predicates, p -> p.getMinCount() == -1, p -> p.testGlobalMin(ctx.getGlobalCount(p)), - p -> SinglePredicateError.minCount(p, ctx.getGlobalCount(p))); + p -> ctx.globalError(p, true)); } @Override public boolean testSliceMin(PredicateContext ctx, MultiPredicate predicates) { - return ctx.layerCache() == null || test(ctx, predicates, + return ctx.layerCache() == null || test(predicates, p -> p.getMinSliceCount() == -1, p -> p.testSliceMin(ctx.getSliceCount(p)), - p -> SinglePredicateError.minLayerCount(p, ctx.getSliceCount(p))); + p -> ctx.sliceError(p, true)); } - private boolean test(PredicateContext ctx, MultiPredicate predicates, + private boolean test(MultiPredicate predicates, Predicate skip, Predicate tester, - Function errorFunction) { + Consumer errorFunction) { int skipped = 0, passed = 0, size = predicates.predicateList.size(); for (BasePredicate predicate : predicates) { if (skip.test(predicate)) { @@ -378,13 +375,14 @@ private boolean test(PredicateContext ctx, MultiPredicate predicates, if (tester.test(predicate)) { if (++passed > 1) { // TODO special xor error - return ctx.error(errorFunction.apply(predicate)); + errorFunction.accept(predicate); + return false; } } } if (passed == 0) { // todo special xor error - predicates.forEach(p -> ctx.error(errorFunction.apply(p))); + predicates.forEach(errorFunction); return false; } return true; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 3d7a6d038cd..15320be6e44 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -750,7 +750,7 @@ private static MultiPredicate rotorHolder(int tier) { .isAir()) { return true; } - return ctx.error(new PartAbilityError(ctx.pos(), PartAbility.ROTOR_HOLDER)); + return ctx.internalError(new PartAbilityError(ctx.pos(), PartAbility.ROTOR_HOLDER)); }, PartAbility.ROTOR_HOLDER.getAllBlocks() .stream() .map(BlockInfo::fromBlock)) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index e82ce82f63b..4202ffc7b65 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -472,7 +472,7 @@ protected static BlockState getGlassState() { protected static MultiPredicate doorPredicate() { return Predicates.customPredicate( - ctx -> ctx.state().getBlock() instanceof DoorBlock || ctx.error(Predicates.PLACEHOLDER), + ctx -> ctx.state().getBlock() instanceof DoorBlock || ctx.internalError(Predicates.PLACEHOLDER), Stream.of(new BlockInfo(Blocks.IRON_DOOR.defaultBlockState()), new BlockInfo(Blocks.IRON_DOOR.defaultBlockState() .setValue(DoorBlock.HALF, DoubleBlockHalf.UPPER)))); @@ -488,7 +488,7 @@ protected static MultiPredicate innerPredicate() { BlockEntity blockEntity = ctx.blockEntity(); if (blockEntity instanceof MetaMachine machine) { if (isMachineBanned(machine)) { - return ctx.error(Predicates.PLACEHOLDER); + return ctx.internalError(Predicates.PLACEHOLDER); } // todo do this in structure form not in the predicate // machine.getTraitOptional(CleanroomReceiverTrait.TYPE).ifPresent(cleanroomReceivers::add); From 211f63f48c70bce8d1444d2b85d352ad8dae0377 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 3 Jul 2026 22:17:26 -0700 Subject: [PATCH 036/101] add check flip method in failure reason (unused) --- .../gregtechceu/gtceu/api/multiblock/PredicateContext.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 6d7482c2785..d3b0d319a69 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -153,5 +153,9 @@ public enum FailureReason { GLOBAL_MIN, SLICE_MAX, SLICE_MIN; + + public boolean shouldCheckFlip() { + return this == INTERNAL; + } } } From 3c961085f3fefbf25e9b8c37289d36f67ff81051 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 3 Jul 2026 23:01:59 -0700 Subject: [PATCH 037/101] fix more error usages make PatternState extend PredicateContext note --- ...CoilWorkableElectricMultiblockMachine.java | 2 +- .../api/multiblock/PredicateContext.java | 48 +++++++++---------- .../gtceu/api/multiblock/Predicates.java | 2 +- .../api/multiblock/pattern/BlockPattern.java | 35 ++++++-------- .../multiblock/pattern/ExpandablePattern.java | 30 +++++------- .../api/multiblock/pattern/PatternState.java | 38 ++++++--------- .../multiblock/predicates/MultiPredicate.java | 17 ++++--- .../electric/ActiveTransformerMachine.java | 2 +- .../multiblock/electric/CleanroomMachine.java | 6 +-- .../electric/DistillationTowerMachine.java | 4 +- .../electric/LargeMinerMachine.java | 2 +- .../electric/PowerSubstationMachine.java | 2 +- .../electric/research/DataBankMachine.java | 2 +- .../research/ResearchStationMachine.java | 8 ++-- .../steam/SteamParallelMultiblockMachine.java | 2 +- 15 files changed, 87 insertions(+), 113 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java b/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java index c986dd6bef9..a9efdb163bf 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java @@ -48,7 +48,7 @@ public void formStructure(@NotNull String substructureName) { if (coilType == null) coilType = coil.coilType; else { if (coilType != coil.coilType) { - patternStates.get(substructureName).setError( + patternStates.get(substructureName).internalError( new CoilMatchingError(BlockPos.of(entry.getLongKey()), coilType, coil.coilType)); invalidateStructure(substructureName); return; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index d3b0d319a69..60da6887c4e 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -8,6 +8,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; @@ -26,25 +27,16 @@ import java.util.List; import java.util.Objects; -public final class PredicateContext { +public class PredicateContext { + protected final List errors = new ArrayList<>(); @Getter - private final CurrentBlockInfo blockInfo; - private final List errors = new ArrayList<>(); - private final Object2IntMap globalCache; - private final @Nullable Object2IntMap layerCache; + protected CurrentBlockInfo currentBlockInfo = new CurrentBlockInfo(); + protected final Object2IntMap globalCount = new Object2IntOpenHashMap<>(); + protected final Object2IntMap layerCount = new Object2IntOpenHashMap<>(); @Getter - @Setter private FailureReason lastFailureReason; - public PredicateContext(CurrentBlockInfo blockInfo, - Object2IntMap globalCache, - @Nullable Object2IntMap layerCache) { - this.blockInfo = blockInfo; - this.globalCache = globalCache; - this.layerCache = layerCache; - } - /// accepts a pattern error /// /// @return false @@ -82,18 +74,28 @@ public boolean sliceError(BasePredicate predicate, boolean min) { return error(error); } + public PredicateContext appendError(PatternError error) { + this.errors.add(error); + return this; + } + + public PredicateContext setFailureReason(FailureReason reason) { + this.lastFailureReason = reason; + return this; + } + public List getErrors() { return Collections.unmodifiableList(errors); } /// @return the current Level public Level level() { - return Objects.requireNonNull(blockInfo.getLevel()); + return Objects.requireNonNull(currentBlockInfo.getLevel()); } /// @return the current Block State public BlockState state() { - return this.blockInfo.retrieveCurrentBlockState(); + return this.currentBlockInfo.retrieveCurrentBlockState(); } /// @return the current Fluid @@ -108,25 +110,19 @@ public FluidState fluidState() { /// @return the current block pos (immutable) public BlockPos pos() { - return this.blockInfo.getPos().immutable(); + return this.currentBlockInfo.getPos().immutable(); } public @Nullable BlockEntity blockEntity() { - return this.blockInfo.retrieveCurrentBlockEntity(); - } - - public static PredicateContext of(CurrentBlockInfo blockInfo, - Object2IntMap cache, - @Nullable Object2IntMap layerCache) { - return new PredicateContext(blockInfo, cache, layerCache); + return this.currentBlockInfo.retrieveCurrentBlockEntity(); } public Object2IntMap globalCache() { - return globalCache; + return this.globalCount; } public @Nullable Object2IntMap layerCache() { - return layerCache; + return this.layerCount; } public int incrementGlobalCount(BasePredicate predicate) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index a7ba5f0b45a..d34951f6289 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -172,7 +172,7 @@ public static MultiPredicate fluidTag(TagKey tag) { public static MultiPredicate customFunction(Function predicate, @Nullable List candidates) { return customPredicate(ctx -> { - PatternError error = predicate.apply(ctx.getBlockInfo()); + PatternError error = predicate.apply(ctx.getCurrentBlockInfo()); return error == null || ctx.internalError(error); }, Objects.>requireNonNullElse(candidates, Collections.emptyList()).stream()); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 554c2ba46bc..4166ee3ead5 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -114,6 +114,7 @@ public void checkPatternFastAt(Level level, PatternState patternState, BlockPos } } + // need to clear some errors, as there's a lot of useless info now boolean valid = checkPatternAt(level, patternState, centerPos, frontFacing, upwardsFacing, false); if (valid) { // reaching here means the cache failed or was empty @@ -122,7 +123,7 @@ public void checkPatternFastAt(Level level, PatternState patternState, BlockPos return; } - if (allowsFlip) { + if (allowsFlip && patternState.getLastFailureReason().shouldCheckFlip()) { // this overwrites any previous errors valid = checkPatternAt(level, patternState, centerPos, frontFacing, upwardsFacing, true); } @@ -142,15 +143,15 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c boolean isFlipped) { Objects.requireNonNull(patternState, "PatternState not set"); - patternState.globalCount.clear(); - patternState.layerCount.clear(); + patternState.globalCache().clear(); + patternState.layerCache().clear(); // only try to clear the cache for structure checking mapping when checking the structure for unflipped // maybe switch to a multiblock state value instead? if (!isFlipped) { - patternState.cache.clear(); + patternState.getCache().clear(); } - patternState.currentBlockInfo.setLevel(level); + patternState.updateLevel(level); BlockPos.MutableBlockPos controllerPos = centerPos.mutable(); @@ -160,15 +161,13 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c if (!sliceStrategy.check(patternState, isFlipped)) return false; // global min check - PredicateContext ctx = patternState.toContext(); for (MultiPredicate predicate : predicates.values()) { - if (!predicate.testGlobalMin(ctx)) { - patternState.setErrors(ctx.getErrors()); + if (!predicate.testGlobalMin(patternState)) { return false; } } - patternState.setError(null); + patternState.clearErrors(); return true; } @@ -200,27 +199,21 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p PatternSlice slice = slices[sliceIndex]; // theoretically, predicates could track their own current layer/global count - patternState.layerCount.clear(); + patternState.layerCache().clear(); - PredicateContext ctx = patternState.toContext(); for (int stringIdx = 0; stringIdx < dimensions[1]; stringIdx++) { for (int charIdx = 0; charIdx < dimensions[2]; charIdx++) { - patternState.currentBlockInfo.setCurrentPos(charPos); + patternState.setPos(charPos); MultiPredicate pred = predicates.get(slice.charAt(stringIdx, charIdx)); - if (!pred.isAny()) { - BlockEntity blockEntity = ctx.blockEntity(); - BlockState state = ctx.state(); - patternState.cache.put(charPos.asLong(), new BlockInfo(state, blockEntity)); - } + if (!pred.isAny()) patternState.updateCache(); // internal predicate check, global/slice max checks // if all internal predicates pass, but global/slice max/min checks fail, then do not flip - if (pred.test(ctx)) { + if (pred.test(patternState)) { charPos.move(absoluteChar); // continue... } else { - patternState.setErrors(ctx.getErrors()); return false; } } @@ -231,8 +224,8 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // slice min check for (MultiPredicate predicate : predicates.values()) { - if (!predicate.testSliceMin(ctx)) { - patternState.setErrors(ctx.getErrors()); + if (!predicate.testSliceMin(patternState)) { + return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index 052e8e84243..5d003cd9ed2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -63,10 +63,10 @@ public ExpandablePattern(BoundsProvider boundsProvider, @Override public void checkPatternFastAt(Level level, PatternState patternState, BlockPos centerPos, Direction frontFacing, Direction upwardsFacing, boolean allowsFlip) { - if (!patternState.cache.isEmpty()) { + if (!patternState.getCache().isEmpty()) { boolean pass = true; BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); - for (var entry : patternState.cache.long2ObjectEntrySet()) { + for (var entry : patternState.getCache().long2ObjectEntrySet()) { pos.set(entry.getLongKey()); BlockState state = level.getBlockState(pos); @@ -102,7 +102,7 @@ public void checkPatternFastAt(Level level, PatternState patternState, BlockPos return; } - if (allowsFlip) { + if (allowsFlip && patternState.getLastFailureReason().shouldCheckFlip()) { valid = checkPatternAt(level, patternState, centerPos, frontFacing, upwardsFacing, true); } if (!valid) { @@ -122,7 +122,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c List bounds = boundsProvider.apply(level, centerPos.mutable(), frontFacing, upwardsFacing); if (bounds.isEmpty()) return false; - patternState.globalCount.clear(); + patternState.globalCache().clear(); BlockPos.MutableBlockPos negCorner = new BlockPos.MutableBlockPos(); BlockPos.MutableBlockPos posCorner = new BlockPos.MutableBlockPos(); @@ -146,7 +146,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c } } - patternState.currentBlockInfo.setLevel(level); + patternState.updateLevel(level); BlockPos.MutableBlockPos translation = centerPos.mutable(); @@ -161,30 +161,22 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c pos.getZ()); // translate from the origin to the center mPos = mPos.offset(translation).mutable(); - patternState.currentBlockInfo.setCurrentPos(mPos); + patternState.setPos(mPos); - if (!pred.isAny()) { - BlockState state = patternState.currentBlockInfo.retrieveCurrentBlockState(); - BlockEntity blockEntity = patternState.currentBlockInfo.retrieveCurrentBlockEntity(); - patternState.cache.put(mPos.asLong(), new BlockInfo(state, blockEntity)); - } + if (!pred.isAny()) patternState.updateCache(); - PredicateContext ctx = patternState.noLayer(); - if (!pred.test(ctx)) { - patternState.setErrors(ctx.getErrors()); + if (!pred.test(patternState)) { return false; } } - for (var entry : patternState.globalCount.object2IntEntrySet()) { - if (entry.getIntValue() < entry.getKey().getMinCount()) { - patternState.setError(SinglePredicateError.minCount(entry.getKey(), - entry.getIntValue())); + for (var entry : patternState.globalCache().object2IntEntrySet()) { + if (!entry.getKey().testGlobalMin(patternState)) { return false; } } - patternState.setError(null); + patternState.clearErrors(); return true; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 3e8e3dd1d15..d61f64a6258 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -3,29 +3,25 @@ import com.gregtechceu.gtceu.api.machine.multiblock.MultiblockControllerMachine; import com.gregtechceu.gtceu.api.multiblock.MultiblockWorldSavedData; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.PatternError; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import lombok.Getter; import lombok.Setter; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.List; - /* * Contains vital information to an instanced version of a structure pattern. */ -public class PatternState { +public class PatternState extends PredicateContext { @Getter protected @Nullable BlockPos controllerPos; @@ -41,16 +37,10 @@ public class PatternState { protected boolean actualFlipped = false; @Setter protected boolean shouldUpdate = true; - @Getter - protected @Nullable List errors; @Setter @Getter protected CheckState state = CheckState.UNINITIALIZED; @Getter - protected CurrentBlockInfo currentBlockInfo = new CurrentBlockInfo(); - protected final Object2IntMap globalCount = new Object2IntOpenHashMap<>(); - protected final Object2IntMap layerCount = new Object2IntOpenHashMap<>(); - @Getter protected final Long2ObjectMap cache = new Long2ObjectOpenHashMap<>(); public void setController(MultiblockControllerMachine controller, BlockPos controllerPos) { @@ -68,15 +58,11 @@ public boolean shouldUpdate() { } public boolean hasErrors() { - return errors != null; + return !this.errors.isEmpty(); } - public void setError(@Nullable PatternError error) { - this.errors = error != null ? List.of(error) : null; - } - - public void setErrors(@Nullable List error) { - this.errors = error; + public void clearErrors() { + this.errors.clear(); } public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState newState) { @@ -110,12 +96,16 @@ public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState ne } } - public PredicateContext toContext() { - return PredicateContext.of(this.currentBlockInfo, this.globalCount, this.layerCount); + protected void updateLevel(Level level) { + getCurrentBlockInfo().setLevel(level); + } + + public void setPos(BlockPos.MutableBlockPos charPos) { + getCurrentBlockInfo().setCurrentPos(charPos); } - public PredicateContext noLayer() { - return PredicateContext.of(this.currentBlockInfo, this.globalCount, null); + protected void updateCache() { + getCache().put(pos().asLong(), new BlockInfo(state(), blockEntity())); } @Getter diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index d7473ab3e60..1e0fcf9a3bc 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -1,10 +1,13 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.PredicateContext.FailureReason; +import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import lombok.Getter; +import net.minecraft.network.chat.Component; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -348,7 +351,8 @@ public boolean testGlobalMin(PredicateContext ctx, MultiPredicate predicates) { return test(predicates, p -> p.getMinCount() == -1, p -> p.testGlobalMin(ctx.getGlobalCount(p)), - p -> ctx.globalError(p, true)); + () -> ctx.appendError(new PatternStringError(Component.literal("One of: " + predicates.predicateList))) + .setFailureReason(FailureReason.GLOBAL_MIN)); } @Override @@ -356,13 +360,14 @@ public boolean testSliceMin(PredicateContext ctx, MultiPredicate predicates) { return ctx.layerCache() == null || test(predicates, p -> p.getMinSliceCount() == -1, p -> p.testSliceMin(ctx.getSliceCount(p)), - p -> ctx.sliceError(p, true)); + () -> ctx.appendError(new PatternStringError(Component.literal("One of: " + predicates.predicateList))) + .setFailureReason(FailureReason.SLICE_MIN)); } private boolean test(MultiPredicate predicates, Predicate skip, Predicate tester, - Consumer errorFunction) { + Runnable errorFunction) { int skipped = 0, passed = 0, size = predicates.predicateList.size(); for (BasePredicate predicate : predicates) { if (skip.test(predicate)) { @@ -374,15 +379,13 @@ private boolean test(MultiPredicate predicates, } if (tester.test(predicate)) { if (++passed > 1) { - // TODO special xor error - errorFunction.accept(predicate); + errorFunction.run(); return false; } } } if (passed == 0) { - // todo special xor error - predicates.forEach(errorFunction); + errorFunction.run(); return false; } return true; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java index 5e324db8a66..792ffc09c69 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java @@ -114,7 +114,7 @@ public void formStructure(@NotNull String substructureName) { // Invalidate the structure if there is not at least one output and one input if (powerInput.isEmpty() || powerOutput.isEmpty()) { - pState.setError( + pState.internalError( new PatternStringError(Component.translatable("gtceu.predicate_error.active_transformer.missing_io", powerInput.isEmpty(), powerOutput.isEmpty()))); this.invalidateStructure(substructureName); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index 4202ffc7b65..61374bf9ae8 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -135,14 +135,14 @@ public void formStructure(@NotNull String substructureName) { int f = bounds.get(4); int b = bounds.get(5); if (d < MIN_DEPTH || l < MIN_RADIUS || r < MIN_RADIUS || b < MIN_RADIUS || f < MIN_RADIUS) { - pState.setError( + pState.internalError( new PatternStringError(Component.translatable("gtceu.predicate_error.cleanroom.too_small"))); invalidateStructure(); return; } if (Math.abs(l - r) > 1 || Math.abs(b - f) > 1) { - pState.setError( + pState.internalError( new PatternStringError(Component.translatable("gtceu.predicate_error.cleanroom.not_centered"))); invalidateStructure(); return; @@ -159,7 +159,7 @@ public void formStructure(@NotNull String substructureName) { if (filterType == null) filterType = filter.getKey(); else { if (filterType != filter.getKey()) { - pState.setError(new FilterMatchingError(BlockPos.of(entry.getLongKey()), + pState.internalError(new FilterMatchingError(BlockPos.of(entry.getLongKey()), filterType.getCleanroomType(), filter.getKey().getCleanroomType())); invalidateStructure(substructureName); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java index 7b959945301..d723d0c3c0c 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java @@ -100,7 +100,7 @@ public void formStructure(String substructureName) { fluidOutputs.add(VoidFluidHandler.INSTANCE); } else { BlockPos p = part.getBlockPos(); - pState.setError(new PatternStringError(Component.translatable( + pState.internalError(new PatternStringError(Component.translatable( "gtceu.predicate_error.distillery.unexpected_hatch", p.getX(), p.getY(), p.getZ()))); // GTCEu.LOGGER.error( // "The Distillation Tower at {} has a fluid export hatch with an unexpected Y position", @@ -110,7 +110,7 @@ public void formStructure(String substructureName) { } } } else { - pState.setError( + pState.internalError( new PatternStringError(Component.translatable("gtceu.predicate_error.distillery.missing_outputs"))); invalidateStructure(substructureName); } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java index a3bd80299bc..624b438c612 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java @@ -99,7 +99,7 @@ public void formStructure(@NotNull String substructureName) { public PatternState checkStructurePattern(String name) { var patternState = super.checkStructurePattern(name); if (this.getUpwardsFacing() != Direction.UP && this.getUpwardsFacing() != Direction.DOWN) { - patternState.setError(Predicates.PLACEHOLDER); + patternState.internalError(Predicates.PLACEHOLDER); } return patternState; } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java index 412825fb517..bab7a6ec1db 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java @@ -157,7 +157,7 @@ public void formStructure(@NotNull String substructureName) { */ if (batteries.isEmpty()) { // only empty batteries found in the structure - pState.setError(new PatternStringError( + pState.internalError(new PatternStringError( Component.translatable("gtceu.predicate_error.power_substation.missing_batteries"))); invalidateStructure(); return; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java index 2380401dbbc..175c77d4955 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java @@ -81,7 +81,7 @@ public void formStructure(@NotNull String substructureName) { this.energyUsage = calculateEnergyUsage(); if (this.maintenance == null) { - pState.setError(new PatternStringError( + pState.internalError(new PatternStringError( Component.translatable("gtceu.predicate_error.databank.missing_maintenance"))); invalidateStructure(substructureName); return; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java index 2f31f1daa0e..495aef74ad4 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java @@ -61,7 +61,7 @@ public void formStructure(@NotNull String substructureName) { for (MultiblockPartMachine part : getParts()) { if (part instanceof ObjectHolderMachine holder) { if (holder.getFrontFacing() != getFrontFacing().getOpposite()) { - pState.setError(new PatternStringError( + pState.internalError(new PatternStringError( Component.translatable("gtceu.predicate_error.object_holder.direction"))); invalidateStructure(substructureName); return; @@ -76,13 +76,13 @@ public void formStructure(@NotNull String substructureName) { // should never happen, but would rather do this than have an obscure NPE if (computationProvider == null) { - pState.setError(new PatternStringError( + pState.internalError(new PatternStringError( Component.translatable("gtceu.predicate_error.research.missing_computation"))); invalidateStructure(substructureName); } if (objectHolder == null) { - pState.setError(new PatternStringError( + pState.internalError(new PatternStringError( Component.translatable("gtceu.predicate_error.research.missing_object_holder"))); invalidateStructure(substructureName); } @@ -100,7 +100,7 @@ public PatternState checkStructurePattern(String name) { } } if (objHolder != null && objHolder.getFrontFacing() != getFrontFacing().getOpposite()) { - patternState.setError( + patternState.internalError( new PatternStringError(Component.translatable("gtceu.predicate_error.object_holder.direction"))); invalidateStructure(name); } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java index 973e0f5d5dd..763c0b0674b 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java @@ -88,7 +88,7 @@ public void formStructure(String substructureName) { } } if (steamEnergy == null) { // No steam hatch found - pState.setError( + pState.internalError( new PatternStringError(Component.translatable("gtceu.predicate_error.steam.missing_steam_hatch"))); invalidateStructure(substructureName); } From 6b25fafb00516d1db1662611a11403e1fd8f56fe Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 3 Jul 2026 23:19:00 -0700 Subject: [PATCH 038/101] commit and clear some errors --- .../gtceu/api/multiblock/PredicateContext.java | 8 +++++++- .../gtceu/api/multiblock/pattern/BlockPattern.java | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 60da6887c4e..d8c87155524 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -30,6 +30,7 @@ public class PredicateContext { protected final List errors = new ArrayList<>(); + protected final List commitedErrors = new ArrayList<>(); @Getter protected CurrentBlockInfo currentBlockInfo = new CurrentBlockInfo(); protected final Object2IntMap globalCount = new Object2IntOpenHashMap<>(); @@ -74,6 +75,11 @@ public boolean sliceError(BasePredicate predicate, boolean min) { return error(error); } + public void commitErrors() { + this.commitedErrors.addAll(this.errors); + this.errors.clear(); + } + public PredicateContext appendError(PatternError error) { this.errors.add(error); return this; @@ -85,7 +91,7 @@ public PredicateContext setFailureReason(FailureReason reason) { } public List getErrors() { - return Collections.unmodifiableList(errors); + return Collections.unmodifiableList(this.commitedErrors); } /// @return the current Level diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 4166ee3ead5..75fab7d29a6 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -163,6 +163,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c // global min check for (MultiPredicate predicate : predicates.values()) { if (!predicate.testGlobalMin(patternState)) { + patternState.commitErrors(); return false; } } @@ -212,8 +213,10 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // if all internal predicates pass, but global/slice max/min checks fail, then do not flip if (pred.test(patternState)) { charPos.move(absoluteChar); + patternState.clearErrors(); // continue... } else { + patternState.commitErrors(); return false; } } @@ -225,10 +228,12 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // slice min check for (MultiPredicate predicate : predicates.values()) { if (!predicate.testSliceMin(patternState)) { + patternState.commitErrors(); return false; } } + patternState.clearErrors(); return true; } From 06465ec70a83812092ee570a10ce8515ed6fb019 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 4 Jul 2026 01:31:59 -0700 Subject: [PATCH 039/101] on error method notes --- .../api/multiblock/predicates/MultiPredicate.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 1e0fcf9a3bc..235658b7cef 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -351,8 +351,7 @@ public boolean testGlobalMin(PredicateContext ctx, MultiPredicate predicates) { return test(predicates, p -> p.getMinCount() == -1, p -> p.testGlobalMin(ctx.getGlobalCount(p)), - () -> ctx.appendError(new PatternStringError(Component.literal("One of: " + predicates.predicateList))) - .setFailureReason(FailureReason.GLOBAL_MIN)); + () -> onError(ctx, predicates)); } @Override @@ -360,10 +359,16 @@ public boolean testSliceMin(PredicateContext ctx, MultiPredicate predicates) { return ctx.layerCache() == null || test(predicates, p -> p.getMinSliceCount() == -1, p -> p.testSliceMin(ctx.getSliceCount(p)), - () -> ctx.appendError(new PatternStringError(Component.literal("One of: " + predicates.predicateList))) - .setFailureReason(FailureReason.SLICE_MIN)); + () -> onError(ctx, predicates)); } + private void onError(PredicateContext ctx, MultiPredicate predicates) { + // todo better error + ctx.appendError(new PatternStringError(Component.literal("One of: " + predicates.predicateList))) + .setFailureReason(FailureReason.SLICE_MIN); + } + + // i hate this private boolean test(MultiPredicate predicates, Predicate skip, Predicate tester, From f0c4f8419c568d56cb7bcc51835a4dc5ccd3c8d8 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 4 Jul 2026 16:52:36 -0700 Subject: [PATCH 040/101] add stats to BasePredicate string --- .../api/multiblock/predicates/BasePredicate.java | 15 +++++++++++++++ .../api/multiblock/predicates/MultiPredicate.java | 3 +++ 2 files changed, 18 insertions(+) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 5cb05e2263e..e0a7d8a341a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -146,11 +146,26 @@ public Optional getFirstCandidate() { /// the contents of this predicate protected void appendContents(StringBuilder builder) {} + protected void appendStats(StringBuilder builder) { + if (minCount != -1 && maxCount != -1) { + builder.append("global=[%02d,%02d] ".formatted(minCount, maxCount)); + } + if (minSliceCount != -1 && maxSliceCount != -1) { + builder.append("slice=[%02d,%02d] ".formatted(minSliceCount, maxSliceCount)); + } + if (previewCount != -1) { + builder.append("preview=%02d".formatted(previewCount)); + } + } + @Override public String toString() { StringBuilder builder = new StringBuilder(getTypeName()); builder.append('{'); + appendStats(builder); + builder.append("contents=["); appendContents(builder); + builder.append(']'); builder.append('}'); return builder.toString(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 235658b7cef..46d3596dcd7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -176,6 +176,9 @@ public String getTypeName() { protected void appendContents(StringBuilder builder) { getParent().appendContents(builder); } + + @Override + protected void appendStats(StringBuilder builder) {} }; } From 93632a8b7d0a51da8ccc41e8fe1ec0a6095240b1 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 4 Jul 2026 20:13:38 -0700 Subject: [PATCH 041/101] more notes tester enum attempt to simplify logic --- .../multiblock/predicates/MultiPredicate.java | 233 ++++++++++++------ 1 file changed, 152 insertions(+), 81 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 46d3596dcd7..2610fecaf18 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -6,6 +6,7 @@ import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import lombok.AccessLevel; import lombok.Getter; import net.minecraft.network.chat.Component; import org.jetbrains.annotations.ApiStatus; @@ -23,7 +24,7 @@ public class MultiPredicate implements Iterable { private static final MultiPredicate EMPTY = new MultiPredicate(); private final List predicateList = new ObjectArrayList<>(); - @Getter(lombok.AccessLevel.PROTECTED) + @Getter(AccessLevel.PROTECTED) private final Logic type; private final boolean hasAir; @Getter @@ -327,84 +328,13 @@ public static MultiPredicate empty() { protected enum Logic { - SINGLE, - OR, - AND { - - @Override - public boolean testGlobalMin(PredicateContext ctx, MultiPredicate predicates) { - for (BasePredicate predicate : predicates) { - if (!predicate.testGlobalMin(ctx)) return false; - } - return true; - } - - @Override - public boolean testSliceMin(PredicateContext ctx, MultiPredicate predicates) { - for (BasePredicate predicate : predicates) { - if (!predicate.testSliceMin(ctx)) return false; - } - return true; - } - }, - XOR { - - @Override - public boolean testGlobalMin(PredicateContext ctx, MultiPredicate predicates) { - return test(predicates, - p -> p.getMinCount() == -1, - p -> p.testGlobalMin(ctx.getGlobalCount(p)), - () -> onError(ctx, predicates)); - } - - @Override - public boolean testSliceMin(PredicateContext ctx, MultiPredicate predicates) { - return ctx.layerCache() == null || test(predicates, - p -> p.getMinSliceCount() == -1, - p -> p.testSliceMin(ctx.getSliceCount(p)), - () -> onError(ctx, predicates)); - } - - private void onError(PredicateContext ctx, MultiPredicate predicates) { - // todo better error - ctx.appendError(new PatternStringError(Component.literal("One of: " + predicates.predicateList))) - .setFailureReason(FailureReason.SLICE_MIN); - } - - // i hate this - private boolean test(MultiPredicate predicates, - Predicate skip, - Predicate tester, - Runnable errorFunction) { - int skipped = 0, passed = 0, size = predicates.predicateList.size(); - for (BasePredicate predicate : predicates) { - if (skip.test(predicate)) { - if (++skipped == size) { - return true; - } else { - continue; - } - } - if (tester.test(predicate)) { - if (++passed > 1) { - errorFunction.run(); - return false; - } - } - } - if (passed == 0) { - errorFunction.run(); - return false; - } - return true; - } - }; + SINGLE, OR, AND, XOR; /// @param a will have type set /// @param b may or may not be a multi predicate /// @return copy of {@code a} combined with {@code b} protected MultiPredicate combine(MultiPredicate a, @Nullable MultiPredicate b) { - if (b == null) return a; // b really should not be null in the first place + if (b == null) return a; // no op if (a.isEmpty()) return b; var ret = new MultiPredicate(this, a.hasAir() || b.hasAir()); appendPredicate(a, ret); @@ -422,6 +352,29 @@ private void appendPredicate(MultiPredicate source, MultiPredicate dest) { } } + /* + * OR logic + * at least one of n predicates must be valid + * AND logic + * must have n valid predicates in multi + * XOR logic + * must only have one of n predicates be valid and present in multi + * + * when it comes to the internal predicates + * any can pass, regardless of logic type + * since a block can only have one state + * and internal predicate is checked per block + * + * this may also introduce the ability + * to have an invalid predicate form a multiblock + * if predicate a has a min of two, + * and predicate b has min of one, + * and you use XOR logic + * the multi predicate would pass since a fails and b succeeds min checks + * really it should be "only one predicate can be present in multi/slice" + * + * how do i handle global/slice max? + */ protected boolean run(PredicateContext ctx, MultiPredicate predicates) { for (BasePredicate basePredicate : predicates) { if (basePredicate.testLimited(ctx)) return true; @@ -430,18 +383,136 @@ protected boolean run(PredicateContext ctx, MultiPredicate predicates) { } public boolean testGlobalMin(PredicateContext ctx, MultiPredicate predicates) { - for (BasePredicate predicate : predicates) { - if (predicate.testGlobalMin(ctx)) return true; - } - return false; + return test(ctx, predicates, Tester.GLOBAL_MIN); } public boolean testSliceMin(PredicateContext ctx, MultiPredicate predicates) { - if (ctx.layerCache() == null) return true; + return test(ctx, predicates, Tester.SLICE_MIN); + } + + // i hate this (but not as much) + private boolean test(PredicateContext ctx, MultiPredicate predicates, + Tester tester) { + if (tester.shouldSkipTest(ctx)) return true; + int skipped = 0, passed = 0, size = predicates.predicateList.size(); for (BasePredicate predicate : predicates) { - if (predicate.testSliceMin(ctx)) return true; + // get min count + int expectedCount = tester.getCount(predicate); + if (expectedCount == -1) { + if (++skipped == size) { + return true; + } else { + continue; + } + } + int actualCount = tester.getActualCount(ctx, predicate); + + boolean success = tester.test(expectedCount, actualCount); + if (success) passed++; + + if (tester.returnEarly(passed, success, this)) { + // get true or false + return tester.hasErrored(passed, size, ctx, predicates, this); + } } - return false; + if (tester.finalReturn(passed, skipped, this)) { + tester.onError(ctx, predicates); + return false; + } + return true; + } + } + + enum Tester { + GLOBAL_MIN, + GLOBAL_MAX, + SLICE_MIN, + SLICE_MAX; + + public int getCount(BasePredicate predicate) { + return switch (this) { + case GLOBAL_MIN -> predicate.getMinCount(); + case GLOBAL_MAX -> predicate.getMaxCount(); + case SLICE_MIN -> predicate.getMinSliceCount(); + case SLICE_MAX -> predicate.getMaxSliceCount(); + }; + } + + public int getActualCount(PredicateContext ctx, BasePredicate predicate) { + return switch (this) { + case GLOBAL_MIN -> ctx.getGlobalCount(predicate); + case GLOBAL_MAX -> ctx.incrementGlobalCount(predicate); + case SLICE_MIN -> ctx.getSliceCount(predicate); + case SLICE_MAX -> ctx.incrementSliceCount(predicate); + }; + } + + public boolean test(int expected, int actual) { + return switch (this) { + case GLOBAL_MIN, SLICE_MIN -> expected <= actual; + case GLOBAL_MAX, SLICE_MAX -> expected >= actual; + }; + } + + public void onError(PredicateContext ctx, MultiPredicate predicates) { + // todo better error + var joiner = new StringJoiner("\n"); + predicates.forEach(p -> joiner.add("\t" + p)); + ctx.appendError(new PatternStringError(Component.literal("One of: \n" + joiner))); + switch (this) { + case GLOBAL_MIN -> ctx.setFailureReason(FailureReason.GLOBAL_MIN); + case GLOBAL_MAX -> ctx.setFailureReason(FailureReason.GLOBAL_MAX); + case SLICE_MIN -> ctx.setFailureReason(FailureReason.SLICE_MIN); + case SLICE_MAX -> ctx.setFailureReason(FailureReason.SLICE_MAX); + } + } + + public boolean returnEarly(int passed, boolean success, Logic logicType) { + // return true to return early + return switch (logicType) { + case XOR -> passed > 1; + case AND -> !success; + default -> false; + }; + } + + public boolean finalReturn(int passed, int size, Logic logicType) { + // return true if failed + return switch (logicType) { + case SINGLE, XOR -> passed != 1; + case OR -> passed == 0; + case AND -> passed != size; + }; + } + + public boolean isGlobal() { + return this == GLOBAL_MIN || this == GLOBAL_MAX; + } + + public boolean isSlice() { + return this == SLICE_MIN || this == SLICE_MAX; + } + + public boolean isMin() { + return this == GLOBAL_MIN || this == SLICE_MIN; + } + + public boolean isMax() { + return this == GLOBAL_MAX || this == SLICE_MAX; + } + + public boolean shouldSkipTest(PredicateContext ctx) { + // skip test if we're slice and slice cache is null + return isSlice() && ctx.layerCache() != null; + } + + // called after return early + public boolean hasErrored(int passed, int size, PredicateContext ctx, MultiPredicate predicates, Logic logic) { + boolean error = finalReturn(passed, size, logic); + if (error) { + onError(ctx, predicates); + } + return error; } } } From 523315ef0c03447d670bd6a44e6f94e20aa7e971 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sun, 5 Jul 2026 18:47:12 -0700 Subject: [PATCH 042/101] dumb shit --- .../api/multiblock/PredicateContext.java | 13 ++-- .../api/multiblock/pattern/BlockPattern.java | 6 +- .../api/multiblock/pattern/PatternState.java | 5 +- .../multiblock/predicates/BasePredicate.java | 18 ++--- .../multiblock/predicates/MultiPredicate.java | 68 +++++++++++++++---- 5 files changed, 81 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index d8c87155524..889012af877 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -9,6 +9,8 @@ import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; @@ -22,15 +24,13 @@ import lombok.Setter; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; +import java.util.*; public class PredicateContext { protected final List errors = new ArrayList<>(); protected final List commitedErrors = new ArrayList<>(); + protected final Object2ObjectMap validationMap = new Object2ObjectArrayMap<>(); @Getter protected CurrentBlockInfo currentBlockInfo = new CurrentBlockInfo(); protected final Object2IntMap globalCount = new Object2IntOpenHashMap<>(); @@ -149,6 +149,11 @@ public int getSliceCount(BasePredicate predicate) { return Objects.requireNonNull(layerCache()).getInt(predicate); } + public void updateState(BasePredicate predicate, FailureReason index, boolean passed) { + validationMap.computeIfAbsent(predicate, p -> new BitSet()) + .set(index.ordinal(), passed); + } + public enum FailureReason { INTERNAL, GLOBAL_MAX, diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 75fab7d29a6..88fb21d4b77 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -123,7 +123,7 @@ public void checkPatternFastAt(Level level, PatternState patternState, BlockPos return; } - if (allowsFlip && patternState.getLastFailureReason().shouldCheckFlip()) { + if (allowsFlip && patternState.shouldCheckFlip()) { // this overwrites any previous errors valid = checkPatternAt(level, patternState, centerPos, frontFacing, upwardsFacing, true); } @@ -162,7 +162,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c // global min check for (MultiPredicate predicate : predicates.values()) { - if (!predicate.testGlobalMin(patternState)) { + if (!predicate.testGlobal(patternState)) { patternState.commitErrors(); return false; } @@ -227,7 +227,7 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // slice min check for (MultiPredicate predicate : predicates.values()) { - if (!predicate.testSliceMin(patternState)) { + if (!predicate.testSlice(patternState)) { patternState.commitErrors(); return false; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index d61f64a6258..7636b8d9a00 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -8,7 +8,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; @@ -108,6 +107,10 @@ protected void updateCache() { getCache().put(pos().asLong(), new BlockInfo(state(), blockEntity())); } + public boolean shouldCheckFlip() { + return this.getLastFailureReason().shouldCheckFlip(); + } + @Getter public enum CheckState { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index e0a7d8a341a..ee01d883bb6 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -2,7 +2,6 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import net.minecraft.client.Minecraft; @@ -58,21 +57,24 @@ public abstract class BasePredicate { /// test with internal function and global/slice max public boolean testLimited(PredicateContext ctx) { - return test(ctx) && testGlobalMax(ctx) && testSliceMax(ctx); + // this is some fucked up shit + boolean passed = test(ctx); + ctx.updateState(this, PredicateContext.FailureReason.INTERNAL, passed); + return passed; } /// test against global max count - public boolean testGlobalMax(PredicateContext ctx) { + public boolean testGlobalMax(boolean b, PredicateContext ctx) { if (getMaxCount() == -1) return true; - int count = ctx.incrementGlobalCount(this); - return testGlobalMax(count) || ctx.globalError(this, false); + int count = b ? ctx.incrementGlobalCount(this) : ctx.getGlobalCount(this); + return testGlobalMax(count) || b || ctx.globalError(this, false); } /// test against slice max count - public boolean testSliceMax(PredicateContext ctx) { + public boolean testSliceMax(boolean b, PredicateContext ctx) { if (getMaxSliceCount() == -1 || ctx.layerCache() == null) return true; - int count = ctx.incrementSliceCount(this); - return testSliceMax(count) || ctx.sliceError(this, false); + int count = b ? ctx.incrementSliceCount(this) : ctx.getSliceCount(this); + return testSliceMax(count) || b || ctx.sliceError(this, false); } /// test against global min count diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 2610fecaf18..b66740a6a52 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -3,6 +3,7 @@ import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.PredicateContext.FailureReason; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; +import com.gregtechceu.gtceu.api.multiblock.pattern.PatternState; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -36,7 +37,9 @@ public class MultiPredicate implements Iterable { @Override public boolean test(PredicateContext ctx) { - return predicate.test(ctx); + boolean passed = predicate.test(ctx); + ctx.updateState(this, FailureReason.INTERNAL, passed); + return passed; } @Override @@ -80,17 +83,32 @@ public boolean isEmpty() { /// delegates to {@link #type} to run {@link BasePredicate#testLimited(PredicateContext)} public boolean test(PredicateContext ctx) { - return getType().run(ctx, this); + boolean passed = false; + for (BasePredicate p : predicateList) { + passed |= p.testLimited(ctx); + } + return passed; +// return getType().run(ctx, this); } /// delegates to {@link #type} to test against global min count public boolean testGlobalMin(PredicateContext ctx) { - return getType().testGlobalMin(ctx, this); + boolean passed = false; + for (BasePredicate p : predicateList) { + ctx.updateState(p, FailureReason.GLOBAL_MIN, passed |= p.testGlobalMin(ctx)); + } + return passed; +// return getType().testGlobalMin(ctx, this); } /// delegates to {@link #type} to test against slice min count public boolean testSliceMin(PredicateContext ctx) { - return getType().testSliceMin(ctx, this); + boolean passed = false; + for (BasePredicate p : predicateList) { + ctx.updateState(p, FailureReason.SLICE_MIN, passed |= p.testSliceMin(ctx)); + } + return passed; +// return getType().testSliceMin(ctx, this); } protected MultiPredicate addPredicates(Iterable predicates) { @@ -326,14 +344,26 @@ public static MultiPredicate empty() { return EMPTY; } - protected enum Logic { + public boolean testGlobal(PredicateContext ctx) { + // this is what depends on logic + return getType().test(ctx, this, Tester.GLOBAL_MIN) && + getType().test(ctx, this, Tester.GLOBAL_MAX); + } + + public boolean testSlice(PredicateContext ctx) { + // this is what depends on logic + return getType().test(ctx, this, Tester.SLICE_MIN) && + getType().test(ctx, this, Tester.SLICE_MAX); + } + + public enum Logic { SINGLE, OR, AND, XOR; /// @param a will have type set /// @param b may or may not be a multi predicate /// @return copy of {@code a} combined with {@code b} - protected MultiPredicate combine(MultiPredicate a, @Nullable MultiPredicate b) { + MultiPredicate combine(MultiPredicate a, @Nullable MultiPredicate b) { if (b == null) return a; // no op if (a.isEmpty()) return b; var ret = new MultiPredicate(this, a.hasAir() || b.hasAir()); @@ -342,7 +372,7 @@ protected MultiPredicate combine(MultiPredicate a, @Nullable MultiPredicate b) { return ret.sorted(); } - private void appendPredicate(MultiPredicate source, MultiPredicate dest) { + void appendPredicate(MultiPredicate source, MultiPredicate dest) { if (source.isSingle()) { dest.addPredicate(source.predicateList.get(0)); } else if (source.type != this) { @@ -374,8 +404,10 @@ private void appendPredicate(MultiPredicate source, MultiPredicate dest) { * really it should be "only one predicate can be present in multi/slice" * * how do i handle global/slice max? + * i dont think i actually need to + * what i really need to do is track passed vs failed predicates */ - protected boolean run(PredicateContext ctx, MultiPredicate predicates) { + boolean run(PredicateContext ctx, MultiPredicate predicates) { for (BasePredicate basePredicate : predicates) { if (basePredicate.testLimited(ctx)) return true; } @@ -396,6 +428,8 @@ private boolean test(PredicateContext ctx, MultiPredicate predicates, if (tester.shouldSkipTest(ctx)) return true; int skipped = 0, passed = 0, size = predicates.predicateList.size(); for (BasePredicate predicate : predicates) { + // this doesn't work with compacted multi predicates + // get min count int expectedCount = tester.getCount(predicate); if (expectedCount == -1) { @@ -409,6 +443,7 @@ private boolean test(PredicateContext ctx, MultiPredicate predicates, boolean success = tester.test(expectedCount, actualCount); if (success) passed++; + ctx.updateState(predicate, tester.getFailureReason(), success); if (tester.returnEarly(passed, success, this)) { // get true or false @@ -423,7 +458,7 @@ private boolean test(PredicateContext ctx, MultiPredicate predicates, } } - enum Tester { + public enum Tester { GLOBAL_MIN, GLOBAL_MAX, SLICE_MIN, @@ -440,10 +475,8 @@ public int getCount(BasePredicate predicate) { public int getActualCount(PredicateContext ctx, BasePredicate predicate) { return switch (this) { - case GLOBAL_MIN -> ctx.getGlobalCount(predicate); - case GLOBAL_MAX -> ctx.incrementGlobalCount(predicate); - case SLICE_MIN -> ctx.getSliceCount(predicate); - case SLICE_MAX -> ctx.incrementSliceCount(predicate); + case GLOBAL_MIN, GLOBAL_MAX -> ctx.getGlobalCount(predicate); + case SLICE_MIN, SLICE_MAX -> ctx.getSliceCount(predicate); }; } @@ -514,5 +547,14 @@ public boolean hasErrored(int passed, int size, PredicateContext ctx, MultiPredi } return error; } + + public FailureReason getFailureReason() { + return switch (this) { + case GLOBAL_MIN -> FailureReason.GLOBAL_MIN; + case GLOBAL_MAX -> FailureReason.GLOBAL_MAX; + case SLICE_MIN -> FailureReason.SLICE_MIN; + case SLICE_MAX -> FailureReason.SLICE_MAX; + }; + } } } From cb194a1af0d998155a66d1e9dfaa1945bfeac16f Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sun, 5 Jul 2026 19:06:31 -0700 Subject: [PATCH 043/101] go back --- .../api/multiblock/PredicateContext.java | 14 +- .../multiblock/predicates/BasePredicate.java | 17 +-- .../multiblock/predicates/MultiPredicate.java | 128 +++++++----------- 3 files changed, 62 insertions(+), 97 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 889012af877..d4cadbf01b2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -21,7 +21,6 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.Getter; -import lombok.Setter; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -30,11 +29,11 @@ public class PredicateContext { protected final List errors = new ArrayList<>(); protected final List commitedErrors = new ArrayList<>(); - protected final Object2ObjectMap validationMap = new Object2ObjectArrayMap<>(); @Getter protected CurrentBlockInfo currentBlockInfo = new CurrentBlockInfo(); protected final Object2IntMap globalCount = new Object2IntOpenHashMap<>(); protected final Object2IntMap layerCount = new Object2IntOpenHashMap<>(); + public final Object2ObjectMap> predicatePositions = new Object2ObjectArrayMap<>(); @Getter private FailureReason lastFailureReason; @@ -132,13 +131,11 @@ public Object2IntMap globalCache() { } public int incrementGlobalCount(BasePredicate predicate) { - globalCache().mergeInt(predicate, 1, Integer::sum); - return globalCache().getInt(predicate); + return globalCache().mergeInt(predicate, 1, Integer::sum); } public int incrementSliceCount(BasePredicate predicate) { - Objects.requireNonNull(layerCache()).mergeInt(predicate, 1, Integer::sum); - return layerCache().getInt(predicate); + return Objects.requireNonNull(layerCache()).mergeInt(predicate, 1, Integer::sum); } public int getGlobalCount(BasePredicate predicate) { @@ -149,11 +146,6 @@ public int getSliceCount(BasePredicate predicate) { return Objects.requireNonNull(layerCache()).getInt(predicate); } - public void updateState(BasePredicate predicate, FailureReason index, boolean passed) { - validationMap.computeIfAbsent(predicate, p -> new BitSet()) - .set(index.ordinal(), passed); - } - public enum FailureReason { INTERNAL, GLOBAL_MAX, diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index ee01d883bb6..004a3a39eff 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -57,24 +57,21 @@ public abstract class BasePredicate { /// test with internal function and global/slice max public boolean testLimited(PredicateContext ctx) { - // this is some fucked up shit - boolean passed = test(ctx); - ctx.updateState(this, PredicateContext.FailureReason.INTERNAL, passed); - return passed; + return test(ctx) && testGlobalMax(ctx) && testSliceMax(ctx); } /// test against global max count - public boolean testGlobalMax(boolean b, PredicateContext ctx) { + public boolean testGlobalMax(PredicateContext ctx) { if (getMaxCount() == -1) return true; - int count = b ? ctx.incrementGlobalCount(this) : ctx.getGlobalCount(this); - return testGlobalMax(count) || b || ctx.globalError(this, false); + int count = ctx.incrementGlobalCount(this); + return testGlobalMax(count) || ctx.globalError(this, false); } /// test against slice max count - public boolean testSliceMax(boolean b, PredicateContext ctx) { + public boolean testSliceMax(PredicateContext ctx) { if (getMaxSliceCount() == -1 || ctx.layerCache() == null) return true; - int count = b ? ctx.incrementSliceCount(this) : ctx.getSliceCount(this); - return testSliceMax(count) || b || ctx.sliceError(this, false); + int count = ctx.incrementSliceCount(this); + return testSliceMax(count) || ctx.sliceError(this, false); } /// test against global min count diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index b66740a6a52..bdac77d8fa8 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -37,9 +37,7 @@ public class MultiPredicate implements Iterable { @Override public boolean test(PredicateContext ctx) { - boolean passed = predicate.test(ctx); - ctx.updateState(this, FailureReason.INTERNAL, passed); - return passed; + return predicate.test(ctx); } @Override @@ -93,22 +91,12 @@ public boolean test(PredicateContext ctx) { /// delegates to {@link #type} to test against global min count public boolean testGlobalMin(PredicateContext ctx) { - boolean passed = false; - for (BasePredicate p : predicateList) { - ctx.updateState(p, FailureReason.GLOBAL_MIN, passed |= p.testGlobalMin(ctx)); - } - return passed; -// return getType().testGlobalMin(ctx, this); + return getType().test(ctx, this, Tester.GLOBAL_MIN); } /// delegates to {@link #type} to test against slice min count public boolean testSliceMin(PredicateContext ctx) { - boolean passed = false; - for (BasePredicate p : predicateList) { - ctx.updateState(p, FailureReason.SLICE_MIN, passed |= p.testSliceMin(ctx)); - } - return passed; -// return getType().testSliceMin(ctx, this); + return getType().test(ctx, this, Tester.SLICE_MIN); } protected MultiPredicate addPredicates(Iterable predicates) { @@ -156,49 +144,7 @@ public boolean hasAir() { } protected BasePredicate compact() { - return new BasePredicate() { - - private MultiPredicate getParent() { - return MultiPredicate.this; - } - - @Override - public boolean test(PredicateContext ctx) { - // this also tests global/slice max, but with no respect to logic type - return getParent().test(ctx); - } - - @Override - public boolean testGlobalMin(PredicateContext ctx) { - return getParent().testGlobalMin(ctx); - } - - @Override - public boolean testSliceMin(PredicateContext ctx) { - return getParent().testSliceMin(ctx); - } - - @Override - public List computeCandidates() { - return getParent().getCandidates() - .stream() - .flatMap(Collection::stream) - .toList(); - } - - @Override - public String getTypeName() { - return getParent().getTypeName(); - } - - @Override - protected void appendContents(StringBuilder builder) { - getParent().appendContents(builder); - } - - @Override - protected void appendStats(StringBuilder builder) {} - }; + return new CompactedPredicate(); } public MultiPredicate setMinGlobalLimited(int min) { @@ -407,28 +353,15 @@ void appendPredicate(MultiPredicate source, MultiPredicate dest) { * i dont think i actually need to * what i really need to do is track passed vs failed predicates */ - boolean run(PredicateContext ctx, MultiPredicate predicates) { - for (BasePredicate basePredicate : predicates) { - if (basePredicate.testLimited(ctx)) return true; - } - return false; - } - - public boolean testGlobalMin(PredicateContext ctx, MultiPredicate predicates) { - return test(ctx, predicates, Tester.GLOBAL_MIN); - } - - public boolean testSliceMin(PredicateContext ctx, MultiPredicate predicates) { - return test(ctx, predicates, Tester.SLICE_MIN); - } - // i hate this (but not as much) private boolean test(PredicateContext ctx, MultiPredicate predicates, Tester tester) { if (tester.shouldSkipTest(ctx)) return true; int skipped = 0, passed = 0, size = predicates.predicateList.size(); for (BasePredicate predicate : predicates) { - // this doesn't work with compacted multi predicates + if (predicate instanceof CompactedPredicate compacted) { + return test(ctx, compacted.getParent(), tester); + } // get min count int expectedCount = tester.getCount(predicate); @@ -443,7 +376,6 @@ private boolean test(PredicateContext ctx, MultiPredicate predicates, boolean success = tester.test(expectedCount, actualCount); if (success) passed++; - ctx.updateState(predicate, tester.getFailureReason(), success); if (tester.returnEarly(passed, success, this)) { // get true or false @@ -490,7 +422,7 @@ public boolean test(int expected, int actual) { public void onError(PredicateContext ctx, MultiPredicate predicates) { // todo better error var joiner = new StringJoiner("\n"); - predicates.forEach(p -> joiner.add("\t" + p)); + predicates.forEach(p -> joiner.add(" " + p)); ctx.appendError(new PatternStringError(Component.literal("One of: \n" + joiner))); switch (this) { case GLOBAL_MIN -> ctx.setFailureReason(FailureReason.GLOBAL_MIN); @@ -557,4 +489,48 @@ public FailureReason getFailureReason() { }; } } + + private class CompactedPredicate extends BasePredicate { + + private MultiPredicate getParent() { + return MultiPredicate.this; + } + + @Override + public boolean test(PredicateContext ctx) { + // this also tests global/slice max, but with no respect to logic type + return getParent().test(ctx); + } + + @Override + public boolean testGlobalMin(PredicateContext ctx) { + return getParent().testGlobalMin(ctx); + } + + @Override + public boolean testSliceMin(PredicateContext ctx) { + return getParent().testSliceMin(ctx); + } + + @Override + public List computeCandidates() { + return getParent().getCandidates() + .stream() + .flatMap(Collection::stream) + .toList(); + } + + @Override + public String getTypeName() { + return getParent().getTypeName(); + } + + @Override + protected void appendContents(StringBuilder builder) { + getParent().appendContents(builder); + } + + @Override + protected void appendStats(StringBuilder builder) {} + } } From 3299315757ad91a08f093f17edd73a745ae034d2 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:43:01 -0700 Subject: [PATCH 044/101] spotless back to basics notes --- .../api/multiblock/PredicateContext.java | 43 ++- .../gtceu/api/multiblock/Predicates.java | 2 - .../pattern/BasicSliceStrategy.java | 1 + .../api/multiblock/pattern/BlockPattern.java | 26 +- .../multiblock/pattern/ExpandablePattern.java | 3 - .../api/multiblock/pattern/PatternState.java | 10 + .../multiblock/predicates/MultiPredicate.java | 277 +++++------------- 7 files changed, 135 insertions(+), 227 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index d4cadbf01b2..2e2918a1019 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -7,10 +7,8 @@ import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; @@ -20,6 +18,9 @@ import net.minecraft.world.level.material.FluidState; import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import lombok.Getter; import org.jetbrains.annotations.Nullable; @@ -35,7 +36,7 @@ public class PredicateContext { protected final Object2IntMap layerCount = new Object2IntOpenHashMap<>(); public final Object2ObjectMap> predicatePositions = new Object2ObjectArrayMap<>(); @Getter - private FailureReason lastFailureReason; + private FailureReason lastFailureReason = FailureReason.NONE; /// accepts a pattern error /// @@ -60,17 +61,15 @@ public boolean internalError(PatternError error) { public boolean globalError(BasePredicate predicate, boolean min) { this.lastFailureReason = min ? FailureReason.GLOBAL_MIN : FailureReason.GLOBAL_MAX; - SinglePredicateError error = min - ? SinglePredicateError.minCount(predicate, getGlobalCount(predicate)) - : SinglePredicateError.maxCount(predicate, getGlobalCount(predicate)); + SinglePredicateError error = min ? SinglePredicateError.minCount(predicate, getGlobalCount(predicate)) : + SinglePredicateError.maxCount(predicate, getGlobalCount(predicate)); return error(error); } public boolean sliceError(BasePredicate predicate, boolean min) { this.lastFailureReason = min ? FailureReason.SLICE_MIN : FailureReason.SLICE_MAX; - SinglePredicateError error = min - ? SinglePredicateError.minLayerCount(predicate, getSliceCount(predicate)) - : SinglePredicateError.maxLayerCount(predicate, getSliceCount(predicate)); + SinglePredicateError error = min ? SinglePredicateError.minLayerCount(predicate, getSliceCount(predicate)) : + SinglePredicateError.maxLayerCount(predicate, getSliceCount(predicate)); return error(error); } @@ -146,7 +145,31 @@ public int getSliceCount(BasePredicate predicate) { return Objects.requireNonNull(layerCache()).getInt(predicate); } + public Object2ObjectMap passedPredicates = new Object2ObjectArrayMap<>(); + + public void onPredicatePass(MultiPredicate multiPredicate, BasePredicate predicate) { + if (!multiPredicate.isAir()) { + this.predicatePositions + .computeIfAbsent(predicate, key -> new HashSet<>()) + .add(pos()); + this.passedPredicates.putIfAbsent(predicate, multiPredicate); + } + incrementGlobalCount(predicate); + if (layerCache() != null) + incrementSliceCount(predicate); + } + + public List getPresentPredicates(List predicates) { + return predicates.stream().filter(this.predicatePositions::containsKey).toList(); + } + + public Set getPredicatePositions(BasePredicate predicate) { + return this.predicatePositions.getOrDefault(predicate, Collections.emptySet()); + } + public enum FailureReason { + + NONE, INTERNAL, GLOBAL_MAX, GLOBAL_MIN, diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index d34951f6289..02b2ad937fc 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -12,8 +12,6 @@ import com.gregtechceu.gtceu.api.machine.MachineDefinition; import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; import com.gregtechceu.gtceu.api.machine.multiblock.PartAbility; -import com.gregtechceu.gtceu.api.multiblock.error.BlockMatchingError; -import com.gregtechceu.gtceu.api.multiblock.error.PartAbilityError; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.error.PlaceholderError; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java index a4d2491c8f8..16cd1df7c5b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java @@ -79,6 +79,7 @@ protected int checkRepeatSlice(PatternState state, int index, int offset, boolea if (!res) { if (i <= slice.minRepeats) return -1; + state.commitSliceErrors(); return slices.get(index).actualRepeats = i - 1; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 88fb21d4b77..19058687263 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -1,9 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; -import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; -import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import net.minecraft.core.BlockPos; @@ -160,9 +158,29 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c sliceStrategy.start(controllerPos, frontFacing, upwardsFacing); if (!sliceStrategy.check(patternState, isFlipped)) return false; + /* + * NOTES + * as we iterate each slice of the multiblock + * check each predicates' state check + * each block pos can only be one predicate + * we need to know what logic type each predicate should uses + * this is only globally + * thought i could see a use for xor in a slice, but not globally + * how exactly would this work + * XOR_SLICE and XOR_GLOBAL? + * and idea i had is that if a xor multi predicate is iterated + * a list of "banned" base predicates could be checked + * so if another predicate from the same multi predicate passes, it would fail + * + * another predicament is handling the edge case of a xor predicate + * having two- + * actually i need the xor logic to run in the state check + * along with the previously mentioned idea of banned predicates + */ + // global min check for (MultiPredicate predicate : predicates.values()) { - if (!predicate.testGlobal(patternState)) { + if (!predicate.testGlobalMin(patternState)) { patternState.commitErrors(); return false; } @@ -227,7 +245,7 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // slice min check for (MultiPredicate predicate : predicates.values()) { - if (!predicate.testSlice(patternState)) { + if (!predicate.testSliceMin(patternState)) { patternState.commitErrors(); return false; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index 5d003cd9ed2..5b6432fb216 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -1,10 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; -import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; -import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 7636b8d9a00..47c967a1c5f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -3,6 +3,7 @@ import com.gregtechceu.gtceu.api.machine.multiblock.MultiblockControllerMachine; import com.gregtechceu.gtceu.api.multiblock.MultiblockWorldSavedData; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import net.minecraft.core.BlockPos; @@ -17,6 +18,9 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.List; + /* * Contains vital information to an instanced version of a structure pattern. */ @@ -64,6 +68,12 @@ public void clearErrors() { this.errors.clear(); } + List> sliceErrors = new ArrayList<>(); + + public void commitSliceErrors() { + this.sliceErrors.add(List.copyOf(this.errors)); + } + public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState newState) { if (!(currentBlockInfo.getLevel() instanceof ServerLevel serverLevel)) return; if (pos.equals(controllerPos)) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index bdac77d8fa8..902a80ab2c2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -1,15 +1,11 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.PredicateContext.FailureReason; -import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; -import com.gregtechceu.gtceu.api.multiblock.pattern.PatternState; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import lombok.AccessLevel; import lombok.Getter; -import net.minecraft.network.chat.Component; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -81,22 +77,33 @@ public boolean isEmpty() { /// delegates to {@link #type} to run {@link BasePredicate#testLimited(PredicateContext)} public boolean test(PredicateContext ctx) { - boolean passed = false; for (BasePredicate p : predicateList) { - passed |= p.testLimited(ctx); + if (p.testLimited(ctx)) { + return true; + } } - return passed; -// return getType().run(ctx, this); + return false; + // return getType().run(ctx, this); } /// delegates to {@link #type} to test against global min count public boolean testGlobalMin(PredicateContext ctx) { - return getType().test(ctx, this, Tester.GLOBAL_MIN); + for (BasePredicate p : predicateList) { + if (p.testGlobalMin(ctx)) { + return true; + } + } + return false; } /// delegates to {@link #type} to test against slice min count public boolean testSliceMin(PredicateContext ctx) { - return getType().test(ctx, this, Tester.SLICE_MIN); + for (BasePredicate p : predicateList) { + if (p.testSliceMin(ctx)) { + return true; + } + } + return false; } protected MultiPredicate addPredicates(Iterable predicates) { @@ -236,15 +243,15 @@ protected MultiPredicate sorted() { } public MultiPredicate or(MultiPredicate other) { - return Logic.OR.combine(this, other); + return combine(this, Logic.OR, other); } public MultiPredicate and(MultiPredicate other) { - return Logic.AND.combine(this, other); + return combine(this, Logic.AND, other); } public MultiPredicate xor(MultiPredicate other) { - return Logic.XOR.combine(this, other); + return combine(this, Logic.XOR, other); } public boolean isSingle() { @@ -290,204 +297,58 @@ public static MultiPredicate empty() { return EMPTY; } - public boolean testGlobal(PredicateContext ctx) { - // this is what depends on logic - return getType().test(ctx, this, Tester.GLOBAL_MIN) && - getType().test(ctx, this, Tester.GLOBAL_MAX); - } - - public boolean testSlice(PredicateContext ctx) { - // this is what depends on logic - return getType().test(ctx, this, Tester.SLICE_MIN) && - getType().test(ctx, this, Tester.SLICE_MAX); - } - - public enum Logic { - - SINGLE, OR, AND, XOR; - - /// @param a will have type set - /// @param b may or may not be a multi predicate - /// @return copy of {@code a} combined with {@code b} - MultiPredicate combine(MultiPredicate a, @Nullable MultiPredicate b) { - if (b == null) return a; // no op - if (a.isEmpty()) return b; - var ret = new MultiPredicate(this, a.hasAir() || b.hasAir()); - appendPredicate(a, ret); - appendPredicate(b, ret); - return ret.sorted(); - } - - void appendPredicate(MultiPredicate source, MultiPredicate dest) { - if (source.isSingle()) { - dest.addPredicate(source.predicateList.get(0)); - } else if (source.type != this) { - dest.addPredicate(source.compact()); - } else { - dest.addPredicates(source); - } - } - - /* - * OR logic - * at least one of n predicates must be valid - * AND logic - * must have n valid predicates in multi - * XOR logic - * must only have one of n predicates be valid and present in multi - * - * when it comes to the internal predicates - * any can pass, regardless of logic type - * since a block can only have one state - * and internal predicate is checked per block - * - * this may also introduce the ability - * to have an invalid predicate form a multiblock - * if predicate a has a min of two, - * and predicate b has min of one, - * and you use XOR logic - * the multi predicate would pass since a fails and b succeeds min checks - * really it should be "only one predicate can be present in multi/slice" - * - * how do i handle global/slice max? - * i dont think i actually need to - * what i really need to do is track passed vs failed predicates - */ - // i hate this (but not as much) - private boolean test(PredicateContext ctx, MultiPredicate predicates, - Tester tester) { - if (tester.shouldSkipTest(ctx)) return true; - int skipped = 0, passed = 0, size = predicates.predicateList.size(); - for (BasePredicate predicate : predicates) { - if (predicate instanceof CompactedPredicate compacted) { - return test(ctx, compacted.getParent(), tester); - } - - // get min count - int expectedCount = tester.getCount(predicate); - if (expectedCount == -1) { - if (++skipped == size) { - return true; - } else { - continue; - } - } - int actualCount = tester.getActualCount(ctx, predicate); - - boolean success = tester.test(expectedCount, actualCount); - if (success) passed++; - - if (tester.returnEarly(passed, success, this)) { - // get true or false - return tester.hasErrored(passed, size, ctx, predicates, this); - } - } - if (tester.finalReturn(passed, skipped, this)) { - tester.onError(ctx, predicates); - return false; - } - return true; + /// @param a will have type set + /// @param b may or may not be a multi predicate + /// @return copy of {@code a} combined with {@code b} + private static MultiPredicate combine(MultiPredicate a, Logic type, @Nullable MultiPredicate b) { + if (b == null) return a; // no op + if (a.isEmpty()) return b; + var ret = new MultiPredicate(type, a.hasAir() || b.hasAir()); + appendPredicate(a, ret, type); + appendPredicate(b, ret, type); + return ret.sorted(); + } + + private static void appendPredicate(MultiPredicate source, MultiPredicate dest, Logic type) { + if (source.isSingle()) { + dest.addPredicate(source.predicateList.get(0)); + } else if (source.type != type) { + dest.addPredicate(source.compact()); + } else { + dest.addPredicates(source); } } - public enum Tester { - GLOBAL_MIN, - GLOBAL_MAX, - SLICE_MIN, - SLICE_MAX; - - public int getCount(BasePredicate predicate) { - return switch (this) { - case GLOBAL_MIN -> predicate.getMinCount(); - case GLOBAL_MAX -> predicate.getMaxCount(); - case SLICE_MIN -> predicate.getMinSliceCount(); - case SLICE_MAX -> predicate.getMaxSliceCount(); - }; - } - - public int getActualCount(PredicateContext ctx, BasePredicate predicate) { - return switch (this) { - case GLOBAL_MIN, GLOBAL_MAX -> ctx.getGlobalCount(predicate); - case SLICE_MIN, SLICE_MAX -> ctx.getSliceCount(predicate); - }; - } - - public boolean test(int expected, int actual) { - return switch (this) { - case GLOBAL_MIN, SLICE_MIN -> expected <= actual; - case GLOBAL_MAX, SLICE_MAX -> expected >= actual; - }; - } - - public void onError(PredicateContext ctx, MultiPredicate predicates) { - // todo better error - var joiner = new StringJoiner("\n"); - predicates.forEach(p -> joiner.add(" " + p)); - ctx.appendError(new PatternStringError(Component.literal("One of: \n" + joiner))); - switch (this) { - case GLOBAL_MIN -> ctx.setFailureReason(FailureReason.GLOBAL_MIN); - case GLOBAL_MAX -> ctx.setFailureReason(FailureReason.GLOBAL_MAX); - case SLICE_MIN -> ctx.setFailureReason(FailureReason.SLICE_MIN); - case SLICE_MAX -> ctx.setFailureReason(FailureReason.SLICE_MAX); - } - } - - public boolean returnEarly(int passed, boolean success, Logic logicType) { - // return true to return early - return switch (logicType) { - case XOR -> passed > 1; - case AND -> !success; - default -> false; - }; - } - - public boolean finalReturn(int passed, int size, Logic logicType) { - // return true if failed - return switch (logicType) { - case SINGLE, XOR -> passed != 1; - case OR -> passed == 0; - case AND -> passed != size; - }; - } - - public boolean isGlobal() { - return this == GLOBAL_MIN || this == GLOBAL_MAX; - } - - public boolean isSlice() { - return this == SLICE_MIN || this == SLICE_MAX; - } - - public boolean isMin() { - return this == GLOBAL_MIN || this == SLICE_MIN; - } - - public boolean isMax() { - return this == GLOBAL_MAX || this == SLICE_MAX; - } - - public boolean shouldSkipTest(PredicateContext ctx) { - // skip test if we're slice and slice cache is null - return isSlice() && ctx.layerCache() != null; - } - - // called after return early - public boolean hasErrored(int passed, int size, PredicateContext ctx, MultiPredicate predicates, Logic logic) { - boolean error = finalReturn(passed, size, logic); - if (error) { - onError(ctx, predicates); - } - return error; - } - - public FailureReason getFailureReason() { - return switch (this) { - case GLOBAL_MIN -> FailureReason.GLOBAL_MIN; - case GLOBAL_MAX -> FailureReason.GLOBAL_MAX; - case SLICE_MIN -> FailureReason.SLICE_MIN; - case SLICE_MAX -> FailureReason.SLICE_MAX; - }; - } + /* + * OR logic + * at least one of n predicates must be valid + * AND logic + * must have n valid predicates in multi + * XOR logic + * must only have one of n predicates be valid and present in multi + * + * when it comes to the internal predicates + * any can pass, regardless of logic type + * since a block can only have one state + * and internal predicate is checked per block + * + * this may also introduce the ability + * to have an invalid predicate form a multiblock + * if predicate a has a min of two, + * and predicate b has min of one, + * and you use XOR logic + * the multi predicate would pass since a fails and b succeeds min checks + * really it should be "only one predicate can be present in multi/slice" + * + * how do i handle global/slice max? + * i dont think i actually need to + * what i really need to do is track passed vs failed predicates + */ + public enum Logic { + SINGLE, + OR, + AND, + XOR; } private class CompactedPredicate extends BasePredicate { From 26ee7010021bf4434a9c03f87f71541d15fc70a1 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 8 Jul 2026 19:12:59 -0700 Subject: [PATCH 045/101] remove special error methods add stage to PredicateContext set stage accordingly a lot of cleanup --- ...CoilWorkableElectricMultiblockMachine.java | 2 +- .../api/multiblock/PredicateContext.java | 84 +++++-------------- .../gtceu/api/multiblock/Predicates.java | 23 ++--- .../api/multiblock/pattern/BlockPattern.java | 3 + .../api/multiblock/pattern/PatternState.java | 1 + .../multiblock/predicates/BasePredicate.java | 53 ++++++++++-- .../multiblock/predicates/MultiPredicate.java | 35 +------- .../common/data/machines/GTMachineUtils.java | 2 +- .../electric/ActiveTransformerMachine.java | 2 +- .../multiblock/electric/CleanroomMachine.java | 10 +-- .../electric/DistillationTowerMachine.java | 4 +- .../electric/LargeMinerMachine.java | 2 +- .../electric/PowerSubstationMachine.java | 2 +- .../electric/research/DataBankMachine.java | 2 +- .../research/ResearchStationMachine.java | 8 +- .../steam/SteamParallelMultiblockMachine.java | 2 +- 16 files changed, 110 insertions(+), 125 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java b/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java index a9efdb163bf..c16ed92fda3 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java @@ -48,7 +48,7 @@ public void formStructure(@NotNull String substructureName) { if (coilType == null) coilType = coil.coilType; else { if (coilType != coil.coilType) { - patternStates.get(substructureName).internalError( + patternStates.get(substructureName).error( new CoilMatchingError(BlockPos.of(entry.getLongKey()), coilType, coil.coilType)); invalidateStructure(substructureName); return; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 2e2918a1019..3c09cf9af4d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -1,17 +1,11 @@ package com.gregtechceu.gtceu.api.multiblock; -import com.gregtechceu.gtceu.api.machine.multiblock.PartAbility; -import com.gregtechceu.gtceu.api.multiblock.error.BlockMatchingError; -import com.gregtechceu.gtceu.api.multiblock.error.PartAbilityError; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; -import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; @@ -19,9 +13,8 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import lombok.Getter; +import lombok.Setter; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -34,45 +27,21 @@ public class PredicateContext { protected CurrentBlockInfo currentBlockInfo = new CurrentBlockInfo(); protected final Object2IntMap globalCount = new Object2IntOpenHashMap<>(); protected final Object2IntMap layerCount = new Object2IntOpenHashMap<>(); - public final Object2ObjectMap> predicatePositions = new Object2ObjectArrayMap<>(); + @Getter private FailureReason lastFailureReason = FailureReason.NONE; + @Setter + private PredicateStage stage = PredicateStage.INTERNAL; + /// accepts a pattern error /// /// @return false - private boolean error(PatternError error) { - this.errors.add(error); + public boolean error(PatternError error) { + appendError(error); return false; } - public boolean abilityError(PartAbility ability) { - return internalError(new PartAbilityError(pos(), ability)); - } - - public boolean blockMatchingError(List blocks) { - return internalError(new BlockMatchingError(pos(), blocks)); - } - - public boolean internalError(PatternError error) { - this.lastFailureReason = FailureReason.INTERNAL; - return error(error); - } - - public boolean globalError(BasePredicate predicate, boolean min) { - this.lastFailureReason = min ? FailureReason.GLOBAL_MIN : FailureReason.GLOBAL_MAX; - SinglePredicateError error = min ? SinglePredicateError.minCount(predicate, getGlobalCount(predicate)) : - SinglePredicateError.maxCount(predicate, getGlobalCount(predicate)); - return error(error); - } - - public boolean sliceError(BasePredicate predicate, boolean min) { - this.lastFailureReason = min ? FailureReason.SLICE_MIN : FailureReason.SLICE_MAX; - SinglePredicateError error = min ? SinglePredicateError.minLayerCount(predicate, getSliceCount(predicate)) : - SinglePredicateError.maxLayerCount(predicate, getSliceCount(predicate)); - return error(error); - } - public void commitErrors() { this.commitedErrors.addAll(this.errors); this.errors.clear(); @@ -80,11 +49,7 @@ public void commitErrors() { public PredicateContext appendError(PatternError error) { this.errors.add(error); - return this; - } - - public PredicateContext setFailureReason(FailureReason reason) { - this.lastFailureReason = reason; + this.lastFailureReason = this.stage.getFailureReason(); return this; } @@ -145,26 +110,23 @@ public int getSliceCount(BasePredicate predicate) { return Objects.requireNonNull(layerCache()).getInt(predicate); } - public Object2ObjectMap passedPredicates = new Object2ObjectArrayMap<>(); + public enum PredicateStage { - public void onPredicatePass(MultiPredicate multiPredicate, BasePredicate predicate) { - if (!multiPredicate.isAir()) { - this.predicatePositions - .computeIfAbsent(predicate, key -> new HashSet<>()) - .add(pos()); - this.passedPredicates.putIfAbsent(predicate, multiPredicate); + INTERNAL, + GLOBAL_MIN, + GLOBAL_MAX, + SLICE_MIN, + SLICE_MAX; + + private FailureReason getFailureReason() { + return switch (this) { + case INTERNAL -> FailureReason.INTERNAL; + case GLOBAL_MIN -> FailureReason.GLOBAL_MIN; + case GLOBAL_MAX -> FailureReason.GLOBAL_MAX; + case SLICE_MIN -> FailureReason.SLICE_MIN; + case SLICE_MAX -> FailureReason.SLICE_MAX; + }; } - incrementGlobalCount(predicate); - if (layerCache() != null) - incrementSliceCount(predicate); - } - - public List getPresentPredicates(List predicates) { - return predicates.stream().filter(this.predicatePositions::containsKey).toList(); - } - - public Set getPredicatePositions(BasePredicate predicate) { - return this.predicatePositions.getOrDefault(predicate, Collections.emptySet()); } public enum FailureReason { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 02b2ad937fc..7bcffd42716 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -12,6 +12,8 @@ import com.gregtechceu.gtceu.api.machine.MachineDefinition; import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; import com.gregtechceu.gtceu.api.machine.multiblock.PartAbility; +import com.gregtechceu.gtceu.api.multiblock.error.BlockMatchingError; +import com.gregtechceu.gtceu.api.multiblock.error.PartAbilityError; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.error.PlaceholderError; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; @@ -73,7 +75,7 @@ public static MultiPredicate states(@Nullable String debugName, BlockState... al } } return customPredicate(debugName, - ctx -> states.contains(ctx.state()) || ctx.internalError(PLACEHOLDER), + ctx -> states.contains(ctx.state()) || ctx.error(PLACEHOLDER), states.stream().map(BlockInfo::fromBlockState), builder -> { StringJoiner joiner = new StringJoiner(", "); @@ -84,7 +86,7 @@ public static MultiPredicate states(@Nullable String debugName, BlockState... al public static MultiPredicate blocks(Block block) { return customPredicate("Block", - ctx -> ctx.state().is(block) || ctx.blockMatchingError(List.of(block)), + ctx -> ctx.state().is(block) || ctx.error(new BlockMatchingError(ctx.pos(), List.of(block))), Stream.of(BlockInfo.fromBlock(block)), builder -> builder.append(blockToString(block))); } @@ -110,7 +112,7 @@ public static MultiPredicate blocks(@Nullable String debugName, for (var block : blocks) { if (ctx.state().is(block)) return true; } - return ctx.blockMatchingError(blocks); + return ctx.error(new BlockMatchingError(ctx.pos(), blocks)); }, candidates.map(BlockInfo::fromBlock), builder -> { StringJoiner joiner = new StringJoiner(", "); blocks.forEach(block -> joiner.add(blockToString(block))); @@ -144,7 +146,7 @@ public static MultiPredicate blockTag(TagKey tag) { public static MultiPredicate fluids(Fluid... fluids) { return customPredicate("Fluids", - ctx -> ArrayUtils.contains(fluids, ctx.fluid()) || ctx.internalError(PLACEHOLDER), + ctx -> ArrayUtils.contains(fluids, ctx.fluid()) || ctx.error(PLACEHOLDER), Arrays.stream(fluids).map(BlockInfo::fromFluid), builder -> { StringJoiner joiner = new StringJoiner(", "); @@ -171,7 +173,7 @@ public static MultiPredicate customFunction(Function candidates) { return customPredicate(ctx -> { PatternError error = predicate.apply(ctx.getCurrentBlockInfo()); - return error == null || ctx.internalError(error); + return error == null || ctx.error(error); }, Objects.>requireNonNullElse(candidates, Collections.emptyList()).stream()); } @@ -203,7 +205,8 @@ public static MultiPredicate air() { public static MultiPredicate abilities(PartAbility ability) { return customPredicate("Ability", - ctx -> ability.isApplicable(ctx.state().getBlock()) || ctx.abilityError(ability), + ctx -> ability.isApplicable(ctx.state().getBlock()) || + ctx.error(new PartAbilityError(ctx.pos(), ability)), ability.getAllBlocks().stream().map(BlockInfo::fromBlock), builder -> builder.append(ability.getName())); } @@ -215,7 +218,7 @@ public static MultiPredicate abilities(PartAbility... abilities) { if (ability.isApplicable(ctx.state().getBlock())) { return true; } - ctx.abilityError(ability); + ctx.error(new PartAbilityError(ctx.pos(), ability)); } return false; }, @@ -238,7 +241,7 @@ public static MultiPredicate ability(PartAbility ability, int... tiers) { } return customPredicate("Ability[" + sb + "]", ctx -> ability.isApplicable(ctx.state().getBlock()) || - ctx.abilityError(ability), + ctx.error(new PartAbilityError(ctx.pos(), ability)), ability.getBlocks(tiers).stream().map(BlockInfo::fromBlock)); } @@ -397,10 +400,10 @@ public static MultiPredicate framedPipes(Material[] frameMaterials, Block[] fram return customPredicate("FramedPipes", ctx -> { BlockEntity tileEntity = ctx.blockEntity(); if (!(tileEntity instanceof IPipeNode pipeNode)) { - return ctx.internalError(PLACEHOLDER); + return ctx.error(PLACEHOLDER); } return ArrayUtils.contains(frameMaterials, pipeNode.getFrameMaterial()) || - ctx.internalError(PLACEHOLDER); + ctx.error(PLACEHOLDER); }, Arrays.stream(frameBlocks).map(BlockInfo::fromBlock)); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 19058687263..ca9d0756f1e 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; @@ -179,6 +180,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c */ // global min check + patternState.setStage(PredicateContext.PredicateStage.GLOBAL_MIN); for (MultiPredicate predicate : predicates.values()) { if (!predicate.testGlobalMin(patternState)) { patternState.commitErrors(); @@ -244,6 +246,7 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p } // slice min check + patternState.setStage(PredicateContext.PredicateStage.SLICE_MIN); for (MultiPredicate predicate : predicates.values()) { if (!predicate.testSliceMin(patternState)) { patternState.commitErrors(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 47c967a1c5f..35cf7bd2123 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -72,6 +72,7 @@ public void clearErrors() { public void commitSliceErrors() { this.sliceErrors.add(List.copyOf(this.errors)); + clearErrors(); } public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState newState) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 004a3a39eff..2264b7e912b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -2,6 +2,7 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import net.minecraft.client.Minecraft; @@ -21,6 +22,7 @@ public abstract class BasePredicate { + // should air use isAir() instead of checking for air block directly? public static final MultiPredicate AIR = create("Air", ctx -> ctx.state().is(Blocks.AIR)); public static final MultiPredicate ANY = create("Any", ctx -> true); @@ -52,40 +54,48 @@ public abstract class BasePredicate { @Setter private @Nullable String nbtParser; // unsure what this does + public abstract MultiPredicate getParent(); + /// the main testing method public abstract boolean test(PredicateContext ctx); /// test with internal function and global/slice max public boolean testLimited(PredicateContext ctx) { - return test(ctx) && testGlobalMax(ctx) && testSliceMax(ctx); + ctx.setStage(PredicateContext.PredicateStage.INTERNAL); + if (!test(ctx)) return false; + ctx.setStage(PredicateContext.PredicateStage.GLOBAL_MAX); + if (!testGlobalMax(ctx)) return false; + ctx.setStage(PredicateContext.PredicateStage.SLICE_MAX); + return testSliceMax(ctx); + // return test(ctx) && testGlobalMax(ctx) && testSliceMax(ctx); } /// test against global max count public boolean testGlobalMax(PredicateContext ctx) { if (getMaxCount() == -1) return true; int count = ctx.incrementGlobalCount(this); - return testGlobalMax(count) || ctx.globalError(this, false); + return testGlobalMax(count) || ctx.error(SinglePredicateError.maxCount(this, count)); } /// test against slice max count public boolean testSliceMax(PredicateContext ctx) { if (getMaxSliceCount() == -1 || ctx.layerCache() == null) return true; int count = ctx.incrementSliceCount(this); - return testSliceMax(count) || ctx.sliceError(this, false); + return testSliceMax(count) || ctx.error(SinglePredicateError.maxLayerCount(this, count)); } /// test against global min count public boolean testGlobalMin(PredicateContext ctx) { if (getMinCount() == -1) return true; int count = ctx.getGlobalCount(this); - return testGlobalMin(count) || ctx.globalError(this, true); + return testGlobalMin(count) || ctx.error(SinglePredicateError.minCount(this, count)); } /// test against slice min count public boolean testSliceMin(PredicateContext ctx) { if (getMinSliceCount() == -1 || ctx.layerCache() == null) return true; int count = ctx.getSliceCount(this); - return testSliceMin(count) || ctx.globalError(this, true); + return testSliceMin(count) || ctx.error(SinglePredicateError.minLayerCount(this, count)); } /// simple test against global min count @@ -178,4 +188,37 @@ public static MultiPredicate create(@Nullable String debugName, Predicate candidateStream, @Nullable Consumer contents) { return new MultiPredicate(debugName, predicate, candidateStream, contents); } + + static BasePredicate of(MultiPredicate parent, @Nullable String debugName, Predicate predicate, + Stream candidateStream, @Nullable Consumer contents) { + return new BasePredicate() { + + @Override + public MultiPredicate getParent() { + return parent; + } + + @Override + public boolean test(PredicateContext ctx) { + return predicate.test(ctx); + } + + @Override + public List computeCandidates() { + return candidateStream.toList(); + } + + @Override + public String getTypeName() { + return Objects.requireNonNullElse(debugName, "Predicate"); + } + + @Override + protected void appendContents(StringBuilder builder) { + if (contents != null) { + contents.accept(builder); + } + } + }; + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 902a80ab2c2..467e424ee83 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -29,30 +29,8 @@ public class MultiPredicate implements Iterable { MultiPredicate(@Nullable String debugName, Predicate predicate, Stream candidateStream, @Nullable Consumer contents) { - this(new BasePredicate() { - - @Override - public boolean test(PredicateContext ctx) { - return predicate.test(ctx); - } - - @Override - public List computeCandidates() { - return candidateStream.toList(); - } - - @Override - public String getTypeName() { - return Objects.requireNonNullElse(debugName, "Predicate"); - } - - @Override - protected void appendContents(StringBuilder builder) { - if (contents != null) { - contents.accept(builder); - } - } - }); + this(); + addPredicate(BasePredicate.of(this, debugName, predicate, candidateStream, contents)); } private MultiPredicate(Logic type, boolean hasAir) { @@ -60,14 +38,9 @@ private MultiPredicate(Logic type, boolean hasAir) { this.hasAir = hasAir; } - private MultiPredicate(BasePredicate singleton) { - this(); - addPredicate(singleton); - } - private MultiPredicate() { this.type = Logic.SINGLE; - this.hasAir = false; + this.hasAir = isAir(); } @ApiStatus.Internal @@ -353,7 +326,7 @@ public enum Logic { private class CompactedPredicate extends BasePredicate { - private MultiPredicate getParent() { + public MultiPredicate getParent() { return MultiPredicate.this; } diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 15320be6e44..3d7a6d038cd 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -750,7 +750,7 @@ private static MultiPredicate rotorHolder(int tier) { .isAir()) { return true; } - return ctx.internalError(new PartAbilityError(ctx.pos(), PartAbility.ROTOR_HOLDER)); + return ctx.error(new PartAbilityError(ctx.pos(), PartAbility.ROTOR_HOLDER)); }, PartAbility.ROTOR_HOLDER.getAllBlocks() .stream() .map(BlockInfo::fromBlock)) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java index 792ffc09c69..22edc92c149 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java @@ -114,7 +114,7 @@ public void formStructure(@NotNull String substructureName) { // Invalidate the structure if there is not at least one output and one input if (powerInput.isEmpty() || powerOutput.isEmpty()) { - pState.internalError( + pState.error( new PatternStringError(Component.translatable("gtceu.predicate_error.active_transformer.missing_io", powerInput.isEmpty(), powerOutput.isEmpty()))); this.invalidateStructure(substructureName); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index 61374bf9ae8..7ffa2980ba0 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -135,14 +135,14 @@ public void formStructure(@NotNull String substructureName) { int f = bounds.get(4); int b = bounds.get(5); if (d < MIN_DEPTH || l < MIN_RADIUS || r < MIN_RADIUS || b < MIN_RADIUS || f < MIN_RADIUS) { - pState.internalError( + pState.error( new PatternStringError(Component.translatable("gtceu.predicate_error.cleanroom.too_small"))); invalidateStructure(); return; } if (Math.abs(l - r) > 1 || Math.abs(b - f) > 1) { - pState.internalError( + pState.error( new PatternStringError(Component.translatable("gtceu.predicate_error.cleanroom.not_centered"))); invalidateStructure(); return; @@ -159,7 +159,7 @@ public void formStructure(@NotNull String substructureName) { if (filterType == null) filterType = filter.getKey(); else { if (filterType != filter.getKey()) { - pState.internalError(new FilterMatchingError(BlockPos.of(entry.getLongKey()), + pState.error(new FilterMatchingError(BlockPos.of(entry.getLongKey()), filterType.getCleanroomType(), filter.getKey().getCleanroomType())); invalidateStructure(substructureName); @@ -472,7 +472,7 @@ protected static BlockState getGlassState() { protected static MultiPredicate doorPredicate() { return Predicates.customPredicate( - ctx -> ctx.state().getBlock() instanceof DoorBlock || ctx.internalError(Predicates.PLACEHOLDER), + ctx -> ctx.state().getBlock() instanceof DoorBlock || ctx.error(Predicates.PLACEHOLDER), Stream.of(new BlockInfo(Blocks.IRON_DOOR.defaultBlockState()), new BlockInfo(Blocks.IRON_DOOR.defaultBlockState() .setValue(DoorBlock.HALF, DoubleBlockHalf.UPPER)))); @@ -488,7 +488,7 @@ protected static MultiPredicate innerPredicate() { BlockEntity blockEntity = ctx.blockEntity(); if (blockEntity instanceof MetaMachine machine) { if (isMachineBanned(machine)) { - return ctx.internalError(Predicates.PLACEHOLDER); + return ctx.error(Predicates.PLACEHOLDER); } // todo do this in structure form not in the predicate // machine.getTraitOptional(CleanroomReceiverTrait.TYPE).ifPresent(cleanroomReceivers::add); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java index d723d0c3c0c..3d3ae0d3199 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java @@ -100,7 +100,7 @@ public void formStructure(String substructureName) { fluidOutputs.add(VoidFluidHandler.INSTANCE); } else { BlockPos p = part.getBlockPos(); - pState.internalError(new PatternStringError(Component.translatable( + pState.error(new PatternStringError(Component.translatable( "gtceu.predicate_error.distillery.unexpected_hatch", p.getX(), p.getY(), p.getZ()))); // GTCEu.LOGGER.error( // "The Distillation Tower at {} has a fluid export hatch with an unexpected Y position", @@ -110,7 +110,7 @@ public void formStructure(String substructureName) { } } } else { - pState.internalError( + pState.error( new PatternStringError(Component.translatable("gtceu.predicate_error.distillery.missing_outputs"))); invalidateStructure(substructureName); } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java index 624b438c612..eb69e8f4bcc 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java @@ -99,7 +99,7 @@ public void formStructure(@NotNull String substructureName) { public PatternState checkStructurePattern(String name) { var patternState = super.checkStructurePattern(name); if (this.getUpwardsFacing() != Direction.UP && this.getUpwardsFacing() != Direction.DOWN) { - patternState.internalError(Predicates.PLACEHOLDER); + patternState.error(Predicates.PLACEHOLDER); } return patternState; } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java index bab7a6ec1db..860c4a4dfad 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java @@ -157,7 +157,7 @@ public void formStructure(@NotNull String substructureName) { */ if (batteries.isEmpty()) { // only empty batteries found in the structure - pState.internalError(new PatternStringError( + pState.error(new PatternStringError( Component.translatable("gtceu.predicate_error.power_substation.missing_batteries"))); invalidateStructure(); return; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java index 175c77d4955..2e065bd621d 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java @@ -81,7 +81,7 @@ public void formStructure(@NotNull String substructureName) { this.energyUsage = calculateEnergyUsage(); if (this.maintenance == null) { - pState.internalError(new PatternStringError( + pState.error(new PatternStringError( Component.translatable("gtceu.predicate_error.databank.missing_maintenance"))); invalidateStructure(substructureName); return; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java index 495aef74ad4..a3372ca6773 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java @@ -61,7 +61,7 @@ public void formStructure(@NotNull String substructureName) { for (MultiblockPartMachine part : getParts()) { if (part instanceof ObjectHolderMachine holder) { if (holder.getFrontFacing() != getFrontFacing().getOpposite()) { - pState.internalError(new PatternStringError( + pState.error(new PatternStringError( Component.translatable("gtceu.predicate_error.object_holder.direction"))); invalidateStructure(substructureName); return; @@ -76,13 +76,13 @@ public void formStructure(@NotNull String substructureName) { // should never happen, but would rather do this than have an obscure NPE if (computationProvider == null) { - pState.internalError(new PatternStringError( + pState.error(new PatternStringError( Component.translatable("gtceu.predicate_error.research.missing_computation"))); invalidateStructure(substructureName); } if (objectHolder == null) { - pState.internalError(new PatternStringError( + pState.error(new PatternStringError( Component.translatable("gtceu.predicate_error.research.missing_object_holder"))); invalidateStructure(substructureName); } @@ -100,7 +100,7 @@ public PatternState checkStructurePattern(String name) { } } if (objHolder != null && objHolder.getFrontFacing() != getFrontFacing().getOpposite()) { - patternState.internalError( + patternState.error( new PatternStringError(Component.translatable("gtceu.predicate_error.object_holder.direction"))); invalidateStructure(name); } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java index 763c0b0674b..577d619755b 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java @@ -88,7 +88,7 @@ public void formStructure(String substructureName) { } } if (steamEnergy == null) { // No steam hatch found - pState.internalError( + pState.error( new PatternStringError(Component.translatable("gtceu.predicate_error.steam.missing_steam_hatch"))); invalidateStructure(substructureName); } From 43a6824405a9979ac74fcb431bcec5406802dfa0 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 9 Jul 2026 20:50:49 -0700 Subject: [PATCH 046/101] errors are not null anymore --- .../gtceu/common/mui/GTMultiblockTextUtil.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/common/mui/GTMultiblockTextUtil.java b/src/main/java/com/gregtechceu/gtceu/common/mui/GTMultiblockTextUtil.java index 6d61e33c5e8..1ff1dcf6501 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/mui/GTMultiblockTextUtil.java +++ b/src/main/java/com/gregtechceu/gtceu/common/mui/GTMultiblockTextUtil.java @@ -51,17 +51,15 @@ public static DynamicWidget addUnformedWarning(MultiblockControllerMachine co () -> new BooleanSyncValue(controller::isFormed)); BooleanSyncValue hasSyncError = syncManager.getOrCreateSyncHandler("hasSyncError", BooleanSyncValue.class, () -> new BooleanSyncValue( - () -> controller.getPatternState(MultiblockControllerMachine.DEFAULT_STRUCTURE).getErrors() != - null)); + () -> controller.getPatternState(MultiblockControllerMachine.DEFAULT_STRUCTURE).hasErrors())); GenericListSyncHandler patternErrors = syncManager.getOrCreateSyncHandler("patternErrors", GenericListSyncHandler.class, () -> GenericListSyncHandler.builder() .getter(() -> { var list = new ArrayList(); for (String structureName : controller.getStructurePatterns().keySet()) { - var errors = controller.getPatternState(structureName) - .getErrors(); - if (errors != null && !errors.isEmpty()) { + var errors = controller.getPatternState(structureName).getErrors(); + if (!errors.isEmpty()) { list.addAll(errors); } } From 3aa727d71fba6ee7574c1a1acad0dc44100c7d50 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 9 Jul 2026 20:51:22 -0700 Subject: [PATCH 047/101] PatternStringError helper methods --- .../api/multiblock/error/PatternStringError.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternStringError.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternStringError.java index 67280cfdab2..55c4e0fefe1 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternStringError.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternStringError.java @@ -28,6 +28,22 @@ public PatternStringError(Component component) { this.component = component; } + public static PatternStringError literal(String s) { + return new PatternStringError(Component.literal(s)); + } + + public static PatternStringError literal(String s, Object... args) { + return new PatternStringError(Component.literal(String.format(s, args))); + } + + public static PatternStringError translatable(String s) { + return new PatternStringError(Component.translatable(s)); + } + + public static PatternStringError translatable(String s, Object... args) { + return new PatternStringError(Component.translatable(s, args)); + } + @Override public PatternErrorUI getPatternErrorUIModifier() { return (parent) -> { From 39bc1ccade5d45890933cd008d371016fe3903d0 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 9 Jul 2026 20:52:32 -0700 Subject: [PATCH 048/101] handle errors better simplify if check --- .../gtceu/api/multiblock/PredicateContext.java | 5 ----- .../multiblock/pattern/BasicSliceStrategy.java | 1 + .../api/multiblock/pattern/BlockPattern.java | 18 +++++++++--------- .../api/multiblock/pattern/PatternState.java | 12 ++++++++++++ 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 3c09cf9af4d..9c4069ded01 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -42,11 +42,6 @@ public boolean error(PatternError error) { return false; } - public void commitErrors() { - this.commitedErrors.addAll(this.errors); - this.errors.clear(); - } - public PredicateContext appendError(PatternError error) { this.errors.add(error); this.lastFailureReason = this.stage.getFailureReason(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java index 16cd1df7c5b..6ec2a2c33b2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java @@ -76,6 +76,7 @@ protected int checkRepeatSlice(PatternState state, int index, int offset, boolea PatternSlice slice = slices.get(index); for (int i = 1; i <= slice.maxRepeats; i++) { boolean res = checkSlice(state, index, offset + i - 1, flip); + state.pushSliceErrors(); if (!res) { if (i <= slice.minRepeats) return -1; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index ca9d0756f1e..5a785946b36 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -154,6 +154,9 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c BlockPos.MutableBlockPos controllerPos = centerPos.mutable(); + // reset predicates for testing + predicates.values().forEach(MultiPredicate::reset); + // handle slices sliceStrategy.setPattern(this); sliceStrategy.start(controllerPos, frontFacing, upwardsFacing); @@ -175,7 +178,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c * * another predicament is handling the edge case of a xor predicate * having two- - * actually i need the xor logic to run in the state check + * actually i could have the xor logic to run in the state check * along with the previously mentioned idea of banned predicates */ @@ -231,14 +234,13 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // internal predicate check, global/slice max checks // if all internal predicates pass, but global/slice max/min checks fail, then do not flip - if (pred.test(patternState)) { - charPos.move(absoluteChar); - patternState.clearErrors(); - // continue... - } else { - patternState.commitErrors(); + if (!pred.test(patternState)) { +// patternState.commitErrors(); return false; } + charPos.move(absoluteChar); + patternState.clearErrors(); + // continue... } stringStart.move(absoluteString); @@ -249,12 +251,10 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p patternState.setStage(PredicateContext.PredicateStage.SLICE_MIN); for (MultiPredicate predicate : predicates.values()) { if (!predicate.testSliceMin(patternState)) { - patternState.commitErrors(); return false; } } - patternState.clearErrors(); return true; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 35cf7bd2123..7383dc1c99f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -71,10 +71,22 @@ public void clearErrors() { List> sliceErrors = new ArrayList<>(); public void commitSliceErrors() { + this.sliceErrors.remove(this.sliceErrors.size() - 1); + this.sliceErrors.forEach(this.commitedErrors::addAll); + clearErrors(); + } + + public void pushSliceErrors() { + if (this.errors.isEmpty()) return; this.sliceErrors.add(List.copyOf(this.errors)); clearErrors(); } + public void commitErrors() { + this.commitedErrors.addAll(this.errors); + clearErrors(); + } + public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState newState) { if (!(currentBlockInfo.getLevel() instanceof ServerLevel serverLevel)) return; if (pos.equals(controllerPos)) { From 04340a3089912e152017a931199940837087ca41 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 9 Jul 2026 20:53:14 -0700 Subject: [PATCH 049/101] another attempt at logic handling for some reason the display widget is busted --- .../multiblock/predicates/MultiPredicate.java | 96 ++++++++++++++++--- 1 file changed, 84 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 467e424ee83..ca9fbc1f8c6 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -48,35 +49,102 @@ public boolean isEmpty() { return this == EMPTY; } + public void reset() { + this.passedPredicates.clear(); + } + + private final List passedPredicates = new ArrayList<>(); + + // this is called for each block /// delegates to {@link #type} to run {@link BasePredicate#testLimited(PredicateContext)} public boolean test(PredicateContext ctx) { + if (isXor() && !passedPredicates.isEmpty()) { + // the idea here is that if we are xor and a predicate previously passed their state check + // ONLY that predicate may pass for future state checks + // logic XOR error + boolean passed = passedPredicates.get(0).testLimited(ctx); + if (!passed) { + ctx.error(PatternStringError.literal("XOR error")); + } + return passed; + } + + // for AND predicates, every predicate in list must pass state check and count for (BasePredicate p : predicateList) { - if (p.testLimited(ctx)) { - return true; + // test deeper for compact predicates + boolean passed = p.test(ctx); + + // passed is for state check + // AND does not care about state checks + // don't include compacted predicates in predicate counts + if (!(p instanceof CompactedPredicate)) { + boolean passedCount = p.testGlobalMax(ctx) && p.testSliceMax(ctx); + if (isAnd()) { + // if failed count checks as AND, early return + if (!passedCount) { + return ctx.error(PatternStringError.literal("AND error")); + } else { + passedPredicates.add(p); + } + } + passed &= passedCount; + } + + // now passed is for global/slice max + state check + if (passed) { + if (isXor() && passedPredicates.isEmpty()) { + passedPredicates.add(p); + return true; + } else if (isAnd()) { + passedPredicates.add(p); + } else { + // OR/SINGLE + return true; + } + } + } + if (isAnd()) { + // logic AND error + boolean passed = passedPredicates.size() == predicateList.size(); + if (!passed) { + ctx.error(PatternStringError.literal("AND error")); } + return passed; } - return false; + return ctx.error(PatternStringError.literal("OR error")); // return getType().run(ctx, this); } /// delegates to {@link #type} to test against global min count public boolean testGlobalMin(PredicateContext ctx) { + if (isXor()) { + // passedPredicates cannot be empty by this point + return passedPredicates.get(0).testGlobalMin(ctx); + } for (BasePredicate p : predicateList) { - if (p.testGlobalMin(ctx)) { - return true; - } + boolean passed = p.testGlobalMin(ctx); + // if AND failed count check, return false, else return true + if (isAnd() && !passed) return false; + else return true; } - return false; + // default return is true for AND, otherwise false + return isAnd(); } /// delegates to {@link #type} to test against slice min count public boolean testSliceMin(PredicateContext ctx) { + if (isXor()) { + // passedPredicates cannot be empty by this point + return passedPredicates.get(0).testSliceMin(ctx); + } for (BasePredicate p : predicateList) { - if (p.testSliceMin(ctx)) { - return true; - } + boolean passed = p.testSliceMin(ctx); + // if AND failed count check, return false, else return true + if (isAnd() && !passed) return false; + else return true; } - return false; + // default return is true for AND, otherwise false + return isAnd(); } protected MultiPredicate addPredicates(Iterable predicates) { @@ -296,9 +364,12 @@ private static void appendPredicate(MultiPredicate source, MultiPredicate dest, * OR logic * at least one of n predicates must be valid * AND logic - * must have n valid predicates in multi + * all predicates must be valid in the multiblock/slice + * this deals with global/slice counts + * AND_SLICE? * XOR logic * must only have one of n predicates be valid and present in multi + * global/slice counts of other predicates must be zero * * when it comes to the internal predicates * any can pass, regardless of logic type @@ -326,6 +397,7 @@ public enum Logic { private class CompactedPredicate extends BasePredicate { + // this should be a different method public MultiPredicate getParent() { return MultiPredicate.this; } From a66a5d6da3682103c5b8b50d47fbacaf47bb2f28 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 9 Jul 2026 20:53:34 -0700 Subject: [PATCH 050/101] spotless --- .../gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 5a785946b36..3089639192a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -235,7 +235,7 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // internal predicate check, global/slice max checks // if all internal predicates pass, but global/slice max/min checks fail, then do not flip if (!pred.test(patternState)) { -// patternState.commitErrors(); + // patternState.commitErrors(); return false; } charPos.move(absoluteChar); From bec5238e6efa8edfa79926a8687f1131a4329e1f Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 11 Jul 2026 19:04:28 -0700 Subject: [PATCH 051/101] only test visited predicates for slice check global/slice passed predicates and reset methods reset failure reason on clear private appendError --- .../api/multiblock/PredicateContext.java | 7 +- .../api/multiblock/pattern/BlockPattern.java | 7 +- .../api/multiblock/pattern/PatternState.java | 2 +- .../multiblock/predicates/MultiPredicate.java | 157 ++++++++++++------ 4 files changed, 118 insertions(+), 55 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 9c4069ded01..57c3ebaf660 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -29,10 +29,10 @@ public class PredicateContext { protected final Object2IntMap layerCount = new Object2IntOpenHashMap<>(); @Getter - private FailureReason lastFailureReason = FailureReason.NONE; + protected FailureReason lastFailureReason = FailureReason.NONE; @Setter - private PredicateStage stage = PredicateStage.INTERNAL; + protected PredicateStage stage = PredicateStage.INTERNAL; /// accepts a pattern error /// @@ -42,10 +42,9 @@ public boolean error(PatternError error) { return false; } - public PredicateContext appendError(PatternError error) { + private void appendError(PatternError error) { this.errors.add(error); this.lastFailureReason = this.stage.getFailureReason(); - return this; } public List getErrors() { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 3089639192a..2ce5fea2d08 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -155,7 +155,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c BlockPos.MutableBlockPos controllerPos = centerPos.mutable(); // reset predicates for testing - predicates.values().forEach(MultiPredicate::reset); + predicates.values().forEach(MultiPredicate::resetGlobal); // handle slices sliceStrategy.setPattern(this); @@ -224,7 +224,9 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // theoretically, predicates could track their own current layer/global count patternState.layerCache().clear(); + predicates.values().forEach(MultiPredicate::resetSlice); + Set visitedPredicates = new HashSet<>(); for (int stringIdx = 0; stringIdx < dimensions[1]; stringIdx++) { for (int charIdx = 0; charIdx < dimensions[2]; charIdx++) { patternState.setPos(charPos); @@ -238,6 +240,7 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // patternState.commitErrors(); return false; } + visitedPredicates.add(pred); charPos.move(absoluteChar); patternState.clearErrors(); // continue... @@ -249,7 +252,7 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // slice min check patternState.setStage(PredicateContext.PredicateStage.SLICE_MIN); - for (MultiPredicate predicate : predicates.values()) { + for (MultiPredicate predicate : visitedPredicates) { if (!predicate.testSliceMin(patternState)) { return false; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 7383dc1c99f..471c8f1cacf 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -66,6 +66,7 @@ public boolean hasErrors() { public void clearErrors() { this.errors.clear(); + this.lastFailureReason = FailureReason.NONE; } List> sliceErrors = new ArrayList<>(); @@ -77,7 +78,6 @@ public void commitSliceErrors() { } public void pushSliceErrors() { - if (this.errors.isEmpty()) return; this.sliceErrors.add(List.copyOf(this.errors)); clearErrors(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index ca9fbc1f8c6..b8886d51325 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -2,6 +2,7 @@ import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; +import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -49,101 +50,145 @@ public boolean isEmpty() { return this == EMPTY; } - public void reset() { + public void resetGlobal() { this.passedPredicates.clear(); + resetSlice(); } - private final List passedPredicates = new ArrayList<>(); + public void resetSlice() { + this.passedSlicePredicates.clear(); + } + + private final Set passedPredicates = new HashSet<>(); + private final Set passedSlicePredicates = new HashSet<>(); + + private void predicatePassed(BasePredicate p) { + this.passedPredicates.add(p); + this.passedSlicePredicates.add(p); + } // this is called for each block /// delegates to {@link #type} to run {@link BasePredicate#testLimited(PredicateContext)} public boolean test(PredicateContext ctx) { if (isXor() && !passedPredicates.isEmpty()) { // the idea here is that if we are xor and a predicate previously passed their state check - // ONLY that predicate may pass for future state checks + // ONLY that predicate may pass for future state/count checks // logic XOR error - boolean passed = passedPredicates.get(0).testLimited(ctx); + boolean passed = passedPredicates.iterator().next().testLimited(ctx); if (!passed) { ctx.error(PatternStringError.literal("XOR error")); } return passed; } - // for AND predicates, every predicate in list must pass state check and count + // for AND predicates, every predicate in list must pass count checks + // AND does not care about state checks for (BasePredicate p : predicateList) { - // test deeper for compact predicates - boolean passed = p.test(ctx); - - // passed is for state check - // AND does not care about state checks - // don't include compacted predicates in predicate counts - if (!(p instanceof CompactedPredicate)) { - boolean passedCount = p.testGlobalMax(ctx) && p.testSliceMax(ctx); - if (isAnd()) { - // if failed count checks as AND, early return - if (!passedCount) { - return ctx.error(PatternStringError.literal("AND error")); - } else { - passedPredicates.add(p); - } - } - passed &= passedCount; - } + boolean passed = p.testLimited(ctx); - // now passed is for global/slice max + state check - if (passed) { - if (isXor() && passedPredicates.isEmpty()) { - passedPredicates.add(p); - return true; - } else if (isAnd()) { - passedPredicates.add(p); - } else { - // OR/SINGLE + if (isXor()) { + if (passed && passedPredicates.isEmpty()) { + predicatePassed(p); return true; } + // continue... + } else if (isAnd()) { + PredicateContext.FailureReason reason = ctx.getLastFailureReason(); + switch (reason) { + case GLOBAL_MAX, SLICE_MAX -> { + if (!passed) ctx.error(PatternStringError.literal("AND error")); + return passed; + } + default -> predicatePassed(p); + // continue... + } + } else if (passed) { + // OR/SINGLE + return true; } } + if (isAnd()) { - // logic AND error - boolean passed = passedPredicates.size() == predicateList.size(); - if (!passed) { - ctx.error(PatternStringError.literal("AND error")); - } - return passed; + // check AND later + return true; } + + if (isXor()) { + // do something + if (!passedSlicePredicates.isEmpty()) return true; + return ctx.error(PatternStringError.literal("XOR error")); + } + return ctx.error(PatternStringError.literal("OR error")); - // return getType().run(ctx, this); } /// delegates to {@link #type} to test against global min count public boolean testGlobalMin(PredicateContext ctx) { if (isXor()) { - // passedPredicates cannot be empty by this point - return passedPredicates.get(0).testGlobalMin(ctx); + if (passedPredicates.isEmpty()) return ctx.error(PatternStringError.literal("XOR error")); + + BasePredicate selected = passedPredicates.iterator().next(); + if (!selected.testGlobalMin(ctx)) return ctx.error(PatternStringError.literal("XOR error")); + // for every other predicate + for (BasePredicate p : predicateList) { + if (p == selected) continue; + // cannot be globally present + if (ctx.getGlobalCount(p) > 0) { + return ctx.error(PatternStringError.literal("XOR error")); + } + } + return true; + } + if (isAnd()) { + if (passedPredicates.size() != predicateList.size()) return ctx.error(PatternStringError.literal("AND error")); + // passed predicates should include all predicates that passed their max count checks } for (BasePredicate p : predicateList) { boolean passed = p.testGlobalMin(ctx); // if AND failed count check, return false, else return true - if (isAnd() && !passed) return false; - else return true; + if (isAnd() ^ passed) { + if (isAnd()) ctx.error(PatternStringError.literal("AND error")); + return passed; + } } // default return is true for AND, otherwise false + if (!isAnd()) ctx.error(PatternStringError.literal("OR error")); return isAnd(); } /// delegates to {@link #type} to test against slice min count public boolean testSliceMin(PredicateContext ctx) { if (isXor()) { - // passedPredicates cannot be empty by this point - return passedPredicates.get(0).testSliceMin(ctx); + if (passedSlicePredicates.isEmpty()) { + return ctx.error(PatternStringError.literal("XOR error")); + } + + BasePredicate selected = passedSlicePredicates.iterator().next(); + if (!selected.testSliceMin(ctx)) { + return ctx.error(PatternStringError.literal("XOR error")); + } + // for every other predicate + for (BasePredicate p : predicateList) { + if (p == selected) continue; + // cannot be present in slice + // todo make configurable? + if (ctx.getSliceCount(p) > 0) { + return ctx.error(PatternStringError.literal("Predicate " + p + + " must not be present in slice " + ctx.pos())); + } + } + return true; } for (BasePredicate p : predicateList) { boolean passed = p.testSliceMin(ctx); // if AND failed count check, return false, else return true - if (isAnd() && !passed) return false; - else return true; + if (isAnd() ^ passed) { + if (isAnd()) ctx.error(PatternStringError.literal("AND error")); + return passed; + } } // default return is true for AND, otherwise false + if (!isAnd()) ctx.error(PatternStringError.literal("OR error")); return isAnd(); } @@ -404,10 +449,26 @@ public MultiPredicate getParent() { @Override public boolean test(PredicateContext ctx) { - // this also tests global/slice max, but with no respect to logic type + // test parent predicates return getParent().test(ctx); } + @Override + public boolean testGlobalMax(PredicateContext ctx) { + for (BasePredicate p : getParent()) { + if (p.testGlobalMax(ctx)) return true; + } + return false; + } + + @Override + public boolean testSliceMax(PredicateContext ctx) { + for (BasePredicate p : getParent()) { + if (p.testSliceMax(ctx)) return true; + } + return false; + } + @Override public boolean testGlobalMin(PredicateContext ctx) { return getParent().testGlobalMin(ctx); From b7d92a93a9610de99a37004e0555b0f96a86225c Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Tue, 14 Jul 2026 23:47:45 -0700 Subject: [PATCH 052/101] notes --- .../api/multiblock/predicates/MultiPredicate.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index b8886d51325..a86b5cf9451 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -82,7 +82,6 @@ public boolean test(PredicateContext ctx) { } // for AND predicates, every predicate in list must pass count checks - // AND does not care about state checks for (BasePredicate p : predicateList) { boolean passed = p.testLimited(ctx); @@ -93,8 +92,8 @@ public boolean test(PredicateContext ctx) { } // continue... } else if (isAnd()) { - PredicateContext.FailureReason reason = ctx.getLastFailureReason(); - switch (reason) { + // AND does not care about state checks + switch (ctx.getLastFailureReason()) { case GLOBAL_MAX, SLICE_MAX -> { if (!passed) ctx.error(PatternStringError.literal("AND error")); return passed; @@ -436,8 +435,10 @@ private static void appendPredicate(MultiPredicate source, MultiPredicate dest, public enum Logic { SINGLE, OR, - AND, - XOR; + AND, // AND_GLOBAL + // AND_SLICE + XOR // XOR_GLOBAL + // XOR_SLICE } private class CompactedPredicate extends BasePredicate { From 86e1628b807b296f7a1bfdef3130d40a1a0a18c1 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 15 Jul 2026 00:27:03 -0700 Subject: [PATCH 053/101] move logic out into own classes --- .../multiblock/predicates/BasePredicate.java | 12 +- .../multiblock/predicates/MultiPredicate.java | 177 +++--------------- .../multiblock/predicates/logic/AndLogic.java | 50 +++++ .../predicates/logic/BaseLogic.java | 23 +++ .../multiblock/predicates/logic/OrLogic.java | 48 +++++ .../multiblock/predicates/logic/XorLogic.java | 65 +++++++ 6 files changed, 218 insertions(+), 157 deletions(-) create mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java create mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java create mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java create mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 2264b7e912b..e44da2da014 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -157,24 +157,20 @@ protected void appendContents(StringBuilder builder) {} protected void appendStats(StringBuilder builder) { if (minCount != -1 && maxCount != -1) { - builder.append("global=[%02d,%02d] ".formatted(minCount, maxCount)); + builder.append("g[%d,%d] ".formatted(minCount, maxCount)); } if (minSliceCount != -1 && maxSliceCount != -1) { - builder.append("slice=[%02d,%02d] ".formatted(minSliceCount, maxSliceCount)); - } - if (previewCount != -1) { - builder.append("preview=%02d".formatted(previewCount)); + builder.append("s[%d,%d] ".formatted(minSliceCount, maxSliceCount)); } } @Override public String toString() { StringBuilder builder = new StringBuilder(getTypeName()); - builder.append('{'); + builder.append(" "); appendStats(builder); - builder.append("contents=["); + builder.append('{'); appendContents(builder); - builder.append(']'); builder.append('}'); return builder.toString(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index a86b5cf9451..4880da8851c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -1,8 +1,10 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; -import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; +import com.gregtechceu.gtceu.api.multiblock.predicates.logic.AndLogic; +import com.gregtechceu.gtceu.api.multiblock.predicates.logic.BaseLogic; +import com.gregtechceu.gtceu.api.multiblock.predicates.logic.OrLogic; +import com.gregtechceu.gtceu.api.multiblock.predicates.logic.XorLogic; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -23,8 +25,7 @@ public class MultiPredicate implements Iterable { private static final MultiPredicate EMPTY = new MultiPredicate(); private final List predicateList = new ObjectArrayList<>(); - @Getter(AccessLevel.PROTECTED) - private final Logic type; + private final BaseLogic logic; private final boolean hasAir; @Getter private boolean controller; @@ -36,12 +37,16 @@ public class MultiPredicate implements Iterable { } private MultiPredicate(Logic type, boolean hasAir) { - this.type = type; this.hasAir = hasAir; + this.logic = switch (type) { + case AND -> new AndLogic(this); + case XOR -> new XorLogic(this); + default -> new OrLogic(this); + }; } - private MultiPredicate() { - this.type = Logic.SINGLE; + MultiPredicate() { + this.logic = new OrLogic(this); this.hasAir = isAir(); } @@ -51,6 +56,7 @@ public boolean isEmpty() { } public void resetGlobal() { + this.logic.reset(); this.passedPredicates.clear(); resetSlice(); } @@ -68,127 +74,19 @@ private void predicatePassed(BasePredicate p) { } // this is called for each block - /// delegates to {@link #type} to run {@link BasePredicate#testLimited(PredicateContext)} + /// delegates to {@link #logic} to run {@link BasePredicate#testLimited(PredicateContext)} public boolean test(PredicateContext ctx) { - if (isXor() && !passedPredicates.isEmpty()) { - // the idea here is that if we are xor and a predicate previously passed their state check - // ONLY that predicate may pass for future state/count checks - // logic XOR error - boolean passed = passedPredicates.iterator().next().testLimited(ctx); - if (!passed) { - ctx.error(PatternStringError.literal("XOR error")); - } - return passed; - } - - // for AND predicates, every predicate in list must pass count checks - for (BasePredicate p : predicateList) { - boolean passed = p.testLimited(ctx); - - if (isXor()) { - if (passed && passedPredicates.isEmpty()) { - predicatePassed(p); - return true; - } - // continue... - } else if (isAnd()) { - // AND does not care about state checks - switch (ctx.getLastFailureReason()) { - case GLOBAL_MAX, SLICE_MAX -> { - if (!passed) ctx.error(PatternStringError.literal("AND error")); - return passed; - } - default -> predicatePassed(p); - // continue... - } - } else if (passed) { - // OR/SINGLE - return true; - } - } - - if (isAnd()) { - // check AND later - return true; - } - - if (isXor()) { - // do something - if (!passedSlicePredicates.isEmpty()) return true; - return ctx.error(PatternStringError.literal("XOR error")); - } - - return ctx.error(PatternStringError.literal("OR error")); + return this.logic.test(ctx); } - /// delegates to {@link #type} to test against global min count + /// delegates to {@link #logic} to test against global min count public boolean testGlobalMin(PredicateContext ctx) { - if (isXor()) { - if (passedPredicates.isEmpty()) return ctx.error(PatternStringError.literal("XOR error")); - - BasePredicate selected = passedPredicates.iterator().next(); - if (!selected.testGlobalMin(ctx)) return ctx.error(PatternStringError.literal("XOR error")); - // for every other predicate - for (BasePredicate p : predicateList) { - if (p == selected) continue; - // cannot be globally present - if (ctx.getGlobalCount(p) > 0) { - return ctx.error(PatternStringError.literal("XOR error")); - } - } - return true; - } - if (isAnd()) { - if (passedPredicates.size() != predicateList.size()) return ctx.error(PatternStringError.literal("AND error")); - // passed predicates should include all predicates that passed their max count checks - } - for (BasePredicate p : predicateList) { - boolean passed = p.testGlobalMin(ctx); - // if AND failed count check, return false, else return true - if (isAnd() ^ passed) { - if (isAnd()) ctx.error(PatternStringError.literal("AND error")); - return passed; - } - } - // default return is true for AND, otherwise false - if (!isAnd()) ctx.error(PatternStringError.literal("OR error")); - return isAnd(); + return this.logic.testGlobalMin(ctx); } - /// delegates to {@link #type} to test against slice min count + /// delegates to {@link #logic} to test against slice min count public boolean testSliceMin(PredicateContext ctx) { - if (isXor()) { - if (passedSlicePredicates.isEmpty()) { - return ctx.error(PatternStringError.literal("XOR error")); - } - - BasePredicate selected = passedSlicePredicates.iterator().next(); - if (!selected.testSliceMin(ctx)) { - return ctx.error(PatternStringError.literal("XOR error")); - } - // for every other predicate - for (BasePredicate p : predicateList) { - if (p == selected) continue; - // cannot be present in slice - // todo make configurable? - if (ctx.getSliceCount(p) > 0) { - return ctx.error(PatternStringError.literal("Predicate " + p + - " must not be present in slice " + ctx.pos())); - } - } - return true; - } - for (BasePredicate p : predicateList) { - boolean passed = p.testSliceMin(ctx); - // if AND failed count check, return false, else return true - if (isAnd() ^ passed) { - if (isAnd()) ctx.error(PatternStringError.literal("AND error")); - return passed; - } - } - // default return is true for AND, otherwise false - if (!isAnd()) ctx.error(PatternStringError.literal("OR error")); - return isAnd(); + return this.logic.testSliceMin(ctx); } protected MultiPredicate addPredicates(Iterable predicates) { @@ -208,19 +106,15 @@ public List> getCandidates() { } public boolean isOr() { - return this.type == Logic.OR; + return this.logic instanceof OrLogic; } public boolean isAnd() { - return this.type == Logic.AND; + return this.logic instanceof AndLogic; } public boolean isXor() { - return this.type == Logic.XOR; - } - - protected boolean sameType(MultiPredicate other) { - return this.type == other.type; + return this.logic instanceof XorLogic; } public boolean isAny() { @@ -340,11 +234,7 @@ public MultiPredicate xor(MultiPredicate other) { } public boolean isSingle() { - return getType() == Logic.SINGLE; - } - - public String getTypeName() { - return String.valueOf(this.type); + return predicateList.size() == 1; } protected void appendContents(StringBuilder builder) { @@ -355,7 +245,7 @@ protected void appendContents(StringBuilder builder) { @Override public String toString() { - StringBuilder builder = new StringBuilder(getTypeName()); + StringBuilder builder = new StringBuilder("MulitPredicate"); if (isController()) builder.append("[Controller]"); builder.append('{'); appendContents(builder); @@ -397,7 +287,7 @@ private static MultiPredicate combine(MultiPredicate a, Logic type, @Nullable Mu private static void appendPredicate(MultiPredicate source, MultiPredicate dest, Logic type) { if (source.isSingle()) { dest.addPredicate(source.predicateList.get(0)); - } else if (source.type != type) { + } else if (source.logic.getType() != type) { dest.addPredicate(source.compact()); } else { dest.addPredicates(source); @@ -455,19 +345,8 @@ public boolean test(PredicateContext ctx) { } @Override - public boolean testGlobalMax(PredicateContext ctx) { - for (BasePredicate p : getParent()) { - if (p.testGlobalMax(ctx)) return true; - } - return false; - } - - @Override - public boolean testSliceMax(PredicateContext ctx) { - for (BasePredicate p : getParent()) { - if (p.testSliceMax(ctx)) return true; - } - return false; + public boolean testLimited(PredicateContext ctx) { + return this.test(ctx); } @Override @@ -490,7 +369,7 @@ public List computeCandidates() { @Override public String getTypeName() { - return getParent().getTypeName(); + return "CompactedPredicate"; } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java new file mode 100644 index 00000000000..9fe36637e3d --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -0,0 +1,50 @@ +package com.gregtechceu.gtceu.api.multiblock.predicates.logic; + +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; + +public class AndLogic extends BaseLogic { + public AndLogic(MultiPredicate rootPredicate) { + super(rootPredicate); + } + + @Override + public boolean test(PredicateContext ctx) { + for (BasePredicate predicate : this.rootPredicate) { + boolean result = predicate.testLimited(ctx); + if (result) continue; + switch (ctx.getLastFailureReason()) { + case SLICE_MAX, GLOBAL_MAX -> { + return false; + } + } + } + return false; + } + + @Override + public boolean testGlobalMin(PredicateContext ctx) { + for (BasePredicate predicate : this.rootPredicate) { + if (!predicate.testGlobalMin(ctx)) { + return false; + } + } + return true; + } + + @Override + public boolean testSliceMin(PredicateContext ctx) { + for (BasePredicate predicate : this.rootPredicate) { + if (!predicate.testSliceMin(ctx)) { + return false; + } + } + return true; + } + + @Override + public MultiPredicate.Logic getType() { + return MultiPredicate.Logic.AND; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java new file mode 100644 index 00000000000..11fd00ea34b --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java @@ -0,0 +1,23 @@ +package com.gregtechceu.gtceu.api.multiblock.predicates.logic; + +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; + +public abstract class BaseLogic { + + protected final MultiPredicate rootPredicate; + + public BaseLogic(MultiPredicate rootPredicate) { + this.rootPredicate = rootPredicate; + } + + public void reset() {} + + public abstract boolean test(PredicateContext ctx); + + public abstract boolean testGlobalMin(PredicateContext ctx); + + public abstract boolean testSliceMin(PredicateContext ctx); + + public abstract MultiPredicate.Logic getType(); +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java new file mode 100644 index 00000000000..4beab468bac --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java @@ -0,0 +1,48 @@ +package com.gregtechceu.gtceu.api.multiblock.predicates.logic; + +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; + +public class OrLogic extends BaseLogic { + + public OrLogic(MultiPredicate rootPredicate) { + super(rootPredicate); + } + + @Override + public boolean test(PredicateContext ctx) { + for (BasePredicate predicate : this.rootPredicate) { + if (predicate.testLimited(ctx)) { + return true; + } + } + return ctx.error(PatternStringError.literal("OR error")); + } + + @Override + public boolean testGlobalMin(PredicateContext ctx) { + for (BasePredicate predicate : this.rootPredicate) { + if (predicate.testGlobalMin(ctx)) { + return true; + } + } + return ctx.error(PatternStringError.literal("OR error")); + } + + @Override + public boolean testSliceMin(PredicateContext ctx) { + for (BasePredicate predicate : this.rootPredicate) { + if (predicate.testSliceMin(ctx)) { + return true; + } + } + return ctx.error(PatternStringError.literal("OR error")); + } + + @Override + public MultiPredicate.Logic getType() { + return MultiPredicate.Logic.OR; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java new file mode 100644 index 00000000000..dee59e6c444 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -0,0 +1,65 @@ +package com.gregtechceu.gtceu.api.multiblock.predicates.logic; + +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; + +public class XorLogic extends BaseLogic { + + private BasePredicate passedPredicate; + + public XorLogic(MultiPredicate rootPredicate) { + super(rootPredicate); + } + + @Override + public void reset() { + this.passedPredicate = null; + } + + @Override + public boolean test(PredicateContext ctx) { + if (passedPredicate != null) { + return passedPredicate.testLimited(ctx) || ctx.error(PatternStringError.literal("XOR error")); + } + for (BasePredicate predicate : this.rootPredicate) { + if (predicate.testLimited(ctx) && this.passedPredicate == null) { + this.passedPredicate = predicate; + return true; + } + } + return ctx.error(PatternStringError.literal("XOR error")); + } + + @Override + public boolean testGlobalMin(PredicateContext ctx) { + if (passedPredicate == null || !passedPredicate.testGlobalMin(ctx)) { + return ctx.error(PatternStringError.literal("XOR error")); + } + for (BasePredicate predicate : this.rootPredicate) { + if (predicate != passedPredicate && ctx.getGlobalCount(predicate) > 0) { + return ctx.error(PatternStringError.literal("XOR error")); + } + } + return true; + } + + @Override + public boolean testSliceMin(PredicateContext ctx) { + if (passedPredicate == null || !passedPredicate.testSliceMin(ctx)) { + return ctx.error(PatternStringError.literal("XOR error")); + } + for (BasePredicate predicate : this.rootPredicate) { + if (predicate != passedPredicate && ctx.getSliceCount(predicate) > 0) { + return ctx.error(PatternStringError.literal("XOR error")); + } + } + return true; + } + + @Override + public MultiPredicate.Logic getType() { + return MultiPredicate.Logic.XOR; + } +} From 976425b089f534c2a6f3405e1c650e48a1d73cec Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 15 Jul 2026 23:25:31 -0700 Subject: [PATCH 054/101] fix rebase --- .../java/com/gregtechceu/gtceu/api/multiblock/Predicates.java | 4 ++-- .../gtceu/api/multiblock/pattern/BlockPattern.java | 4 ++-- .../api/multiblock/pattern/MultiblockPatternBuilder.java | 3 ++- .../gtceu/api/multiblock/util/BlockPatternHelper.java | 3 ++- .../gregtechceu/gtceu/common/data/machines/GCYMMachines.java | 1 + .../gtceu/common/data/machines/GTMachineUtils.java | 1 + .../multiblock/primitive/CharcoalPileIgniterMachine.java | 4 ++-- 7 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 7bcffd42716..67947eda061 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -196,11 +196,11 @@ public static MultiPredicate customPredicate(@Nullable String debugName, } public static MultiPredicate any() { - return BasePredicate.ANY; + return MultiPredicate.ANY; } public static MultiPredicate air() { - return BasePredicate.AIR; + return MultiPredicate.AIR; } public static MultiPredicate abilities(PartAbility ability) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 2ce5fea2d08..6892d3545f2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -155,7 +155,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c BlockPos.MutableBlockPos controllerPos = centerPos.mutable(); // reset predicates for testing - predicates.values().forEach(MultiPredicate::resetGlobal); + predicates.values().forEach(MultiPredicate::reset); // handle slices sliceStrategy.setPattern(this); @@ -224,7 +224,7 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // theoretically, predicates could track their own current layer/global count patternState.layerCache().clear(); - predicates.values().forEach(MultiPredicate::resetSlice); + predicates.values().forEach(MultiPredicate::reset); Set visitedPredicates = new HashSet<>(); for (int stringIdx = 0; stringIdx < dimensions[1]; stringIdx++) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java index 2acb3a76a6f..3c733175f77 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; +import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; @@ -63,7 +64,7 @@ private MultiblockPatternBuilder(RelativeDirection sliceDir, RelativeDirection s directions[2] = charDir; RelativeDirection.validateFacingsArray(directions); // todo is this wanted? - this.symbolMap.put(' ', BasePredicate.ANY); + this.symbolMap.put(' ', Predicates.any()); } public MultiblockPatternBuilder sliceRepeatable(int minRepeats, int maxRepeats, String... slice) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java index 6eed8a1b615..f1656d82015 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java @@ -1,5 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock.util; +import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.BlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.PatternSlice; @@ -35,7 +36,7 @@ public MultiPredicate getPredicateFromPos(IBlockPattern pattern, BlockPos pos, if (pos.getX() < 0 || pos.getX() >= dimensions.getX() || pos.getY() < 0 || pos.getY() >= dimensions.getY() || pos.getZ() < 0 || pos.getZ() >= dimensions.getZ()) { - return BasePredicate.AIR; + return Predicates.air(); } char c = adjustedBlockPattern[pos.getX()][pos.getY()][pos.getZ()]; return blockPattern.getPredicates().get(c); diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java index 7fab1ece5e5..5daf85e9711 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java @@ -17,6 +17,7 @@ import com.gregtechceu.gtceu.common.data.GTMaterials; import com.gregtechceu.gtceu.common.data.GTRecipeModifiers; import com.gregtechceu.gtceu.common.data.GTRecipeTypes; +import com.gregtechceu.gtceu.common.machine.GTMachineInstanceFactories; import com.gregtechceu.gtceu.common.machine.multiblock.electric.DistillationTowerMachine; import com.gregtechceu.gtceu.common.machine.multiblock.electric.gcym.*; import com.gregtechceu.gtceu.common.machine.multiblock.part.ParallelHatchPartMachine; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 3d7a6d038cd..0c620ee5443 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -23,6 +23,7 @@ import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; import com.gregtechceu.gtceu.api.mui.factory.PanelFactory; import com.gregtechceu.gtceu.api.multiblock.Predicates; +import com.gregtechceu.gtceu.api.multiblock.error.PartAbilityError; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java index 36f737572d7..f24a9f50a4c 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java @@ -117,7 +117,7 @@ public static Function getPattern() return (definition) -> { var floor = Predicates.blocks(Blocks.BRICKS); - var logs = BasePredicate.AIR.or(logPredicate()); + var logs = Predicates.air().or(logPredicate()); var walls = wallPredicate(); return ExpandableMultiblockPatternBuilder @@ -139,7 +139,7 @@ public static Function getPattern() if (bp.getY() == -b.get(2) || bp.getY() == b.get(3)) intersects++; if (bp.getZ() == b.get(4) || bp.getZ() == -b.get(5)) intersects++; - if (intersects >= 2) return BasePredicate.ANY; + if (intersects >= 2) return Predicates.any(); if (intersects == 1) { if (bottomAisle) return floor; From 43bbc0b9b93f7b1b1124783860a1e76a94aae236 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 15 Jul 2026 23:26:30 -0700 Subject: [PATCH 055/101] add libs as flatdir --- gradle/scripts/repositories.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/gradle/scripts/repositories.gradle b/gradle/scripts/repositories.gradle index ec88ce35dd9..fc6ba281dd1 100644 --- a/gradle/scripts/repositories.gradle +++ b/gradle/scripts/repositories.gradle @@ -41,6 +41,7 @@ repositories { url = "https://maven.firstdark.dev/snapshots" } + flatDir dirs: 'libs' exclusiveContent { // Create, Ponder, Flywheel forRepository { maven { url = "https://maven.createmod.net" } } From d248a38bd82d420c12c1d42c9bb88c77d089ded2 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 15 Jul 2026 23:31:08 -0700 Subject: [PATCH 056/101] improve MultiPredicate constructors bit more work on the logics remove redundant code split air/any predicate set parent in BasePredicate seperate parent in compact predicate move anon BasePredicate class to named class --- .../multiblock/predicates/BasePredicate.java | 43 ++----- .../multiblock/predicates/MultiPredicate.java | 105 +++++++++--------- .../predicates/SinglePredicate.java | 49 ++++++++ .../multiblock/predicates/logic/AndLogic.java | 9 +- .../predicates/logic/BaseLogic.java | 18 +++ .../multiblock/predicates/logic/XorLogic.java | 6 +- 6 files changed, 138 insertions(+), 92 deletions(-) create mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/SinglePredicate.java diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index e44da2da014..39879dab2ca 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -22,10 +22,9 @@ public abstract class BasePredicate { - // should air use isAir() instead of checking for air block directly? - public static final MultiPredicate AIR = create("Air", ctx -> ctx.state().is(Blocks.AIR)); + static final BasePredicate AIR = of("Air", ctx -> ctx.state().isAir(), Stream.empty(), null); - public static final MultiPredicate ANY = create("Any", ctx -> true); + static final BasePredicate ANY = of("Any", ctx -> true, Stream.empty(), null); private @Nullable List candidates; @@ -53,8 +52,12 @@ public abstract class BasePredicate { @Getter @Setter private @Nullable String nbtParser; // unsure what this does + @Setter + private @Nullable MultiPredicate parent; - public abstract MultiPredicate getParent(); + public MultiPredicate getParent() { + return Objects.requireNonNull(this.parent); + } /// the main testing method public abstract boolean test(PredicateContext ctx); @@ -185,36 +188,8 @@ public static MultiPredicate create(@Nullable String debugName, Predicate predicate, + static BasePredicate of(@Nullable String debugName, Predicate predicate, Stream candidateStream, @Nullable Consumer contents) { - return new BasePredicate() { - - @Override - public MultiPredicate getParent() { - return parent; - } - - @Override - public boolean test(PredicateContext ctx) { - return predicate.test(ctx); - } - - @Override - public List computeCandidates() { - return candidateStream.toList(); - } - - @Override - public String getTypeName() { - return Objects.requireNonNullElse(debugName, "Predicate"); - } - - @Override - protected void appendContents(StringBuilder builder) { - if (contents != null) { - contents.accept(builder); - } - } - }; + return new SinglePredicate(predicate, candidateStream, debugName, contents); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 4880da8851c..ab5fd6f2df9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -8,7 +8,6 @@ import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import lombok.AccessLevel; import lombok.Getter; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -22,9 +21,15 @@ public class MultiPredicate implements Iterable { private static final Comparator PREDICATE_COMPARATOR = Comparator .comparingInt(BasePredicate::getPriority); - private static final MultiPredicate EMPTY = new MultiPredicate(); + + private static final MultiPredicate EMPTY = new MultiPredicate(Logic.OR, false); + + public static final MultiPredicate AIR = new MultiPredicate(BasePredicate.AIR); + + public static final MultiPredicate ANY = new MultiPredicate(BasePredicate.ANY); private final List predicateList = new ObjectArrayList<>(); + @Getter private final BaseLogic logic; private final boolean hasAir; @Getter @@ -32,53 +37,29 @@ public class MultiPredicate implements Iterable { MultiPredicate(@Nullable String debugName, Predicate predicate, Stream candidateStream, @Nullable Consumer contents) { - this(); - addPredicate(BasePredicate.of(this, debugName, predicate, candidateStream, contents)); - } - - private MultiPredicate(Logic type, boolean hasAir) { - this.hasAir = hasAir; - this.logic = switch (type) { - case AND -> new AndLogic(this); - case XOR -> new XorLogic(this); - default -> new OrLogic(this); - }; + this(BasePredicate.of(debugName, predicate, candidateStream, contents)); } - MultiPredicate() { - this.logic = new OrLogic(this); - this.hasAir = isAir(); + MultiPredicate(BasePredicate predicate) { + this(Logic.OR, predicate == BasePredicate.AIR); + addPredicate(predicate); } - @ApiStatus.Internal - public boolean isEmpty() { - return this == EMPTY; + private MultiPredicate(Logic type, boolean hasAir) { + this.hasAir = hasAir; + this.logic = type.createLogic(this); } - public void resetGlobal() { + public void reset() { this.logic.reset(); - this.passedPredicates.clear(); - resetSlice(); - } - - public void resetSlice() { - this.passedSlicePredicates.clear(); } - private final Set passedPredicates = new HashSet<>(); - private final Set passedSlicePredicates = new HashSet<>(); - - private void predicatePassed(BasePredicate p) { - this.passedPredicates.add(p); - this.passedSlicePredicates.add(p); - } // this is called for each block /// delegates to {@link #logic} to run {@link BasePredicate#testLimited(PredicateContext)} public boolean test(PredicateContext ctx) { return this.logic.test(ctx); } - /// delegates to {@link #logic} to test against global min count public boolean testGlobalMin(PredicateContext ctx) { return this.logic.testGlobalMin(ctx); @@ -90,12 +71,15 @@ public boolean testSliceMin(PredicateContext ctx) { } protected MultiPredicate addPredicates(Iterable predicates) { - predicates.forEach(this::addPredicate); + for (BasePredicate predicate : predicates) { + addPredicate(predicate); + } return this; } protected MultiPredicate addPredicate(BasePredicate predicate) { this.predicateList.add(predicate); + predicate.setParent(this); return this; } @@ -117,20 +101,25 @@ public boolean isXor() { return this.logic instanceof XorLogic; } + @ApiStatus.Internal + public boolean isEmpty() { + return this == EMPTY; + } + public boolean isAny() { - return this == BasePredicate.ANY; + return this == ANY; } public boolean isAir() { - return this == BasePredicate.AIR; + return this == AIR; } public boolean hasAir() { - return this.isAir() || this.hasAir; + return this.hasAir; } protected BasePredicate compact() { - return new CompactedPredicate(); + return new CompactedPredicate(this); } public MultiPredicate setMinGlobalLimited(int min) { @@ -323,25 +312,35 @@ private static void appendPredicate(MultiPredicate source, MultiPredicate dest, * what i really need to do is track passed vs failed predicates */ public enum Logic { - SINGLE, OR, - AND, // AND_GLOBAL - // AND_SLICE - XOR // XOR_GLOBAL - // XOR_SLICE + AND, + XOR; + + public BaseLogic createLogic(MultiPredicate source) { + return switch (this) { + case AND -> new AndLogic(source); + case XOR -> new XorLogic(source); + default -> new OrLogic(source); + }; + } } - private class CompactedPredicate extends BasePredicate { + public static class CompactedPredicate extends BasePredicate { + + private final MultiPredicate root; + + private CompactedPredicate(MultiPredicate root) { + this.root = root; + } - // this should be a different method - public MultiPredicate getParent() { - return MultiPredicate.this; + public MultiPredicate expand() { + return this.root; } @Override public boolean test(PredicateContext ctx) { // test parent predicates - return getParent().test(ctx); + return expand().test(ctx); } @Override @@ -351,17 +350,17 @@ public boolean testLimited(PredicateContext ctx) { @Override public boolean testGlobalMin(PredicateContext ctx) { - return getParent().testGlobalMin(ctx); + return expand().testGlobalMin(ctx); } @Override public boolean testSliceMin(PredicateContext ctx) { - return getParent().testSliceMin(ctx); + return expand().testSliceMin(ctx); } @Override public List computeCandidates() { - return getParent().getCandidates() + return expand().getCandidates() .stream() .flatMap(Collection::stream) .toList(); @@ -374,7 +373,7 @@ public String getTypeName() { @Override protected void appendContents(StringBuilder builder) { - getParent().appendContents(builder); + expand().appendContents(builder); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/SinglePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/SinglePredicate.java new file mode 100644 index 00000000000..6dc09e0aa65 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/SinglePredicate.java @@ -0,0 +1,49 @@ +package com.gregtechceu.gtceu.api.multiblock.predicates; + +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; + +public class SinglePredicate extends BasePredicate { + + private final Predicate predicate; + private final Stream candidateStream; + private final @Nullable String debugName; + private final @Nullable Consumer contents; + + public SinglePredicate(Predicate predicate, Stream candidateStream, + @Nullable String debugName, @Nullable Consumer contents) { + this.predicate = predicate; + this.candidateStream = candidateStream; + this.debugName = debugName; + this.contents = contents; + } + + @Override + public boolean test(PredicateContext ctx) { + return predicate.test(ctx); + } + + @Override + public List computeCandidates() { + return candidateStream.toList(); + } + + @Override + public String getTypeName() { + return Objects.requireNonNullElse(debugName, "Predicate"); + } + + @Override + protected void appendContents(StringBuilder builder) { + if (contents != null) { + contents.accept(builder); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java index 9fe36637e3d..d12a3866734 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.predicates.logic; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; @@ -16,18 +17,18 @@ public boolean test(PredicateContext ctx) { if (result) continue; switch (ctx.getLastFailureReason()) { case SLICE_MAX, GLOBAL_MAX -> { - return false; + return ctx.error(PatternStringError.literal("AND error")); } } } - return false; + return true; } @Override public boolean testGlobalMin(PredicateContext ctx) { for (BasePredicate predicate : this.rootPredicate) { if (!predicate.testGlobalMin(ctx)) { - return false; + return ctx.error(PatternStringError.literal("AND error")); } } return true; @@ -37,7 +38,7 @@ public boolean testGlobalMin(PredicateContext ctx) { public boolean testSliceMin(PredicateContext ctx) { for (BasePredicate predicate : this.rootPredicate) { if (!predicate.testSliceMin(ctx)) { - return false; + return ctx.error(PatternStringError.literal("AND error")); } } return true; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java index 11fd00ea34b..cb4cf19c229 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java @@ -1,14 +1,32 @@ package com.gregtechceu.gtceu.api.multiblock.predicates.logic; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import lombok.Setter; public abstract class BaseLogic { protected final MultiPredicate rootPredicate; + protected final boolean noneValid; // used for XOR, AND + @Setter + protected boolean global = true; // used for XOR, AND public BaseLogic(MultiPredicate rootPredicate) { this.rootPredicate = rootPredicate; + boolean noneValid = true; + for (BasePredicate predicate : rootPredicate) { + if (predicate instanceof MultiPredicate.CompactedPredicate cp) { + if (!cp.expand().getLogic().noneValid) { + noneValid = false; + break; + } + } else if (predicate.getMinCount() > 0 || predicate.getMinSliceCount() > 0) { + noneValid = false; + break; + } + } + this.noneValid = noneValid; } public void reset() {} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index dee59e6c444..ed1f4b36b3b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -29,14 +29,16 @@ public boolean test(PredicateContext ctx) { return true; } } - return ctx.error(PatternStringError.literal("XOR error")); + return noneValid || ctx.error(PatternStringError.literal("XOR error")); } @Override public boolean testGlobalMin(PredicateContext ctx) { + if (passedPredicate == null && noneValid) return true; if (passedPredicate == null || !passedPredicate.testGlobalMin(ctx)) { return ctx.error(PatternStringError.literal("XOR error")); } + if (!global) return true; for (BasePredicate predicate : this.rootPredicate) { if (predicate != passedPredicate && ctx.getGlobalCount(predicate) > 0) { return ctx.error(PatternStringError.literal("XOR error")); @@ -47,9 +49,11 @@ public boolean testGlobalMin(PredicateContext ctx) { @Override public boolean testSliceMin(PredicateContext ctx) { + if (passedPredicate == null && noneValid) return true; if (passedPredicate == null || !passedPredicate.testSliceMin(ctx)) { return ctx.error(PatternStringError.literal("XOR error")); } + if (global) return true; for (BasePredicate predicate : this.rootPredicate) { if (predicate != passedPredicate && ctx.getSliceCount(predicate) > 0) { return ctx.error(PatternStringError.literal("XOR error")); From caf64a7234fa9a6d4987a1673f8bda4fba9e0ea6 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 15 Jul 2026 23:32:23 -0700 Subject: [PATCH 057/101] spotless --- .../gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java | 1 - .../gtceu/api/multiblock/predicates/BasePredicate.java | 1 - .../gtceu/api/multiblock/predicates/MultiPredicate.java | 3 ++- .../gtceu/api/multiblock/predicates/SinglePredicate.java | 1 + .../gtceu/api/multiblock/predicates/logic/AndLogic.java | 1 + .../gtceu/api/multiblock/predicates/logic/BaseLogic.java | 1 + .../multiblock/primitive/CharcoalPileIgniterMachine.java | 1 - 7 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java index 3c733175f77..dd78cdbc90b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java @@ -2,7 +2,6 @@ import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.Predicates; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 39879dab2ca..8018528a310 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -9,7 +9,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Blocks; import lombok.Getter; import lombok.Setter; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index ab5fd6f2df9..4746d96a3e9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -54,12 +54,12 @@ public void reset() { this.logic.reset(); } - // this is called for each block /// delegates to {@link #logic} to run {@link BasePredicate#testLimited(PredicateContext)} public boolean test(PredicateContext ctx) { return this.logic.test(ctx); } + /// delegates to {@link #logic} to test against global min count public boolean testGlobalMin(PredicateContext ctx) { return this.logic.testGlobalMin(ctx); @@ -312,6 +312,7 @@ private static void appendPredicate(MultiPredicate source, MultiPredicate dest, * what i really need to do is track passed vs failed predicates */ public enum Logic { + OR, AND, XOR; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/SinglePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/SinglePredicate.java index 6dc09e0aa65..2807f53a1ef 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/SinglePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/SinglePredicate.java @@ -2,6 +2,7 @@ import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; + import org.jetbrains.annotations.Nullable; import java.util.List; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java index d12a3866734..785ef20fa89 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -6,6 +6,7 @@ import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; public class AndLogic extends BaseLogic { + public AndLogic(MultiPredicate rootPredicate) { super(rootPredicate); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java index cb4cf19c229..a8437ffe795 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java @@ -3,6 +3,7 @@ import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; + import lombok.Setter; public abstract class BaseLogic { diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java index f24a9f50a4c..12b9e206515 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java @@ -12,7 +12,6 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandableMultiblockPatternBuilder; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.common.data.GTBlocks; From 5b63d7390999a4004fe4bdbe9c51fecf40478093 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 16 Jul 2026 02:14:37 -0700 Subject: [PATCH 058/101] almost working, but not quite --- .../gtceu/api/multiblock/Predicates.java | 2 +- .../multiblock/predicates/MultiPredicate.java | 1 + .../multiblock/predicates/logic/AndLogic.java | 25 +++++++++++++++---- .../predicates/logic/BaseLogic.java | 24 ++++++++++-------- .../multiblock/predicates/logic/XorLogic.java | 16 +++++++----- 5 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 67947eda061..4eededc2f76 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -373,7 +373,7 @@ public static MultiPredicate powerSubstationBatteries() { // TODO xor predicate matching :) return abilities(PartAbility.DATA_ACCESS) .xor(abilities(PartAbility.OPTICAL_DATA_RECEPTION)) - .setExactLimit(1) + .setGlobalMinMax(0, 1) .setPriority(1); // return abilities(PartAbility.DATA_ACCESS, PartAbility.OPTICAL_DATA_RECEPTION) // .setExactLimit(1) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 4746d96a3e9..ac6dda64f9b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -80,6 +80,7 @@ protected MultiPredicate addPredicates(Iterable predicates) { protected MultiPredicate addPredicate(BasePredicate predicate) { this.predicateList.add(predicate); predicate.setParent(this); + this.logic.onPredicateAdd(predicate); return this; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java index 785ef20fa89..e9448c6a7c2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -13,18 +13,33 @@ public AndLogic(MultiPredicate rootPredicate) { @Override public boolean test(PredicateContext ctx) { + int passed = 0; for (BasePredicate predicate : this.rootPredicate) { - boolean result = predicate.testLimited(ctx); - if (result) continue; - switch (ctx.getLastFailureReason()) { - case SLICE_MAX, GLOBAL_MAX -> { - return ctx.error(PatternStringError.literal("AND error")); + boolean result = predicate.test(ctx); + if (result) { + passed++; + result = predicate.testGlobalMax(ctx) && predicate.testSliceMax(ctx); + if (result) { + continue; // fully passed } } + + // count manually + if (failedMaxCount(ctx, predicate, true) || failedMaxCount(ctx, predicate, false)) + return ctx.error(PatternStringError.literal("AND error")); + // continue... + } + if (passed == 0) { + return ctx.error(PatternStringError.literal("AND error")); } return true; } + private static boolean failedMaxCount(PredicateContext ctx, BasePredicate predicate, boolean global) { + int count = global ? ctx.getGlobalCount(predicate) : ctx.getSliceCount(predicate); + return global ? !predicate.testGlobalMax(count) : !predicate.testSliceMax(count); + } + @Override public boolean testGlobalMin(PredicateContext ctx) { for (BasePredicate predicate : this.rootPredicate) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java index a8437ffe795..ec34b32b774 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java @@ -9,25 +9,24 @@ public abstract class BaseLogic { protected final MultiPredicate rootPredicate; - protected final boolean noneValid; // used for XOR, AND + protected boolean noneValid; // used for XOR, AND @Setter protected boolean global = true; // used for XOR, AND public BaseLogic(MultiPredicate rootPredicate) { this.rootPredicate = rootPredicate; + } + + public void onPredicateAdd(BasePredicate predicate) { boolean noneValid = true; - for (BasePredicate predicate : rootPredicate) { - if (predicate instanceof MultiPredicate.CompactedPredicate cp) { - if (!cp.expand().getLogic().noneValid) { - noneValid = false; - break; - } - } else if (predicate.getMinCount() > 0 || predicate.getMinSliceCount() > 0) { + if (predicate instanceof MultiPredicate.CompactedPredicate cp) { + if (!cp.expand().getLogic().noneValid) { noneValid = false; - break; } + } else if (predicate.getMinCount() > 0 || predicate.getMinSliceCount() > 0) { + noneValid = false; } - this.noneValid = noneValid; + this.noneValid |= noneValid; } public void reset() {} @@ -39,4 +38,9 @@ public void reset() {} public abstract boolean testSliceMin(PredicateContext ctx); public abstract MultiPredicate.Logic getType(); + + @Override + public String toString() { + return getType().name(); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index ed1f4b36b3b..e5031e45f07 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -20,16 +20,20 @@ public void reset() { @Override public boolean test(PredicateContext ctx) { - if (passedPredicate != null) { - return passedPredicate.testLimited(ctx) || ctx.error(PatternStringError.literal("XOR error")); - } + int passed = 0; for (BasePredicate predicate : this.rootPredicate) { - if (predicate.testLimited(ctx) && this.passedPredicate == null) { + boolean result = predicate.testLimited(ctx); + if (result && this.passedPredicate == null) { this.passedPredicate = predicate; - return true; } + if (result) passed++; } - return noneValid || ctx.error(PatternStringError.literal("XOR error")); + return passed > 0 || ctx.error(PatternStringError.literal("XOR error")); + } + + private static boolean passedMaxCount(PredicateContext ctx, BasePredicate predicate, boolean global) { + int count = global ? ctx.getGlobalCount(predicate) : ctx.getSliceCount(predicate); + return global ? predicate.testGlobalMax(count) : predicate.testSliceMax(count); } @Override From 79ddfdd854fb319afbc2ade76b19ba3dc5c95813 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 00:31:19 -0700 Subject: [PATCH 059/101] more work on logics move noneValid into XorLogic try and fix errors? --- .../api/multiblock/PredicateContext.java | 2 +- .../api/multiblock/pattern/BlockPattern.java | 2 -- .../api/multiblock/pattern/PatternState.java | 10 +++---- .../multiblock/predicates/MultiPredicate.java | 2 +- .../predicates/logic/BaseLogic.java | 23 +++++++++------- .../multiblock/predicates/logic/XorLogic.java | 26 +++++++++++++++---- 6 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 57c3ebaf660..35d6894fb5c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -21,7 +21,7 @@ public class PredicateContext { - protected final List errors = new ArrayList<>(); + protected List errors = new ArrayList<>(); protected final List commitedErrors = new ArrayList<>(); @Getter protected CurrentBlockInfo currentBlockInfo = new CurrentBlockInfo(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 6892d3545f2..8af3d6d5032 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -186,7 +186,6 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c patternState.setStage(PredicateContext.PredicateStage.GLOBAL_MIN); for (MultiPredicate predicate : predicates.values()) { if (!predicate.testGlobalMin(patternState)) { - patternState.commitErrors(); return false; } } @@ -224,7 +223,6 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // theoretically, predicates could track their own current layer/global count patternState.layerCache().clear(); - predicates.values().forEach(MultiPredicate::reset); Set visitedPredicates = new HashSet<>(); for (int stringIdx = 0; stringIdx < dimensions[1]; stringIdx++) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 471c8f1cacf..4b39e084707 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -65,7 +65,7 @@ public boolean hasErrors() { } public void clearErrors() { - this.errors.clear(); + this.errors = new ArrayList<>(); this.lastFailureReason = FailureReason.NONE; } @@ -74,16 +74,12 @@ public void clearErrors() { public void commitSliceErrors() { this.sliceErrors.remove(this.sliceErrors.size() - 1); this.sliceErrors.forEach(this.commitedErrors::addAll); + this.sliceErrors.clear(); clearErrors(); } public void pushSliceErrors() { - this.sliceErrors.add(List.copyOf(this.errors)); - clearErrors(); - } - - public void commitErrors() { - this.commitedErrors.addAll(this.errors); + this.sliceErrors.add(this.errors); clearErrors(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index ac6dda64f9b..27bc5f38fb8 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -80,7 +80,7 @@ protected MultiPredicate addPredicates(Iterable predicates) { protected MultiPredicate addPredicate(BasePredicate predicate) { this.predicateList.add(predicate); predicate.setParent(this); - this.logic.onPredicateAdd(predicate); + this.logic.onPredicateAdded(); return this; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java index ec34b32b774..ef041b47212 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java @@ -6,10 +6,13 @@ import lombok.Setter; +import java.util.HashSet; +import java.util.Set; + public abstract class BaseLogic { protected final MultiPredicate rootPredicate; - protected boolean noneValid; // used for XOR, AND + private Set compactedPredicates = new HashSet<>(); @Setter protected boolean global = true; // used for XOR, AND @@ -17,19 +20,19 @@ public BaseLogic(MultiPredicate rootPredicate) { this.rootPredicate = rootPredicate; } - public void onPredicateAdd(BasePredicate predicate) { - boolean noneValid = true; - if (predicate instanceof MultiPredicate.CompactedPredicate cp) { - if (!cp.expand().getLogic().noneValid) { - noneValid = false; + public void onPredicateAdded() { + for (BasePredicate predicate : this.rootPredicate) { + if (predicate instanceof MultiPredicate.CompactedPredicate cp) { + this.compactedPredicates.add(cp); } - } else if (predicate.getMinCount() > 0 || predicate.getMinSliceCount() > 0) { - noneValid = false; } - this.noneValid |= noneValid; } - public void reset() {} + public void reset() { + for (MultiPredicate.CompactedPredicate predicate : this.compactedPredicates) { + predicate.expand().getLogic().reset(); + } + } public abstract boolean test(PredicateContext ctx); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index e5031e45f07..c3a1c58932b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -8,6 +8,9 @@ public class XorLogic extends BaseLogic { private BasePredicate passedPredicate; + /// {@code true} if any base predicate have a min count of 0 or -1, + /// meaning that it is possible that no predicates may be present in the multi. + protected boolean noneValid; public XorLogic(MultiPredicate rootPredicate) { super(rootPredicate); @@ -15,9 +18,27 @@ public XorLogic(MultiPredicate rootPredicate) { @Override public void reset() { + super.reset(); this.passedPredicate = null; } + public void onPredicateAdded() { + super.onPredicateAdded(); + this.noneValid = isNoneValid(this.rootPredicate); + } + + private static boolean isNoneValid(MultiPredicate rootPredicate) { + boolean noneValid = false; + for (BasePredicate predicate : rootPredicate) { + if (predicate instanceof MultiPredicate.CompactedPredicate cp) { + noneValid |= isNoneValid(cp.expand()); + } else { + noneValid |= predicate.getMinCount() <= 0 && predicate.getMinSliceCount() <= 0; + } + } + return noneValid; + } + @Override public boolean test(PredicateContext ctx) { int passed = 0; @@ -31,11 +52,6 @@ public boolean test(PredicateContext ctx) { return passed > 0 || ctx.error(PatternStringError.literal("XOR error")); } - private static boolean passedMaxCount(PredicateContext ctx, BasePredicate predicate, boolean global) { - int count = global ? ctx.getGlobalCount(predicate) : ctx.getSliceCount(predicate); - return global ? predicate.testGlobalMax(count) : predicate.testSliceMax(count); - } - @Override public boolean testGlobalMin(PredicateContext ctx) { if (passedPredicate == null && noneValid) return true; From b12c2ea40414a469a21743f9ed4c0e06b2f2f74d Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 01:19:45 -0700 Subject: [PATCH 060/101] make predicate list immutable attempt two at fixing errors --- .../pattern/BasicSliceStrategy.java | 4 +- .../api/multiblock/pattern/PatternState.java | 5 +- .../multiblock/predicates/MultiPredicate.java | 73 ++++++++----------- .../predicates/logic/BaseLogic.java | 5 +- .../multiblock/predicates/logic/XorLogic.java | 6 +- 5 files changed, 37 insertions(+), 56 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java index 6ec2a2c33b2..731b6843320 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java @@ -58,7 +58,9 @@ protected int checkMultiSlice(PatternState state, MultiblockSlice multiblockSlic for (int i = 1; i <= multiblockSlice.maxRepeats; i++) { for (int j = multiblockSlice.startInclusive; j < multiblockSlice.endExclusive; j++) { int res = checkRepeatSlice(state, j, offset + temp, flip); + state.pushSliceErrors(); if (res == -1) { + state.commitSliceErrors(); if (i <= multiblockSlice.minRepeats) return -1; multiblockSlice.actualRepeats = i - 1; return sliceOffset; @@ -76,11 +78,9 @@ protected int checkRepeatSlice(PatternState state, int index, int offset, boolea PatternSlice slice = slices.get(index); for (int i = 1; i <= slice.maxRepeats; i++) { boolean res = checkSlice(state, index, offset + i - 1, flip); - state.pushSliceErrors(); if (!res) { if (i <= slice.minRepeats) return -1; - state.commitSliceErrors(); return slices.get(index).actualRepeats = i - 1; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 4b39e084707..1c139296a6e 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -71,11 +71,12 @@ public void clearErrors() { List> sliceErrors = new ArrayList<>(); + // it's committing errors just fine + // all the widgets are added to the col on server and client + // but nothing shows for some reason public void commitSliceErrors() { - this.sliceErrors.remove(this.sliceErrors.size() - 1); this.sliceErrors.forEach(this.commitedErrors::addAll); this.sliceErrors.clear(); - clearErrors(); } public void pushSliceErrors() { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 27bc5f38fb8..f99afc84148 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -7,7 +7,6 @@ import com.gregtechceu.gtceu.api.multiblock.predicates.logic.XorLogic; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; import lombok.Getter; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -22,13 +21,13 @@ public class MultiPredicate implements Iterable { private static final Comparator PREDICATE_COMPARATOR = Comparator .comparingInt(BasePredicate::getPriority); - private static final MultiPredicate EMPTY = new MultiPredicate(Logic.OR, false); + private static final MultiPredicate EMPTY = new MultiPredicate(); public static final MultiPredicate AIR = new MultiPredicate(BasePredicate.AIR); public static final MultiPredicate ANY = new MultiPredicate(BasePredicate.ANY); - private final List predicateList = new ObjectArrayList<>(); + private final List predicateList; @Getter private final BaseLogic logic; private final boolean hasAir; @@ -41,13 +40,33 @@ public class MultiPredicate implements Iterable { } MultiPredicate(BasePredicate predicate) { - this(Logic.OR, predicate == BasePredicate.AIR); - addPredicate(predicate); + this.predicateList = List.of(predicate); + this.logic = Logic.OR.createLogic(this); + this.hasAir = predicate == BasePredicate.AIR; } - private MultiPredicate(Logic type, boolean hasAir) { - this.hasAir = hasAir; + MultiPredicate() { + this.predicateList = List.of(); + this.logic = Logic.OR.createLogic(this); + this.hasAir = false; + } + + private MultiPredicate(Logic type, MultiPredicate a, MultiPredicate b) { + ArrayList builder = new ArrayList<>(); + if (a.logic.getType() != type) { + builder.add(a.compact()); + } else { + builder.addAll(a.predicateList); + } + if (b.logic.getType() != type) { + builder.add(b.compact()); + } else { + builder.addAll(b.predicateList); + } + builder.sort(PREDICATE_COMPARATOR); + this.predicateList = Collections.unmodifiableList(builder); this.logic = type.createLogic(this); + this.hasAir = a.hasAir || b.hasAir; } public void reset() { @@ -70,20 +89,6 @@ public boolean testSliceMin(PredicateContext ctx) { return this.logic.testSliceMin(ctx); } - protected MultiPredicate addPredicates(Iterable predicates) { - for (BasePredicate predicate : predicates) { - addPredicate(predicate); - } - return this; - } - - protected MultiPredicate addPredicate(BasePredicate predicate) { - this.predicateList.add(predicate); - predicate.setParent(this); - this.logic.onPredicateAdded(); - return this; - } - public List> getCandidates() { return this.predicateList.stream() .map(BasePredicate::getCandidates) @@ -91,15 +96,15 @@ public List> getCandidates() { } public boolean isOr() { - return this.logic instanceof OrLogic; + return this.logic.getType() == Logic.OR; } public boolean isAnd() { - return this.logic instanceof AndLogic; + return this.logic.getType() == Logic.AND; } public boolean isXor() { - return this.logic instanceof XorLogic; + return this.logic.getType() == Logic.XOR; } @ApiStatus.Internal @@ -206,11 +211,6 @@ private MultiPredicate setDisableRenderFormed(boolean disable) { return this; } - protected MultiPredicate sorted() { - this.predicateList.sort(PREDICATE_COMPARATOR); - return this; - } - public MultiPredicate or(MultiPredicate other) { return combine(this, Logic.OR, other); } @@ -268,20 +268,7 @@ public static MultiPredicate empty() { private static MultiPredicate combine(MultiPredicate a, Logic type, @Nullable MultiPredicate b) { if (b == null) return a; // no op if (a.isEmpty()) return b; - var ret = new MultiPredicate(type, a.hasAir() || b.hasAir()); - appendPredicate(a, ret, type); - appendPredicate(b, ret, type); - return ret.sorted(); - } - - private static void appendPredicate(MultiPredicate source, MultiPredicate dest, Logic type) { - if (source.isSingle()) { - dest.addPredicate(source.predicateList.get(0)); - } else if (source.logic.getType() != type) { - dest.addPredicate(source.compact()); - } else { - dest.addPredicates(source); - } + return new MultiPredicate(type, a, b); } /* diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java index ef041b47212..6036230ca44 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java @@ -18,10 +18,7 @@ public abstract class BaseLogic { public BaseLogic(MultiPredicate rootPredicate) { this.rootPredicate = rootPredicate; - } - - public void onPredicateAdded() { - for (BasePredicate predicate : this.rootPredicate) { + for (BasePredicate predicate : rootPredicate) { if (predicate instanceof MultiPredicate.CompactedPredicate cp) { this.compactedPredicates.add(cp); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index c3a1c58932b..c14944d0ceb 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -14,6 +14,7 @@ public class XorLogic extends BaseLogic { public XorLogic(MultiPredicate rootPredicate) { super(rootPredicate); + this.noneValid = isNoneValid(this.rootPredicate); } @Override @@ -22,11 +23,6 @@ public void reset() { this.passedPredicate = null; } - public void onPredicateAdded() { - super.onPredicateAdded(); - this.noneValid = isNoneValid(this.rootPredicate); - } - private static boolean isNoneValid(MultiPredicate rootPredicate) { boolean noneValid = false; for (BasePredicate predicate : rootPredicate) { From 0321eca7282f3e61a9269f4ba1384eb7dd5d59d6 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 13:57:52 -0700 Subject: [PATCH 061/101] actually fix errors predicates are broken --- .../pattern/BasicSliceStrategy.java | 2 +- .../api/multiblock/pattern/BlockPattern.java | 1 + .../api/multiblock/pattern/PatternState.java | 23 +++++++++++++++---- .../multiblock/predicates/logic/AndLogic.java | 9 +++----- .../multiblock/predicates/logic/OrLogic.java | 6 ++--- .../multiblock/predicates/logic/XorLogic.java | 2 +- 6 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java index 731b6843320..dbb3cdb8d4f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java @@ -58,7 +58,6 @@ protected int checkMultiSlice(PatternState state, MultiblockSlice multiblockSlic for (int i = 1; i <= multiblockSlice.maxRepeats; i++) { for (int j = multiblockSlice.startInclusive; j < multiblockSlice.endExclusive; j++) { int res = checkRepeatSlice(state, j, offset + temp, flip); - state.pushSliceErrors(); if (res == -1) { state.commitSliceErrors(); if (i <= multiblockSlice.minRepeats) return -1; @@ -78,6 +77,7 @@ protected int checkRepeatSlice(PatternState state, int index, int offset, boolea PatternSlice slice = slices.get(index); for (int i = 1; i <= slice.maxRepeats; i++) { boolean res = checkSlice(state, index, offset + i - 1, flip); + state.pushSliceErrors(index, offset); if (!res) { if (i <= slice.minRepeats) return -1; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 8af3d6d5032..7f5670754bc 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -151,6 +151,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c } patternState.updateLevel(level); + patternState.reset(); // clear any existing committed errors BlockPos.MutableBlockPos controllerPos = centerPos.mutable(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 1c139296a6e..23449c15714 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -6,6 +6,10 @@ import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; @@ -61,7 +65,7 @@ public boolean shouldUpdate() { } public boolean hasErrors() { - return !this.errors.isEmpty(); + return !this.commitedErrors.isEmpty(); } public void clearErrors() { @@ -69,21 +73,30 @@ public void clearErrors() { this.lastFailureReason = FailureReason.NONE; } - List> sliceErrors = new ArrayList<>(); + public void reset() { + this.commitedErrors.clear(); + } + + Object2ObjectMap> sliceErrors = new Object2ObjectArrayMap<>(); // it's committing errors just fine // all the widgets are added to the col on server and client // but nothing shows for some reason public void commitSliceErrors() { - this.sliceErrors.forEach(this.commitedErrors::addAll); + for (Slice slice : this.sliceErrors.keySet()) { + this.commitedErrors.addAll(this.sliceErrors.get(slice)); + } this.sliceErrors.clear(); } - public void pushSliceErrors() { - this.sliceErrors.add(this.errors); + public void pushSliceErrors(int index, int offset) { + Slice slice = new Slice(index, offset); + this.sliceErrors.put(slice, this.errors); clearErrors(); } + private record Slice(int index, int offset) {} + public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState newState) { if (!(currentBlockInfo.getLevel() instanceof ServerLevel serverLevel)) return; if (pos.equals(controllerPos)) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java index e9448c6a7c2..48312c2244a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -29,10 +29,7 @@ public boolean test(PredicateContext ctx) { return ctx.error(PatternStringError.literal("AND error")); // continue... } - if (passed == 0) { - return ctx.error(PatternStringError.literal("AND error")); - } - return true; + return passed != 0; } private static boolean failedMaxCount(PredicateContext ctx, BasePredicate predicate, boolean global) { @@ -44,7 +41,7 @@ private static boolean failedMaxCount(PredicateContext ctx, BasePredicate predic public boolean testGlobalMin(PredicateContext ctx) { for (BasePredicate predicate : this.rootPredicate) { if (!predicate.testGlobalMin(ctx)) { - return ctx.error(PatternStringError.literal("AND error")); + return false; } } return true; @@ -54,7 +51,7 @@ public boolean testGlobalMin(PredicateContext ctx) { public boolean testSliceMin(PredicateContext ctx) { for (BasePredicate predicate : this.rootPredicate) { if (!predicate.testSliceMin(ctx)) { - return ctx.error(PatternStringError.literal("AND error")); + return false; } } return true; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java index 4beab468bac..7fabf7062fd 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java @@ -18,7 +18,7 @@ public boolean test(PredicateContext ctx) { return true; } } - return ctx.error(PatternStringError.literal("OR error")); + return false; } @Override @@ -28,7 +28,7 @@ public boolean testGlobalMin(PredicateContext ctx) { return true; } } - return ctx.error(PatternStringError.literal("OR error")); + return false; } @Override @@ -38,7 +38,7 @@ public boolean testSliceMin(PredicateContext ctx) { return true; } } - return ctx.error(PatternStringError.literal("OR error")); + return false; } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index c14944d0ceb..c7b77ef8c66 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -45,7 +45,7 @@ public boolean test(PredicateContext ctx) { } if (result) passed++; } - return passed > 0 || ctx.error(PatternStringError.literal("XOR error")); + return passed > 0; } @Override From 9de11834550507a610c4f3ad75faaba7166a70ff Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 14:09:29 -0700 Subject: [PATCH 062/101] fix predicates commit global errors --- .../api/multiblock/pattern/BlockPattern.java | 1 + .../api/multiblock/pattern/PatternState.java | 5 +++++ .../multiblock/predicates/MultiPredicate.java | 20 +++++++++---------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 7f5670754bc..aa7747b36dc 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -187,6 +187,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c patternState.setStage(PredicateContext.PredicateStage.GLOBAL_MIN); for (MultiPredicate predicate : predicates.values()) { if (!predicate.testGlobalMin(patternState)) { + patternState.commitErrors(); return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 23449c15714..10a810887d0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -95,6 +95,11 @@ public void pushSliceErrors(int index, int offset) { clearErrors(); } + public void commitErrors() { + this.commitedErrors.addAll(this.errors); + clearErrors(); + } + private record Slice(int index, int offset) {} public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState newState) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index f99afc84148..3500601ed94 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -53,22 +53,22 @@ public class MultiPredicate implements Iterable { private MultiPredicate(Logic type, MultiPredicate a, MultiPredicate b) { ArrayList builder = new ArrayList<>(); - if (a.logic.getType() != type) { - builder.add(a.compact()); - } else { - builder.addAll(a.predicateList); - } - if (b.logic.getType() != type) { - builder.add(b.compact()); - } else { - builder.addAll(b.predicateList); - } + appendPredicates(type, a, builder); + appendPredicates(type, b, builder); builder.sort(PREDICATE_COMPARATOR); this.predicateList = Collections.unmodifiableList(builder); this.logic = type.createLogic(this); this.hasAir = a.hasAir || b.hasAir; } + private static void appendPredicates(Logic type, MultiPredicate b, ArrayList builder) { + if (b.isSingle() || b.logic.getType() == type) { + builder.addAll(b.predicateList); + } else { + builder.add(b.compact()); + } + } + public void reset() { this.logic.reset(); } From 6432a8996a99411175f0aa18980c0d7d109a3246 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 14:17:36 -0700 Subject: [PATCH 063/101] move CompactedPredicate out --- .../predicates/CompactedPredicate.java | 67 +++++++++++++++++++ .../multiblock/predicates/MultiPredicate.java | 55 --------------- .../predicates/logic/BaseLogic.java | 9 ++- .../multiblock/predicates/logic/XorLogic.java | 3 +- 4 files changed, 73 insertions(+), 61 deletions(-) create mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java new file mode 100644 index 00000000000..4f499eb1b39 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java @@ -0,0 +1,67 @@ +package com.gregtechceu.gtceu.api.multiblock.predicates; + +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; + +import java.util.Collection; +import java.util.List; + +public class CompactedPredicate extends BasePredicate { + + private final MultiPredicate root; + + CompactedPredicate(MultiPredicate root) { + this.root = root; + } + + public MultiPredicate expand() { + return this.root; + } + + @Override + public boolean test(PredicateContext ctx) { + // test parent predicates + return expand().test(ctx); + } + + @Override + public boolean testLimited(PredicateContext ctx) { + return this.test(ctx); + } + + @Override + public boolean testGlobalMin(PredicateContext ctx) { + return expand().testGlobalMin(ctx); + } + + @Override + public boolean testSliceMin(PredicateContext ctx) { + return expand().testSliceMin(ctx); + } + + @Override + public List computeCandidates() { + return expand().getCandidates() + .stream() + .flatMap(Collection::stream) + .toList(); + } + + @Override + public String getTypeName() { + return "CompactedPredicate"; + } + + @Override + protected void appendContents(StringBuilder builder) { + expand().appendContents(builder); + } + + @Override + protected void appendStats(StringBuilder builder) { + } + + public void reset() { + this.root.reset(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index 3500601ed94..c31c57409de 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -313,59 +313,4 @@ public BaseLogic createLogic(MultiPredicate source) { }; } } - - public static class CompactedPredicate extends BasePredicate { - - private final MultiPredicate root; - - private CompactedPredicate(MultiPredicate root) { - this.root = root; - } - - public MultiPredicate expand() { - return this.root; - } - - @Override - public boolean test(PredicateContext ctx) { - // test parent predicates - return expand().test(ctx); - } - - @Override - public boolean testLimited(PredicateContext ctx) { - return this.test(ctx); - } - - @Override - public boolean testGlobalMin(PredicateContext ctx) { - return expand().testGlobalMin(ctx); - } - - @Override - public boolean testSliceMin(PredicateContext ctx) { - return expand().testSliceMin(ctx); - } - - @Override - public List computeCandidates() { - return expand().getCandidates() - .stream() - .flatMap(Collection::stream) - .toList(); - } - - @Override - public String getTypeName() { - return "CompactedPredicate"; - } - - @Override - protected void appendContents(StringBuilder builder) { - expand().appendContents(builder); - } - - @Override - protected void appendStats(StringBuilder builder) {} - } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java index 6036230ca44..625923f5ff2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java @@ -2,6 +2,7 @@ import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import lombok.Setter; @@ -12,23 +13,21 @@ public abstract class BaseLogic { protected final MultiPredicate rootPredicate; - private Set compactedPredicates = new HashSet<>(); + private final Set compactedPredicates = new HashSet<>(); @Setter protected boolean global = true; // used for XOR, AND public BaseLogic(MultiPredicate rootPredicate) { this.rootPredicate = rootPredicate; for (BasePredicate predicate : rootPredicate) { - if (predicate instanceof MultiPredicate.CompactedPredicate cp) { + if (predicate instanceof CompactedPredicate cp) { this.compactedPredicates.add(cp); } } } public void reset() { - for (MultiPredicate.CompactedPredicate predicate : this.compactedPredicates) { - predicate.expand().getLogic().reset(); - } + this.compactedPredicates.forEach(CompactedPredicate::reset); } public abstract boolean test(PredicateContext ctx); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index c7b77ef8c66..3190ec52b52 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -3,6 +3,7 @@ import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; public class XorLogic extends BaseLogic { @@ -26,7 +27,7 @@ public void reset() { private static boolean isNoneValid(MultiPredicate rootPredicate) { boolean noneValid = false; for (BasePredicate predicate : rootPredicate) { - if (predicate instanceof MultiPredicate.CompactedPredicate cp) { + if (predicate instanceof CompactedPredicate cp) { noneValid |= isNoneValid(cp.expand()); } else { noneValid |= predicate.getMinCount() <= 0 && predicate.getMinSliceCount() <= 0; From a28589163b21891fb4b06ac84944fb254e45f238 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 14:18:00 -0700 Subject: [PATCH 064/101] spotless --- .../gtceu/api/multiblock/pattern/PatternState.java | 6 ++---- .../gtceu/api/multiblock/predicates/CompactedPredicate.java | 3 +-- .../gtceu/api/multiblock/predicates/logic/OrLogic.java | 1 - 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 10a810887d0..30a48c117d5 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -6,10 +6,6 @@ import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectMap; -import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; -import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; @@ -17,6 +13,8 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import lombok.Getter; import lombok.Setter; import org.jetbrains.annotations.ApiStatus; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java index 4f499eb1b39..0f7d84a896a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java @@ -58,8 +58,7 @@ protected void appendContents(StringBuilder builder) { } @Override - protected void appendStats(StringBuilder builder) { - } + protected void appendStats(StringBuilder builder) {} public void reset() { this.root.reset(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java index 7fabf7062fd..d86706f19af 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java @@ -1,7 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock.predicates.logic; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; From c827ad2be0e34dff6a970d3803b0404c768de17d Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 15:25:29 -0700 Subject: [PATCH 065/101] improve xor errors predicate list getter --- .../api/multiblock/predicates/MultiPredicate.java | 1 + .../api/multiblock/predicates/logic/XorLogic.java | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java index c31c57409de..1def994dafd 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java @@ -27,6 +27,7 @@ public class MultiPredicate implements Iterable { public static final MultiPredicate ANY = new MultiPredicate(BasePredicate.ANY); + @Getter private final List predicateList; @Getter private final BaseLogic logic; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index 3190ec52b52..05f559f7732 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -53,12 +53,14 @@ public boolean test(PredicateContext ctx) { public boolean testGlobalMin(PredicateContext ctx) { if (passedPredicate == null && noneValid) return true; if (passedPredicate == null || !passedPredicate.testGlobalMin(ctx)) { - return ctx.error(PatternStringError.literal("XOR error")); + return ctx.error(PatternStringError.literal("need one of: " + rootPredicate)); } if (!global) return true; for (BasePredicate predicate : this.rootPredicate) { if (predicate != passedPredicate && ctx.getGlobalCount(predicate) > 0) { - return ctx.error(PatternStringError.literal("XOR error")); + ctx.error(PatternStringError.literal("need one of:\n" + rootPredicate.getPredicateList())); + ctx.error(PatternStringError.literal(predicate + " present in multi")); + return false; } } return true; @@ -68,12 +70,14 @@ public boolean testGlobalMin(PredicateContext ctx) { public boolean testSliceMin(PredicateContext ctx) { if (passedPredicate == null && noneValid) return true; if (passedPredicate == null || !passedPredicate.testSliceMin(ctx)) { - return ctx.error(PatternStringError.literal("XOR error")); + return ctx.error(PatternStringError.literal("need one of: " + rootPredicate)); } if (global) return true; for (BasePredicate predicate : this.rootPredicate) { if (predicate != passedPredicate && ctx.getSliceCount(predicate) > 0) { - return ctx.error(PatternStringError.literal("XOR error")); + ctx.error(PatternStringError.literal("need one of:\n" + rootPredicate.getPredicateList())); + ctx.error(PatternStringError.literal(predicate + " present in multi")); + return false; } } return true; From ff6a6694a1f40b62f45c79f9d8398154ac18620a Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 15:29:18 -0700 Subject: [PATCH 066/101] simplify logic --- .../gtceu/api/multiblock/predicates/logic/AndLogic.java | 9 ++++----- .../gtceu/api/multiblock/predicates/logic/XorLogic.java | 9 +++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java index 48312c2244a..9ab6afec3f4 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -15,11 +15,9 @@ public AndLogic(MultiPredicate rootPredicate) { public boolean test(PredicateContext ctx) { int passed = 0; for (BasePredicate predicate : this.rootPredicate) { - boolean result = predicate.test(ctx); - if (result) { + if (predicate.test(ctx)) { passed++; - result = predicate.testGlobalMax(ctx) && predicate.testSliceMax(ctx); - if (result) { + if (predicate.testGlobalMax(ctx) && predicate.testSliceMax(ctx)) { continue; // fully passed } } @@ -27,9 +25,10 @@ public boolean test(PredicateContext ctx) { // count manually if (failedMaxCount(ctx, predicate, true) || failedMaxCount(ctx, predicate, false)) return ctx.error(PatternStringError.literal("AND error")); + passed++; // continue... } - return passed != 0; + return passed > 0; } private static boolean failedMaxCount(PredicateContext ctx, BasePredicate predicate, boolean global) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index 05f559f7732..58bbe43d28f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -40,11 +40,12 @@ private static boolean isNoneValid(MultiPredicate rootPredicate) { public boolean test(PredicateContext ctx) { int passed = 0; for (BasePredicate predicate : this.rootPredicate) { - boolean result = predicate.testLimited(ctx); - if (result && this.passedPredicate == null) { - this.passedPredicate = predicate; + if (predicate.testLimited(ctx)) { + passed++; + if (this.passedPredicate == null) { + this.passedPredicate = predicate; + } } - if (result) passed++; } return passed > 0; } From 5f2279fc2b6f6cd5e79f9fe716359afe5d4b5eb9 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 16:03:01 -0700 Subject: [PATCH 067/101] move MultiPredicate to proper package --- .../gtceu/api/mui/MultiblockSchemaInfo.java | 2 +- .../{predicates => }/MultiPredicate.java | 17 +++++------------ .../gtceu/api/multiblock/Predicates.java | 1 - .../api/multiblock/pattern/BlockPattern.java | 2 +- .../ExpandableMultiblockPatternBuilder.java | 2 +- .../multiblock/pattern/ExpandablePattern.java | 2 +- .../pattern/MultiblockPatternBuilder.java | 2 +- .../multiblock/predicates/BasePredicate.java | 13 +++++++++---- .../predicates/CompactedPredicate.java | 1 + .../multiblock/predicates/logic/AndLogic.java | 2 +- .../multiblock/predicates/logic/BaseLogic.java | 2 +- .../multiblock/predicates/logic/OrLogic.java | 2 +- .../multiblock/predicates/logic/XorLogic.java | 2 +- .../util/AbstractStructureHelper.java | 2 +- .../api/multiblock/util/BlockPatternHelper.java | 2 +- .../util/ExpandablePatternHelper.java | 2 +- .../common/data/machines/GCYMMachines.java | 2 +- .../common/data/machines/GTMachineUtils.java | 2 +- .../common/data/machines/GTMultiMachines.java | 2 +- .../electric/ActiveTransformerMachine.java | 2 +- .../electric/CentralMonitorMachine.java | 2 +- .../multiblock/electric/CleanroomMachine.java | 2 +- .../primitive/CharcoalPileIgniterMachine.java | 2 +- .../widgets/MultiblockPreviewWidget.java | 2 +- 24 files changed, 35 insertions(+), 37 deletions(-) rename src/main/java/com/gregtechceu/gtceu/api/multiblock/{predicates => }/MultiPredicate.java (94%) diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java b/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java index 54d8dfd56f8..50486195f25 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java @@ -5,7 +5,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.AbstractStructureHelper; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.client.mui.schema.MutableSchema; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java similarity index 94% rename from src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java rename to src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index 1def994dafd..c3c1bef2872 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -1,6 +1,7 @@ -package com.gregtechceu.gtceu.api.multiblock.predicates; +package com.gregtechceu.gtceu.api.multiblock; -import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.logic.AndLogic; import com.gregtechceu.gtceu.api.multiblock.predicates.logic.BaseLogic; import com.gregtechceu.gtceu.api.multiblock.predicates.logic.OrLogic; @@ -12,9 +13,6 @@ import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.stream.Stream; public class MultiPredicate implements Iterable { @@ -35,18 +33,13 @@ public class MultiPredicate implements Iterable { @Getter private boolean controller; - MultiPredicate(@Nullable String debugName, Predicate predicate, - Stream candidateStream, @Nullable Consumer contents) { - this(BasePredicate.of(debugName, predicate, candidateStream, contents)); - } - - MultiPredicate(BasePredicate predicate) { + public MultiPredicate(BasePredicate predicate) { this.predicateList = List.of(predicate); this.logic = Logic.OR.createLogic(this); this.hasAir = predicate == BasePredicate.AIR; } - MultiPredicate() { + private MultiPredicate() { this.predicateList = List.of(); this.logic = Logic.OR.createLogic(this); this.hasAir = false; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 4eededc2f76..95d30b6594c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -18,7 +18,6 @@ import com.gregtechceu.gtceu.api.multiblock.error.PlaceholderError; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.pipenet.IPipeNode; import com.gregtechceu.gtceu.api.recipe.GTRecipeType; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index aa7747b36dc..993593c0033 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -2,7 +2,7 @@ import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandableMultiblockPatternBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandableMultiblockPatternBuilder.java index de05d5519fd..fd1a0bf5438 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandableMultiblockPatternBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandableMultiblockPatternBuilder.java @@ -1,6 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index 5b6432fb216..715fd234754 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java index dd78cdbc90b..8eb4b862163 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java @@ -2,7 +2,7 @@ import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.Predicates; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.google.common.base.Joiner; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 8018528a310..d707502dfc4 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; @@ -21,9 +22,9 @@ public abstract class BasePredicate { - static final BasePredicate AIR = of("Air", ctx -> ctx.state().isAir(), Stream.empty(), null); + public static final BasePredicate AIR = of("Air", ctx -> ctx.state().isAir()); - static final BasePredicate ANY = of("Any", ctx -> true, Stream.empty(), null); + public static final BasePredicate ANY = of("Any", ctx -> true); private @Nullable List candidates; @@ -184,11 +185,15 @@ public static MultiPredicate create(@Nullable String debugName, Predicate predicate, Stream candidateStream, @Nullable Consumer contents) { - return new MultiPredicate(debugName, predicate, candidateStream, contents); + return new MultiPredicate(of(debugName, predicate, candidateStream, contents)); } - static BasePredicate of(@Nullable String debugName, Predicate predicate, + public static BasePredicate of(@Nullable String debugName, Predicate predicate, Stream candidateStream, @Nullable Consumer contents) { return new SinglePredicate(predicate, candidateStream, debugName, contents); } + + private static BasePredicate of(@Nullable String debugName, Predicate predicate) { + return of(debugName, predicate, Stream.empty(), null); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java index 0f7d84a896a..459897b28a2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java @@ -1,5 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java index 9ab6afec3f4..35d66b8c45d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -3,7 +3,7 @@ import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; public class AndLogic extends BaseLogic { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java index 625923f5ff2..b2712655948 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java @@ -3,7 +3,7 @@ import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import lombok.Setter; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java index d86706f19af..60287ec9bb0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java @@ -2,7 +2,7 @@ import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; public class OrLogic extends BaseLogic { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index 58bbe43d28f..02dc2f36699 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -4,7 +4,7 @@ import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; public class XorLogic extends BaseLogic { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java index 5c7befa8336..27196f0ea42 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java @@ -4,7 +4,7 @@ import com.gregtechceu.gtceu.api.block.property.GTBlockStateProperties; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java index f1656d82015..6e06b3085a8 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java @@ -5,7 +5,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.PatternSlice; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java index abf4bea2d7b..57735c5434d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java @@ -3,7 +3,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java index 5daf85e9711..11e45de7bd4 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java @@ -12,7 +12,7 @@ import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderHelper; import com.gregtechceu.gtceu.common.data.GTMaterials; import com.gregtechceu.gtceu.common.data.GTRecipeModifiers; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 0c620ee5443..e44c197d442 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -25,7 +25,7 @@ import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.error.PartAbilityError; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.recipe.GTRecipeType; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java index f94af9ad8ab..1a1f6e74f77 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java @@ -15,7 +15,7 @@ import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderHelper; import com.gregtechceu.gtceu.client.util.TooltipHelper; import com.gregtechceu.gtceu.common.block.BoilerFireboxType; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java index 22edc92c149..17757387f79 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java @@ -12,7 +12,7 @@ import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; import com.gregtechceu.gtceu.api.misc.EnergyContainerList; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.common.mui.GTMultiblockTextUtil; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.utils.FormattingUtil; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java index d3d94de4a1a..56d4a14bd94 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java @@ -14,7 +14,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.sync_system.annotations.RerenderOnChanged; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index 7ffa2980ba0..682f2fa7fd0 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -22,7 +22,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java index 12b9e206515..538f6260b5d 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java @@ -12,7 +12,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandableMultiblockPatternBuilder; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.common.data.GTBlocks; import com.gregtechceu.gtceu.common.item.behavior.LighterBehavior; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java index fdac4154d30..189096c99e0 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java @@ -7,7 +7,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.client.renderer.PatternPreviewRenderer; import com.gregtechceu.gtceu.common.mui.GTGuiTextures; From e849f45f704a9abc7fc5365f39f418f592c0b079 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 17:39:39 -0700 Subject: [PATCH 068/101] use lombok lazy getter for candidates --- .../api/multiblock/predicates/BasePredicate.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index d707502dfc4..3d0f0886f32 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -26,7 +26,8 @@ public abstract class BasePredicate { public static final BasePredicate ANY = of("Any", ctx -> true); - private @Nullable List candidates; + @Getter(lazy = true) + private final List candidates = computeCandidates(); @Getter @Setter @@ -124,14 +125,6 @@ public boolean testSliceMax(int count) { /// computes the candidates for this predicate public abstract List computeCandidates(); - /// @return the candidate blocks for this predicate, may be empty, lazily initialized - public List getCandidates() { - if (candidates == null) { - candidates = computeCandidates(); - } - return candidates; - } - public List getCandidateStacks() { return getCandidates().stream() .filter(BlockInfo::nonAir) From 722ff7fa773795f8e218536fc658c508b15dc872 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 17:56:26 -0700 Subject: [PATCH 069/101] use first candidate optional --- .../com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java | 2 +- .../gtceu/api/multiblock/predicates/CompactedPredicate.java | 2 +- .../gtceu/api/multiblock/util/BlockPatternHelper.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index c3c1bef2872..0ec1dc39a28 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -221,7 +221,7 @@ public boolean isSingle() { return predicateList.size() == 1; } - protected void appendContents(StringBuilder builder) { + public void appendContents(StringBuilder builder) { StringJoiner joiner = new StringJoiner(", "); this.forEach(p -> joiner.add(p.toString())); builder.append(joiner); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java index 459897b28a2..19e65eb4762 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java @@ -11,7 +11,7 @@ public class CompactedPredicate extends BasePredicate { private final MultiPredicate root; - CompactedPredicate(MultiPredicate root) { + public CompactedPredicate(MultiPredicate root) { this.root = root; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java index 6e06b3085a8..7530e33365b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java @@ -143,7 +143,7 @@ private boolean tryMinCount(Map resultStructure, MultiPredi BlockInfo toInsert = blockPreferences.get(predicate, basePredicate); if (toInsert == null) { - toInsert = basePredicate.getCandidates().get(0); + toInsert = basePredicate.getFirstCandidate().orElse(BlockInfo.EMPTY); } // TODO: is this needed? doesn't this just do what we're already doing? if (isValidCandidate(resultStructure, predicate, pos, toInsert, dir)) { @@ -172,7 +172,7 @@ private boolean tryMaxCount(Map resultStructure, MultiPredi BlockInfo toInsert = blockPreferences.get(predicate, basePredicate); if (toInsert == null) { - toInsert = basePredicate.getCandidates().get(0); + toInsert = basePredicate.getFirstCandidate().orElse(BlockInfo.EMPTY); } // TODO: is this needed? doesn't this just do what we're already doing? if (isValidCandidate(resultStructure, predicate, pos, toInsert, dir)) { From 0e08888dc59db66536ce3e53841e8e2fd9fa9ed6 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 18:16:05 -0700 Subject: [PATCH 070/101] simplify block info stack form getter --- .../gtceu/api/multiblock/predicates/BasePredicate.java | 9 +-------- .../gregtechceu/gtceu/api/multiblock/util/BlockInfo.java | 6 ++++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 3d0f0886f32..7791e91bc13 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -128,14 +128,7 @@ public boolean testSliceMax(int count) { public List getCandidateStacks() { return getCandidates().stream() .filter(BlockInfo::nonAir) - .map(info -> { - if (GTCEu.isClientSide()) { - Level level = Objects.requireNonNull(Minecraft.getInstance().level); - return info.getItemStackForm(level, BlockPos.ZERO); - } - - return info.getItemStackForm(); - }) + .map(BlockInfo::getItemStackForm) .toList(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java index ea2af0c9756..99eeb07f09e 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockInfo.java @@ -1,7 +1,9 @@ package com.gregtechceu.gtceu.api.multiblock.util; +import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.client.util.FakeBlockTintGetter; +import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockAndTintGetter; @@ -80,6 +82,10 @@ public static BlockInfo fromBlock(Block block) { } public ItemStack getItemStackForm() { + if (GTCEu.isClientSide()) { + Level level = Objects.requireNonNull(Minecraft.getInstance().level); + return getItemStackForm(level, BlockPos.ZERO); + } return itemStack == null ? new ItemStack(blockState.getBlock()) : itemStack; } From e305694971cacb8a5bfc367000b357458eae7252 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:00:57 -0700 Subject: [PATCH 071/101] clean up a bit move methods in MultiPredicate and lombok chained setter --- .../gtceu/api/multiblock/MultiPredicate.java | 63 +++++-------------- .../gtceu/api/multiblock/Predicates.java | 5 -- .../api/multiblock/pattern/BlockPattern.java | 25 +------- .../multiblock/predicates/BasePredicate.java | 1 - 4 files changed, 18 insertions(+), 76 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index 0ec1dc39a28..1d4687666e5 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -9,6 +9,8 @@ import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -31,6 +33,8 @@ public class MultiPredicate implements Iterable { private final BaseLogic logic; private final boolean hasAir; @Getter + @Setter + @Accessors(chain = true) private boolean controller; public MultiPredicate(BasePredicate predicate) { @@ -55,14 +59,6 @@ private MultiPredicate(Logic type, MultiPredicate a, MultiPredicate b) { this.hasAir = a.hasAir || b.hasAir; } - private static void appendPredicates(Logic type, MultiPredicate b, ArrayList builder) { - if (b.isSingle() || b.logic.getType() == type) { - builder.addAll(b.predicateList); - } else { - builder.add(b.compact()); - } - } - public void reset() { this.logic.reset(); } @@ -122,6 +118,11 @@ protected BasePredicate compact() { return new CompactedPredicate(this); } + public MultiPredicate setPriority(int priority) { + this.forEach(p -> p.setPriority(priority)); + return this; + } + public MultiPredicate setMinGlobalLimited(int min) { return this.setMinCount(min); } @@ -242,16 +243,6 @@ public Iterator iterator() { return this.predicateList.iterator(); } - public MultiPredicate setController(boolean controller) { - this.controller = controller; - return this; - } - - public MultiPredicate setPriority(int priority) { - this.forEach(p -> p.setPriority(priority)); - return this; - } - public static MultiPredicate empty() { return EMPTY; } @@ -265,34 +256,14 @@ private static MultiPredicate combine(MultiPredicate a, Logic type, @Nullable Mu return new MultiPredicate(type, a, b); } - /* - * OR logic - * at least one of n predicates must be valid - * AND logic - * all predicates must be valid in the multiblock/slice - * this deals with global/slice counts - * AND_SLICE? - * XOR logic - * must only have one of n predicates be valid and present in multi - * global/slice counts of other predicates must be zero - * - * when it comes to the internal predicates - * any can pass, regardless of logic type - * since a block can only have one state - * and internal predicate is checked per block - * - * this may also introduce the ability - * to have an invalid predicate form a multiblock - * if predicate a has a min of two, - * and predicate b has min of one, - * and you use XOR logic - * the multi predicate would pass since a fails and b succeeds min checks - * really it should be "only one predicate can be present in multi/slice" - * - * how do i handle global/slice max? - * i dont think i actually need to - * what i really need to do is track passed vs failed predicates - */ + private static void appendPredicates(Logic type, MultiPredicate multiPredicate, ArrayList builder) { + if (multiPredicate.isSingle() || multiPredicate.logic.getType() == type) { + builder.addAll(multiPredicate.predicateList); + } else { + builder.add(multiPredicate.compact()); + } + } + public enum Logic { OR, diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 95d30b6594c..2c25715a913 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -369,16 +369,11 @@ public static MultiPredicate powerSubstationBatteries() { public static @Nullable MultiPredicate dataHatchPredicate() { // if research is enabled, require the data hatch, otherwise use a grate instead if (ConfigHolder.INSTANCE.machines.enableResearch) { - // TODO xor predicate matching :) return abilities(PartAbility.DATA_ACCESS) .xor(abilities(PartAbility.OPTICAL_DATA_RECEPTION)) .setGlobalMinMax(0, 1) .setPriority(1); - // return abilities(PartAbility.DATA_ACCESS, PartAbility.OPTICAL_DATA_RECEPTION) - // .setExactLimit(1) - // .setPriority(1); } - // this really should not be null return null; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 993593c0033..dfe4c357fc5 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -123,7 +123,6 @@ public void checkPatternFastAt(Level level, PatternState patternState, BlockPos } if (allowsFlip && patternState.shouldCheckFlip()) { - // this overwrites any previous errors valid = checkPatternAt(level, patternState, centerPos, frontFacing, upwardsFacing, true); } if (!valid) { @@ -163,26 +162,6 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c sliceStrategy.start(controllerPos, frontFacing, upwardsFacing); if (!sliceStrategy.check(patternState, isFlipped)) return false; - /* - * NOTES - * as we iterate each slice of the multiblock - * check each predicates' state check - * each block pos can only be one predicate - * we need to know what logic type each predicate should uses - * this is only globally - * thought i could see a use for xor in a slice, but not globally - * how exactly would this work - * XOR_SLICE and XOR_GLOBAL? - * and idea i had is that if a xor multi predicate is iterated - * a list of "banned" base predicates could be checked - * so if another predicate from the same multi predicate passes, it would fail - * - * another predicament is handling the edge case of a xor predicate - * having two- - * actually i could have the xor logic to run in the state check - * along with the previously mentioned idea of banned predicates - */ - // global min check patternState.setStage(PredicateContext.PredicateStage.GLOBAL_MIN); for (MultiPredicate predicate : predicates.values()) { @@ -223,7 +202,6 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p BlockPos.MutableBlockPos charPos = sliceStart.mutable(); PatternSlice slice = slices[sliceIndex]; - // theoretically, predicates could track their own current layer/global count patternState.layerCache().clear(); Set visitedPredicates = new HashSet<>(); @@ -237,12 +215,11 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // internal predicate check, global/slice max checks // if all internal predicates pass, but global/slice max/min checks fail, then do not flip if (!pred.test(patternState)) { - // patternState.commitErrors(); return false; } + visitedPredicates.add(pred); charPos.move(absoluteChar); - patternState.clearErrors(); // continue... } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 7791e91bc13..a70941b10ad 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -71,7 +71,6 @@ public boolean testLimited(PredicateContext ctx) { if (!testGlobalMax(ctx)) return false; ctx.setStage(PredicateContext.PredicateStage.SLICE_MAX); return testSliceMax(ctx); - // return test(ctx) && testGlobalMax(ctx) && testSliceMax(ctx); } /// test against global max count From f01224af500333c60fab34124a62f0439b9a9a6a Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:13:40 -0700 Subject: [PATCH 072/101] address todo --- .../gtceu/api/multiblock/error/PatternError.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java index b0777fe42f6..9e92144f355 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java @@ -1,5 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock.error; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.registry.GTRegistries; @@ -29,10 +30,9 @@ public PatternError(@Nullable BlockPos pos, List> candidates) { this.candidates = candidates; } - // TODO FIX - // public PatternError(@Nullable BlockPos pos, PatternPredicate predicate) { - // this(pos, predicate.getCandidates()); - // } + public PatternError(@Nullable BlockPos pos, MultiPredicate predicate) { + this(pos, predicate.getCandidates()); + } public PatternError(@Nullable BlockPos pos, BasePredicate failingPredicate) { this(pos, Collections.singletonList(failingPredicate.getCandidates())); From 67eb54d703be3233ff21ef11a66c66db00656a93 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:39:43 -0700 Subject: [PATCH 073/101] add new helper method to PatternStringError try out new error string for XorLogic --- .../multiblock/error/PatternStringError.java | 4 +++ .../multiblock/predicates/logic/XorLogic.java | 31 +++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternStringError.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternStringError.java index 55c4e0fefe1..3ee2bd1a85d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternStringError.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternStringError.java @@ -28,6 +28,10 @@ public PatternStringError(Component component) { this.component = component; } + public static PatternStringError component(Component component) { + return new PatternStringError(component); + } + public static PatternStringError literal(String s) { return new PatternStringError(Component.literal(s)); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index 02dc2f36699..f7419d1c567 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -1,10 +1,15 @@ package com.gregtechceu.gtceu.api.multiblock.predicates.logic; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; public class XorLogic extends BaseLogic { @@ -54,19 +59,39 @@ public boolean test(PredicateContext ctx) { public boolean testGlobalMin(PredicateContext ctx) { if (passedPredicate == null && noneValid) return true; if (passedPredicate == null || !passedPredicate.testGlobalMin(ctx)) { - return ctx.error(PatternStringError.literal("need one of: " + rootPredicate)); + return ctx.error(onError()); } if (!global) return true; for (BasePredicate predicate : this.rootPredicate) { if (predicate != passedPredicate && ctx.getGlobalCount(predicate) > 0) { - ctx.error(PatternStringError.literal("need one of:\n" + rootPredicate.getPredicateList())); - ctx.error(PatternStringError.literal(predicate + " present in multi")); + ctx.error(onError()); + ctx.error(PatternStringError.literal("%s present in multi", predicate)); return false; } } return true; } + private PatternError onError() { + MutableComponent component = Component.literal("Need one of:\n") + .withStyle(ChatFormatting.WHITE); + + for (BasePredicate predicate : this.rootPredicate) { + for (BlockInfo candidate : predicate.getCandidates()) { + component.append(" ") + .append(candidate.getItemStackForm().getHoverName()) + .append("\n"); + } + } + + if (this.passedPredicate != null) { + component.append("\n") + .append("Expected predicate: " + this.passedPredicate); + } + + return PatternStringError.component(component); + } + @Override public boolean testSliceMin(PredicateContext ctx) { if (passedPredicate == null && noneValid) return true; From e58a6c6cd4b24c870496df53cb75724766d760c3 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:40:32 -0700 Subject: [PATCH 074/101] spotless --- .../com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java | 2 +- .../gtceu/api/multiblock/error/PatternError.java | 4 ++-- .../gtceu/api/multiblock/pattern/BlockPattern.java | 2 +- .../gtceu/api/multiblock/pattern/ExpandablePattern.java | 2 +- .../api/multiblock/pattern/MultiblockPatternBuilder.java | 2 +- .../gtceu/api/multiblock/predicates/BasePredicate.java | 6 +----- .../gtceu/api/multiblock/predicates/logic/AndLogic.java | 2 +- .../gtceu/api/multiblock/predicates/logic/BaseLogic.java | 2 +- .../gtceu/api/multiblock/predicates/logic/OrLogic.java | 2 +- .../gtceu/api/multiblock/predicates/logic/XorLogic.java | 3 ++- .../gtceu/api/multiblock/util/AbstractStructureHelper.java | 2 +- .../gtceu/api/multiblock/util/BlockPatternHelper.java | 2 +- .../gtceu/api/multiblock/util/ExpandablePatternHelper.java | 2 +- .../gtceu/common/data/machines/GCYMMachines.java | 2 +- .../gtceu/common/data/machines/GTMachineUtils.java | 2 +- .../gtceu/common/data/machines/GTMultiMachines.java | 2 +- .../multiblock/electric/ActiveTransformerMachine.java | 2 +- .../machine/multiblock/electric/CentralMonitorMachine.java | 2 +- .../machine/multiblock/electric/CleanroomMachine.java | 2 +- .../multiblock/primitive/CharcoalPileIgniterMachine.java | 2 +- .../recipeviewer/widgets/MultiblockPreviewWidget.java | 2 +- 21 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java b/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java index 50486195f25..ad0828170b6 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/MultiblockSchemaInfo.java @@ -1,11 +1,11 @@ package com.gregtechceu.gtceu.api.mui; import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.pattern.BlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.AbstractStructureHelper; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.client.mui.schema.MutableSchema; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java index 9e92144f355..26fe2425ec2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/error/PatternError.java @@ -30,9 +30,9 @@ public PatternError(@Nullable BlockPos pos, List> candidates) { this.candidates = candidates; } - public PatternError(@Nullable BlockPos pos, MultiPredicate predicate) { + public PatternError(@Nullable BlockPos pos, MultiPredicate predicate) { this(pos, predicate.getCandidates()); - } + } public PatternError(@Nullable BlockPos pos, BasePredicate failingPredicate) { this(pos, Collections.singletonList(failingPredicate.getCandidates())); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index dfe4c357fc5..0e77c4db8ce 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -1,8 +1,8 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index 715fd234754..434937fadd3 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; -import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java index 8eb4b862163..c3c1dbf0dbc 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java @@ -1,8 +1,8 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.Predicates; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.google.common.base.Joiner; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index a70941b10ad..c183e37eaaf 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -1,15 +1,11 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; -import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; -import net.minecraft.client.Minecraft; -import net.minecraft.core.BlockPos; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; import lombok.Getter; import lombok.Setter; @@ -174,7 +170,7 @@ public static MultiPredicate create(@Nullable String debugName, Predicate predicate, - Stream candidateStream, @Nullable Consumer contents) { + Stream candidateStream, @Nullable Consumer contents) { return new SinglePredicate(predicate, candidateStream, debugName, contents); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java index 35d66b8c45d..f0264f7b69e 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -1,9 +1,9 @@ package com.gregtechceu.gtceu.api.multiblock.predicates.logic; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; public class AndLogic extends BaseLogic { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java index b2712655948..622d02529f3 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java @@ -1,9 +1,9 @@ package com.gregtechceu.gtceu.api.multiblock.predicates.logic; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import lombok.Setter; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java index 60287ec9bb0..6e498d8a8c0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java @@ -1,8 +1,8 @@ package com.gregtechceu.gtceu.api.multiblock.predicates.logic; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; public class OrLogic extends BaseLogic { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index f7419d1c567..7177cd5cbdd 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -1,12 +1,13 @@ package com.gregtechceu.gtceu.api.multiblock.predicates.logic; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; + import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java index 27196f0ea42..2207ae75b9f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/AbstractStructureHelper.java @@ -2,9 +2,9 @@ import com.gregtechceu.gtceu.api.block.MetaMachineBlock; import com.gregtechceu.gtceu.api.block.property.GTBlockStateProperties; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java index 7530e33365b..a15dceeb888 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java @@ -1,11 +1,11 @@ package com.gregtechceu.gtceu.api.multiblock.util; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.BlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.PatternSlice; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java index 57735c5434d..1cf6bfcd619 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java @@ -1,9 +1,9 @@ package com.gregtechceu.gtceu.api.multiblock.util; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java index 11e45de7bd4..0c0cf0a8d1c 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java @@ -10,9 +10,9 @@ import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.gregtechceu.gtceu.api.machine.property.GTMachineModelProperties; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderHelper; import com.gregtechceu.gtceu.common.data.GTMaterials; import com.gregtechceu.gtceu.common.data.GTRecipeModifiers; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index e44c197d442..cfe5d1a9aa0 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -22,10 +22,10 @@ import com.gregtechceu.gtceu.api.machine.steam.SimpleSteamMachine; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; import com.gregtechceu.gtceu.api.mui.factory.PanelFactory; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.error.PartAbilityError; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.recipe.GTRecipeType; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java index 1a1f6e74f77..eb33b808d4d 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java @@ -13,9 +13,9 @@ import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.gregtechceu.gtceu.api.machine.property.GTMachineModelProperties; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderHelper; import com.gregtechceu.gtceu.client.util.TooltipHelper; import com.gregtechceu.gtceu.common.block.BoilerFireboxType; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java index 17757387f79..f894e9375ee 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java @@ -11,8 +11,8 @@ import com.gregtechceu.gtceu.api.machine.multiblock.part.MultiblockPartMachine; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; import com.gregtechceu.gtceu.api.misc.EnergyContainerList; -import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.common.mui.GTMultiblockTextUtil; import com.gregtechceu.gtceu.config.ConfigHolder; import com.gregtechceu.gtceu.utils.FormattingUtil; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java index 56d4a14bd94..d4ad7279011 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java @@ -10,11 +10,11 @@ import com.gregtechceu.gtceu.api.machine.multiblock.PartAbility; import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.gregtechceu.gtceu.api.misc.EnergyContainerList; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.sync_system.annotations.RerenderOnChanged; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index 682f2fa7fd0..ea44032c866 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -15,6 +15,7 @@ import com.gregtechceu.gtceu.api.machine.multiblock.WorkableElectricMultiblockMachine; import com.gregtechceu.gtceu.api.machine.multiblock.part.MultiblockPartMachine; import com.gregtechceu.gtceu.api.misc.EnergyContainerList; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.error.FilterMatchingError; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; @@ -22,7 +23,6 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java index 538f6260b5d..d0aa1d889ac 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java @@ -7,12 +7,12 @@ import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; import com.gregtechceu.gtceu.api.machine.multiblock.WorkableMultiblockMachine; import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandableMultiblockPatternBuilder; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.common.data.GTBlocks; import com.gregtechceu.gtceu.common.item.behavior.LighterBehavior; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java index 189096c99e0..4b469ea484b 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java @@ -3,11 +3,11 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; import com.gregtechceu.gtceu.api.mui.MultiblockSchemaInfo; +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.pattern.BlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.client.renderer.PatternPreviewRenderer; import com.gregtechceu.gtceu.common.mui.GTGuiTextures; From 3d555a165555c609d1898401b517ffdf4b97054c Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 18 Jul 2026 02:30:23 -0700 Subject: [PATCH 075/101] commit errors outside BlockPattern directly --- .../multiblock/CoilWorkableElectricMultiblockMachine.java | 2 +- .../gtceu/api/multiblock/pattern/PatternState.java | 8 +++++--- .../multiblock/electric/ActiveTransformerMachine.java | 2 +- .../machine/multiblock/electric/CleanroomMachine.java | 6 +++--- .../multiblock/electric/DistillationTowerMachine.java | 4 ++-- .../machine/multiblock/electric/LargeMinerMachine.java | 2 +- .../multiblock/electric/PowerSubstationMachine.java | 2 +- .../multiblock/electric/research/DataBankMachine.java | 2 +- .../electric/research/ResearchStationMachine.java | 8 ++++---- .../multiblock/steam/SteamParallelMultiblockMachine.java | 2 +- 10 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java b/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java index c16ed92fda3..a096ac0e840 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java @@ -48,7 +48,7 @@ public void formStructure(@NotNull String substructureName) { if (coilType == null) coilType = coil.coilType; else { if (coilType != coil.coilType) { - patternStates.get(substructureName).error( + patternStates.get(substructureName).commitError( new CoilMatchingError(BlockPos.of(entry.getLongKey()), coilType, coil.coilType)); invalidateStructure(substructureName); return; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 30a48c117d5..875c1660ef8 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -77,9 +77,6 @@ public void reset() { Object2ObjectMap> sliceErrors = new Object2ObjectArrayMap<>(); - // it's committing errors just fine - // all the widgets are added to the col on server and client - // but nothing shows for some reason public void commitSliceErrors() { for (Slice slice : this.sliceErrors.keySet()) { this.commitedErrors.addAll(this.sliceErrors.get(slice)); @@ -98,6 +95,11 @@ public void commitErrors() { clearErrors(); } + /// usage intended for outside {@link BlockPattern} + public void commitError(PatternError error) { + this.commitedErrors.add(error); + } + private record Slice(int index, int offset) {} public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState newState) { diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java index f894e9375ee..6a7ebbfafb9 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java @@ -114,7 +114,7 @@ public void formStructure(@NotNull String substructureName) { // Invalidate the structure if there is not at least one output and one input if (powerInput.isEmpty() || powerOutput.isEmpty()) { - pState.error( + pState.commitError( new PatternStringError(Component.translatable("gtceu.predicate_error.active_transformer.missing_io", powerInput.isEmpty(), powerOutput.isEmpty()))); this.invalidateStructure(substructureName); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index ea44032c866..516447daf45 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -135,14 +135,14 @@ public void formStructure(@NotNull String substructureName) { int f = bounds.get(4); int b = bounds.get(5); if (d < MIN_DEPTH || l < MIN_RADIUS || r < MIN_RADIUS || b < MIN_RADIUS || f < MIN_RADIUS) { - pState.error( + pState.commitError( new PatternStringError(Component.translatable("gtceu.predicate_error.cleanroom.too_small"))); invalidateStructure(); return; } if (Math.abs(l - r) > 1 || Math.abs(b - f) > 1) { - pState.error( + pState.commitError( new PatternStringError(Component.translatable("gtceu.predicate_error.cleanroom.not_centered"))); invalidateStructure(); return; @@ -159,7 +159,7 @@ public void formStructure(@NotNull String substructureName) { if (filterType == null) filterType = filter.getKey(); else { if (filterType != filter.getKey()) { - pState.error(new FilterMatchingError(BlockPos.of(entry.getLongKey()), + pState.commitError(new FilterMatchingError(BlockPos.of(entry.getLongKey()), filterType.getCleanroomType(), filter.getKey().getCleanroomType())); invalidateStructure(substructureName); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java index 3d3ae0d3199..ebd2bdd7f3d 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java @@ -100,7 +100,7 @@ public void formStructure(String substructureName) { fluidOutputs.add(VoidFluidHandler.INSTANCE); } else { BlockPos p = part.getBlockPos(); - pState.error(new PatternStringError(Component.translatable( + pState.commitError(new PatternStringError(Component.translatable( "gtceu.predicate_error.distillery.unexpected_hatch", p.getX(), p.getY(), p.getZ()))); // GTCEu.LOGGER.error( // "The Distillation Tower at {} has a fluid export hatch with an unexpected Y position", @@ -110,7 +110,7 @@ public void formStructure(String substructureName) { } } } else { - pState.error( + pState.commitError( new PatternStringError(Component.translatable("gtceu.predicate_error.distillery.missing_outputs"))); invalidateStructure(substructureName); } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java index eb69e8f4bcc..e3b4aac8f34 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java @@ -99,7 +99,7 @@ public void formStructure(@NotNull String substructureName) { public PatternState checkStructurePattern(String name) { var patternState = super.checkStructurePattern(name); if (this.getUpwardsFacing() != Direction.UP && this.getUpwardsFacing() != Direction.DOWN) { - patternState.error(Predicates.PLACEHOLDER); + patternState.commitError(Predicates.PLACEHOLDER); } return patternState; } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java index 860c4a4dfad..a43841eedb8 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java @@ -157,7 +157,7 @@ public void formStructure(@NotNull String substructureName) { */ if (batteries.isEmpty()) { // only empty batteries found in the structure - pState.error(new PatternStringError( + pState.commitError(new PatternStringError( Component.translatable("gtceu.predicate_error.power_substation.missing_batteries"))); invalidateStructure(); return; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java index 2e065bd621d..c23c47c84aa 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java @@ -81,7 +81,7 @@ public void formStructure(@NotNull String substructureName) { this.energyUsage = calculateEnergyUsage(); if (this.maintenance == null) { - pState.error(new PatternStringError( + pState.commitError(new PatternStringError( Component.translatable("gtceu.predicate_error.databank.missing_maintenance"))); invalidateStructure(substructureName); return; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java index a3372ca6773..f8bdf28ab70 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java @@ -61,7 +61,7 @@ public void formStructure(@NotNull String substructureName) { for (MultiblockPartMachine part : getParts()) { if (part instanceof ObjectHolderMachine holder) { if (holder.getFrontFacing() != getFrontFacing().getOpposite()) { - pState.error(new PatternStringError( + pState.commitError(new PatternStringError( Component.translatable("gtceu.predicate_error.object_holder.direction"))); invalidateStructure(substructureName); return; @@ -76,13 +76,13 @@ public void formStructure(@NotNull String substructureName) { // should never happen, but would rather do this than have an obscure NPE if (computationProvider == null) { - pState.error(new PatternStringError( + pState.commitError(new PatternStringError( Component.translatable("gtceu.predicate_error.research.missing_computation"))); invalidateStructure(substructureName); } if (objectHolder == null) { - pState.error(new PatternStringError( + pState.commitError(new PatternStringError( Component.translatable("gtceu.predicate_error.research.missing_object_holder"))); invalidateStructure(substructureName); } @@ -100,7 +100,7 @@ public PatternState checkStructurePattern(String name) { } } if (objHolder != null && objHolder.getFrontFacing() != getFrontFacing().getOpposite()) { - patternState.error( + patternState.commitError( new PatternStringError(Component.translatable("gtceu.predicate_error.object_holder.direction"))); invalidateStructure(name); } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java index 577d619755b..84175bcabdb 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java @@ -88,7 +88,7 @@ public void formStructure(String substructureName) { } } if (steamEnergy == null) { // No steam hatch found - pState.error( + pState.commitError( new PatternStringError(Component.translatable("gtceu.predicate_error.steam.missing_steam_hatch"))); invalidateStructure(substructureName); } From dda65d40dfc603f411720ac9628a5cee3947e10c Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 18 Jul 2026 02:35:34 -0700 Subject: [PATCH 076/101] fix ExpandablePattern --- .../gtceu/api/multiblock/pattern/ExpandablePattern.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index 434937fadd3..5386a00a384 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -17,7 +17,9 @@ import lombok.Setter; import org.jetbrains.annotations.Nullable; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.function.BiFunction; public class ExpandablePattern implements IBlockPattern { @@ -149,6 +151,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c // SOUTH, UP, EAST means point is +z, line is +y, plane is +x. this basically means the x val of the iter is // aisle count, y is str count, and z is char count. + Set visited = new HashSet<>(); for (var pos : BlockPos.betweenClosed(negCorner, posCorner)) { BlockPos.MutableBlockPos mPos = pos.mutable(); MultiPredicate pred = predicateProvider.apply(mPos, bounds); @@ -165,10 +168,12 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c if (!pred.test(patternState)) { return false; } + visited.add(pred); } - for (var entry : patternState.globalCache().object2IntEntrySet()) { - if (!entry.getKey().testGlobalMin(patternState)) { + for (MultiPredicate multiPredicate : visited) { + if (!multiPredicate.testGlobalMin(patternState)) { + patternState.commitErrors(); return false; } } From 209d602933d1f8e090db3b1cae97ab5b1d9c7bb4 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 18 Jul 2026 18:05:11 -0700 Subject: [PATCH 077/101] fix AndLogic --- .../gtceu/api/multiblock/predicates/logic/AndLogic.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java index f0264f7b69e..e1e57fb0f15 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -25,7 +25,6 @@ public boolean test(PredicateContext ctx) { // count manually if (failedMaxCount(ctx, predicate, true) || failedMaxCount(ctx, predicate, false)) return ctx.error(PatternStringError.literal("AND error")); - passed++; // continue... } return passed > 0; From a8e1140ae8bdcdcc09501b6c5b2c2a5d400aa45c Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 18 Jul 2026 18:07:06 -0700 Subject: [PATCH 078/101] split PatternState and PredicateContext --- ...CoilWorkableElectricMultiblockMachine.java | 2 +- .../api/multiblock/PredicateContext.java | 44 +++++++++++-- .../pattern/BasicSliceStrategy.java | 13 +++- .../api/multiblock/pattern/BlockPattern.java | 22 +++---- .../multiblock/pattern/ExpandablePattern.java | 11 ++-- .../api/multiblock/pattern/PatternState.java | 65 ++++++++----------- .../electric/ActiveTransformerMachine.java | 2 +- .../multiblock/electric/CleanroomMachine.java | 6 +- .../electric/DistillationTowerMachine.java | 4 +- .../electric/LargeMinerMachine.java | 2 +- .../electric/PowerSubstationMachine.java | 2 +- .../electric/research/DataBankMachine.java | 2 +- .../research/ResearchStationMachine.java | 8 +-- .../steam/SteamParallelMultiblockMachine.java | 2 +- 14 files changed, 108 insertions(+), 77 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java b/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java index a096ac0e840..c986dd6bef9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/api/machine/multiblock/CoilWorkableElectricMultiblockMachine.java @@ -48,7 +48,7 @@ public void formStructure(@NotNull String substructureName) { if (coilType == null) coilType = coil.coilType; else { if (coilType != coil.coilType) { - patternStates.get(substructureName).commitError( + patternStates.get(substructureName).setError( new CoilMatchingError(BlockPos.of(entry.getLongKey()), coilType, coil.coilType)); invalidateStructure(substructureName); return; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 35d6894fb5c..55ed98e7a56 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -13,6 +13,8 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import lombok.Getter; import lombok.Setter; import org.jetbrains.annotations.Nullable; @@ -21,12 +23,15 @@ public class PredicateContext { + @Getter protected List errors = new ArrayList<>(); - protected final List commitedErrors = new ArrayList<>(); @Getter protected CurrentBlockInfo currentBlockInfo = new CurrentBlockInfo(); protected final Object2IntMap globalCount = new Object2IntOpenHashMap<>(); protected final Object2IntMap layerCount = new Object2IntOpenHashMap<>(); + @Getter + @Setter + private boolean checkLayer = true; @Getter protected FailureReason lastFailureReason = FailureReason.NONE; @@ -47,10 +52,6 @@ private void appendError(PatternError error) { this.lastFailureReason = this.stage.getFailureReason(); } - public List getErrors() { - return Collections.unmodifiableList(this.commitedErrors); - } - /// @return the current Level public Level level() { return Objects.requireNonNull(currentBlockInfo.getLevel()); @@ -84,8 +85,9 @@ public Object2IntMap globalCache() { return this.globalCount; } + /// @return {@code null} if {@link #checkLayer} is false, else returns the layer cache map public @Nullable Object2IntMap layerCache() { - return this.layerCount; + return isCheckLayer() ? this.layerCount : null; } public int incrementGlobalCount(BasePredicate predicate) { @@ -104,6 +106,36 @@ public int getSliceCount(BasePredicate predicate) { return Objects.requireNonNull(layerCache()).getInt(predicate); } + public void clearErrors() { + this.errors = new ArrayList<>(); + this.lastFailureReason = FailureReason.NONE; + } + + Object2ObjectMap> sliceErrors = new Object2ObjectArrayMap<>(); + + public void commitSliceErrors() { + for (Slice slice : this.sliceErrors.keySet()) { + this.errors.addAll(this.sliceErrors.get(slice)); + } + this.sliceErrors.clear(); + } + + public void pushSliceErrors(int index, int offset) { + if (this.errors.isEmpty()) return; + Slice slice = new Slice(index, offset); + this.sliceErrors.merge(slice, this.errors, (l1, l2) -> { + l1.addAll(l2); + return l1; + }); + clearErrors(); + } + + public void updateLevel(Level level) { + this.currentBlockInfo.setLevel(level); + } + + private record Slice(int index, int offset) {} + public enum PredicateStage { INTERNAL, diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java index dbb3cdb8d4f..d18f17427a9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.multiblock.pattern; import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.google.common.base.Preconditions; @@ -55,11 +56,13 @@ public int getMultiSliceRepeats(int index) { protected int checkMultiSlice(PatternState state, MultiblockSlice multiblockSlice, int offset, boolean flip) { int sliceOffset = 0; int temp = 0; + PredicateContext context = state.getContext(); for (int i = 1; i <= multiblockSlice.maxRepeats; i++) { for (int j = multiblockSlice.startInclusive; j < multiblockSlice.endExclusive; j++) { int res = checkRepeatSlice(state, j, offset + temp, flip); if (res == -1) { - state.commitSliceErrors(); + context.commitSliceErrors(); + state.setErrors(context.getErrors()); if (i <= multiblockSlice.minRepeats) return -1; multiblockSlice.actualRepeats = i - 1; return sliceOffset; @@ -75,10 +78,14 @@ protected int checkMultiSlice(PatternState state, MultiblockSlice multiblockSlic protected int checkRepeatSlice(PatternState state, int index, int offset, boolean flip) { PatternSlice slice = slices.get(index); + PredicateContext context = state.getContext(); for (int i = 1; i <= slice.maxRepeats; i++) { boolean res = checkSlice(state, index, offset + i - 1, flip); - state.pushSliceErrors(index, offset); - if (!res) { + if (res) { + context.clearErrors(); + // continue... + } else { + context.pushSliceErrors(index, offset); if (i <= slice.minRepeats) return -1; return slices.get(index).actualRepeats = i - 1; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 0e77c4db8ce..abd74c1edc8 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -141,16 +141,15 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c boolean isFlipped) { Objects.requireNonNull(patternState, "PatternState not set"); - patternState.globalCache().clear(); - patternState.layerCache().clear(); + PredicateContext context = patternState.resetContext(true); // only try to clear the cache for structure checking mapping when checking the structure for unflipped // maybe switch to a multiblock state value instead? if (!isFlipped) { patternState.getCache().clear(); } - patternState.updateLevel(level); - patternState.reset(); // clear any existing committed errors + context.updateLevel(level); + // context.reset(); // clear any existing committed errors BlockPos.MutableBlockPos controllerPos = centerPos.mutable(); @@ -163,10 +162,10 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c if (!sliceStrategy.check(patternState, isFlipped)) return false; // global min check - patternState.setStage(PredicateContext.PredicateStage.GLOBAL_MIN); + context.setStage(PredicateContext.PredicateStage.GLOBAL_MIN); for (MultiPredicate predicate : predicates.values()) { - if (!predicate.testGlobalMin(patternState)) { - patternState.commitErrors(); + if (!predicate.testGlobalMin(context)) { + patternState.setErrors(context.getErrors()); return false; } } @@ -202,7 +201,8 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p BlockPos.MutableBlockPos charPos = sliceStart.mutable(); PatternSlice slice = slices[sliceIndex]; - patternState.layerCache().clear(); + PredicateContext context = patternState.getContext(); + context.layerCache().clear(); Set visitedPredicates = new HashSet<>(); for (int stringIdx = 0; stringIdx < dimensions[1]; stringIdx++) { @@ -214,7 +214,7 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p // internal predicate check, global/slice max checks // if all internal predicates pass, but global/slice max/min checks fail, then do not flip - if (!pred.test(patternState)) { + if (!pred.test(context)) { return false; } @@ -228,9 +228,9 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p } // slice min check - patternState.setStage(PredicateContext.PredicateStage.SLICE_MIN); + context.setStage(PredicateContext.PredicateStage.SLICE_MIN); for (MultiPredicate predicate : visitedPredicates) { - if (!predicate.testSliceMin(patternState)) { + if (!predicate.testSliceMin(context)) { return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index 5386a00a384..419ef3af9b7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -2,6 +2,7 @@ import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import net.minecraft.core.BlockPos; @@ -101,7 +102,7 @@ public void checkPatternFastAt(Level level, PatternState patternState, BlockPos return; } - if (allowsFlip && patternState.getLastFailureReason().shouldCheckFlip()) { + if (allowsFlip && patternState.shouldCheckFlip()) { valid = checkPatternAt(level, patternState, centerPos, frontFacing, upwardsFacing, true); } if (!valid) { @@ -121,7 +122,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c List bounds = boundsProvider.apply(level, centerPos.mutable(), frontFacing, upwardsFacing); if (bounds.isEmpty()) return false; - patternState.globalCache().clear(); + PredicateContext context = patternState.resetContext(false); BlockPos.MutableBlockPos negCorner = new BlockPos.MutableBlockPos(); BlockPos.MutableBlockPos posCorner = new BlockPos.MutableBlockPos(); @@ -165,15 +166,15 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c if (!pred.isAny()) patternState.updateCache(); - if (!pred.test(patternState)) { + if (!pred.test(context)) { return false; } visited.add(pred); } for (MultiPredicate multiPredicate : visited) { - if (!multiPredicate.testGlobalMin(patternState)) { - patternState.commitErrors(); + if (!multiPredicate.testGlobalMin(context)) { + patternState.setErrors(context.getErrors()); return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 875c1660ef8..b121f19d2a8 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -9,24 +9,23 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import lombok.Getter; import lombok.Setter; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; /* * Contains vital information to an instanced version of a structure pattern. */ -public class PatternState extends PredicateContext { +public class PatternState { @Getter protected @Nullable BlockPos controllerPos; @@ -42,10 +41,14 @@ public class PatternState extends PredicateContext { protected boolean actualFlipped = false; @Setter protected boolean shouldUpdate = true; + @Getter + protected List errors = List.of(); @Setter @Getter protected CheckState state = CheckState.UNINITIALIZED; @Getter + protected final PredicateContext context = new PredicateContext(); + @Getter protected final Long2ObjectMap cache = new Long2ObjectOpenHashMap<>(); public void setController(MultiblockControllerMachine controller, BlockPos controllerPos) { @@ -63,47 +66,32 @@ public boolean shouldUpdate() { } public boolean hasErrors() { - return !this.commitedErrors.isEmpty(); + return !this.errors.isEmpty(); } public void clearErrors() { - this.errors = new ArrayList<>(); - this.lastFailureReason = FailureReason.NONE; - } - - public void reset() { - this.commitedErrors.clear(); + this.errors = List.of(); } - Object2ObjectMap> sliceErrors = new Object2ObjectArrayMap<>(); - - public void commitSliceErrors() { - for (Slice slice : this.sliceErrors.keySet()) { - this.commitedErrors.addAll(this.sliceErrors.get(slice)); - } - this.sliceErrors.clear(); - } - - public void pushSliceErrors(int index, int offset) { - Slice slice = new Slice(index, offset); - this.sliceErrors.put(slice, this.errors); - clearErrors(); - } - - public void commitErrors() { - this.commitedErrors.addAll(this.errors); - clearErrors(); + public PredicateContext resetContext(boolean withLayer) { + this.context.clearErrors(); + this.context.globalCache().clear(); + if (withLayer) this.context.layerCache().clear(); + this.context.setCheckLayer(withLayer); + return this.context; } /// usage intended for outside {@link BlockPattern} - public void commitError(PatternError error) { - this.commitedErrors.add(error); + public void setError(PatternError error) { + this.errors = List.of(error); } - private record Slice(int index, int offset) {} + public void setErrors(List errors) { + this.errors = Collections.unmodifiableList(errors); + } public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState newState) { - if (!(currentBlockInfo.getLevel() instanceof ServerLevel serverLevel)) return; + if (!(context.level() instanceof ServerLevel serverLevel)) return; if (pos.equals(controllerPos)) { if (controller != null && !newState.is(controller.getBlockState().getBlock())) { controller.invalidateStructure(MultiblockControllerMachine.DEFAULT_STRUCTURE); @@ -134,19 +122,22 @@ public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState ne } protected void updateLevel(Level level) { - getCurrentBlockInfo().setLevel(level); + context.getCurrentBlockInfo().setLevel(level); } public void setPos(BlockPos.MutableBlockPos charPos) { - getCurrentBlockInfo().setCurrentPos(charPos); + context.getCurrentBlockInfo().setCurrentPos(charPos); } protected void updateCache() { - getCache().put(pos().asLong(), new BlockInfo(state(), blockEntity())); + BlockPos pos = context.pos(); + BlockState blockState = context.state(); + BlockEntity blockEntity = context.blockEntity(); + getCache().put(pos.asLong(), new BlockInfo(blockState, blockEntity)); } public boolean shouldCheckFlip() { - return this.getLastFailureReason().shouldCheckFlip(); + return context.getLastFailureReason().shouldCheckFlip(); } @Getter diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java index 6a7ebbfafb9..3391715c93b 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/ActiveTransformerMachine.java @@ -114,7 +114,7 @@ public void formStructure(@NotNull String substructureName) { // Invalidate the structure if there is not at least one output and one input if (powerInput.isEmpty() || powerOutput.isEmpty()) { - pState.commitError( + pState.setError( new PatternStringError(Component.translatable("gtceu.predicate_error.active_transformer.missing_io", powerInput.isEmpty(), powerOutput.isEmpty()))); this.invalidateStructure(substructureName); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index 516447daf45..cb18fcab298 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -135,14 +135,14 @@ public void formStructure(@NotNull String substructureName) { int f = bounds.get(4); int b = bounds.get(5); if (d < MIN_DEPTH || l < MIN_RADIUS || r < MIN_RADIUS || b < MIN_RADIUS || f < MIN_RADIUS) { - pState.commitError( + pState.setError( new PatternStringError(Component.translatable("gtceu.predicate_error.cleanroom.too_small"))); invalidateStructure(); return; } if (Math.abs(l - r) > 1 || Math.abs(b - f) > 1) { - pState.commitError( + pState.setError( new PatternStringError(Component.translatable("gtceu.predicate_error.cleanroom.not_centered"))); invalidateStructure(); return; @@ -159,7 +159,7 @@ public void formStructure(@NotNull String substructureName) { if (filterType == null) filterType = filter.getKey(); else { if (filterType != filter.getKey()) { - pState.commitError(new FilterMatchingError(BlockPos.of(entry.getLongKey()), + pState.setError(new FilterMatchingError(BlockPos.of(entry.getLongKey()), filterType.getCleanroomType(), filter.getKey().getCleanroomType())); invalidateStructure(substructureName); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java index ebd2bdd7f3d..7b959945301 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java @@ -100,7 +100,7 @@ public void formStructure(String substructureName) { fluidOutputs.add(VoidFluidHandler.INSTANCE); } else { BlockPos p = part.getBlockPos(); - pState.commitError(new PatternStringError(Component.translatable( + pState.setError(new PatternStringError(Component.translatable( "gtceu.predicate_error.distillery.unexpected_hatch", p.getX(), p.getY(), p.getZ()))); // GTCEu.LOGGER.error( // "The Distillation Tower at {} has a fluid export hatch with an unexpected Y position", @@ -110,7 +110,7 @@ public void formStructure(String substructureName) { } } } else { - pState.commitError( + pState.setError( new PatternStringError(Component.translatable("gtceu.predicate_error.distillery.missing_outputs"))); invalidateStructure(substructureName); } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java index e3b4aac8f34..a3bd80299bc 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/LargeMinerMachine.java @@ -99,7 +99,7 @@ public void formStructure(@NotNull String substructureName) { public PatternState checkStructurePattern(String name) { var patternState = super.checkStructurePattern(name); if (this.getUpwardsFacing() != Direction.UP && this.getUpwardsFacing() != Direction.DOWN) { - patternState.commitError(Predicates.PLACEHOLDER); + patternState.setError(Predicates.PLACEHOLDER); } return patternState; } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java index a43841eedb8..412825fb517 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/PowerSubstationMachine.java @@ -157,7 +157,7 @@ public void formStructure(@NotNull String substructureName) { */ if (batteries.isEmpty()) { // only empty batteries found in the structure - pState.commitError(new PatternStringError( + pState.setError(new PatternStringError( Component.translatable("gtceu.predicate_error.power_substation.missing_batteries"))); invalidateStructure(); return; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java index c23c47c84aa..2380401dbbc 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/DataBankMachine.java @@ -81,7 +81,7 @@ public void formStructure(@NotNull String substructureName) { this.energyUsage = calculateEnergyUsage(); if (this.maintenance == null) { - pState.commitError(new PatternStringError( + pState.setError(new PatternStringError( Component.translatable("gtceu.predicate_error.databank.missing_maintenance"))); invalidateStructure(substructureName); return; diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java index f8bdf28ab70..2f31f1daa0e 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/research/ResearchStationMachine.java @@ -61,7 +61,7 @@ public void formStructure(@NotNull String substructureName) { for (MultiblockPartMachine part : getParts()) { if (part instanceof ObjectHolderMachine holder) { if (holder.getFrontFacing() != getFrontFacing().getOpposite()) { - pState.commitError(new PatternStringError( + pState.setError(new PatternStringError( Component.translatable("gtceu.predicate_error.object_holder.direction"))); invalidateStructure(substructureName); return; @@ -76,13 +76,13 @@ public void formStructure(@NotNull String substructureName) { // should never happen, but would rather do this than have an obscure NPE if (computationProvider == null) { - pState.commitError(new PatternStringError( + pState.setError(new PatternStringError( Component.translatable("gtceu.predicate_error.research.missing_computation"))); invalidateStructure(substructureName); } if (objectHolder == null) { - pState.commitError(new PatternStringError( + pState.setError(new PatternStringError( Component.translatable("gtceu.predicate_error.research.missing_object_holder"))); invalidateStructure(substructureName); } @@ -100,7 +100,7 @@ public PatternState checkStructurePattern(String name) { } } if (objHolder != null && objHolder.getFrontFacing() != getFrontFacing().getOpposite()) { - patternState.commitError( + patternState.setError( new PatternStringError(Component.translatable("gtceu.predicate_error.object_holder.direction"))); invalidateStructure(name); } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java index 84175bcabdb..973e0f5d5dd 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/steam/SteamParallelMultiblockMachine.java @@ -88,7 +88,7 @@ public void formStructure(String substructureName) { } } if (steamEnergy == null) { // No steam hatch found - pState.commitError( + pState.setError( new PatternStringError(Component.translatable("gtceu.predicate_error.steam.missing_steam_hatch"))); invalidateStructure(substructureName); } From 9926af2c76254259105dda262f3d701a2356233f Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Sat, 18 Jul 2026 18:27:51 -0700 Subject: [PATCH 079/101] improve and fix the pattern helpers --- .../multiblock/util/BlockPatternHelper.java | 24 +++++++++++++------ .../util/ExpandablePatternHelper.java | 17 +++++++++++-- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java index a15dceeb888..2e25d628be2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java @@ -7,6 +7,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.PatternSlice; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Vec3i; @@ -131,14 +132,19 @@ protected void populateFromPattern(Map resultStructure, IBl private boolean tryMinCount(Map resultStructure, MultiPredicate predicate, BlockPos pos, Direction dir, int offset) { for (BasePredicate basePredicate : predicate) { + if (basePredicate instanceof CompactedPredicate compactedPredicate) { + if (!tryMinCount(resultStructure, compactedPredicate.expand(), pos, dir, offset)) { + continue; + } + return true; + } int minCount = getMinCount(predicate, basePredicate); if (minCount == 0) continue; int totalAlreadyPopulated = countPopulatedGlobal(resultStructure, basePredicate); int layerAlreadyPopulated = countPopulatedInLayer(resultStructure, basePredicate, dir, offset); - boolean globalMinUnmet = minCount > 0 && totalAlreadyPopulated < minCount; - boolean layerMinUnmet = basePredicate.getMinSliceCount() > 0 && - layerAlreadyPopulated < basePredicate.getMinSliceCount(); + boolean globalMinUnmet = basePredicate.testGlobalMin(totalAlreadyPopulated); + boolean layerMinUnmet = basePredicate.testSliceMin(layerAlreadyPopulated); if (!globalMinUnmet && !layerMinUnmet) continue; BlockInfo toInsert = blockPreferences.get(predicate, basePredicate); @@ -160,15 +166,19 @@ private boolean tryMinCount(Map resultStructure, MultiPredi private boolean tryMaxCount(Map resultStructure, MultiPredicate predicate, BlockPos pos, Direction dir, int offset) { for (BasePredicate basePredicate : predicate) { + if (basePredicate instanceof CompactedPredicate compactedPredicate) { + if (!tryMaxCount(resultStructure, compactedPredicate.expand(), pos, dir, offset)) { + continue; + } + return true; + } int maxCount = getMaxCount(predicate, basePredicate); if (maxCount == 0) continue; int totalAlreadyPopulated = countPopulatedGlobal(resultStructure, basePredicate); int layerAlreadyPopulated = countPopulatedInLayer(resultStructure, basePredicate, dir, offset); - if (maxCount != -1 && totalAlreadyPopulated >= maxCount) continue; - if (basePredicate.getMaxSliceCount() != -1 && layerAlreadyPopulated >= basePredicate.getMaxSliceCount()) { - continue; - } + if (!basePredicate.testGlobalMax(totalAlreadyPopulated)) continue; + if (!basePredicate.testSliceMax(layerAlreadyPopulated)) continue; BlockInfo toInsert = blockPreferences.get(predicate, basePredicate); if (toInsert == null) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java index 1cf6bfcd619..d98c1b0a17f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java @@ -5,6 +5,7 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.levelgen.structure.BoundingBox; @@ -111,11 +112,17 @@ public void populateFromPattern(Map resultStructure, IBlock private boolean tryMinCount(Map resultStructure, MultiPredicate predicate, BlockPos pos) { for (BasePredicate basePredicate : predicate) { + if (basePredicate instanceof CompactedPredicate compactedPredicate) { + if (!tryMinCount(resultStructure, compactedPredicate.expand(), pos)) { + continue; + } + return true; + } int minCount = getMinCount(predicate, basePredicate); if (minCount == 0) continue; int totalAlreadyPopulated = countPopulatedGlobal(resultStructure, basePredicate); - if (minCount <= 0 || totalAlreadyPopulated >= minCount) continue; + if (!basePredicate.testGlobalMax(totalAlreadyPopulated)) continue; BlockInfo toInsert = null; if (blockPreferences.contains(predicate, basePredicate)) { @@ -132,11 +139,17 @@ private boolean tryMinCount(Map resultStructure, MultiPredi private boolean tryMaxCount(Map resultStructure, MultiPredicate predicate, BlockPos pos) { for (BasePredicate basePredicate : predicate) { + if (basePredicate instanceof CompactedPredicate compactedPredicate) { + if (!tryMaxCount(resultStructure, compactedPredicate.expand(), pos)) { + continue; + } + return true; + } int maxCount = getMaxCount(predicate, basePredicate); if (maxCount == 0) continue; int totalAlreadyPopulated = countPopulatedGlobal(resultStructure, basePredicate); - if (maxCount != -1 && totalAlreadyPopulated >= maxCount) continue; + if (!basePredicate.testGlobalMax(totalAlreadyPopulated)) continue; BlockInfo toInsert = null; if (blockPreferences.contains(predicate, basePredicate)) { From 6104b83ad744d23ebc6969ea387ec5d257c90dcf Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Mon, 27 Jul 2026 18:40:13 -0700 Subject: [PATCH 080/101] split PatternState and PredicateContext apart --- .../api/multiblock/PredicateContext.java | 75 ++++++++++++++----- .../pattern/BasicSliceStrategy.java | 9 +-- .../api/multiblock/pattern/BlockPattern.java | 3 +- .../multiblock/pattern/CurrentBlockInfo.java | 5 -- .../multiblock/pattern/ExpandablePattern.java | 6 +- .../api/multiblock/pattern/PatternState.java | 42 +++++------ 6 files changed, 83 insertions(+), 57 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 55ed98e7a56..563341aad1a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -1,9 +1,13 @@ package com.gregtechceu.gtceu.api.multiblock; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; +import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; +import com.gregtechceu.gtceu.api.multiblock.pattern.PatternState; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; +import it.unimi.dsi.fastutil.objects.*; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; @@ -11,20 +15,16 @@ import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import lombok.Getter; import lombok.Setter; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; public class PredicateContext { - @Getter - protected List errors = new ArrayList<>(); + private final PatternState state; @Getter protected CurrentBlockInfo currentBlockInfo = new CurrentBlockInfo(); protected final Object2IntMap globalCount = new Object2IntOpenHashMap<>(); @@ -36,9 +36,12 @@ public class PredicateContext { @Getter protected FailureReason lastFailureReason = FailureReason.NONE; - @Setter protected PredicateStage stage = PredicateStage.INTERNAL; + public PredicateContext(PatternState state) { + this.state = state; + } + /// accepts a pattern error /// /// @return false @@ -48,10 +51,18 @@ public boolean error(PatternError error) { } private void appendError(PatternError error) { - this.errors.add(error); + if (currentSlice != null) { + getCurrentSliceErrors().add(error); + } else { + this.state.setError(error); + } this.lastFailureReason = this.stage.getFailureReason(); } + private List getCurrentSliceErrors() { + return this.sliceErrors.computeIfAbsent(Objects.requireNonNull(currentSlice), k -> new ArrayList<>()); + } + /// @return the current Level public Level level() { return Objects.requireNonNull(currentBlockInfo.getLevel()); @@ -107,34 +118,58 @@ public int getSliceCount(BasePredicate predicate) { } public void clearErrors() { - this.errors = new ArrayList<>(); + this.sliceErrors.remove(currentSlice); this.lastFailureReason = FailureReason.NONE; } - Object2ObjectMap> sliceErrors = new Object2ObjectArrayMap<>(); + Object2ObjectMap> sliceErrors = new Object2ObjectAVLTreeMap<>( + Comparator.comparingInt(Slice::index).thenComparing(Slice::offset) + ); public void commitSliceErrors() { for (Slice slice : this.sliceErrors.keySet()) { - this.errors.addAll(this.sliceErrors.get(slice)); + this.state.appendErrors(List.of(PatternStringError.literal("error(s) at %s", slice))); + this.state.appendErrors(this.sliceErrors.get(slice)); } this.sliceErrors.clear(); } - public void pushSliceErrors(int index, int offset) { - if (this.errors.isEmpty()) return; - Slice slice = new Slice(index, offset); - this.sliceErrors.merge(slice, this.errors, (l1, l2) -> { - l1.addAll(l2); - return l1; - }); - clearErrors(); + private @Nullable Slice currentSlice; + + public void pushSlice(int index, int offset) { + currentSlice = new Slice(index, offset); } public void updateLevel(Level level) { this.currentBlockInfo.setLevel(level); } - private record Slice(int index, int offset) {} + public void updatePos(BlockPos pos) { + this.currentBlockInfo.setCurrentPos(pos); + } + + public BlockInfo computeBlockInfo() { + return new BlockInfo(state(), blockEntity()); + } + + public void setStage(PredicateStage stage) { + this.stage = stage; +// if (stage == PredicateStage.GLOBAL_MIN || stage == PredicateStage.SLICE_MIN) { +// this.currentSlice = null; +// } + } + + private record Slice(int index, int offset) implements Comparable { + + @Override + public int compareTo(PredicateContext.Slice o) { + int i = Integer.compare(this.index, o.index); + if (i == 0) { + return Integer.compare(this.offset, o.offset); + } + return i; + } + } public enum PredicateStage { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java index d18f17427a9..5f4524bcdb7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java @@ -62,7 +62,6 @@ protected int checkMultiSlice(PatternState state, MultiblockSlice multiblockSlic int res = checkRepeatSlice(state, j, offset + temp, flip); if (res == -1) { context.commitSliceErrors(); - state.setErrors(context.getErrors()); if (i <= multiblockSlice.minRepeats) return -1; multiblockSlice.actualRepeats = i - 1; return sliceOffset; @@ -80,16 +79,14 @@ protected int checkRepeatSlice(PatternState state, int index, int offset, boolea PatternSlice slice = slices.get(index); PredicateContext context = state.getContext(); for (int i = 1; i <= slice.maxRepeats; i++) { + context.pushSlice(index, offset + i - 1); boolean res = checkSlice(state, index, offset + i - 1, flip); - if (res) { - context.clearErrors(); - // continue... - } else { - context.pushSliceErrors(index, offset); + if (!res) { if (i <= slice.minRepeats) return -1; return slices.get(index).actualRepeats = i - 1; } + context.clearErrors(); } return slices.get(index).actualRepeats = slice.maxRepeats; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index abd74c1edc8..e1bf0cfba3c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -165,7 +165,6 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c context.setStage(PredicateContext.PredicateStage.GLOBAL_MIN); for (MultiPredicate predicate : predicates.values()) { if (!predicate.testGlobalMin(context)) { - patternState.setErrors(context.getErrors()); return false; } } @@ -207,7 +206,7 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p Set visitedPredicates = new HashSet<>(); for (int stringIdx = 0; stringIdx < dimensions[1]; stringIdx++) { for (int charIdx = 0; charIdx < dimensions[2]; charIdx++) { - patternState.setPos(charPos); + context.updatePos(charPos); MultiPredicate pred = predicates.get(slice.charAt(stringIdx, charIdx)); if (!pred.isAny()) patternState.updateCache(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/CurrentBlockInfo.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/CurrentBlockInfo.java index c849a4d38f4..080d331656d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/CurrentBlockInfo.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/CurrentBlockInfo.java @@ -51,11 +51,6 @@ public void setCurrentPos(BlockPos pos) { updateStateAndEntity(); } - public void setCurrentPos(BlockPos.MutableBlockPos pos) { - this.pos.set(pos); - updateStateAndEntity(); - } - public BlockPos getBlockPos() { return pos; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index 419ef3af9b7..58569960709 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -146,7 +146,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c } } - patternState.updateLevel(level); + context.updateLevel(level); BlockPos.MutableBlockPos translation = centerPos.mutable(); @@ -162,7 +162,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c pos.getZ()); // translate from the origin to the center mPos = mPos.offset(translation).mutable(); - patternState.setPos(mPos); + context.updatePos(mPos); if (!pred.isAny()) patternState.updateCache(); @@ -172,9 +172,9 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c visited.add(pred); } + context.setStage(PredicateContext.PredicateStage.GLOBAL_MIN); for (MultiPredicate multiPredicate : visited) { if (!multiPredicate.testGlobalMin(context)) { - patternState.setErrors(context.getErrors()); return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index b121f19d2a8..2cd13f4d3eb 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -8,7 +8,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; @@ -19,6 +18,7 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -46,8 +46,7 @@ public class PatternState { @Setter @Getter protected CheckState state = CheckState.UNINITIALIZED; - @Getter - protected final PredicateContext context = new PredicateContext(); + protected @Nullable PredicateContext context; @Getter protected final Long2ObjectMap cache = new Long2ObjectOpenHashMap<>(); @@ -74,10 +73,15 @@ public void clearErrors() { } public PredicateContext resetContext(boolean withLayer) { - this.context.clearErrors(); - this.context.globalCache().clear(); - if (withLayer) this.context.layerCache().clear(); - this.context.setCheckLayer(withLayer); + PredicateContext context = getContext(); + context.setCheckLayer(withLayer); + return context; + } + + public PredicateContext getContext() { + if (this.context == null) { + this.context = new PredicateContext(this); + } return this.context; } @@ -90,8 +94,14 @@ public void setErrors(List errors) { this.errors = Collections.unmodifiableList(errors); } + public void appendErrors(List errors) { + ArrayList list = new ArrayList<>(this.errors); + list.addAll(errors); + setErrors(list); + } + public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState newState) { - if (!(context.level() instanceof ServerLevel serverLevel)) return; + if (!(getContext().level() instanceof ServerLevel serverLevel)) return; if (pos.equals(controllerPos)) { if (controller != null && !newState.is(controller.getBlockState().getBlock())) { controller.invalidateStructure(MultiblockControllerMachine.DEFAULT_STRUCTURE); @@ -121,23 +131,13 @@ public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState ne } } - protected void updateLevel(Level level) { - context.getCurrentBlockInfo().setLevel(level); - } - - public void setPos(BlockPos.MutableBlockPos charPos) { - context.getCurrentBlockInfo().setCurrentPos(charPos); - } - protected void updateCache() { - BlockPos pos = context.pos(); - BlockState blockState = context.state(); - BlockEntity blockEntity = context.blockEntity(); - getCache().put(pos.asLong(), new BlockInfo(blockState, blockEntity)); + PredicateContext context = getContext(); + getCache().put(context.pos().asLong(), context.computeBlockInfo()); } public boolean shouldCheckFlip() { - return context.getLastFailureReason().shouldCheckFlip(); + return getContext().getLastFailureReason().shouldCheckFlip(); } @Getter From 31973e855e37e917f708dc0e604c4aab67d24027 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Tue, 28 Jul 2026 12:45:36 -0700 Subject: [PATCH 081/101] set parent for base predicates --- .../com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index 1d4687666e5..cc269a20455 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -39,6 +39,7 @@ public class MultiPredicate implements Iterable { public MultiPredicate(BasePredicate predicate) { this.predicateList = List.of(predicate); + predicate.setParent(this); this.logic = Logic.OR.createLogic(this); this.hasAir = predicate == BasePredicate.AIR; } @@ -53,6 +54,7 @@ private MultiPredicate(Logic type, MultiPredicate a, MultiPredicate b) { ArrayList builder = new ArrayList<>(); appendPredicates(type, a, builder); appendPredicates(type, b, builder); + builder.forEach(p -> p.setParent(this)); builder.sort(PREDICATE_COMPARATOR); this.predicateList = Collections.unmodifiableList(builder); this.logic = type.createLogic(this); From 7f1bea589d6b01e91ad18775593c713a08d1dff9 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Tue, 28 Jul 2026 18:06:27 -0700 Subject: [PATCH 082/101] select innermost BasePredicate for testing rework how max count checks are performed (again) make predicate context in PatternState final add reset method to PredicateContext add boolean field for check flip simplify map comparator --- .../gtceu/api/multiblock/MultiPredicate.java | 19 +++++++++ .../api/multiblock/PredicateContext.java | 39 ++++++++++++------- .../api/multiblock/pattern/BlockPattern.java | 24 ++++++++++-- .../api/multiblock/pattern/PatternState.java | 23 ++++++----- .../multiblock/predicates/BasePredicate.java | 18 +++++---- .../multiblock/predicates/logic/AndLogic.java | 10 +++++ .../predicates/logic/BaseLogic.java | 9 ++++- .../multiblock/predicates/logic/OrLogic.java | 5 +++ .../multiblock/predicates/logic/XorLogic.java | 20 +++++++++- .../multiblock/util/BlockPatternHelper.java | 2 +- .../util/ExpandablePatternHelper.java | 2 +- 11 files changed, 130 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index cc269a20455..063edf29ae7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -266,6 +266,25 @@ private static void appendPredicates(Logic type, MultiPredicate multiPredicate, } } + /// @return innermost base predicate that passes state check at given pos + public @Nullable BasePredicate getPredicateAtPos(PredicateContext context) { + for (BasePredicate predicate : this) { + if (predicate instanceof CompactedPredicate compacted) { + var p = compacted.expand().getPredicateAtPos(context); + if (p != null) return p; + // else continue... + } else if (predicate.test(context)) { + // logic needs to capture this + getLogic().predicatePassed(predicate); + return predicate; + } else { + // handle errors better than this + context.clearErrors(); + } + } + return null; + } + public enum Logic { OR, diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 563341aad1a..17c0b1f6b3a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -5,9 +5,8 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.pattern.PatternState; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; - import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; -import it.unimi.dsi.fastutil.objects.*; + import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; @@ -15,9 +14,9 @@ import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; +import it.unimi.dsi.fastutil.objects.*; import lombok.Getter; import lombok.Setter; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -34,8 +33,15 @@ public class PredicateContext { private boolean checkLayer = true; @Getter - protected FailureReason lastFailureReason = FailureReason.NONE; + private boolean checkFlipped = false; + + @Getter + private FailureReason lastFailureReason = FailureReason.NONE; + // if (stage == PredicateStage.GLOBAL_MIN || stage == PredicateStage.SLICE_MIN) { + // this.currentSlice = null; + // } + @Setter protected PredicateStage stage = PredicateStage.INTERNAL; public PredicateContext(PatternState state) { @@ -57,6 +63,7 @@ private void appendError(PatternError error) { this.state.setError(error); } this.lastFailureReason = this.stage.getFailureReason(); + this.checkFlipped = this.lastFailureReason.shouldCheckFlip(); } private List getCurrentSliceErrors() { @@ -122,13 +129,11 @@ public void clearErrors() { this.lastFailureReason = FailureReason.NONE; } - Object2ObjectMap> sliceErrors = new Object2ObjectAVLTreeMap<>( - Comparator.comparingInt(Slice::index).thenComparing(Slice::offset) - ); + Object2ObjectMap> sliceErrors = new Object2ObjectAVLTreeMap<>(Slice::compareTo); public void commitSliceErrors() { for (Slice slice : this.sliceErrors.keySet()) { - this.state.appendErrors(List.of(PatternStringError.literal("error(s) at %s", slice))); + this.state.appendError(PatternStringError.literal("error(s) at %s", slice)); this.state.appendErrors(this.sliceErrors.get(slice)); } this.sliceErrors.clear(); @@ -137,7 +142,7 @@ public void commitSliceErrors() { private @Nullable Slice currentSlice; public void pushSlice(int index, int offset) { - currentSlice = new Slice(index, offset); + this.currentSlice = new Slice(index, offset); } public void updateLevel(Level level) { @@ -152,11 +157,17 @@ public BlockInfo computeBlockInfo() { return new BlockInfo(state(), blockEntity()); } - public void setStage(PredicateStage stage) { - this.stage = stage; -// if (stage == PredicateStage.GLOBAL_MIN || stage == PredicateStage.SLICE_MIN) { -// this.currentSlice = null; -// } + public void skipFlipCheck() { + this.checkFlipped = false; + } + + public void reset() { + setStage(PredicateStage.INTERNAL); + this.currentBlockInfo = new CurrentBlockInfo(); + this.currentSlice = null; + this.sliceErrors.clear(); + this.globalCount.clear(); + this.layerCount.clear(); } private record Slice(int index, int offset) implements Comparable { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index e1bf0cfba3c..d41c08a4474 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -3,6 +3,7 @@ import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import net.minecraft.core.BlockPos; @@ -211,12 +212,29 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p if (!pred.isAny()) patternState.updateCache(); - // internal predicate check, global/slice max checks - // if all internal predicates pass, but global/slice max/min checks fail, then do not flip - if (!pred.test(context)) { + context.setStage(PredicateContext.PredicateStage.INTERNAL); + // state check + BasePredicate predicateAtPos = pred.getPredicateAtPos(context); + /* + * a{ f, + * b, + * c{ d, e } } + * if d + * get reference to c + * which is get parent + */ + + // max count checks + if (predicateAtPos == null || !predicateAtPos.checkMaxCount(context)) { return false; } + // internal predicate check, global/slice max checks + // if all internal predicates pass, but global/slice max/min checks fail, then do not flip + // if (!pred.test(context)) { + // return false; + // } + visitedPredicates.add(pred); charPos.move(absoluteChar); // continue... diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 2cd13f4d3eb..147c12375be 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -8,7 +8,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; @@ -46,7 +45,8 @@ public class PatternState { @Setter @Getter protected CheckState state = CheckState.UNINITIALIZED; - protected @Nullable PredicateContext context; + @Getter + protected final PredicateContext context = new PredicateContext(this); @Getter protected final Long2ObjectMap cache = new Long2ObjectOpenHashMap<>(); @@ -73,15 +73,8 @@ public void clearErrors() { } public PredicateContext resetContext(boolean withLayer) { - PredicateContext context = getContext(); - context.setCheckLayer(withLayer); - return context; - } - - public PredicateContext getContext() { - if (this.context == null) { - this.context = new PredicateContext(this); - } + this.context.reset(); + this.context.setCheckLayer(withLayer); return this.context; } @@ -94,6 +87,12 @@ public void setErrors(List errors) { this.errors = Collections.unmodifiableList(errors); } + public void appendError(PatternError error) { + ArrayList errors = new ArrayList<>(this.errors); + errors.add(error); + setErrors(errors); + } + public void appendErrors(List errors) { ArrayList list = new ArrayList<>(this.errors); list.addAll(errors); @@ -137,7 +136,7 @@ protected void updateCache() { } public boolean shouldCheckFlip() { - return getContext().getLastFailureReason().shouldCheckFlip(); + return getContext().isCheckFlipped(); } @Getter diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index c183e37eaaf..da7747a4a1b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -63,24 +63,24 @@ public MultiPredicate getParent() { public boolean testLimited(PredicateContext ctx) { ctx.setStage(PredicateContext.PredicateStage.INTERNAL); if (!test(ctx)) return false; - ctx.setStage(PredicateContext.PredicateStage.GLOBAL_MAX); - if (!testGlobalMax(ctx)) return false; - ctx.setStage(PredicateContext.PredicateStage.SLICE_MAX); - return testSliceMax(ctx); + return testGlobalMax(ctx) && testSliceMax(ctx); } /// test against global max count public boolean testGlobalMax(PredicateContext ctx) { if (getMaxCount() == -1) return true; + ctx.setStage(PredicateContext.PredicateStage.GLOBAL_MAX); int count = ctx.incrementGlobalCount(this); return testGlobalMax(count) || ctx.error(SinglePredicateError.maxCount(this, count)); } /// test against slice max count public boolean testSliceMax(PredicateContext ctx) { - if (getMaxSliceCount() == -1 || ctx.layerCache() == null) return true; + if (!ctx.isCheckLayer()) return true; + ctx.setStage(PredicateContext.PredicateStage.SLICE_MAX); int count = ctx.incrementSliceCount(this); - return testSliceMax(count) || ctx.error(SinglePredicateError.maxLayerCount(this, count)); + return getMaxSliceCount() == -1 || testSliceMax(count) || + ctx.error(SinglePredicateError.maxLayerCount(this, count)); } /// test against global min count @@ -92,7 +92,7 @@ public boolean testGlobalMin(PredicateContext ctx) { /// test against slice min count public boolean testSliceMin(PredicateContext ctx) { - if (getMinSliceCount() == -1 || ctx.layerCache() == null) return true; + if (getMinSliceCount() == -1 || !ctx.isCheckLayer()) return true; int count = ctx.getSliceCount(this); return testSliceMin(count) || ctx.error(SinglePredicateError.minLayerCount(this, count)); } @@ -148,6 +148,10 @@ protected void appendStats(StringBuilder builder) { } } + public boolean checkMaxCount(PredicateContext context) { + return getParent().getLogic().testMaxCount(this, context); + } + @Override public String toString() { StringBuilder builder = new StringBuilder(getTypeName()); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java index e1e57fb0f15..7ff3fe724a8 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -55,6 +55,16 @@ public boolean testSliceMin(PredicateContext ctx) { return true; } + @Override + public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context) { + for (BasePredicate predicate : this.rootPredicate) { + if (!predicate.testGlobalMax(context) || !predicate.testSliceMax(context)) { + return false; + } + } + return true; + } + @Override public MultiPredicate.Logic getType() { return MultiPredicate.Logic.AND; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java index 622d02529f3..4a166416bca 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java @@ -20,8 +20,8 @@ public abstract class BaseLogic { public BaseLogic(MultiPredicate rootPredicate) { this.rootPredicate = rootPredicate; for (BasePredicate predicate : rootPredicate) { - if (predicate instanceof CompactedPredicate cp) { - this.compactedPredicates.add(cp); + if (predicate instanceof CompactedPredicate compacted) { + this.compactedPredicates.add(compacted); } } } @@ -42,4 +42,9 @@ public void reset() { public String toString() { return getType().name(); } + + /// check max counts plus any additional logic + public abstract boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context); + + public void predicatePassed(BasePredicate predicate) {} } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java index 6e498d8a8c0..37107b94865 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java @@ -40,6 +40,11 @@ public boolean testSliceMin(PredicateContext ctx) { return false; } + @Override + public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext ctx) { + return passedPredicate.testGlobalMax(ctx) && passedPredicate.testSliceMax(ctx); + } + @Override public MultiPredicate.Logic getType() { return MultiPredicate.Logic.OR; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index 7177cd5cbdd..504d5ccc3bb 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -46,7 +46,7 @@ private static boolean isNoneValid(MultiPredicate rootPredicate) { public boolean test(PredicateContext ctx) { int passed = 0; for (BasePredicate predicate : this.rootPredicate) { - if (predicate.testLimited(ctx)) { + if (predicate.test(ctx)) { passed++; if (this.passedPredicate == null) { this.passedPredicate = predicate; @@ -110,6 +110,24 @@ public boolean testSliceMin(PredicateContext ctx) { return true; } + @Override + public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context) { + if (passedPredicate != this.passedPredicate) { + // skip flipped check + context.skipFlipCheck(); + context.error(PatternStringError.literal(passedPredicate + " present in multi")); + return false; + } + return this.passedPredicate.testGlobalMax(context) && this.passedPredicate.testSliceMax(context); + } + + @Override + public void predicatePassed(BasePredicate predicate) { + if (this.passedPredicate == null) { + this.passedPredicate = predicate; + } + } + @Override public MultiPredicate.Logic getType() { return MultiPredicate.Logic.XOR; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java index 2e25d628be2..3ad9e40f0ec 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java @@ -6,8 +6,8 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.PatternSlice; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; - import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; + import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Vec3i; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java index d98c1b0a17f..08babb662f4 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java @@ -4,8 +4,8 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; - import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; + import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.levelgen.structure.BoundingBox; From 3c523fb676ab9a49bf44fe013a07fd1a7f36874b Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Tue, 28 Jul 2026 21:01:55 -0700 Subject: [PATCH 083/101] replace SinglePredicate.java with BasePredicate builder utilize predicate builder in Predicates.java and other classes add predicate getter in BasePredicate new MultiPredicate constructor prefer using appendError() over error() fix slice errors a bit --- .../gtceu/api/multiblock/MultiPredicate.java | 24 ++- .../api/multiblock/PredicateContext.java | 4 +- .../gtceu/api/multiblock/Predicates.java | 198 ++++++++---------- .../pattern/BasicSliceStrategy.java | 3 + .../api/multiblock/pattern/BlockPattern.java | 26 +-- .../multiblock/predicates/BasePredicate.java | 129 +++++++++--- .../predicates/CompactedPredicate.java | 19 +- .../predicates/SinglePredicate.java | 50 ----- .../multiblock/predicates/logic/AndLogic.java | 6 +- .../multiblock/predicates/logic/XorLogic.java | 16 +- .../common/data/machines/GTMachineUtils.java | 24 +-- .../common/data/machines/GTMultiMachines.java | 7 +- .../multiblock/electric/CleanroomMachine.java | 36 ++-- .../primitive/CharcoalPileIgniterMachine.java | 25 ++- 14 files changed, 303 insertions(+), 264 deletions(-) delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/SinglePredicate.java diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index 063edf29ae7..118179b3170 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -1,5 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock; +import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.logic.AndLogic; @@ -50,6 +51,13 @@ private MultiPredicate() { this.hasAir = false; } + public MultiPredicate(Logic type, List predicates) { + this.predicateList = Collections.unmodifiableList(predicates); + forEach(p -> p.setParent(this)); + this.logic = type.createLogic(this); + this.hasAir = predicates.stream().anyMatch(p -> p == BasePredicate.AIR); + } + private MultiPredicate(Logic type, MultiPredicate a, MultiPredicate b) { ArrayList builder = new ArrayList<>(); appendPredicates(type, a, builder); @@ -61,6 +69,10 @@ private MultiPredicate(Logic type, MultiPredicate a, MultiPredicate b) { this.hasAir = a.hasAir || b.hasAir; } + public static MultiPredicate or(List predicates) { + return new MultiPredicate(Logic.OR, predicates); + } + public void reset() { this.logic.reset(); } @@ -273,18 +285,22 @@ private static void appendPredicates(Logic type, MultiPredicate multiPredicate, var p = compacted.expand().getPredicateAtPos(context); if (p != null) return p; // else continue... - } else if (predicate.test(context)) { + } else if (predicate.getPredicate().test(context)) { // logic needs to capture this getLogic().predicatePassed(predicate); return predicate; - } else { - // handle errors better than this - context.clearErrors(); } } return null; } + /// called when all predicates failed + public void onError(PredicateContext ctx) { + // todo make this prettier + ctx.appendError(PatternStringError.literal("error at " + ctx.pos())); + ctx.appendError(PatternStringError.literal("missing one of\n" + this)); + } + public enum Logic { OR, diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 17c0b1f6b3a..87d6e9c287b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -56,7 +56,7 @@ public boolean error(PatternError error) { return false; } - private void appendError(PatternError error) { + public void appendError(PatternError error) { if (currentSlice != null) { getCurrentSliceErrors().add(error); } else { @@ -133,7 +133,7 @@ public void clearErrors() { public void commitSliceErrors() { for (Slice slice : this.sliceErrors.keySet()) { - this.state.appendError(PatternStringError.literal("error(s) at %s", slice)); + this.state.appendError(PatternStringError.literal("error(s) at slice %s", slice.index + slice.offset)); this.state.appendErrors(this.sliceErrors.get(slice)); } this.sliceErrors.clear(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 2c25715a913..9683d5f34aa 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -14,9 +14,7 @@ import com.gregtechceu.gtceu.api.machine.multiblock.PartAbility; import com.gregtechceu.gtceu.api.multiblock.error.BlockMatchingError; import com.gregtechceu.gtceu.api.multiblock.error.PartAbilityError; -import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.error.PlaceholderError; -import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.pipenet.IPipeNode; @@ -31,6 +29,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.tags.ITagManager; import com.tterrag.registrate.util.entry.RegistryEntry; import org.apache.commons.lang3.ArrayUtils; @@ -38,9 +37,6 @@ import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; @@ -73,21 +69,25 @@ public static MultiPredicate states(@Nullable String debugName, BlockState... al states.add(block.changeActive(state, !block.isActive(state))); } } - return customPredicate(debugName, - ctx -> states.contains(ctx.state()) || ctx.error(PLACEHOLDER), - states.stream().map(BlockInfo::fromBlockState), - builder -> { + return builder(debugName) + .predicate(ctx -> states.contains(ctx.state())) + // .onError(ctx -> PLACEHOLDER) + .candidates(states.stream().map(BlockInfo::fromBlockState)) + .contents(builder -> { StringJoiner joiner = new StringJoiner(", "); states.forEach(state -> joiner.add(blockToString(state))); builder.append(joiner); - }); + }) + .toMultiPredicate(); } public static MultiPredicate blocks(Block block) { - return customPredicate("Block", - ctx -> ctx.state().is(block) || ctx.error(new BlockMatchingError(ctx.pos(), List.of(block))), - Stream.of(BlockInfo.fromBlock(block)), - builder -> builder.append(blockToString(block))); + return builder("Block") + .predicate(ctx -> ctx.state().is(block)) + .onError(ctx -> new BlockMatchingError(ctx.pos(), List.of(block))) + .candidates(Stream.of(BlockInfo.fromBlock(block))) + .contents(builder -> builder.append(blockToString(block))) + .toMultiPredicate(); } public static MultiPredicate blocks(Block... blocks) { @@ -107,18 +107,24 @@ public static MultiPredicate blocks(@Nullable String debugName, public static MultiPredicate blocks(@Nullable String debugName, List blocks, Stream candidates) { - return customPredicate(debugName, ctx -> { - for (var block : blocks) { - if (ctx.state().is(block)) return true; - } - return ctx.error(new BlockMatchingError(ctx.pos(), blocks)); - }, candidates.map(BlockInfo::fromBlock), builder -> { - StringJoiner joiner = new StringJoiner(", "); - blocks.forEach(block -> joiner.add(blockToString(block))); - builder.append(joiner); - }); + return builder(debugName) + .predicate(ctx -> { + for (var block : blocks) { + if (ctx.state().is(block)) return true; + } + return false; + }) + .onError(ctx -> new BlockMatchingError(ctx.pos(), blocks)) + .candidates(candidates.map(BlockInfo::fromBlock)) + .contents(builder -> { + StringJoiner joiner = new StringJoiner(", "); + blocks.forEach(block -> joiner.add(blockToString(block))); + builder.append(joiner); + }) + .toMultiPredicate(); } + // todo these two methods below should be moved into a util class private static String blockToString(BlockState blockState) { return blockToString(blockState.getBlock()); } @@ -135,19 +141,23 @@ public static MultiPredicate machines(MachineDefinition... definitions) { } public static MultiPredicate blockTag(TagKey tag) { - return customPredicate("BlockTag", - ctx -> ctx.state().is(tag), - Objects.requireNonNull(ForgeRegistries.BLOCKS.tags()) - .getTag(tag).stream() - .map(BlockInfo::fromBlock), - builder -> builder.append(tag.location())); + ITagManager manager = Objects.requireNonNull(ForgeRegistries.BLOCKS.tags()); + return builder("BlockTag") + .predicate(ctx -> ctx.state().is(tag)) + .onError(ctx -> new BlockMatchingError(ctx.pos(), manager.getTag(tag) + .stream().toList())) + .candidates(manager.getTag(tag) + .stream().map(BlockInfo::fromBlock)) + .contents(builder -> builder.append(tag.location())) + .toMultiPredicate(); } public static MultiPredicate fluids(Fluid... fluids) { - return customPredicate("Fluids", - ctx -> ArrayUtils.contains(fluids, ctx.fluid()) || ctx.error(PLACEHOLDER), - Arrays.stream(fluids).map(BlockInfo::fromFluid), - builder -> { + return builder("Fluids") + .predicate(ctx -> ArrayUtils.contains(fluids, ctx.fluid())) + .onError(ctx -> ctx.appendError(PLACEHOLDER)) + .candidates(Arrays.stream(fluids).map(BlockInfo::fromFluid)) + .contents(builder -> { StringJoiner joiner = new StringJoiner(", "); for (Fluid fluid : fluids) { joiner.add(ForgeRegistries.FLUIDS.getDelegate(fluid) @@ -155,43 +165,16 @@ public static MultiPredicate fluids(Fluid... fluids) { .orElse("unknown")); } builder.append(joiner); - }); + }) + .toMultiPredicate(); } public static MultiPredicate fluidTag(TagKey tag) { - return customPredicate("FluidTag", - ctx -> ctx.fluidState().is(tag), - Objects.requireNonNull(ForgeRegistries.FLUIDS.tags()) - .getTag(tag).stream() - .map(BlockInfo::fromFluid), - builder -> builder.append(tag.location())); - } - - @Deprecated - public static MultiPredicate customFunction(Function predicate, - @Nullable List candidates) { - return customPredicate(ctx -> { - PatternError error = predicate.apply(ctx.getCurrentBlockInfo()); - return error == null || ctx.error(error); - }, Objects.>requireNonNullElse(candidates, Collections.emptyList()).stream()); - } - - public static MultiPredicate customPredicate(Predicate predicate, - Stream candidates) { - return customPredicate(null, predicate, candidates); - } - - public static MultiPredicate customPredicate(@Nullable String debugName, - Predicate predicate, - Stream candidates) { - return customPredicate(debugName, predicate, candidates, null); - } - - public static MultiPredicate customPredicate(@Nullable String debugName, - Predicate predicate, - Stream candidates, - @Nullable Consumer contents) { - return BasePredicate.create(debugName, predicate, candidates, contents); + return builder("FluidTag") + .predicate(ctx -> ctx.fluidState().is(tag)) + .onError(ctx -> ctx.appendError(PLACEHOLDER)) + .fluidTag(tag) + .toMultiPredicate(); } public static MultiPredicate any() { @@ -203,34 +186,25 @@ public static MultiPredicate air() { } public static MultiPredicate abilities(PartAbility ability) { - return customPredicate("Ability", - ctx -> ability.isApplicable(ctx.state().getBlock()) || - ctx.error(new PartAbilityError(ctx.pos(), ability)), - ability.getAllBlocks().stream().map(BlockInfo::fromBlock), - builder -> builder.append(ability.getName())); + return builder("Ability") + .predicate(ctx -> ability.isApplicable(ctx.state().getBlock())) + .onError(ctx -> new PartAbilityError(ctx.pos(), ability)) + .candidates(ability.getAllBlocks().stream().map(BlockInfo::fromBlock)) + .contents(builder -> builder.append(ability.getName())) + .toMultiPredicate(); } public static MultiPredicate abilities(PartAbility... abilities) { - return customPredicate("Abilities", - ctx -> { - for (PartAbility ability : abilities) { - if (ability.isApplicable(ctx.state().getBlock())) { - return true; - } - ctx.error(new PartAbilityError(ctx.pos(), ability)); - } - return false; - }, - Arrays.stream(abilities) - .flatMap(a -> a.getAllBlocks().stream()) - .map(BlockInfo::fromBlock), - builder -> { - StringJoiner sb = new StringJoiner(", "); - for (PartAbility ability : abilities) { - sb.add(ability.getName()); - } - builder.append(sb); - }); + List predicates = new ArrayList<>(); + for (PartAbility ability : abilities) { + predicates.add(builder("Ability") + .predicate(ctx -> ability.isApplicable(ctx.state().getBlock())) + .onError(ctx -> new PartAbilityError(ctx.pos(), ability)) + .candidates(ability.getAllBlocks().stream().map(BlockInfo::fromBlock)) + .contents(builder -> builder.append(ability.getName())) + .build()); + } + return MultiPredicate.or(predicates); } public static MultiPredicate ability(PartAbility ability, int... tiers) { @@ -238,10 +212,12 @@ public static MultiPredicate ability(PartAbility ability, int... tiers) { for (int tier : tiers) { sb.add(GTValues.VN[tier]); } - return customPredicate("Ability[" + sb + "]", - ctx -> ability.isApplicable(ctx.state().getBlock()) || - ctx.error(new PartAbilityError(ctx.pos(), ability)), - ability.getBlocks(tiers).stream().map(BlockInfo::fromBlock)); + return builder("TieredAbility") + .predicate(ctx -> ability.getBlocks(tiers).contains(ctx.state().getBlock())) + .onError(ctx -> new PartAbilityError(ctx.pos(), ability)) + .candidates(ability.getBlocks(tiers).stream().map(BlockInfo::fromBlock)) + .contents(builder -> builder.append(ability.getName()).append(" ").append(sb)) + .toMultiPredicate(); } public static MultiPredicate autoAbilities(GTRecipeType... recipeType) { @@ -391,13 +367,25 @@ public static MultiPredicate frames(Material... frameMaterials) { } public static MultiPredicate framedPipes(Material[] frameMaterials, Block[] frameBlocks) { - return customPredicate("FramedPipes", ctx -> { - BlockEntity tileEntity = ctx.blockEntity(); - if (!(tileEntity instanceof IPipeNode pipeNode)) { - return ctx.error(PLACEHOLDER); - } - return ArrayUtils.contains(frameMaterials, pipeNode.getFrameMaterial()) || - ctx.error(PLACEHOLDER); - }, Arrays.stream(frameBlocks).map(BlockInfo::fromBlock)); + return builder("FramedPipes") + .predicate(ctx -> { + BlockEntity tileEntity = ctx.blockEntity(); + if (!(tileEntity instanceof IPipeNode pipeNode)) { + return false; + } + return ArrayUtils.contains(frameMaterials, pipeNode.getFrameMaterial()); + }) + // .onError(ctx -> PLACEHOLDER) + .candidates(Arrays.stream(frameBlocks).map(BlockInfo::fromBlock)) + .contents(builder -> { + StringJoiner joiner = new StringJoiner(", "); + Arrays.stream(frameBlocks).forEach(block -> joiner.add(blockToString(block))); + builder.append(joiner); + }) + .toMultiPredicate(); + } + + public static BasePredicate.Builder builder(@Nullable String debugName) { + return new BasePredicate.Builder(debugName); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java index 5f4524bcdb7..00d3d21a6be 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java @@ -84,8 +84,11 @@ protected int checkRepeatSlice(PatternState state, int index, int offset, boolea if (!res) { if (i <= slice.minRepeats) return -1; + // invalid, but within max repeats so may be valid overall + context.clearErrors(); return slices.get(index).actualRepeats = i - 1; } + // valid slice, clear errors just in case context.clearErrors(); } return slices.get(index).actualRepeats = slice.maxRepeats; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index d41c08a4474..327625870cd 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -215,25 +215,21 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p context.setStage(PredicateContext.PredicateStage.INTERNAL); // state check BasePredicate predicateAtPos = pred.getPredicateAtPos(context); - /* - * a{ f, - * b, - * c{ d, e } } - * if d - * get reference to c - * which is get parent - */ - // max count checks - if (predicateAtPos == null || !predicateAtPos.checkMaxCount(context)) { + // all predicates failed + // errors are PUSHED in slice strategy + // need to add them here, since they aren't added with getPredicateAtPos + if (predicateAtPos == null) { + pred.onError(context); + // todo this causes a flipped check, add error? return false; } - // internal predicate check, global/slice max checks - // if all internal predicates pass, but global/slice max/min checks fail, then do not flip - // if (!pred.test(context)) { - // return false; - // } + // max count checks + if (!predicateAtPos.checkMaxCount(context)) { + // error handled + return false; + } visitedPredicates.add(pred); charPos.move(absoluteChar); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index da7747a4a1b..b3535916bcc 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -2,13 +2,19 @@ import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.PlaceholderError; import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; +import net.minecraft.tags.TagKey; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.material.Fluid; +import net.minecraftforge.registries.ForgeRegistries; import lombok.Getter; import lombok.Setter; +import lombok.experimental.Accessors; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -18,9 +24,14 @@ public abstract class BasePredicate { - public static final BasePredicate AIR = of("Air", ctx -> ctx.state().isAir()); + public static final BasePredicate AIR = new Builder("Air") + .predicate(ctx -> ctx.state().isAir()) + // todo error? + .build(); - public static final BasePredicate ANY = of("Any", ctx -> true); + public static final BasePredicate ANY = new Builder("Any") + .predicate(ctx -> true) + .build(); @Getter(lazy = true) private final List candidates = computeCandidates(); @@ -57,13 +68,22 @@ public MultiPredicate getParent() { } /// the main testing method - public abstract boolean test(PredicateContext ctx); + public boolean test(PredicateContext ctx) { + ctx.setStage(PredicateContext.PredicateStage.INTERNAL); + if (!getPredicate().test(ctx)) { + onError(ctx); + return false; + } + return true; + } + + public abstract void onError(PredicateContext ctx); + + public abstract Predicate getPredicate(); /// test with internal function and global/slice max public boolean testLimited(PredicateContext ctx) { - ctx.setStage(PredicateContext.PredicateStage.INTERNAL); - if (!test(ctx)) return false; - return testGlobalMax(ctx) && testSliceMax(ctx); + return test(ctx) && testGlobalMax(ctx) && testSliceMax(ctx); } /// test against global max count @@ -139,15 +159,6 @@ public Optional getFirstCandidate() { /// the contents of this predicate protected void appendContents(StringBuilder builder) {} - protected void appendStats(StringBuilder builder) { - if (minCount != -1 && maxCount != -1) { - builder.append("g[%d,%d] ".formatted(minCount, maxCount)); - } - if (minSliceCount != -1 && maxSliceCount != -1) { - builder.append("s[%d,%d] ".formatted(minSliceCount, maxSliceCount)); - } - } - public boolean checkMaxCount(PredicateContext context) { return getParent().getLogic().testMaxCount(this, context); } @@ -155,30 +166,86 @@ public boolean checkMaxCount(PredicateContext context) { @Override public String toString() { StringBuilder builder = new StringBuilder(getTypeName()); - builder.append(" "); - appendStats(builder); builder.append('{'); appendContents(builder); builder.append('}'); return builder.toString(); } - public static MultiPredicate create(@Nullable String debugName, Predicate predicate) { - return create(debugName, predicate, Stream.empty(), null); - } + @Accessors(chain = true, fluent = true) + public static class Builder { - // this uses stream for lazy initialization - public static MultiPredicate create(@Nullable String debugName, Predicate predicate, - Stream candidateStream, @Nullable Consumer contents) { - return new MultiPredicate(of(debugName, predicate, candidateStream, contents)); - } + private final String name; + @Setter + private Predicate predicate; + @Setter + private Stream candidates = Stream.empty(); + @Setter + private @Nullable Consumer contents; + @Setter + private @Nullable Consumer onError; - public static BasePredicate of(@Nullable String debugName, Predicate predicate, - Stream candidateStream, @Nullable Consumer contents) { - return new SinglePredicate(predicate, candidateStream, debugName, contents); - } + public Builder(@Nullable String debugName) { + this.name = debugName != null ? debugName : "Predicate"; + } + + /// fills candidates and sets string contents with this block tag + public Builder blockTag(TagKey tag) { + this.candidates = Objects.requireNonNull(ForgeRegistries.BLOCKS.tags()) + .getTag(tag).stream().map(BlockInfo::fromBlock); + this.contents = builder -> builder.append(tag.location()); + return this; + } - private static BasePredicate of(@Nullable String debugName, Predicate predicate) { - return of(debugName, predicate, Stream.empty(), null); + /// fills candidates and sets string contents with this fluid tag + public Builder fluidTag(TagKey tag) { + this.candidates = Objects.requireNonNull(ForgeRegistries.FLUIDS.tags()) + .getTag(tag).stream().map(BlockInfo::fromFluid); + this.contents = builder -> builder.append(tag.location()); + return this; + } + + public MultiPredicate toMultiPredicate() { + return new MultiPredicate(build()); + } + + public BasePredicate build() { + return new BasePredicate() { + + @Override + public void onError(PredicateContext ctx) { + if (onError != null) { + onError.accept(ctx); + } + placeholderError(ctx); + } + + private void placeholderError(PredicateContext ctx) { + ctx.appendError(new PlaceholderError(ctx.pos(), List.of(getCandidates()))); + } + + @Override + public Predicate getPredicate() { + return Objects.requireNonNull(predicate, name + " predicate == null"); + } + + @Override + public List computeCandidates() { + return Objects.requireNonNull(candidates).toList(); + } + + @Override + public String getTypeName() { + return name; + } + + @Override + protected void appendContents(StringBuilder builder) { + if (contents != null) { + contents.accept(builder); + } + } + }; + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java index 19e65eb4762..8908fa2846a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java @@ -6,6 +6,7 @@ import java.util.Collection; import java.util.List; +import java.util.function.Predicate; public class CompactedPredicate extends BasePredicate { @@ -20,11 +21,20 @@ public MultiPredicate expand() { } @Override - public boolean test(PredicateContext ctx) { - // test parent predicates - return expand().test(ctx); + public Predicate getPredicate() { + return ctx -> { + for (BasePredicate predicate : this.root) { + if (predicate.getPredicate().test(ctx)) { + return true; + } + } + return false; + }; } + @Override + public void onError(PredicateContext ctx) {} + @Override public boolean testLimited(PredicateContext ctx) { return this.test(ctx); @@ -58,9 +68,6 @@ protected void appendContents(StringBuilder builder) { expand().appendContents(builder); } - @Override - protected void appendStats(StringBuilder builder) {} - public void reset() { this.root.reset(); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/SinglePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/SinglePredicate.java deleted file mode 100644 index 2807f53a1ef..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/SinglePredicate.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.gregtechceu.gtceu.api.multiblock.predicates; - -import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; - -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.stream.Stream; - -public class SinglePredicate extends BasePredicate { - - private final Predicate predicate; - private final Stream candidateStream; - private final @Nullable String debugName; - private final @Nullable Consumer contents; - - public SinglePredicate(Predicate predicate, Stream candidateStream, - @Nullable String debugName, @Nullable Consumer contents) { - this.predicate = predicate; - this.candidateStream = candidateStream; - this.debugName = debugName; - this.contents = contents; - } - - @Override - public boolean test(PredicateContext ctx) { - return predicate.test(ctx); - } - - @Override - public List computeCandidates() { - return candidateStream.toList(); - } - - @Override - public String getTypeName() { - return Objects.requireNonNullElse(debugName, "Predicate"); - } - - @Override - protected void appendContents(StringBuilder builder) { - if (contents != null) { - contents.accept(builder); - } - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java index 7ff3fe724a8..9a20f2cab96 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -23,8 +23,10 @@ public boolean test(PredicateContext ctx) { } // count manually - if (failedMaxCount(ctx, predicate, true) || failedMaxCount(ctx, predicate, false)) - return ctx.error(PatternStringError.literal("AND error")); + if (failedMaxCount(ctx, predicate, true) || failedMaxCount(ctx, predicate, false)) { + ctx.appendError(PatternStringError.literal("AND error")); + return false; + } // continue... } return passed > 0; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index 504d5ccc3bb..412b87e1640 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -60,13 +60,14 @@ public boolean test(PredicateContext ctx) { public boolean testGlobalMin(PredicateContext ctx) { if (passedPredicate == null && noneValid) return true; if (passedPredicate == null || !passedPredicate.testGlobalMin(ctx)) { - return ctx.error(onError()); + ctx.appendError(onError()); + return false; } if (!global) return true; for (BasePredicate predicate : this.rootPredicate) { if (predicate != passedPredicate && ctx.getGlobalCount(predicate) > 0) { - ctx.error(onError()); - ctx.error(PatternStringError.literal("%s present in multi", predicate)); + ctx.appendError(onError()); + ctx.appendError(PatternStringError.literal("%s present in multi", predicate)); return false; } } @@ -97,13 +98,14 @@ private PatternError onError() { public boolean testSliceMin(PredicateContext ctx) { if (passedPredicate == null && noneValid) return true; if (passedPredicate == null || !passedPredicate.testSliceMin(ctx)) { - return ctx.error(PatternStringError.literal("need one of: " + rootPredicate)); + ctx.appendError(PatternStringError.literal("need one of: " + rootPredicate)); + return false; } if (global) return true; for (BasePredicate predicate : this.rootPredicate) { if (predicate != passedPredicate && ctx.getSliceCount(predicate) > 0) { - ctx.error(PatternStringError.literal("need one of:\n" + rootPredicate.getPredicateList())); - ctx.error(PatternStringError.literal(predicate + " present in multi")); + ctx.appendError(PatternStringError.literal("need one of:\n" + rootPredicate.getPredicateList())); + ctx.appendError(PatternStringError.literal(predicate + " present in multi")); return false; } } @@ -115,7 +117,7 @@ public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext cont if (passedPredicate != this.passedPredicate) { // skip flipped check context.skipFlipCheck(); - context.error(PatternStringError.literal(passedPredicate + " present in multi")); + context.appendError(PatternStringError.literal(passedPredicate + " present in multi")); return false; } return this.passedPredicate.testGlobalMax(context) && this.passedPredicate.testSliceMax(context); diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index cfe5d1a9aa0..5439a25309b 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -743,18 +743,18 @@ public static MultiblockMachineDefinition registerLargeTurbine(GTRegistrate regi } private static MultiPredicate rotorHolder(int tier) { - return Predicates.customPredicate("RotorHolder", ctx -> { - if (MetaMachine.getMachine(ctx.level(), - ctx.pos()) instanceof RotorHolderPartMachine rotorHolder && - ctx.level().getBlockState(ctx.pos() - .relative(rotorHolder.getFrontFacing())) - .isAir()) { - return true; - } - return ctx.error(new PartAbilityError(ctx.pos(), PartAbility.ROTOR_HOLDER)); - }, PartAbility.ROTOR_HOLDER.getAllBlocks() - .stream() - .map(BlockInfo::fromBlock)) + return builder("RotorHolder") + .predicate(ctx -> { + if (MetaMachine.getMachine(ctx.level(), ctx.pos()) instanceof RotorHolderPartMachine rotorHolder) { + return ctx.level().getBlockState(ctx.pos().relative(rotorHolder.getFrontFacing())).isAir(); + } + return false; + }) + .onError(ctx -> new PartAbilityError(ctx.pos(), PartAbility.ROTOR_HOLDER)) + .candidates(PartAbility.ROTOR_HOLDER.getAllBlocks() + .stream().map(BlockInfo::fromBlock)) + .contents(builder -> builder.append(PartAbility.ROTOR_HOLDER.getName())) + .toMultiPredicate() // .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")) // .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", VN[tier])) ; diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java index eb33b808d4d..5798b4486fe 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java @@ -123,9 +123,10 @@ public class GTMultiMachines { .where('X', blocks(CASING_PRIMITIVE_BRICKS.get())) .where('#', Predicates.air()) .where('&', Predicates.air() - .or(Predicates.customFunction(bws -> GTUtil.isBlockSnow(bws.retrieveCurrentBlockState()) ? - null : Predicates.PLACEHOLDER, - null))) + .or(builder("SnowPredicate") + .predicate(ctx -> GTUtil.isBlockSnow(ctx.state())) + // .onError(ctx -> PLACEHOLDER) + .toMultiPredicate())) .where('Y', Predicates.controller(blocks(definition.getBlock()))) .build()) .themeId((i) -> GTGuiTheme.PRIMITIVE.getId()) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index cb18fcab298..ccc558989fd 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -22,7 +22,6 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandableMultiblockPatternBuilder; import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; @@ -471,11 +470,17 @@ protected static BlockState getGlassState() { } protected static MultiPredicate doorPredicate() { - return Predicates.customPredicate( - ctx -> ctx.state().getBlock() instanceof DoorBlock || ctx.error(Predicates.PLACEHOLDER), - Stream.of(new BlockInfo(Blocks.IRON_DOOR.defaultBlockState()), + return builder("DoorPredicate") + .predicate(ctx -> ctx.state().getBlock() instanceof DoorBlock) + .onError(ctx -> ctx.appendError(PLACEHOLDER)) + // spotless:off + .candidates(Stream.of( + new BlockInfo(Blocks.IRON_DOOR), new BlockInfo(Blocks.IRON_DOOR.defaultBlockState() - .setValue(DoorBlock.HALF, DoubleBlockHalf.UPPER)))); + .setValue(DoorBlock.HALF, DoubleBlockHalf.UPPER)) + )) + //spotless:on + .toMultiPredicate(); } private static MultiPredicate getValidFloorBlocks() { @@ -483,18 +488,15 @@ private static MultiPredicate getValidFloorBlocks() { } protected static MultiPredicate innerPredicate() { - return BasePredicate.create("InnerPredicate", ctx -> { - // all non-GTMachines are allowed inside by default - BlockEntity blockEntity = ctx.blockEntity(); - if (blockEntity instanceof MetaMachine machine) { - if (isMachineBanned(machine)) { - return ctx.error(Predicates.PLACEHOLDER); - } - // todo do this in structure form not in the predicate - // machine.getTraitOptional(CleanroomReceiverTrait.TYPE).ifPresent(cleanroomReceivers::add); - } - return true; - }); + return builder("InnerPredicate") + .predicate(ctx -> { + if (ctx.blockEntity() instanceof MetaMachine machine) { + return isMachineBanned(machine); + } + return true; + }) + .onError(ctx -> ctx.appendError(PLACEHOLDER)) + .toMultiPredicate(); } protected static boolean isMachineBanned(MetaMachine machine) { diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java index d0aa1d889ac..9a4b283a173 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java @@ -151,19 +151,24 @@ public static Function getPattern() } private static MultiPredicate wallPredicate() { - return Predicates.customFunction(multiblockState -> { - BlockPos p = multiblockState.getBlockPos(); - return multiblockState.retrieveCurrentBlockState().is(CustomTags.CHARCOAL_PILE_IGNITER_WALLS) ? - null : new PatternStringError(Component.translatable("gtceu.predicate_error.charcoal.walls", - p.getX(), p.getY(), p.getZ())); - }, null); + return Predicates.builder("WallPredicate") + .predicate(ctx -> ctx.state().is(CustomTags.CHARCOAL_PILE_IGNITER_WALLS)) + .onError(ctx -> { + BlockPos p = ctx.pos(); + ctx.appendError( + PatternStringError.component(Component.translatable("gtceu.predicate_error.charcoal.walls", + p.getX(), p.getY(), p.getZ()))); + }) + .blockTag(CustomTags.CHARCOAL_PILE_IGNITER_WALLS) + .toMultiPredicate(); } private static MultiPredicate logPredicate() { - return Predicates.customFunction(multiblockState -> { - boolean match = multiblockState.retrieveCurrentBlockState().is(BlockTags.LOGS_THAT_BURN); - return match ? null : new PatternStringError(Component.translatable("gtceu.predicate_error.charcoal.logs")); - }, null); + return Predicates.builder("LogPredicate") + .predicate(ctx -> ctx.state().is(BlockTags.LOGS_THAT_BURN)) + .onError(ctx -> new PatternStringError(Component.translatable("gtceu.predicate_error.charcoal.logs"))) + .blockTag(BlockTags.LOGS_THAT_BURN) + .toMultiPredicate(); } private static int findWallPos(Level level, Direction direction, BlockPos.MutableBlockPos pos) { From cf182053c3b71d550226c12c6fe249d6231eebdc Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 29 Jul 2026 18:10:20 -0700 Subject: [PATCH 084/101] move slice related fields around keep errors from previous check for flipped check --- .../gtceu/api/multiblock/MultiPredicate.java | 7 +++---- .../gtceu/api/multiblock/PredicateContext.java | 16 +++++++--------- .../api/multiblock/pattern/BlockPattern.java | 6 ++++++ 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index 118179b3170..800a50505cb 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -1,6 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock; -import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; +import com.gregtechceu.gtceu.api.multiblock.error.SimplePatternError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.logic.AndLogic; @@ -52,6 +52,7 @@ private MultiPredicate() { } public MultiPredicate(Logic type, List predicates) { + predicates.sort(PREDICATE_COMPARATOR); this.predicateList = Collections.unmodifiableList(predicates); forEach(p -> p.setParent(this)); this.logic = type.createLogic(this); @@ -296,9 +297,7 @@ private static void appendPredicates(Logic type, MultiPredicate multiPredicate, /// called when all predicates failed public void onError(PredicateContext ctx) { - // todo make this prettier - ctx.appendError(PatternStringError.literal("error at " + ctx.pos())); - ctx.appendError(PatternStringError.literal("missing one of\n" + this)); + ctx.appendError(new SimplePatternError(ctx.pos(), getCandidates())); } public enum Logic { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 87d6e9c287b..c1ed00daa4a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -1,7 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock; import com.gregtechceu.gtceu.api.multiblock.error.PatternError; -import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.pattern.CurrentBlockInfo; import com.gregtechceu.gtceu.api.multiblock.pattern.PatternState; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; @@ -129,22 +128,21 @@ public void clearErrors() { this.lastFailureReason = FailureReason.NONE; } - Object2ObjectMap> sliceErrors = new Object2ObjectAVLTreeMap<>(Slice::compareTo); + private Object2ObjectMap> sliceErrors = new Object2ObjectAVLTreeMap<>(Slice::compareTo); + + private @Nullable Slice currentSlice; + + public void pushSlice(int index, int offset) { + this.currentSlice = new Slice(index, offset); + } public void commitSliceErrors() { for (Slice slice : this.sliceErrors.keySet()) { - this.state.appendError(PatternStringError.literal("error(s) at slice %s", slice.index + slice.offset)); this.state.appendErrors(this.sliceErrors.get(slice)); } this.sliceErrors.clear(); } - private @Nullable Slice currentSlice; - - public void pushSlice(int index, int offset) { - this.currentSlice = new Slice(index, offset); - } - public void updateLevel(Level level) { this.currentBlockInfo.setLevel(level); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 327625870cd..5d524f23e0e 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -3,6 +3,7 @@ import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; @@ -142,7 +143,12 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c boolean isFlipped) { Objects.requireNonNull(patternState, "PatternState not set"); + List errors = List.of(); + // keep old errors if flipped + if (isFlipped) errors = patternState.getErrors(); PredicateContext context = patternState.resetContext(true); + patternState.setErrors(errors); + // only try to clear the cache for structure checking mapping when checking the structure for unflipped // maybe switch to a multiblock state value instead? if (!isFlipped) { From 672f0c5194af68540ff8e8bd5b218a76cf65fd6d Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 29 Jul 2026 18:11:06 -0700 Subject: [PATCH 085/101] update multiblock saved data for valid pattern state --- .../gtceu/api/multiblock/pattern/PatternState.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 147c12375be..29795892487 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -119,12 +119,15 @@ public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState ne PatternState patternState = controller.checkStructurePattern(name); if (!patternState.hasErrors()) { controller.formStructure(name); + // previous formation may not have added the full multiblock the saved data + // todo there's probably a better way to do this + MultiblockWorldSavedData.getOrCreate(serverLevel).addMapping(this); } else { controller.invalidateStructure(name); if (name.equals(MultiblockControllerMachine.DEFAULT_STRUCTURE)) { MultiblockWorldSavedData.getOrCreate(serverLevel).removeMapping(this); controller.checkAndFormStructure(); - } + } } } } From b5ce8206c0267a7acad91a5af45b909f461a27fb Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 29 Jul 2026 18:46:06 -0700 Subject: [PATCH 086/101] simplify logic simplify retaining errors make logic type a constructor field instead of method override improve MultiPredicate constructors fix typo --- .../gtceu/api/multiblock/MultiPredicate.java | 57 +++++++++++-------- .../api/multiblock/pattern/BlockPattern.java | 10 +--- .../predicates/CompactedPredicate.java | 4 -- .../multiblock/predicates/logic/AndLogic.java | 7 +-- .../predicates/logic/BaseLogic.java | 22 ++----- .../multiblock/predicates/logic/OrLogic.java | 7 +-- .../multiblock/predicates/logic/XorLogic.java | 12 +--- 7 files changed, 48 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index 800a50505cb..70f6c8e9595 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -51,31 +51,18 @@ private MultiPredicate() { this.hasAir = false; } + /// @param predicates list must be modifiable public MultiPredicate(Logic type, List predicates) { - predicates.sort(PREDICATE_COMPARATOR); - this.predicateList = Collections.unmodifiableList(predicates); - forEach(p -> p.setParent(this)); - this.logic = type.createLogic(this); - this.hasAir = predicates.stream().anyMatch(p -> p == BasePredicate.AIR); + this(type, predicates, predicates.stream().anyMatch(p -> p == BasePredicate.AIR)); } - private MultiPredicate(Logic type, MultiPredicate a, MultiPredicate b) { - ArrayList builder = new ArrayList<>(); - appendPredicates(type, a, builder); - appendPredicates(type, b, builder); - builder.forEach(p -> p.setParent(this)); - builder.sort(PREDICATE_COMPARATOR); - this.predicateList = Collections.unmodifiableList(builder); + /// @param predicates list must be modifiable + private MultiPredicate(Logic type, List predicates, boolean hasAir) { + predicates.forEach(p -> p.setParent(this)); + predicates.sort(PREDICATE_COMPARATOR); + this.predicateList = Collections.unmodifiableList(predicates); this.logic = type.createLogic(this); - this.hasAir = a.hasAir || b.hasAir; - } - - public static MultiPredicate or(List predicates) { - return new MultiPredicate(Logic.OR, predicates); - } - - public void reset() { - this.logic.reset(); + this.hasAir = hasAir; } // this is called for each block @@ -100,6 +87,15 @@ public List> getCandidates() { .toList(); } + public void resetLogic() { + this.logic.reset(); + for (BasePredicate p : this.predicateList) { + if (p instanceof CompactedPredicate compacted) { + compacted.expand().resetLogic(); + } + } + } + public boolean isOr() { return this.logic.getType() == Logic.OR; } @@ -233,6 +229,18 @@ public MultiPredicate xor(MultiPredicate other) { return combine(this, Logic.XOR, other); } + public static MultiPredicate or(List predicates) { + return new MultiPredicate(Logic.OR, predicates); + } + + public static MultiPredicate and(List predicates) { + return new MultiPredicate(Logic.AND, predicates); + } + + public static MultiPredicate xor(List predicates) { + return new MultiPredicate(Logic.XOR, predicates); + } + public boolean isSingle() { return predicateList.size() == 1; } @@ -245,7 +253,7 @@ public void appendContents(StringBuilder builder) { @Override public String toString() { - StringBuilder builder = new StringBuilder("MulitPredicate"); + StringBuilder builder = new StringBuilder("MultiPredicate"); if (isController()) builder.append("[Controller]"); builder.append('{'); appendContents(builder); @@ -268,7 +276,10 @@ public static MultiPredicate empty() { private static MultiPredicate combine(MultiPredicate a, Logic type, @Nullable MultiPredicate b) { if (b == null) return a; // no op if (a.isEmpty()) return b; - return new MultiPredicate(type, a, b); + ArrayList builder = new ArrayList<>(); + appendPredicates(type, a, builder); + appendPredicates(type, b, builder); + return new MultiPredicate(type, builder, a.hasAir || b.hasAir); } private static void appendPredicates(Logic type, MultiPredicate multiPredicate, ArrayList builder) { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 5d524f23e0e..62c98f865e9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -115,7 +115,6 @@ public void checkPatternFastAt(Level level, PatternState patternState, BlockPos } } - // need to clear some errors, as there's a lot of useless info now boolean valid = checkPatternAt(level, patternState, centerPos, frontFacing, upwardsFacing, false); if (valid) { // reaching here means the cache failed or was empty @@ -143,25 +142,22 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c boolean isFlipped) { Objects.requireNonNull(patternState, "PatternState not set"); - List errors = List.of(); - // keep old errors if flipped - if (isFlipped) errors = patternState.getErrors(); PredicateContext context = patternState.resetContext(true); - patternState.setErrors(errors); // only try to clear the cache for structure checking mapping when checking the structure for unflipped // maybe switch to a multiblock state value instead? if (!isFlipped) { patternState.getCache().clear(); + // keep old errors if flipped + patternState.clearErrors(); } context.updateLevel(level); - // context.reset(); // clear any existing committed errors BlockPos.MutableBlockPos controllerPos = centerPos.mutable(); // reset predicates for testing - predicates.values().forEach(MultiPredicate::reset); + predicates.values().forEach(MultiPredicate::resetLogic); // handle slices sliceStrategy.setPattern(this); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java index 8908fa2846a..2d62777feca 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java @@ -67,8 +67,4 @@ public String getTypeName() { protected void appendContents(StringBuilder builder) { expand().appendContents(builder); } - - public void reset() { - this.root.reset(); - } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java index 9a20f2cab96..5be12a5304d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -8,7 +8,7 @@ public class AndLogic extends BaseLogic { public AndLogic(MultiPredicate rootPredicate) { - super(rootPredicate); + super(rootPredicate, MultiPredicate.Logic.AND); } @Override @@ -66,9 +66,4 @@ public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext cont } return true; } - - @Override - public MultiPredicate.Logic getType() { - return MultiPredicate.Logic.AND; - } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java index 4a166416bca..e92ff5a8ada 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java @@ -3,32 +3,24 @@ import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; +import lombok.Getter; import lombok.Setter; -import java.util.HashSet; -import java.util.Set; - public abstract class BaseLogic { protected final MultiPredicate rootPredicate; - private final Set compactedPredicates = new HashSet<>(); + @Getter + private final MultiPredicate.Logic type; @Setter protected boolean global = true; // used for XOR, AND - public BaseLogic(MultiPredicate rootPredicate) { + public BaseLogic(MultiPredicate rootPredicate, MultiPredicate.Logic type) { this.rootPredicate = rootPredicate; - for (BasePredicate predicate : rootPredicate) { - if (predicate instanceof CompactedPredicate compacted) { - this.compactedPredicates.add(compacted); - } - } + this.type = type; } - public void reset() { - this.compactedPredicates.forEach(CompactedPredicate::reset); - } + public void reset() {} public abstract boolean test(PredicateContext ctx); @@ -36,8 +28,6 @@ public void reset() { public abstract boolean testSliceMin(PredicateContext ctx); - public abstract MultiPredicate.Logic getType(); - @Override public String toString() { return getType().name(); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java index 37107b94865..36f3732a48c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java @@ -7,7 +7,7 @@ public class OrLogic extends BaseLogic { public OrLogic(MultiPredicate rootPredicate) { - super(rootPredicate); + super(rootPredicate, MultiPredicate.Logic.OR); } @Override @@ -44,9 +44,4 @@ public boolean testSliceMin(PredicateContext ctx) { public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext ctx) { return passedPredicate.testGlobalMax(ctx) && passedPredicate.testSliceMax(ctx); } - - @Override - public MultiPredicate.Logic getType() { - return MultiPredicate.Logic.OR; - } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index 412b87e1640..84209abb03b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -20,21 +20,20 @@ public class XorLogic extends BaseLogic { protected boolean noneValid; public XorLogic(MultiPredicate rootPredicate) { - super(rootPredicate); + super(rootPredicate, MultiPredicate.Logic.XOR); this.noneValid = isNoneValid(this.rootPredicate); } @Override public void reset() { - super.reset(); this.passedPredicate = null; } private static boolean isNoneValid(MultiPredicate rootPredicate) { boolean noneValid = false; for (BasePredicate predicate : rootPredicate) { - if (predicate instanceof CompactedPredicate cp) { - noneValid |= isNoneValid(cp.expand()); + if (predicate instanceof CompactedPredicate compacted) { + noneValid |= isNoneValid(compacted.expand()); } else { noneValid |= predicate.getMinCount() <= 0 && predicate.getMinSliceCount() <= 0; } @@ -129,9 +128,4 @@ public void predicatePassed(BasePredicate predicate) { this.passedPredicate = predicate; } } - - @Override - public MultiPredicate.Logic getType() { - return MultiPredicate.Logic.XOR; - } } From 3d98910f5f30ac358a1d620b6d0119666fad164f Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:57:30 -0700 Subject: [PATCH 087/101] remove redundant testing methods to reflect recent refactor remove redundant predicate getter simplify XorLogic slice/global min methods update ExpandablePattern to match BlockPattern improve MultiPredicate errors --- .../gtceu/api/multiblock/MultiPredicate.java | 12 +--- .../api/multiblock/pattern/BlockPattern.java | 1 - .../multiblock/pattern/ExpandablePattern.java | 18 +++++- .../api/multiblock/pattern/PatternState.java | 2 +- .../multiblock/predicates/BasePredicate.java | 30 +++------ .../predicates/CompactedPredicate.java | 20 ++---- .../multiblock/predicates/logic/AndLogic.java | 28 +------- .../predicates/logic/BaseLogic.java | 6 +- .../multiblock/predicates/logic/OrLogic.java | 15 +---- .../multiblock/predicates/logic/XorLogic.java | 64 ++----------------- 10 files changed, 47 insertions(+), 149 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index 70f6c8e9595..34c3e414344 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -1,6 +1,5 @@ package com.gregtechceu.gtceu.api.multiblock; -import com.gregtechceu.gtceu.api.multiblock.error.SimplePatternError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.logic.AndLogic; @@ -65,12 +64,6 @@ private MultiPredicate(Logic type, List predicates, boolean hasAi this.hasAir = hasAir; } - // this is called for each block - /// delegates to {@link #logic} to run {@link BasePredicate#testLimited(PredicateContext)} - public boolean test(PredicateContext ctx) { - return this.logic.test(ctx); - } - /// delegates to {@link #logic} to test against global min count public boolean testGlobalMin(PredicateContext ctx) { return this.logic.testGlobalMin(ctx); @@ -297,7 +290,7 @@ private static void appendPredicates(Logic type, MultiPredicate multiPredicate, var p = compacted.expand().getPredicateAtPos(context); if (p != null) return p; // else continue... - } else if (predicate.getPredicate().test(context)) { + } else if (predicate.test(context)) { // logic needs to capture this getLogic().predicatePassed(predicate); return predicate; @@ -308,7 +301,8 @@ private static void appendPredicates(Logic type, MultiPredicate multiPredicate, /// called when all predicates failed public void onError(PredicateContext ctx) { - ctx.appendError(new SimplePatternError(ctx.pos(), getCandidates())); + // ctx.appendError(new SimplePatternError(ctx.pos(), getCandidates())); + forEach(p -> p.onError(ctx)); } public enum Logic { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 62c98f865e9..b6848f5a0d4 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -3,7 +3,6 @@ import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index 58569960709..64860ba658f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -3,6 +3,7 @@ import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.OriginOffset; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection; import net.minecraft.core.BlockPos; @@ -166,9 +167,24 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c if (!pred.isAny()) patternState.updateCache(); - if (!pred.test(context)) { + context.setStage(PredicateContext.PredicateStage.INTERNAL); + // state check + BasePredicate predicateAtPos = pred.getPredicateAtPos(context); + + // all predicates failed + // errors are PUSHED in slice strategy + // need to add them here, since they aren't added with getPredicateAtPos + if (predicateAtPos == null) { + pred.onError(context); return false; } + + // max count checks + if (!predicateAtPos.checkMaxCount(context)) { + predicateAtPos.onError(context); + return false; + } + visited.add(pred); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java index 29795892487..6d30503e346 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/PatternState.java @@ -127,7 +127,7 @@ public void onBlockStateChanged(BlockPos pos, BlockState oldState, BlockState ne if (name.equals(MultiblockControllerMachine.DEFAULT_STRUCTURE)) { MultiblockWorldSavedData.getOrCreate(serverLevel).removeMapping(this); controller.checkAndFormStructure(); - } + } } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index b3535916bcc..3b8d3ebced1 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -68,22 +68,12 @@ public MultiPredicate getParent() { } /// the main testing method - public boolean test(PredicateContext ctx) { - ctx.setStage(PredicateContext.PredicateStage.INTERNAL); - if (!getPredicate().test(ctx)) { - onError(ctx); - return false; - } - return true; - } + public abstract boolean test(PredicateContext ctx); public abstract void onError(PredicateContext ctx); - public abstract Predicate getPredicate(); - - /// test with internal function and global/slice max - public boolean testLimited(PredicateContext ctx) { - return test(ctx) && testGlobalMax(ctx) && testSliceMax(ctx); + public boolean checkMaxCount(PredicateContext context) { + return getParent().getLogic().testMaxCount(this, context); } /// test against global max count @@ -159,10 +149,6 @@ public Optional getFirstCandidate() { /// the contents of this predicate protected void appendContents(StringBuilder builder) {} - public boolean checkMaxCount(PredicateContext context) { - return getParent().getLogic().testMaxCount(this, context); - } - @Override public String toString() { StringBuilder builder = new StringBuilder(getTypeName()); @@ -212,12 +198,16 @@ public MultiPredicate toMultiPredicate() { public BasePredicate build() { return new BasePredicate() { + private final Predicate finalPredicate = Objects.requireNonNull(predicate, + name + " predicate == null"); + @Override public void onError(PredicateContext ctx) { if (onError != null) { onError.accept(ctx); + } else { + placeholderError(ctx); } - placeholderError(ctx); } private void placeholderError(PredicateContext ctx) { @@ -225,8 +215,8 @@ private void placeholderError(PredicateContext ctx) { } @Override - public Predicate getPredicate() { - return Objects.requireNonNull(predicate, name + " predicate == null"); + public boolean test(PredicateContext ctx) { + return this.finalPredicate.test(ctx); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java index 2d62777feca..496124adf71 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java @@ -6,7 +6,6 @@ import java.util.Collection; import java.util.List; -import java.util.function.Predicate; public class CompactedPredicate extends BasePredicate { @@ -20,24 +19,15 @@ public MultiPredicate expand() { return this.root; } + // this should never be called @Override - public Predicate getPredicate() { - return ctx -> { - for (BasePredicate predicate : this.root) { - if (predicate.getPredicate().test(ctx)) { - return true; - } - } - return false; - }; + public boolean test(PredicateContext ctx) { + throw new UnsupportedOperationException(); } @Override - public void onError(PredicateContext ctx) {} - - @Override - public boolean testLimited(PredicateContext ctx) { - return this.test(ctx); + public void onError(PredicateContext ctx) { + expand().onError(ctx); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java index 5be12a5304d..749688eecde 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -2,7 +2,6 @@ import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; public class AndLogic extends BaseLogic { @@ -11,32 +10,6 @@ public AndLogic(MultiPredicate rootPredicate) { super(rootPredicate, MultiPredicate.Logic.AND); } - @Override - public boolean test(PredicateContext ctx) { - int passed = 0; - for (BasePredicate predicate : this.rootPredicate) { - if (predicate.test(ctx)) { - passed++; - if (predicate.testGlobalMax(ctx) && predicate.testSliceMax(ctx)) { - continue; // fully passed - } - } - - // count manually - if (failedMaxCount(ctx, predicate, true) || failedMaxCount(ctx, predicate, false)) { - ctx.appendError(PatternStringError.literal("AND error")); - return false; - } - // continue... - } - return passed > 0; - } - - private static boolean failedMaxCount(PredicateContext ctx, BasePredicate predicate, boolean global) { - int count = global ? ctx.getGlobalCount(predicate) : ctx.getSliceCount(predicate); - return global ? !predicate.testGlobalMax(count) : !predicate.testSliceMax(count); - } - @Override public boolean testGlobalMin(PredicateContext ctx) { for (BasePredicate predicate : this.rootPredicate) { @@ -61,6 +34,7 @@ public boolean testSliceMin(PredicateContext ctx) { public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context) { for (BasePredicate predicate : this.rootPredicate) { if (!predicate.testGlobalMax(context) || !predicate.testSliceMax(context)) { + // error? return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java index e92ff5a8ada..c22897d27f9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java @@ -22,7 +22,8 @@ public BaseLogic(MultiPredicate rootPredicate, MultiPredicate.Logic type) { public void reset() {} - public abstract boolean test(PredicateContext ctx); + /// check max counts plus any additional logic + public abstract boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context); public abstract boolean testGlobalMin(PredicateContext ctx); @@ -33,8 +34,5 @@ public String toString() { return getType().name(); } - /// check max counts plus any additional logic - public abstract boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context); - public void predicatePassed(BasePredicate predicate) {} } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java index 36f3732a48c..19544b1c6ee 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java @@ -11,13 +11,9 @@ public OrLogic(MultiPredicate rootPredicate) { } @Override - public boolean test(PredicateContext ctx) { - for (BasePredicate predicate : this.rootPredicate) { - if (predicate.testLimited(ctx)) { - return true; - } - } - return false; + public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext ctx) { + // error? + return passedPredicate.testGlobalMax(ctx) && passedPredicate.testSliceMax(ctx); } @Override @@ -39,9 +35,4 @@ public boolean testSliceMin(PredicateContext ctx) { } return false; } - - @Override - public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext ctx) { - return passedPredicate.testGlobalMax(ctx) && passedPredicate.testSliceMax(ctx); - } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index 84209abb03b..7ed630c2ad1 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -2,15 +2,9 @@ import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.PatternError; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; -import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; - -import net.minecraft.ChatFormatting; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; public class XorLogic extends BaseLogic { @@ -41,58 +35,17 @@ private static boolean isNoneValid(MultiPredicate rootPredicate) { return noneValid; } - @Override - public boolean test(PredicateContext ctx) { - int passed = 0; - for (BasePredicate predicate : this.rootPredicate) { - if (predicate.test(ctx)) { - passed++; - if (this.passedPredicate == null) { - this.passedPredicate = predicate; - } - } - } - return passed > 0; - } - @Override public boolean testGlobalMin(PredicateContext ctx) { if (passedPredicate == null && noneValid) return true; if (passedPredicate == null || !passedPredicate.testGlobalMin(ctx)) { - ctx.appendError(onError()); + ctx.appendError(PatternStringError.literal("need one of: " + rootPredicate)); return false; } - if (!global) return true; - for (BasePredicate predicate : this.rootPredicate) { - if (predicate != passedPredicate && ctx.getGlobalCount(predicate) > 0) { - ctx.appendError(onError()); - ctx.appendError(PatternStringError.literal("%s present in multi", predicate)); - return false; - } - } + // if (!global) return true; return true; } - private PatternError onError() { - MutableComponent component = Component.literal("Need one of:\n") - .withStyle(ChatFormatting.WHITE); - - for (BasePredicate predicate : this.rootPredicate) { - for (BlockInfo candidate : predicate.getCandidates()) { - component.append(" ") - .append(candidate.getItemStackForm().getHoverName()) - .append("\n"); - } - } - - if (this.passedPredicate != null) { - component.append("\n") - .append("Expected predicate: " + this.passedPredicate); - } - - return PatternStringError.component(component); - } - @Override public boolean testSliceMin(PredicateContext ctx) { if (passedPredicate == null && noneValid) return true; @@ -100,22 +53,15 @@ public boolean testSliceMin(PredicateContext ctx) { ctx.appendError(PatternStringError.literal("need one of: " + rootPredicate)); return false; } - if (global) return true; - for (BasePredicate predicate : this.rootPredicate) { - if (predicate != passedPredicate && ctx.getSliceCount(predicate) > 0) { - ctx.appendError(PatternStringError.literal("need one of:\n" + rootPredicate.getPredicateList())); - ctx.appendError(PatternStringError.literal(predicate + " present in multi")); - return false; - } - } + // if (global) return true; + if (!global) reset(); return true; } @Override public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context) { + context.setStage(PredicateContext.PredicateStage.GLOBAL_MAX); // set stage early to avoid flip check if (passedPredicate != this.passedPredicate) { - // skip flipped check - context.skipFlipCheck(); context.appendError(PatternStringError.literal(passedPredicate + " present in multi")); return false; } From 20b58999deaba08ebbf2643d6bbfb16fbe7c0f38 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:36:09 -0700 Subject: [PATCH 088/101] add missing append error calls --- .../gtceu/api/multiblock/Predicates.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 9683d5f34aa..4db141dae33 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -84,7 +84,7 @@ public static MultiPredicate states(@Nullable String debugName, BlockState... al public static MultiPredicate blocks(Block block) { return builder("Block") .predicate(ctx -> ctx.state().is(block)) - .onError(ctx -> new BlockMatchingError(ctx.pos(), List.of(block))) + .onError(ctx -> ctx.appendError(new BlockMatchingError(ctx.pos(), List.of(block)))) .candidates(Stream.of(BlockInfo.fromBlock(block))) .contents(builder -> builder.append(blockToString(block))) .toMultiPredicate(); @@ -114,7 +114,7 @@ public static MultiPredicate blocks(@Nullable String debugName, } return false; }) - .onError(ctx -> new BlockMatchingError(ctx.pos(), blocks)) + .onError(ctx -> ctx.appendError(new BlockMatchingError(ctx.pos(), blocks))) .candidates(candidates.map(BlockInfo::fromBlock)) .contents(builder -> { StringJoiner joiner = new StringJoiner(", "); @@ -144,8 +144,8 @@ public static MultiPredicate blockTag(TagKey tag) { ITagManager manager = Objects.requireNonNull(ForgeRegistries.BLOCKS.tags()); return builder("BlockTag") .predicate(ctx -> ctx.state().is(tag)) - .onError(ctx -> new BlockMatchingError(ctx.pos(), manager.getTag(tag) - .stream().toList())) + .onError(ctx -> ctx.appendError(new BlockMatchingError(ctx.pos(), manager.getTag(tag) + .stream().toList()))) .candidates(manager.getTag(tag) .stream().map(BlockInfo::fromBlock)) .contents(builder -> builder.append(tag.location())) @@ -155,7 +155,7 @@ public static MultiPredicate blockTag(TagKey tag) { public static MultiPredicate fluids(Fluid... fluids) { return builder("Fluids") .predicate(ctx -> ArrayUtils.contains(fluids, ctx.fluid())) - .onError(ctx -> ctx.appendError(PLACEHOLDER)) +// .onError(ctx -> ctx.appendError(PLACEHOLDER)) .candidates(Arrays.stream(fluids).map(BlockInfo::fromFluid)) .contents(builder -> { StringJoiner joiner = new StringJoiner(", "); @@ -172,7 +172,7 @@ public static MultiPredicate fluids(Fluid... fluids) { public static MultiPredicate fluidTag(TagKey tag) { return builder("FluidTag") .predicate(ctx -> ctx.fluidState().is(tag)) - .onError(ctx -> ctx.appendError(PLACEHOLDER)) +// .onError(ctx -> ctx.appendError(PLACEHOLDER)) .fluidTag(tag) .toMultiPredicate(); } @@ -188,7 +188,7 @@ public static MultiPredicate air() { public static MultiPredicate abilities(PartAbility ability) { return builder("Ability") .predicate(ctx -> ability.isApplicable(ctx.state().getBlock())) - .onError(ctx -> new PartAbilityError(ctx.pos(), ability)) + .onError(ctx -> ctx.appendError(new PartAbilityError(ctx.pos(), ability))) .candidates(ability.getAllBlocks().stream().map(BlockInfo::fromBlock)) .contents(builder -> builder.append(ability.getName())) .toMultiPredicate(); @@ -199,7 +199,7 @@ public static MultiPredicate abilities(PartAbility... abilities) { for (PartAbility ability : abilities) { predicates.add(builder("Ability") .predicate(ctx -> ability.isApplicable(ctx.state().getBlock())) - .onError(ctx -> new PartAbilityError(ctx.pos(), ability)) + .onError(ctx -> ctx.appendError(new PartAbilityError(ctx.pos(), ability))) .candidates(ability.getAllBlocks().stream().map(BlockInfo::fromBlock)) .contents(builder -> builder.append(ability.getName())) .build()); @@ -214,7 +214,7 @@ public static MultiPredicate ability(PartAbility ability, int... tiers) { } return builder("TieredAbility") .predicate(ctx -> ability.getBlocks(tiers).contains(ctx.state().getBlock())) - .onError(ctx -> new PartAbilityError(ctx.pos(), ability)) + .onError(ctx -> ctx.appendError(new PartAbilityError(ctx.pos(), ability))) .candidates(ability.getBlocks(tiers).stream().map(BlockInfo::fromBlock)) .contents(builder -> builder.append(ability.getName()).append(" ").append(sb)) .toMultiPredicate(); From 9fd5370f60944020b47e6fa07135912bfa84d80a Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 30 Jul 2026 01:55:09 -0700 Subject: [PATCH 089/101] add additional tooltips back --- .../gtceu/api/multiblock/MultiPredicate.java | 7 ++++++ .../gtceu/api/multiblock/Predicates.java | 22 ++++++++----------- .../multiblock/predicates/BasePredicate.java | 16 ++++++++++---- .../common/data/machines/GTMachineUtils.java | 13 +++++------ .../common/data/machines/GTMultiMachines.java | 3 +-- 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index 34c3e414344..e27ee187d0c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -8,6 +8,8 @@ import com.gregtechceu.gtceu.api.multiblock.predicates.logic.XorLogic; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; +import net.minecraft.network.chat.Component; + import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; @@ -122,6 +124,11 @@ protected BasePredicate compact() { return new CompactedPredicate(this); } + public MultiPredicate addTooltips(Component tooltip) { + forEach(p -> p.addTooltips(tooltip)); + return this; + } + public MultiPredicate setPriority(int priority) { this.forEach(p -> p.setPriority(priority)); return this; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 4db141dae33..058884c0cbe 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -23,6 +23,7 @@ import com.gregtechceu.gtceu.config.ConfigHolder; import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; import net.minecraft.tags.TagKey; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; @@ -155,7 +156,7 @@ public static MultiPredicate blockTag(TagKey tag) { public static MultiPredicate fluids(Fluid... fluids) { return builder("Fluids") .predicate(ctx -> ArrayUtils.contains(fluids, ctx.fluid())) -// .onError(ctx -> ctx.appendError(PLACEHOLDER)) + // .onError(ctx -> ctx.appendError(PLACEHOLDER)) .candidates(Arrays.stream(fluids).map(BlockInfo::fromFluid)) .contents(builder -> { StringJoiner joiner = new StringJoiner(", "); @@ -172,7 +173,7 @@ public static MultiPredicate fluids(Fluid... fluids) { public static MultiPredicate fluidTag(TagKey tag) { return builder("FluidTag") .predicate(ctx -> ctx.fluidState().is(tag)) -// .onError(ctx -> ctx.appendError(PLACEHOLDER)) + // .onError(ctx -> ctx.appendError(PLACEHOLDER)) .fluidTag(tag) .toMultiPredicate(); } @@ -312,22 +313,18 @@ public static MultiPredicate autoAbilities(boolean checkMaintenance, boolean che } public static MultiPredicate heatingCoils() { - return blocks("HeatingCoils", - GTCEuAPI.HEATING_COILS.values().stream().map(Supplier::get)) - // .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")) + return blocks("HeatingCoils", GTCEuAPI.HEATING_COILS.values().stream().map(Supplier::get)) + .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.coils")) .setPriority(0); } public static MultiPredicate cleanroomFilters() { return blocks("CleanroomFilters", - GTCEuAPI.CLEANROOM_FILTERS.values() - .stream().map(Supplier::get).toList(), - GTCEuAPI.CLEANROOM_FILTERS.entrySet() - .stream() + GTCEuAPI.CLEANROOM_FILTERS.values().stream().map(Supplier::get).toList(), + GTCEuAPI.CLEANROOM_FILTERS.entrySet().stream() .sorted(Comparator.comparingInt(e -> e.getKey().getCleanroomType().getTier())) .map(entry -> entry.getValue().get())) - // .addTooltips(Component.translatable("gtceu.multiblock.pattern.cleanroom")) - ; + .addTooltips(Component.translatable("gtceu.multiblock.pattern.cleanroom")); } public static MultiPredicate powerSubstationBatteries() { @@ -338,8 +335,7 @@ public static MultiPredicate powerSubstationBatteries() { .stream() .sorted(Comparator.comparingInt(e -> e.getKey().getTier())) .map(e -> e.getValue().get())) - // .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.batteries")) - ; + .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.batteries")); } public static @Nullable MultiPredicate dataHatchPredicate() { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 3b8d3ebced1..0eec0c04c92 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -2,10 +2,12 @@ import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.error.PlaceholderError; import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; +import net.minecraft.network.chat.Component; import net.minecraft.tags.TagKey; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; @@ -63,6 +65,9 @@ public abstract class BasePredicate { @Setter private @Nullable MultiPredicate parent; + @Getter + private final List additionalTooltips = new ArrayList<>(); + public MultiPredicate getParent() { return Objects.requireNonNull(this.parent); } @@ -72,6 +77,10 @@ public MultiPredicate getParent() { public abstract void onError(PredicateContext ctx); + public void addTooltips(Component tooltip) { + this.additionalTooltips.add(tooltip); + } + public boolean checkMaxCount(PredicateContext context) { return getParent().getLogic().testMaxCount(this, context); } @@ -196,11 +205,9 @@ public MultiPredicate toMultiPredicate() { } public BasePredicate build() { + final Predicate finalPredicate = Objects.requireNonNull(predicate); return new BasePredicate() { - private final Predicate finalPredicate = Objects.requireNonNull(predicate, - name + " predicate == null"); - @Override public void onError(PredicateContext ctx) { if (onError != null) { @@ -208,6 +215,7 @@ public void onError(PredicateContext ctx) { } else { placeholderError(ctx); } + this.getAdditionalTooltips().forEach(c -> ctx.appendError(PatternStringError.component(c))); } private void placeholderError(PredicateContext ctx) { @@ -216,7 +224,7 @@ private void placeholderError(PredicateContext ctx) { @Override public boolean test(PredicateContext ctx) { - return this.finalPredicate.test(ctx); + return finalPredicate.test(ctx); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 5439a25309b..09604922ed2 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -671,13 +671,11 @@ public static MultiblockMachineDefinition registerLargeCombustionEngine(GTRegist IntStream.of(ULV, LV, MV, HV, EV, IV, LuV, ZPM, UV, UHV) .filter(t -> t >= tier) .toArray()) - // .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", - // GTValues.VN[tier])) - ) + .addTooltips(Component.translatable( + "gtceu.multiblock.pattern.error.limited.1", GTValues.VN[tier]))) .where('A', blocks(intake.get()) - // .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_1")) - ) + .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_1"))) .where('Y', controller(blocks(definition.getBlock()))) .build()) .recoveryItems( @@ -755,9 +753,8 @@ private static MultiPredicate rotorHolder(int tier) { .stream().map(BlockInfo::fromBlock)) .contents(builder -> builder.append(PartAbility.ROTOR_HOLDER.getName())) .toMultiPredicate() - // .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")) - // .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", VN[tier])) - ; + .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")) + .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", VN[tier])); } // Tooltips diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java index 5798b4486fe..96853dd5f1a 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java @@ -390,8 +390,7 @@ public class GTMultiMachines { Predicates.abilities(PartAbility.IMPORT_FLUIDS_1X).setMaxGlobalLimited(4))) .where('O', Predicates.abilities(PartAbility.EXPORT_ITEMS) - // .addTooltips(Component.translatable("gtceu.multiblock.pattern.location_end")) - ) + .addTooltips(Component.translatable("gtceu.multiblock.pattern.location_end"))) .where('Y', blocks(CASING_STEEL_SOLID.get()).or(Predicates.abilities(PartAbility.INPUT_ENERGY) .setMinGlobalLimited(1).setMaxGlobalLimited(2))) From e11081e5022eb7421804bbbb351930cb295f123e Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 30 Jul 2026 02:04:33 -0700 Subject: [PATCH 090/101] cleanup comments and rename local variables add todo --- .../api/multiblock/pattern/BlockPattern.java | 18 +++++++----------- .../multiblock/pattern/ExpandablePattern.java | 17 +++++++---------- .../multiblock/predicates/logic/AndLogic.java | 1 - .../multiblock/predicates/logic/OrLogic.java | 1 - .../multiblock/predicates/logic/XorLogic.java | 1 + 5 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index b6848f5a0d4..9e26c919f04 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -209,30 +209,26 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p for (int stringIdx = 0; stringIdx < dimensions[1]; stringIdx++) { for (int charIdx = 0; charIdx < dimensions[2]; charIdx++) { context.updatePos(charPos); - MultiPredicate pred = predicates.get(slice.charAt(stringIdx, charIdx)); + MultiPredicate multiPredicate = predicates.get(slice.charAt(stringIdx, charIdx)); - if (!pred.isAny()) patternState.updateCache(); + if (!multiPredicate.isAny()) patternState.updateCache(); context.setStage(PredicateContext.PredicateStage.INTERNAL); // state check - BasePredicate predicateAtPos = pred.getPredicateAtPos(context); + BasePredicate innerPredicate = multiPredicate.getPredicateAtPos(context); // all predicates failed - // errors are PUSHED in slice strategy - // need to add them here, since they aren't added with getPredicateAtPos - if (predicateAtPos == null) { - pred.onError(context); - // todo this causes a flipped check, add error? + if (innerPredicate == null) { + multiPredicate.onError(context); return false; } // max count checks - if (!predicateAtPos.checkMaxCount(context)) { - // error handled + if (!innerPredicate.checkMaxCount(context)) { return false; } - visitedPredicates.add(pred); + visitedPredicates.add(multiPredicate); charPos.move(absoluteChar); // continue... } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index 64860ba658f..0ea872211f0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -156,7 +156,7 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c Set visited = new HashSet<>(); for (var pos : BlockPos.betweenClosed(negCorner, posCorner)) { BlockPos.MutableBlockPos mPos = pos.mutable(); - MultiPredicate pred = predicateProvider.apply(mPos, bounds); + MultiPredicate multiPredicate = predicateProvider.apply(mPos, bounds); // this basically reshuffles the coordinates into absolute form from relative form mPos.set(BlockPos.ZERO).move(absolutes[0], pos.getX()).move(absolutes[1], pos.getY()).move(absolutes[2], @@ -165,27 +165,24 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c mPos = mPos.offset(translation).mutable(); context.updatePos(mPos); - if (!pred.isAny()) patternState.updateCache(); + if (!multiPredicate.isAny()) patternState.updateCache(); context.setStage(PredicateContext.PredicateStage.INTERNAL); // state check - BasePredicate predicateAtPos = pred.getPredicateAtPos(context); + BasePredicate innerPredicate = multiPredicate.getPredicateAtPos(context); // all predicates failed - // errors are PUSHED in slice strategy - // need to add them here, since they aren't added with getPredicateAtPos - if (predicateAtPos == null) { - pred.onError(context); + if (innerPredicate == null) { + multiPredicate.onError(context); return false; } // max count checks - if (!predicateAtPos.checkMaxCount(context)) { - predicateAtPos.onError(context); + if (!innerPredicate.checkMaxCount(context)) { return false; } - visited.add(pred); + visited.add(multiPredicate); } context.setStage(PredicateContext.PredicateStage.GLOBAL_MIN); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java index 749688eecde..f839d074730 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java @@ -34,7 +34,6 @@ public boolean testSliceMin(PredicateContext ctx) { public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context) { for (BasePredicate predicate : this.rootPredicate) { if (!predicate.testGlobalMax(context) || !predicate.testSliceMax(context)) { - // error? return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java index 19544b1c6ee..d2a23327659 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java @@ -12,7 +12,6 @@ public OrLogic(MultiPredicate rootPredicate) { @Override public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext ctx) { - // error? return passedPredicate.testGlobalMax(ctx) && passedPredicate.testSliceMax(ctx); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java index 7ed630c2ad1..708bd15297f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java @@ -62,6 +62,7 @@ public boolean testSliceMin(PredicateContext ctx) { public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context) { context.setStage(PredicateContext.PredicateStage.GLOBAL_MAX); // set stage early to avoid flip check if (passedPredicate != this.passedPredicate) { + // todo prettier error context.appendError(PatternStringError.literal(passedPredicate + " present in multi")); return false; } From 4cce55435ac609be15c68fb71187d595f362dabd Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 30 Jul 2026 02:25:56 -0700 Subject: [PATCH 091/101] more cleanup, move slice methods remove global/layer count getters replace layer "null" checks with boolean replace slice record with int --- .../api/multiblock/PredicateContext.java | 97 +++++++++---------- .../pattern/BasicSliceStrategy.java | 4 +- .../api/multiblock/pattern/BlockPattern.java | 2 +- 3 files changed, 47 insertions(+), 56 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index c1ed00daa4a..51e157c49a9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -6,6 +6,9 @@ import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; +import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.IntComparators; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; @@ -27,6 +30,10 @@ public class PredicateContext { protected CurrentBlockInfo currentBlockInfo = new CurrentBlockInfo(); protected final Object2IntMap globalCount = new Object2IntOpenHashMap<>(); protected final Object2IntMap layerCount = new Object2IntOpenHashMap<>(); + + private final Int2ObjectMap> sliceErrors = new Int2ObjectAVLTreeMap<>(IntComparators.NATURAL_COMPARATOR); + + private int currentSlice = 0; @Getter @Setter private boolean checkLayer = true; @@ -37,9 +44,6 @@ public class PredicateContext { @Getter private FailureReason lastFailureReason = FailureReason.NONE; - // if (stage == PredicateStage.GLOBAL_MIN || stage == PredicateStage.SLICE_MIN) { - // this.currentSlice = null; - // } @Setter protected PredicateStage stage = PredicateStage.INTERNAL; @@ -56,7 +60,7 @@ public boolean error(PatternError error) { } public void appendError(PatternError error) { - if (currentSlice != null) { + if (currentSlice != -1) { getCurrentSliceErrors().add(error); } else { this.state.setError(error); @@ -65,8 +69,30 @@ public void appendError(PatternError error) { this.checkFlipped = this.lastFailureReason.shouldCheckFlip(); } + public void clearErrors() { + this.sliceErrors.remove(currentSlice); + this.lastFailureReason = FailureReason.NONE; + } + private List getCurrentSliceErrors() { - return this.sliceErrors.computeIfAbsent(Objects.requireNonNull(currentSlice), k -> new ArrayList<>()); + return this.sliceErrors.computeIfAbsent(currentSlice, k -> new ArrayList<>()); + } + + public void pushSlice() { + this.currentSlice++; + } + + public void popSlice() { + clearErrors(); + this.currentSlice--; + } + + public void commitSliceErrors() { + for (var entry : this.sliceErrors.int2ObjectEntrySet()) { + this.state.appendErrors(entry.getValue()); + } + this.sliceErrors.clear(); + this.currentSlice = -1; } /// @return the current Level @@ -98,49 +124,30 @@ public BlockPos pos() { return this.currentBlockInfo.retrieveCurrentBlockEntity(); } - public Object2IntMap globalCache() { - return this.globalCount; + public void clearGlobalCounts() { + this.globalCount.clear(); } - /// @return {@code null} if {@link #checkLayer} is false, else returns the layer cache map - public @Nullable Object2IntMap layerCache() { - return isCheckLayer() ? this.layerCount : null; + public void clearLayerCounts() { + this.layerCount.clear(); } public int incrementGlobalCount(BasePredicate predicate) { - return globalCache().mergeInt(predicate, 1, Integer::sum); + return this.globalCount.mergeInt(predicate, 1, Integer::sum); } public int incrementSliceCount(BasePredicate predicate) { - return Objects.requireNonNull(layerCache()).mergeInt(predicate, 1, Integer::sum); + if (!checkLayer) return 0; + return this.layerCount.mergeInt(predicate, 1, Integer::sum); } public int getGlobalCount(BasePredicate predicate) { - return globalCache().getInt(predicate); + return this.globalCount.getInt(predicate); } public int getSliceCount(BasePredicate predicate) { - return Objects.requireNonNull(layerCache()).getInt(predicate); - } - - public void clearErrors() { - this.sliceErrors.remove(currentSlice); - this.lastFailureReason = FailureReason.NONE; - } - - private Object2ObjectMap> sliceErrors = new Object2ObjectAVLTreeMap<>(Slice::compareTo); - - private @Nullable Slice currentSlice; - - public void pushSlice(int index, int offset) { - this.currentSlice = new Slice(index, offset); - } - - public void commitSliceErrors() { - for (Slice slice : this.sliceErrors.keySet()) { - this.state.appendErrors(this.sliceErrors.get(slice)); - } - this.sliceErrors.clear(); + if (!checkLayer) return 0; + return this.layerCount.getInt(predicate); } public void updateLevel(Level level) { @@ -155,31 +162,15 @@ public BlockInfo computeBlockInfo() { return new BlockInfo(state(), blockEntity()); } - public void skipFlipCheck() { - this.checkFlipped = false; - } - public void reset() { setStage(PredicateStage.INTERNAL); this.currentBlockInfo = new CurrentBlockInfo(); - this.currentSlice = null; - this.sliceErrors.clear(); - this.globalCount.clear(); + this.currentSlice = 0; + this.clearGlobalCounts(); + this.clearLayerCounts(); this.layerCount.clear(); } - private record Slice(int index, int offset) implements Comparable { - - @Override - public int compareTo(PredicateContext.Slice o) { - int i = Integer.compare(this.index, o.index); - if (i == 0) { - return Integer.compare(this.offset, o.offset); - } - return i; - } - } - public enum PredicateStage { INTERNAL, diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java index 00d3d21a6be..ac1922a2b68 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BasicSliceStrategy.java @@ -79,13 +79,13 @@ protected int checkRepeatSlice(PatternState state, int index, int offset, boolea PatternSlice slice = slices.get(index); PredicateContext context = state.getContext(); for (int i = 1; i <= slice.maxRepeats; i++) { - context.pushSlice(index, offset + i - 1); + context.pushSlice(); boolean res = checkSlice(state, index, offset + i - 1, flip); if (!res) { if (i <= slice.minRepeats) return -1; // invalid, but within max repeats so may be valid overall - context.clearErrors(); + context.popSlice(); return slices.get(index).actualRepeats = i - 1; } // valid slice, clear errors just in case diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 9e26c919f04..36875075b1b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -203,7 +203,7 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p PatternSlice slice = slices[sliceIndex]; PredicateContext context = patternState.getContext(); - context.layerCache().clear(); + context.clearLayerCounts(); Set visitedPredicates = new HashSet<>(); for (int stringIdx = 0; stringIdx < dimensions[1]; stringIdx++) { From 5363a1f6d2bfff982bbfda867afc3ee8b64913c5 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 30 Jul 2026 02:41:23 -0700 Subject: [PATCH 092/101] move MultiPredicate error call inside merge failure checks --- .../gregtechceu/gtceu/api/multiblock/MultiPredicate.java | 1 + .../gtceu/api/multiblock/pattern/BlockPattern.java | 7 +------ .../gtceu/api/multiblock/pattern/ExpandablePattern.java | 7 +------ 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index e27ee187d0c..7371c3bb6ee 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -303,6 +303,7 @@ private static void appendPredicates(Logic type, MultiPredicate multiPredicate, return predicate; } } + onError(context); return null; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java index 36875075b1b..3e49055d831 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/BlockPattern.java @@ -218,13 +218,8 @@ public boolean checkSlice(BlockPos.MutableBlockPos controllerPos, PatternState p BasePredicate innerPredicate = multiPredicate.getPredicateAtPos(context); // all predicates failed - if (innerPredicate == null) { - multiPredicate.onError(context); - return false; - } - // max count checks - if (!innerPredicate.checkMaxCount(context)) { + if (innerPredicate == null || !innerPredicate.checkMaxCount(context)) { return false; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java index 0ea872211f0..37373ee4531 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/ExpandablePattern.java @@ -172,13 +172,8 @@ public boolean checkPatternAt(Level level, PatternState patternState, BlockPos c BasePredicate innerPredicate = multiPredicate.getPredicateAtPos(context); // all predicates failed - if (innerPredicate == null) { - multiPredicate.onError(context); - return false; - } - // max count checks - if (!innerPredicate.checkMaxCount(context)) { + if (innerPredicate == null || !innerPredicate.checkMaxCount(context)) { return false; } From b5fac044854101012360c6218cc932d10d4c9a60 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:07:33 -0700 Subject: [PATCH 093/101] remove last few usages of the boolean error method javadoc --- .../gtceu/api/multiblock/PredicateContext.java | 10 +++------- .../multiblock/predicates/BasePredicate.java | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 51e157c49a9..411d71d87d2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -51,14 +51,10 @@ public PredicateContext(PatternState state) { this.state = state; } - /// accepts a pattern error + /// If a multiblock is currently being iterated, errors are queued to be added to the + /// PatternState later /// - /// @return false - public boolean error(PatternError error) { - appendError(error); - return false; - } - + /// @param error The error to add to PatternState public void appendError(PatternError error) { if (currentSlice != -1) { getCurrentSliceErrors().add(error); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 0eec0c04c92..e731ade26e5 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -90,7 +90,9 @@ public boolean testGlobalMax(PredicateContext ctx) { if (getMaxCount() == -1) return true; ctx.setStage(PredicateContext.PredicateStage.GLOBAL_MAX); int count = ctx.incrementGlobalCount(this); - return testGlobalMax(count) || ctx.error(SinglePredicateError.maxCount(this, count)); + if (testGlobalMax(count)) return true; + ctx.appendError(SinglePredicateError.maxCount(this, count)); + return false; } /// test against slice max count @@ -98,22 +100,27 @@ public boolean testSliceMax(PredicateContext ctx) { if (!ctx.isCheckLayer()) return true; ctx.setStage(PredicateContext.PredicateStage.SLICE_MAX); int count = ctx.incrementSliceCount(this); - return getMaxSliceCount() == -1 || testSliceMax(count) || - ctx.error(SinglePredicateError.maxLayerCount(this, count)); + if (getMaxSliceCount() == -1 || testSliceMax(count)) return true; + ctx.appendError(SinglePredicateError.maxLayerCount(this, count)); + return false; } /// test against global min count public boolean testGlobalMin(PredicateContext ctx) { if (getMinCount() == -1) return true; int count = ctx.getGlobalCount(this); - return testGlobalMin(count) || ctx.error(SinglePredicateError.minCount(this, count)); + if (testGlobalMin(count)) return true; + ctx.appendError(SinglePredicateError.minCount(this, count)); + return false; } /// test against slice min count public boolean testSliceMin(PredicateContext ctx) { if (getMinSliceCount() == -1 || !ctx.isCheckLayer()) return true; int count = ctx.getSliceCount(this); - return testSliceMin(count) || ctx.error(SinglePredicateError.minLayerCount(this, count)); + if (testSliceMin(count)) return true; + ctx.appendError(SinglePredicateError.minLayerCount(this, count)); + return false; } /// simple test against global min count From 4d6bf551a8a34233cc1f26bb0e57972a8de8613d Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:28:37 -0700 Subject: [PATCH 094/101] just move shit around tbh --- .../gtceu/api/multiblock/PredicateContext.java | 2 +- .../api/multiblock/predicates/BasePredicate.java | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index 411d71d87d2..e21488187be 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -162,9 +162,9 @@ public void reset() { setStage(PredicateStage.INTERNAL); this.currentBlockInfo = new CurrentBlockInfo(); this.currentSlice = 0; + this.sliceErrors.clear(); this.clearGlobalCounts(); this.clearLayerCounts(); - this.layerCount.clear(); } public enum PredicateStage { diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index e731ade26e5..266528fa7d0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -3,7 +3,7 @@ import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; -import com.gregtechceu.gtceu.api.multiblock.error.PlaceholderError; +import com.gregtechceu.gtceu.api.multiblock.error.SimplePatternError; import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; @@ -212,26 +212,24 @@ public MultiPredicate toMultiPredicate() { } public BasePredicate build() { - final Predicate finalPredicate = Objects.requireNonNull(predicate); return new BasePredicate() { + final Predicate internalPredicate = Objects.requireNonNull(predicate); + final Consumer onError = Objects.requireNonNullElse(Builder.this.onError, + this::placeholderError); @Override public void onError(PredicateContext ctx) { - if (onError != null) { - onError.accept(ctx); - } else { - placeholderError(ctx); - } + this.onError.accept(ctx); this.getAdditionalTooltips().forEach(c -> ctx.appendError(PatternStringError.component(c))); } private void placeholderError(PredicateContext ctx) { - ctx.appendError(new PlaceholderError(ctx.pos(), List.of(getCandidates()))); + ctx.appendError(new SimplePatternError(ctx.pos(), List.of(getCandidates()))); } @Override public boolean test(PredicateContext ctx) { - return finalPredicate.test(ctx); + return this.internalPredicate.test(ctx); } @Override From c8b67880ebd6ca3c912a6fbb0bcb21133e0b47e6 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Mon, 3 Aug 2026 00:20:35 -0700 Subject: [PATCH 095/101] mmmm yes 15 changed files... delete logics and compacted predicate store MultiPredicate children directly in a list make MultiPredicate abstract to replace logics with subclasses make BasePredicate implement comparable spotless for good measure --- .../gtceu/api/multiblock/AndPredicate.java | 57 ++++++ .../gtceu/api/multiblock/MultiPredicate.java | 193 ++++++++++-------- .../gtceu/api/multiblock/OrPredicate.java | 47 +++++ .../api/multiblock/PredicateContext.java | 9 +- .../gtceu/api/multiblock/Predicates.java | 6 +- .../logic/XorLogic.java => XorPredicate.java} | 54 ++--- .../pattern/MultiblockPatternBuilder.java | 2 +- .../multiblock/predicates/BasePredicate.java | 18 +- .../predicates/CompactedPredicate.java | 60 ------ .../multiblock/predicates/logic/AndLogic.java | 42 ---- .../predicates/logic/BaseLogic.java | 38 ---- .../multiblock/predicates/logic/OrLogic.java | 37 ---- .../multiblock/util/BlockPatternHelper.java | 19 +- .../util/ExpandablePatternHelper.java | 17 +- .../widgets/MultiblockPreviewWidget.java | 6 +- 15 files changed, 268 insertions(+), 337 deletions(-) create mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/AndPredicate.java create mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/OrPredicate.java rename src/main/java/com/gregtechceu/gtceu/api/multiblock/{predicates/logic/XorLogic.java => XorPredicate.java} (64%) delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java delete mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/AndPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/AndPredicate.java new file mode 100644 index 00000000000..292791dab40 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/AndPredicate.java @@ -0,0 +1,57 @@ +package com.gregtechceu.gtceu.api.multiblock; + +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; + +import java.util.List; + +public class AndPredicate extends MultiPredicate { + + public AndPredicate(List children, List predicates, boolean hasAir) { + super(Logic.AND, children, predicates, hasAir); + } + + @Override + public boolean testGlobalMin(PredicateContext ctx) { + for (BasePredicate predicate : predicates()) { + if (!predicate.testGlobalMin(ctx)) { + return false; + } + } + for (MultiPredicate child : children()) { + if (!child.testGlobalMin(ctx)) { + return false; + } + } + return true; + } + + @Override + public boolean testSliceMin(PredicateContext ctx) { + for (BasePredicate predicate : predicates()) { + if (!predicate.testSliceMin(ctx)) { + return false; + } + } + for (MultiPredicate child : children()) { + if (!child.testSliceMin(ctx)) { + return false; + } + } + return true; + } + + @Override + public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context) { + for (BasePredicate predicate : predicates()) { + if (!predicate.testGlobalMax(context) || !predicate.testSliceMax(context)) { + return false; + } + } + for (MultiPredicate child : children()) { + if (!child.testMaxCount(passedPredicate, context)) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index 7371c3bb6ee..d598710454f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -1,11 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.logic.AndLogic; -import com.gregtechceu.gtceu.api.multiblock.predicates.logic.BaseLogic; -import com.gregtechceu.gtceu.api.multiblock.predicates.logic.OrLogic; -import com.gregtechceu.gtceu.api.multiblock.predicates.logic.XorLogic; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import net.minecraft.network.chat.Component; @@ -17,90 +12,86 @@ import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.Consumer; -public class MultiPredicate implements Iterable { +public abstract class MultiPredicate { - private static final Comparator PREDICATE_COMPARATOR = Comparator - .comparingInt(BasePredicate::getPriority); + private static final MultiPredicate EMPTY = of(Logic.OR, List.of()); - private static final MultiPredicate EMPTY = new MultiPredicate(); + public static final MultiPredicate AIR = of(BasePredicate.AIR); - public static final MultiPredicate AIR = new MultiPredicate(BasePredicate.AIR); + public static final MultiPredicate ANY = of(BasePredicate.ANY); - public static final MultiPredicate ANY = new MultiPredicate(BasePredicate.ANY); - - @Getter - private final List predicateList; - @Getter - private final BaseLogic logic; + private final List predicates; + private final List children; private final boolean hasAir; @Getter + private final Logic type; + @Getter @Setter @Accessors(chain = true) private boolean controller; - public MultiPredicate(BasePredicate predicate) { - this.predicateList = List.of(predicate); - predicate.setParent(this); - this.logic = Logic.OR.createLogic(this); - this.hasAir = predicate == BasePredicate.AIR; - } + @Nullable + @Getter + @Setter + private MultiPredicate parent; - private MultiPredicate() { - this.predicateList = List.of(); - this.logic = Logic.OR.createLogic(this); - this.hasAir = false; + public static MultiPredicate of(BasePredicate predicate) { + return Logic.OR.makePredicate(predicate, predicate == BasePredicate.AIR); } /// @param predicates list must be modifiable - public MultiPredicate(Logic type, List predicates) { - this(type, predicates, predicates.stream().anyMatch(p -> p == BasePredicate.AIR)); + private static MultiPredicate of(Logic type, List predicates) { + return type.makePredicate(List.of(), predicates, predicates.stream().anyMatch(p -> p == BasePredicate.AIR)); } - /// @param predicates list must be modifiable - private MultiPredicate(Logic type, List predicates, boolean hasAir) { + /// @param children list of multi predicate children + /// @param predicates list of testable predicates, must be modifiable + protected MultiPredicate(Logic type, List children, List predicates, + boolean hasAir) { + predicates.sort(BasePredicate::compareTo); predicates.forEach(p -> p.setParent(this)); - predicates.sort(PREDICATE_COMPARATOR); - this.predicateList = Collections.unmodifiableList(predicates); - this.logic = type.createLogic(this); + children.forEach(mp -> mp.setParent(this)); + this.predicates = Collections.unmodifiableList(predicates); + this.children = Collections.unmodifiableList(children); + this.type = type; this.hasAir = hasAir; } - /// delegates to {@link #logic} to test against global min count - public boolean testGlobalMin(PredicateContext ctx) { - return this.logic.testGlobalMin(ctx); - } + /// test against global min count + public abstract boolean testGlobalMin(PredicateContext ctx); - /// delegates to {@link #logic} to test against slice min count - public boolean testSliceMin(PredicateContext ctx) { - return this.logic.testSliceMin(ctx); - } + /// test against slice min count + public abstract boolean testSliceMin(PredicateContext ctx); + + /// test against global/slice max counts + public abstract boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context); public List> getCandidates() { - return this.predicateList.stream() + return this.predicates.stream() .map(BasePredicate::getCandidates) .toList(); } public void resetLogic() { - this.logic.reset(); - for (BasePredicate p : this.predicateList) { - if (p instanceof CompactedPredicate compacted) { - compacted.expand().resetLogic(); - } - } + children.forEach(MultiPredicate::resetLogic); } public boolean isOr() { - return this.logic.getType() == Logic.OR; + return this.getType() == Logic.OR; } public boolean isAnd() { - return this.logic.getType() == Logic.AND; + return this.getType() == Logic.AND; } public boolean isXor() { - return this.logic.getType() == Logic.XOR; + return this.getType() == Logic.XOR; + } + + private boolean isType(Logic type) { + return this.type == type; } @ApiStatus.Internal @@ -120,12 +111,8 @@ public boolean hasAir() { return this.hasAir; } - protected BasePredicate compact() { - return new CompactedPredicate(this); - } - public MultiPredicate addTooltips(Component tooltip) { - forEach(p -> p.addTooltips(tooltip)); + this.forEach(p -> p.addTooltips(tooltip)); return this; } @@ -230,19 +217,23 @@ public MultiPredicate xor(MultiPredicate other) { } public static MultiPredicate or(List predicates) { - return new MultiPredicate(Logic.OR, predicates); + return of(Logic.OR, predicates); } public static MultiPredicate and(List predicates) { - return new MultiPredicate(Logic.AND, predicates); + return of(Logic.AND, predicates); } public static MultiPredicate xor(List predicates) { - return new MultiPredicate(Logic.XOR, predicates); + return of(Logic.XOR, predicates); } public boolean isSingle() { - return predicateList.size() == 1; + return predicates.size() == 1 && !hasChildren(); + } + + private boolean hasChildren() { + return !this.children.isEmpty(); } public void appendContents(StringBuilder builder) { @@ -261,9 +252,28 @@ public String toString() { return builder.toString(); } - @Override - public Iterator iterator() { - return this.predicateList.iterator(); + protected void forEach(Consumer action) { + this.predicates.forEach(action); + } + + public List predicates() { + return this.predicates; + } + + public void forEachChild(Consumer action) { + this.children.forEach(action); + } + + public List children() { + return this.children; + } + + public List expand() { + List expanded = new ArrayList<>(this.predicates); + if (hasChildren()) { + forEachChild(mp -> expanded.addAll(mp.expand())); + } + return expanded; } public static MultiPredicate empty() { @@ -276,55 +286,62 @@ public static MultiPredicate empty() { private static MultiPredicate combine(MultiPredicate a, Logic type, @Nullable MultiPredicate b) { if (b == null) return a; // no op if (a.isEmpty()) return b; - ArrayList builder = new ArrayList<>(); - appendPredicates(type, a, builder); - appendPredicates(type, b, builder); - return new MultiPredicate(type, builder, a.hasAir || b.hasAir); + List predicates = new ArrayList<>(); + List children = new ArrayList<>(); + appendPredicates(type, a, predicates, children); + appendPredicates(type, b, predicates, children); + return type.makePredicate(children, predicates, a.hasAir || b.hasAir); } - private static void appendPredicates(Logic type, MultiPredicate multiPredicate, ArrayList builder) { - if (multiPredicate.isSingle() || multiPredicate.logic.getType() == type) { - builder.addAll(multiPredicate.predicateList); + private static void appendPredicates(Logic type, MultiPredicate multiPredicate, + List predicates, List children) { + if (multiPredicate.isSingle() || multiPredicate.isType(type)) { + predicates.addAll(multiPredicate.predicates()); } else { - builder.add(multiPredicate.compact()); + children.add(multiPredicate); } } /// @return innermost base predicate that passes state check at given pos public @Nullable BasePredicate getPredicateAtPos(PredicateContext context) { - for (BasePredicate predicate : this) { - if (predicate instanceof CompactedPredicate compacted) { - var p = compacted.expand().getPredicateAtPos(context); - if (p != null) return p; - // else continue... - } else if (predicate.test(context)) { - // logic needs to capture this - getLogic().predicatePassed(predicate); + for (BasePredicate predicate : predicates()) { + if (predicate.test(context)) { return predicate; } } - onError(context); + for (MultiPredicate predicates : children()) { + BasePredicate p = predicates.getPredicateAtPos(context); + if (p != null) return p; + } + if (!hasChildren()) { + onError(context); + } return null; } /// called when all predicates failed - public void onError(PredicateContext ctx) { - // ctx.appendError(new SimplePatternError(ctx.pos(), getCandidates())); - forEach(p -> p.onError(ctx)); + protected void onError(PredicateContext ctx) { + this.forEach(p -> p.onError(ctx)); + this.forEachChild(mp -> mp.onError(ctx)); } - public enum Logic { + protected enum Logic { OR, AND, XOR; - public BaseLogic createLogic(MultiPredicate source) { + public MultiPredicate makePredicate(List children, List predicates, + boolean hasAir) { return switch (this) { - case AND -> new AndLogic(source); - case XOR -> new XorLogic(source); - default -> new OrLogic(source); + case OR -> new OrPredicate(children, predicates, hasAir); + case AND -> new AndPredicate(children, predicates, hasAir); + case XOR -> new XorPredicate(children, predicates, hasAir); }; } + + public MultiPredicate makePredicate(BasePredicate predicate, boolean hasAir) { + return makePredicate(List.of(), List.of(predicate), hasAir); + } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/OrPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/OrPredicate.java new file mode 100644 index 00000000000..9f9c3facd37 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/OrPredicate.java @@ -0,0 +1,47 @@ +package com.gregtechceu.gtceu.api.multiblock; + +import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; + +import java.util.List; + +public class OrPredicate extends MultiPredicate { + + public OrPredicate(List children, List predicates, boolean hasAir) { + super(Logic.OR, children, predicates, hasAir); + } + + @Override + public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext ctx) { + return passedPredicate.testGlobalMax(ctx) && passedPredicate.testSliceMax(ctx); + } + + @Override + public boolean testGlobalMin(PredicateContext ctx) { + for (BasePredicate predicate : predicates()) { + if (predicate.testGlobalMin(ctx)) { + return true; + } + } + for (MultiPredicate child : children()) { + if (child.testGlobalMin(ctx)) { + return true; + } + } + return false; + } + + @Override + public boolean testSliceMin(PredicateContext ctx) { + for (BasePredicate predicate : predicates()) { + if (predicate.testSliceMin(ctx)) { + return true; + } + } + for (MultiPredicate child : children()) { + if (child.testSliceMin(ctx)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java index e21488187be..ca1edf262de 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/PredicateContext.java @@ -6,9 +6,6 @@ import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; -import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.IntComparators; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; @@ -16,6 +13,9 @@ import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; +import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.IntComparators; import it.unimi.dsi.fastutil.objects.*; import lombok.Getter; import lombok.Setter; @@ -31,7 +31,8 @@ public class PredicateContext { protected final Object2IntMap globalCount = new Object2IntOpenHashMap<>(); protected final Object2IntMap layerCount = new Object2IntOpenHashMap<>(); - private final Int2ObjectMap> sliceErrors = new Int2ObjectAVLTreeMap<>(IntComparators.NATURAL_COMPARATOR); + private final Int2ObjectMap> sliceErrors = new Int2ObjectAVLTreeMap<>( + IntComparators.NATURAL_COMPARATOR); private int currentSlice = 0; @Getter diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 058884c0cbe..44a9a2613c0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -382,6 +382,10 @@ public static MultiPredicate framedPipes(Material[] frameMaterials, Block[] fram } public static BasePredicate.Builder builder(@Nullable String debugName) { - return new BasePredicate.Builder(debugName); + return new BasePredicate.Builder(debugName == null ? "Predicate" : debugName); + } + + public static BasePredicate.Builder builder() { + return builder(null); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/XorPredicate.java similarity index 64% rename from src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java rename to src/main/java/com/gregtechceu/gtceu/api/multiblock/XorPredicate.java index 708bd15297f..a9f7aa43f4b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/XorLogic.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/XorPredicate.java @@ -1,45 +1,46 @@ -package com.gregtechceu.gtceu.api.multiblock.predicates.logic; +package com.gregtechceu.gtceu.api.multiblock; -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; -import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; -public class XorLogic extends BaseLogic { +import org.jetbrains.annotations.Nullable; - private BasePredicate passedPredicate; +import java.util.List; + +public class XorPredicate extends MultiPredicate { + + private @Nullable BasePredicate passedPredicate; /// {@code true} if any base predicate have a min count of 0 or -1, /// meaning that it is possible that no predicates may be present in the multi. protected boolean noneValid; - public XorLogic(MultiPredicate rootPredicate) { - super(rootPredicate, MultiPredicate.Logic.XOR); - this.noneValid = isNoneValid(this.rootPredicate); - } - - @Override - public void reset() { - this.passedPredicate = null; + public XorPredicate(List children, List predicates, boolean hasAir) { + super(Logic.XOR, children, predicates, hasAir); + this.noneValid = isNoneValid(this); } private static boolean isNoneValid(MultiPredicate rootPredicate) { boolean noneValid = false; - for (BasePredicate predicate : rootPredicate) { - if (predicate instanceof CompactedPredicate compacted) { - noneValid |= isNoneValid(compacted.expand()); - } else { - noneValid |= predicate.getMinCount() <= 0 && predicate.getMinSliceCount() <= 0; - } + for (BasePredicate predicate : rootPredicate.expand()) { + noneValid |= predicate.getMinCount() <= 0 && predicate.getMinSliceCount() <= 0; } return noneValid; } + @Override + public @Nullable BasePredicate getPredicateAtPos(PredicateContext context) { + BasePredicate predicate = super.getPredicateAtPos(context); + if (predicate != null && this.passedPredicate == null) { + this.passedPredicate = predicate; + } + return predicate; + } + @Override public boolean testGlobalMin(PredicateContext ctx) { if (passedPredicate == null && noneValid) return true; if (passedPredicate == null || !passedPredicate.testGlobalMin(ctx)) { - ctx.appendError(PatternStringError.literal("need one of: " + rootPredicate)); + ctx.appendError(PatternStringError.literal("need one of: " + this)); return false; } // if (!global) return true; @@ -50,11 +51,11 @@ public boolean testGlobalMin(PredicateContext ctx) { public boolean testSliceMin(PredicateContext ctx) { if (passedPredicate == null && noneValid) return true; if (passedPredicate == null || !passedPredicate.testSliceMin(ctx)) { - ctx.appendError(PatternStringError.literal("need one of: " + rootPredicate)); + ctx.appendError(PatternStringError.literal("need one of: " + this)); return false; } // if (global) return true; - if (!global) reset(); + // if (!global) resetLogic(); return true; } @@ -70,9 +71,8 @@ public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext cont } @Override - public void predicatePassed(BasePredicate predicate) { - if (this.passedPredicate == null) { - this.passedPredicate = predicate; - } + public void resetLogic() { + super.resetLogic(); + this.passedPredicate = null; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java index c3c1dbf0dbc..ee6afd34d6d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/pattern/MultiblockPatternBuilder.java @@ -176,7 +176,7 @@ private void checkGlobalConstraints() { MultiPredicate predicate = entry.getValue(); if (predicate == null) throw new IllegalArgumentException("Predicate for symbol " + symbol + " was null."); int maxCount = -1; - for (var basePredicate : predicate) { + for (var basePredicate : predicate.expand()) { if (basePredicate.getMaxCount() == -1) { maxCount = -1; break; diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 266528fa7d0..4ccf0817bae 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -24,7 +24,7 @@ import java.util.function.Predicate; import java.util.stream.Stream; -public abstract class BasePredicate { +public abstract class BasePredicate implements Comparable { public static final BasePredicate AIR = new Builder("Air") .predicate(ctx -> ctx.state().isAir()) @@ -82,7 +82,7 @@ public void addTooltips(Component tooltip) { } public boolean checkMaxCount(PredicateContext context) { - return getParent().getLogic().testMaxCount(this, context); + return getParent().testMaxCount(this, context); } /// test against global max count @@ -174,7 +174,12 @@ public String toString() { return builder.toString(); } - @Accessors(chain = true, fluent = true) + @Override + public int compareTo(BasePredicate o) { + return Integer.compare(this.priority, o.priority); + } + + @Accessors(fluent = true) public static class Builder { private final String name; @@ -187,8 +192,8 @@ public static class Builder { @Setter private @Nullable Consumer onError; - public Builder(@Nullable String debugName) { - this.name = debugName != null ? debugName : "Predicate"; + public Builder(String debugName) { + this.name = debugName; } /// fills candidates and sets string contents with this block tag @@ -208,11 +213,12 @@ public Builder fluidTag(TagKey tag) { } public MultiPredicate toMultiPredicate() { - return new MultiPredicate(build()); + return MultiPredicate.of(build()); } public BasePredicate build() { return new BasePredicate() { + final Predicate internalPredicate = Objects.requireNonNull(predicate); final Consumer onError = Objects.requireNonNullElse(Builder.this.onError, this::placeholderError); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java deleted file mode 100644 index 496124adf71..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/CompactedPredicate.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.gregtechceu.gtceu.api.multiblock.predicates; - -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; -import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; - -import java.util.Collection; -import java.util.List; - -public class CompactedPredicate extends BasePredicate { - - private final MultiPredicate root; - - public CompactedPredicate(MultiPredicate root) { - this.root = root; - } - - public MultiPredicate expand() { - return this.root; - } - - // this should never be called - @Override - public boolean test(PredicateContext ctx) { - throw new UnsupportedOperationException(); - } - - @Override - public void onError(PredicateContext ctx) { - expand().onError(ctx); - } - - @Override - public boolean testGlobalMin(PredicateContext ctx) { - return expand().testGlobalMin(ctx); - } - - @Override - public boolean testSliceMin(PredicateContext ctx) { - return expand().testSliceMin(ctx); - } - - @Override - public List computeCandidates() { - return expand().getCandidates() - .stream() - .flatMap(Collection::stream) - .toList(); - } - - @Override - public String getTypeName() { - return "CompactedPredicate"; - } - - @Override - protected void appendContents(StringBuilder builder) { - expand().appendContents(builder); - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java deleted file mode 100644 index f839d074730..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/AndLogic.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.gregtechceu.gtceu.api.multiblock.predicates.logic; - -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; -import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; - -public class AndLogic extends BaseLogic { - - public AndLogic(MultiPredicate rootPredicate) { - super(rootPredicate, MultiPredicate.Logic.AND); - } - - @Override - public boolean testGlobalMin(PredicateContext ctx) { - for (BasePredicate predicate : this.rootPredicate) { - if (!predicate.testGlobalMin(ctx)) { - return false; - } - } - return true; - } - - @Override - public boolean testSliceMin(PredicateContext ctx) { - for (BasePredicate predicate : this.rootPredicate) { - if (!predicate.testSliceMin(ctx)) { - return false; - } - } - return true; - } - - @Override - public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context) { - for (BasePredicate predicate : this.rootPredicate) { - if (!predicate.testGlobalMax(context) || !predicate.testSliceMax(context)) { - return false; - } - } - return true; - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java deleted file mode 100644 index c22897d27f9..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/BaseLogic.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.gregtechceu.gtceu.api.multiblock.predicates.logic; - -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; -import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; - -import lombok.Getter; -import lombok.Setter; - -public abstract class BaseLogic { - - protected final MultiPredicate rootPredicate; - @Getter - private final MultiPredicate.Logic type; - @Setter - protected boolean global = true; // used for XOR, AND - - public BaseLogic(MultiPredicate rootPredicate, MultiPredicate.Logic type) { - this.rootPredicate = rootPredicate; - this.type = type; - } - - public void reset() {} - - /// check max counts plus any additional logic - public abstract boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context); - - public abstract boolean testGlobalMin(PredicateContext ctx); - - public abstract boolean testSliceMin(PredicateContext ctx); - - @Override - public String toString() { - return getType().name(); - } - - public void predicatePassed(BasePredicate predicate) {} -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java deleted file mode 100644 index d2a23327659..00000000000 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/logic/OrLogic.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.gregtechceu.gtceu.api.multiblock.predicates.logic; - -import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; -import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; - -public class OrLogic extends BaseLogic { - - public OrLogic(MultiPredicate rootPredicate) { - super(rootPredicate, MultiPredicate.Logic.OR); - } - - @Override - public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext ctx) { - return passedPredicate.testGlobalMax(ctx) && passedPredicate.testSliceMax(ctx); - } - - @Override - public boolean testGlobalMin(PredicateContext ctx) { - for (BasePredicate predicate : this.rootPredicate) { - if (predicate.testGlobalMin(ctx)) { - return true; - } - } - return false; - } - - @Override - public boolean testSliceMin(PredicateContext ctx) { - for (BasePredicate predicate : this.rootPredicate) { - if (predicate.testSliceMin(ctx)) { - return true; - } - } - return false; - } -} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java index 3ad9e40f0ec..2386da69011 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/BlockPatternHelper.java @@ -6,7 +6,6 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.pattern.PatternSlice; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -131,13 +130,7 @@ protected void populateFromPattern(Map resultStructure, IBl private boolean tryMinCount(Map resultStructure, MultiPredicate predicate, BlockPos pos, Direction dir, int offset) { - for (BasePredicate basePredicate : predicate) { - if (basePredicate instanceof CompactedPredicate compactedPredicate) { - if (!tryMinCount(resultStructure, compactedPredicate.expand(), pos, dir, offset)) { - continue; - } - return true; - } + for (BasePredicate basePredicate : predicate.predicates()) { int minCount = getMinCount(predicate, basePredicate); if (minCount == 0) continue; @@ -165,13 +158,7 @@ private boolean tryMinCount(Map resultStructure, MultiPredi private boolean tryMaxCount(Map resultStructure, MultiPredicate predicate, BlockPos pos, Direction dir, int offset) { - for (BasePredicate basePredicate : predicate) { - if (basePredicate instanceof CompactedPredicate compactedPredicate) { - if (!tryMaxCount(resultStructure, compactedPredicate.expand(), pos, dir, offset)) { - continue; - } - return true; - } + for (BasePredicate basePredicate : predicate.expand()) { int maxCount = getMaxCount(predicate, basePredicate); if (maxCount == 0) continue; @@ -203,7 +190,7 @@ private boolean isValidCandidate(Map resultStructure, Multi // newInfo is valid if there's a basePredicate it qualifies for whose maxCount (global) and maxSliceCount // (this slice) wouldn't be exceeded by placing it here. - for (BasePredicate basePredicate : predicate) { + for (BasePredicate basePredicate : predicate.expand()) { if (!basePredicate.getCandidates().contains(newInfo)) continue; int maxCount = getMaxCount(predicate, basePredicate); diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java index 08babb662f4..3b228b85639 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/util/ExpandablePatternHelper.java @@ -4,7 +4,6 @@ import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; -import com.gregtechceu.gtceu.api.multiblock.predicates.CompactedPredicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -111,13 +110,7 @@ public void populateFromPattern(Map resultStructure, IBlock private boolean tryMinCount(Map resultStructure, MultiPredicate predicate, BlockPos pos) { - for (BasePredicate basePredicate : predicate) { - if (basePredicate instanceof CompactedPredicate compactedPredicate) { - if (!tryMinCount(resultStructure, compactedPredicate.expand(), pos)) { - continue; - } - return true; - } + for (BasePredicate basePredicate : predicate.expand()) { int minCount = getMinCount(predicate, basePredicate); if (minCount == 0) continue; @@ -138,13 +131,7 @@ private boolean tryMinCount(Map resultStructure, MultiPredi private boolean tryMaxCount(Map resultStructure, MultiPredicate predicate, BlockPos pos) { - for (BasePredicate basePredicate : predicate) { - if (basePredicate instanceof CompactedPredicate compactedPredicate) { - if (!tryMaxCount(resultStructure, compactedPredicate.expand(), pos)) { - continue; - } - return true; - } + for (BasePredicate basePredicate : predicate.expand()) { int maxCount = getMaxCount(predicate, basePredicate); if (maxCount == 0) continue; diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java index 4b469ea484b..c9a032b03ce 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java @@ -253,7 +253,8 @@ private ContextMenuButton createSelectedBlockMenu(MultiPredicate predicate) { .coverChildrenWidth() .collapseDisabledChildren() .childSeparator(Icon.EMPTY_2PX) - .children(predicate, basePredicate -> { + // todo handle children + .children(predicate.expand(), basePredicate -> { List candidates = basePredicate.getCandidates(); if (candidates.isEmpty()) return new EmptyWidget(); @@ -328,7 +329,8 @@ private void createPredicateMenus(Flow predicatesRow, BlockPattern blockPattern) .coverChildrenWidth() .collapseDisabledChildren() .childSeparator(Icon.EMPTY_2PX) - .children(predicate, basePredicate -> { + // todo handle children + .children(predicate.expand(), basePredicate -> { List candidates = basePredicate.getCandidates(); if (candidates.isEmpty()) { return new EmptyWidget(); From df5d21abcf07787d29ca707c2d3681bdb7bc50ec Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Mon, 3 Aug 2026 00:31:57 -0700 Subject: [PATCH 096/101] move builder class out replace anon class with TestablePredicate --- .../gtceu/api/multiblock/Predicates.java | 9 +- .../multiblock/predicates/BasePredicate.java | 93 +--------------- .../predicates/PredicateBuilder.java | 65 +++++++++++ .../predicates/TestablePredicate.java | 105 ++++++++++++++++++ 4 files changed, 177 insertions(+), 95 deletions(-) create mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateBuilder.java create mode 100644 src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/TestablePredicate.java diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java index 44a9a2613c0..8b19536b5f3 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/Predicates.java @@ -16,6 +16,7 @@ import com.gregtechceu.gtceu.api.multiblock.error.PartAbilityError; import com.gregtechceu.gtceu.api.multiblock.error.PlaceholderError; import com.gregtechceu.gtceu.api.multiblock.predicates.BasePredicate; +import com.gregtechceu.gtceu.api.multiblock.predicates.PredicateBuilder; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.pipenet.IPipeNode; import com.gregtechceu.gtceu.api.recipe.GTRecipeType; @@ -381,11 +382,11 @@ public static MultiPredicate framedPipes(Material[] frameMaterials, Block[] fram .toMultiPredicate(); } - public static BasePredicate.Builder builder(@Nullable String debugName) { - return new BasePredicate.Builder(debugName == null ? "Predicate" : debugName); + public static PredicateBuilder builder(String debugName) { + return new PredicateBuilder(debugName); } - public static BasePredicate.Builder builder() { - return builder(null); + public static PredicateBuilder builder() { + return builder("Predicate"); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 4ccf0817bae..9487fe37655 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -2,36 +2,26 @@ import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; -import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; -import com.gregtechceu.gtceu.api.multiblock.error.SimplePatternError; import com.gregtechceu.gtceu.api.multiblock.error.SinglePredicateError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import net.minecraft.network.chat.Component; -import net.minecraft.tags.TagKey; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.registries.ForgeRegistries; import lombok.Getter; import lombok.Setter; -import lombok.experimental.Accessors; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.stream.Stream; public abstract class BasePredicate implements Comparable { - public static final BasePredicate AIR = new Builder("Air") + public static final BasePredicate AIR = new PredicateBuilder("Air") .predicate(ctx -> ctx.state().isAir()) // todo error? .build(); - public static final BasePredicate ANY = new Builder("Any") + public static final BasePredicate ANY = new PredicateBuilder("Any") .predicate(ctx -> true) .build(); @@ -178,83 +168,4 @@ public String toString() { public int compareTo(BasePredicate o) { return Integer.compare(this.priority, o.priority); } - - @Accessors(fluent = true) - public static class Builder { - - private final String name; - @Setter - private Predicate predicate; - @Setter - private Stream candidates = Stream.empty(); - @Setter - private @Nullable Consumer contents; - @Setter - private @Nullable Consumer onError; - - public Builder(String debugName) { - this.name = debugName; - } - - /// fills candidates and sets string contents with this block tag - public Builder blockTag(TagKey tag) { - this.candidates = Objects.requireNonNull(ForgeRegistries.BLOCKS.tags()) - .getTag(tag).stream().map(BlockInfo::fromBlock); - this.contents = builder -> builder.append(tag.location()); - return this; - } - - /// fills candidates and sets string contents with this fluid tag - public Builder fluidTag(TagKey tag) { - this.candidates = Objects.requireNonNull(ForgeRegistries.FLUIDS.tags()) - .getTag(tag).stream().map(BlockInfo::fromFluid); - this.contents = builder -> builder.append(tag.location()); - return this; - } - - public MultiPredicate toMultiPredicate() { - return MultiPredicate.of(build()); - } - - public BasePredicate build() { - return new BasePredicate() { - - final Predicate internalPredicate = Objects.requireNonNull(predicate); - final Consumer onError = Objects.requireNonNullElse(Builder.this.onError, - this::placeholderError); - - @Override - public void onError(PredicateContext ctx) { - this.onError.accept(ctx); - this.getAdditionalTooltips().forEach(c -> ctx.appendError(PatternStringError.component(c))); - } - - private void placeholderError(PredicateContext ctx) { - ctx.appendError(new SimplePatternError(ctx.pos(), List.of(getCandidates()))); - } - - @Override - public boolean test(PredicateContext ctx) { - return this.internalPredicate.test(ctx); - } - - @Override - public List computeCandidates() { - return Objects.requireNonNull(candidates).toList(); - } - - @Override - public String getTypeName() { - return name; - } - - @Override - protected void appendContents(StringBuilder builder) { - if (contents != null) { - contents.accept(builder); - } - } - }; - } - } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateBuilder.java new file mode 100644 index 00000000000..9e13bc8d908 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/PredicateBuilder.java @@ -0,0 +1,65 @@ +package com.gregtechceu.gtceu.api.multiblock.predicates; + +import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; + +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.material.Fluid; +import net.minecraftforge.registries.ForgeRegistries; + +import lombok.Setter; +import lombok.experimental.Accessors; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; + +@Accessors(fluent = true) +public class PredicateBuilder { + + private final String name; + @Setter + private Predicate predicate; + @Setter + private Stream candidates = Stream.empty(); + @Setter + private @Nullable Consumer contents; + @Setter + private @Nullable Consumer onError; + + public PredicateBuilder(String debugName) { + this.name = debugName; + } + + /// fills candidates and sets string contents with this block tag + public PredicateBuilder blockTag(TagKey tag) { + this.candidates = Objects.requireNonNull(ForgeRegistries.BLOCKS.tags()) + .getTag(tag).stream().map(BlockInfo::fromBlock); + this.contents = builder -> builder.append(tag.location()); + return this; + } + + /// fills candidates and sets string contents with this fluid tag + public PredicateBuilder fluidTag(TagKey tag) { + this.candidates = Objects.requireNonNull(ForgeRegistries.FLUIDS.tags()) + .getTag(tag).stream().map(BlockInfo::fromFluid); + this.contents = builder -> builder.append(tag.location()); + return this; + } + + public MultiPredicate toMultiPredicate() { + return MultiPredicate.of(build()); + } + + public BasePredicate build() { + return new TestablePredicate(name, + Objects.requireNonNull(predicate, "predicate == null"), + candidates, + contents, + onError); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/TestablePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/TestablePredicate.java new file mode 100644 index 00000000000..45b1e85f44c --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/TestablePredicate.java @@ -0,0 +1,105 @@ +package com.gregtechceu.gtceu.api.multiblock.predicates; + +import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; +import com.gregtechceu.gtceu.api.mui.MultiblockSchemaInfo; +import com.gregtechceu.gtceu.api.multiblock.PredicateContext; +import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; +import com.gregtechceu.gtceu.api.multiblock.error.SimplePatternError; +import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; +import com.gregtechceu.gtceu.data.lang.LangHandler; + +import net.minecraft.client.Camera; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.network.chat.Component; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.Level; +import net.minecraftforge.client.event.RenderLevelStageEvent; + +import com.mojang.blaze3d.vertex.PoseStack; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; + +class TestablePredicate extends BasePredicate { + + private final Consumer onError; + private final Stream candidates; + private final @Nullable Consumer contents; + private final String name; + private final Predicate predicate; + + /** + * @param name The debug name + * @param predicate The predicate function for being a valid block state or tile entity in a pattern + * @param candidates The qualifying blocks or item stacks valid in this predicate based on information from + * either the + * {@link com.gregtechceu.gtceu.common.item.behavior.TerminalBehavior#use(Item, Level, Player, InteractionHand) + * Terminal Auto-Builder}, + * {@link com.gregtechceu.gtceu.client.renderer.PatternPreviewRenderer#draw(PoseStack, MultiBufferSource.BufferSource, Camera, RenderLevelStageEvent.Stage, float) + * In-world Preview} or + * {@link com.gregtechceu.gtceu.integration.recipeviewer.widgets.MultiblockPreviewWidget#MultiblockPreviewWidget(MultiblockMachineDefinition definition, MultiblockSchemaInfo schemaInfo, int width,int height) + * XEI Preview} + */ + TestablePredicate(String name, Predicate predicate, + Stream candidates, + @Nullable Consumer contents, + @Nullable Consumer onError) { + this.name = name; + this.predicate = predicate; + this.candidates = candidates; + this.contents = contents; + this.onError = Objects.requireNonNullElse(onError, this::placeholderError); + } + + @Override + public void onError(PredicateContext ctx) { + this.onError.accept(ctx); + List tooltips = new ArrayList<>(this.getAdditionalTooltips()); + if (minCount == maxCount && maxCount != -1) { + tooltips.add(Component.translatable("gtceu.multiblock.pattern.error.limited_exact", minCount)); + } else if (minCount != maxCount && minCount != -1 && maxCount != -1) { + tooltips.add(Component.translatable("gtceu.multiblock.pattern.error.limited_within", minCount, maxCount)); + } else { + if (minCount != -1) { + tooltips.add(LangHandler.getFromMultiLang("gtceu.multiblock.pattern.error.limited", 1, minCount)); + } + if (maxCount != -1) { + tooltips.add(LangHandler.getFromMultiLang("gtceu.multiblock.pattern.error.limited", 0, maxCount)); + } + } + tooltips.forEach(c -> ctx.appendError(PatternStringError.component(c))); + } + + private void placeholderError(PredicateContext ctx) { + ctx.appendError(new SimplePatternError(ctx.pos(), List.of(getCandidates()))); + } + + @Override + public boolean test(PredicateContext ctx) { + return this.predicate.test(ctx); + } + + @Override + public List computeCandidates() { + return this.candidates.toList(); + } + + @Override + public String getTypeName() { + return this.name; + } + + @Override + protected void appendContents(StringBuilder builder) { + if (this.contents != null) { + this.contents.accept(builder); + } + } +} From 4b40ebc597805efbbb5d228097168e796e103cb1 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Mon, 3 Aug 2026 18:51:38 -0700 Subject: [PATCH 097/101] move sort out of constructor dont iterate children in max count check improve XorPredicate's passed predicate --- .../gtceu/api/multiblock/AndPredicate.java | 5 -- .../gtceu/api/multiblock/MultiPredicate.java | 6 +- .../gtceu/api/multiblock/OrPredicate.java | 10 --- .../gtceu/api/multiblock/XorPredicate.java | 65 ++++++++++++++++--- .../multiblock/predicates/BasePredicate.java | 2 + 5 files changed, 60 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/AndPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/AndPredicate.java index 292791dab40..3dc663433e0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/AndPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/AndPredicate.java @@ -47,11 +47,6 @@ public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext cont return false; } } - for (MultiPredicate child : children()) { - if (!child.testMaxCount(passedPredicate, context)) { - return false; - } - } return true; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index d598710454f..a7a89740391 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -47,10 +47,9 @@ private static MultiPredicate of(Logic type, List predicates) { } /// @param children list of multi predicate children - /// @param predicates list of testable predicates, must be modifiable + /// @param predicates list of testable predicates, should be sorted already protected MultiPredicate(Logic type, List children, List predicates, boolean hasAir) { - predicates.sort(BasePredicate::compareTo); predicates.forEach(p -> p.setParent(this)); children.forEach(mp -> mp.setParent(this)); this.predicates = Collections.unmodifiableList(predicates); @@ -232,7 +231,7 @@ public boolean isSingle() { return predicates.size() == 1 && !hasChildren(); } - private boolean hasChildren() { + protected boolean hasChildren() { return !this.children.isEmpty(); } @@ -290,6 +289,7 @@ private static MultiPredicate combine(MultiPredicate a, Logic type, @Nullable Mu List children = new ArrayList<>(); appendPredicates(type, a, predicates, children); appendPredicates(type, b, predicates, children); + predicates.sort(BasePredicate::compareTo); return type.makePredicate(children, predicates, a.hasAir || b.hasAir); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/OrPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/OrPredicate.java index 9f9c3facd37..698f6a870d5 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/OrPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/OrPredicate.java @@ -22,11 +22,6 @@ public boolean testGlobalMin(PredicateContext ctx) { return true; } } - for (MultiPredicate child : children()) { - if (child.testGlobalMin(ctx)) { - return true; - } - } return false; } @@ -37,11 +32,6 @@ public boolean testSliceMin(PredicateContext ctx) { return true; } } - for (MultiPredicate child : children()) { - if (child.testSliceMin(ctx)) { - return true; - } - } return false; } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/XorPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/XorPredicate.java index a9f7aa43f4b..bb5257a7372 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/XorPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/XorPredicate.java @@ -6,22 +6,24 @@ import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Objects; public class XorPredicate extends MultiPredicate { - private @Nullable BasePredicate passedPredicate; + // this could be a base predicate or a child + private @Nullable PassedPredicate passedPredicate; /// {@code true} if any base predicate have a min count of 0 or -1, /// meaning that it is possible that no predicates may be present in the multi. protected boolean noneValid; public XorPredicate(List children, List predicates, boolean hasAir) { super(Logic.XOR, children, predicates, hasAir); - this.noneValid = isNoneValid(this); + this.noneValid = isNoneValid(); } - private static boolean isNoneValid(MultiPredicate rootPredicate) { + private boolean isNoneValid() { boolean noneValid = false; - for (BasePredicate predicate : rootPredicate.expand()) { + for (BasePredicate predicate : expand()) { noneValid |= predicate.getMinCount() <= 0 && predicate.getMinSliceCount() <= 0; } return noneValid; @@ -29,11 +31,29 @@ private static boolean isNoneValid(MultiPredicate rootPredicate) { @Override public @Nullable BasePredicate getPredicateAtPos(PredicateContext context) { - BasePredicate predicate = super.getPredicateAtPos(context); - if (predicate != null && this.passedPredicate == null) { - this.passedPredicate = predicate; + for (BasePredicate predicate : predicates()) { + if (predicate.test(context)) { + setPassedPredicate(predicate, null); + return predicate; + } + } + for (MultiPredicate predicates : children()) { + BasePredicate p = predicates.getPredicateAtPos(context); + if (p != null) { + setPassedPredicate(p, predicates); + return p; + } + } + if (!hasChildren()) { + onError(context); + } + return null; + } + + private void setPassedPredicate(BasePredicate predicate, @Nullable MultiPredicate multiPredicate) { + if (this.passedPredicate == null) { + this.passedPredicate = new PassedPredicate(predicate, multiPredicate); } - return predicate; } @Override @@ -61,13 +81,14 @@ public boolean testSliceMin(PredicateContext ctx) { @Override public boolean testMaxCount(BasePredicate passedPredicate, PredicateContext context) { + Objects.requireNonNull(this.passedPredicate); // should not be null by this pouint context.setStage(PredicateContext.PredicateStage.GLOBAL_MAX); // set stage early to avoid flip check - if (passedPredicate != this.passedPredicate) { + if (!this.passedPredicate.matches(passedPredicate)) { // todo prettier error context.appendError(PatternStringError.literal(passedPredicate + " present in multi")); return false; } - return this.passedPredicate.testGlobalMax(context) && this.passedPredicate.testSliceMax(context); + return this.passedPredicate.testMaxCount(context); } @Override @@ -75,4 +96,28 @@ public void resetLogic() { super.resetLogic(); this.passedPredicate = null; } + + private record PassedPredicate(BasePredicate predicate, @Nullable MultiPredicate multiPredicate) { + + public boolean testGlobalMin(PredicateContext ctx) { + return predicate.testGlobalMin(ctx); + } + + + public boolean testSliceMin(PredicateContext ctx) { + return predicate.testSliceMin(ctx); + } + + public boolean testMaxCount(PredicateContext context) { + if (multiPredicate == null) { + return predicate.testGlobalMax(context) && predicate.testSliceMax(context); + } else { + return multiPredicate.testMaxCount(predicate, context); + } + } + + public boolean matches(BasePredicate p) { + return p == predicate && (multiPredicate == null || p.getParent() == multiPredicate); + } + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 9487fe37655..9e5f66ed8c9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -71,6 +71,8 @@ public void addTooltips(Component tooltip) { this.additionalTooltips.add(tooltip); } + /// delegates to {@link MultiPredicate#testMaxCount(BasePredicate, PredicateContext)}, + /// with this predicate as the passing predicate public boolean checkMaxCount(PredicateContext context) { return getParent().testMaxCount(this, context); } From 1f404260cf6accca59b65cfc62ad73c3e9b62135 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Mon, 3 Aug 2026 19:20:11 -0700 Subject: [PATCH 098/101] mark other predicate params nullable javadoc --- .../gtceu/api/multiblock/MultiPredicate.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java index a7a89740391..842e49b5bf1 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/MultiPredicate.java @@ -203,15 +203,15 @@ private MultiPredicate setDisableRenderFormed(boolean disable) { return this; } - public MultiPredicate or(MultiPredicate other) { + public MultiPredicate or(@Nullable MultiPredicate other) { return combine(this, Logic.OR, other); } - public MultiPredicate and(MultiPredicate other) { + public MultiPredicate and(@Nullable MultiPredicate other) { return combine(this, Logic.AND, other); } - public MultiPredicate xor(MultiPredicate other) { + public MultiPredicate xor(@Nullable MultiPredicate other) { return combine(this, Logic.XOR, other); } @@ -267,11 +267,11 @@ public List children() { return this.children; } + /// @return a flattened list of all base predicates public List expand() { + if (!hasChildren()) return this.predicates; List expanded = new ArrayList<>(this.predicates); - if (hasChildren()) { - forEachChild(mp -> expanded.addAll(mp.expand())); - } + forEachChild(mp -> expanded.addAll(mp.expand())); return expanded; } @@ -279,9 +279,12 @@ public static MultiPredicate empty() { return EMPTY; } - /// @param a will have type set - /// @param b may or may not be a multi predicate - /// @return copy of {@code a} combined with {@code b} + /// @param a left operand + /// @param type logic of the new predicate + /// @param b right operand, may be null + /// @return If {@code b} is null, returns {@code a}.
+ /// If {@code a} is EMPTY, returns {@code b}.
+ /// Otherwise, returns a new MultiPredicate that combines {@code a} and {@code b} private static MultiPredicate combine(MultiPredicate a, Logic type, @Nullable MultiPredicate b) { if (b == null) return a; // no op if (a.isEmpty()) return b; From 912dbfb434cf8b02fbf65d67882d095c1afad961 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Mon, 3 Aug 2026 19:34:36 -0700 Subject: [PATCH 099/101] fix lang --- .../api/multiblock/predicates/TestablePredicate.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/TestablePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/TestablePredicate.java index 45b1e85f44c..50c7202fe5f 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/TestablePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/TestablePredicate.java @@ -1,5 +1,6 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; +import brachy.modularui.api.drawable.Text; import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; import com.gregtechceu.gtceu.api.mui.MultiblockSchemaInfo; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; @@ -63,15 +64,18 @@ public void onError(PredicateContext ctx) { this.onError.accept(ctx); List tooltips = new ArrayList<>(this.getAdditionalTooltips()); if (minCount == maxCount && maxCount != -1) { - tooltips.add(Component.translatable("gtceu.multiblock.pattern.error.limited_exact", minCount)); + tooltips.add(Component.translatable("gtceu.multiblock.pattern.error.limited.exact", minCount)); } else if (minCount != maxCount && minCount != -1 && maxCount != -1) { - tooltips.add(Component.translatable("gtceu.multiblock.pattern.error.limited_within", minCount, maxCount)); + tooltips.add(Component.translatable("gtceu.multiblock.pattern.error.limited.range", minCount, maxCount)); } else { + // todo actual lang if (minCount != -1) { - tooltips.add(LangHandler.getFromMultiLang("gtceu.multiblock.pattern.error.limited", 1, minCount)); + tooltips.add(Component.literal(Text.RED + "At least: " + Text.RESET + minCount)); +// tooltips.add(Component.translatable("gtceu.multiblock.pattern.error.limited.min_count", minCount, ctx.getGlobalCount(this))); } if (maxCount != -1) { - tooltips.add(LangHandler.getFromMultiLang("gtceu.multiblock.pattern.error.limited", 0, maxCount)); + tooltips.add(Component.literal( Text.RED + "At most: " + Text.RESET + maxCount)); +// tooltips.add(Component.translatable("gtceu.multiblock.pattern.error.limited.max_count", maxCount, ctx.getGlobalCount(this))); } } tooltips.forEach(c -> ctx.appendError(PatternStringError.component(c))); From 9591c8e20df1d159fe9fb85e9bc12813f546d0da Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Mon, 3 Aug 2026 20:20:34 -0700 Subject: [PATCH 100/101] minor fixes and cleanup --- .../gtceu/api/multiblock/predicates/BasePredicate.java | 1 - .../gtceu/common/data/machines/GTMachineUtils.java | 5 +++-- .../gtceu/common/data/machines/GTMultiMachines.java | 10 ++++++---- .../machine/multiblock/electric/CleanroomMachine.java | 3 ++- .../primitive/CharcoalPileIgniterMachine.java | 8 ++++---- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java index 9e5f66ed8c9..142e2cb56cc 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/BasePredicate.java @@ -18,7 +18,6 @@ public abstract class BasePredicate implements Comparable { public static final BasePredicate AIR = new PredicateBuilder("Air") .predicate(ctx -> ctx.state().isAir()) - // todo error? .build(); public static final BasePredicate ANY = new PredicateBuilder("Any") diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java index 09604922ed2..abc983f97bb 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMachineUtils.java @@ -748,13 +748,14 @@ private static MultiPredicate rotorHolder(int tier) { } return false; }) - .onError(ctx -> new PartAbilityError(ctx.pos(), PartAbility.ROTOR_HOLDER)) + .onError(ctx -> ctx.appendError(new PartAbilityError(ctx.pos(), PartAbility.ROTOR_HOLDER))) .candidates(PartAbility.ROTOR_HOLDER.getAllBlocks() .stream().map(BlockInfo::fromBlock)) .contents(builder -> builder.append(PartAbility.ROTOR_HOLDER.getName())) .toMultiPredicate() .addTooltips(Component.translatable("gtceu.multiblock.pattern.clear_amount_3")) - .addTooltips(Component.translatable("gtceu.multiblock.pattern.error.limited.1", VN[tier])); + // todo lang: must be of tier %s + .addTooltips(Component.literal("Can only be of tier: %s".formatted(VN[tier]))); } // Tooltips diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java index 96853dd5f1a..a4436937bae 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GTMultiMachines.java @@ -15,6 +15,7 @@ import com.gregtechceu.gtceu.api.machine.trait.recipe.RecipeLogic; import com.gregtechceu.gtceu.api.multiblock.MultiPredicate; import com.gregtechceu.gtceu.api.multiblock.Predicates; +import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.pattern.MultiblockPatternBuilder; import com.gregtechceu.gtceu.client.renderer.machine.DynamicRenderHelper; import com.gregtechceu.gtceu.client.util.TooltipHelper; @@ -121,13 +122,14 @@ public class GTMultiMachines { .slice("XXX", "X&X", "X#X", "X#X") .slice("XXX", "XYX", "XXX", "XXX") .where('X', blocks(CASING_PRIMITIVE_BRICKS.get())) - .where('#', Predicates.air()) - .where('&', Predicates.air() + .where('#', air()) + .where('&', air() .or(builder("SnowPredicate") .predicate(ctx -> GTUtil.isBlockSnow(ctx.state())) - // .onError(ctx -> PLACEHOLDER) + // todo lang + .onError(ctx -> ctx.appendError(PatternStringError.literal("Can be snow"))) .toMultiPredicate())) - .where('Y', Predicates.controller(blocks(definition.getBlock()))) + .where('Y', controller(blocks(definition.getBlock()))) .build()) .themeId((i) -> GTGuiTheme.PRIMITIVE.getId()) .register(); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index ccc558989fd..ed569ae77c8 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -490,8 +490,9 @@ private static MultiPredicate getValidFloorBlocks() { protected static MultiPredicate innerPredicate() { return builder("InnerPredicate") .predicate(ctx -> { + // all non-GTMachines are allowed inside by default if (ctx.blockEntity() instanceof MetaMachine machine) { - return isMachineBanned(machine); + return !isMachineBanned(machine); } return true; }) diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java index 9a4b283a173..81a91282468 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java @@ -155,9 +155,8 @@ private static MultiPredicate wallPredicate() { .predicate(ctx -> ctx.state().is(CustomTags.CHARCOAL_PILE_IGNITER_WALLS)) .onError(ctx -> { BlockPos p = ctx.pos(); - ctx.appendError( - PatternStringError.component(Component.translatable("gtceu.predicate_error.charcoal.walls", - p.getX(), p.getY(), p.getZ()))); + ctx.appendError(PatternStringError.translatable( + "gtceu.predicate_error.charcoal.walls", p.getX(), p.getY(), p.getZ())); }) .blockTag(CustomTags.CHARCOAL_PILE_IGNITER_WALLS) .toMultiPredicate(); @@ -166,7 +165,8 @@ private static MultiPredicate wallPredicate() { private static MultiPredicate logPredicate() { return Predicates.builder("LogPredicate") .predicate(ctx -> ctx.state().is(BlockTags.LOGS_THAT_BURN)) - .onError(ctx -> new PatternStringError(Component.translatable("gtceu.predicate_error.charcoal.logs"))) + .onError(ctx -> ctx.appendError(PatternStringError.translatable( + "gtceu.predicate_error.charcoal.logs"))) .blockTag(BlockTags.LOGS_THAT_BURN) .toMultiPredicate(); } From 1b836104572231d5d76fa09fd27b5cd4576f6fc6 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Mon, 3 Aug 2026 20:21:00 -0700 Subject: [PATCH 101/101] spotless --- .../gtceu/api/multiblock/XorPredicate.java | 1 - .../api/multiblock/predicates/TestablePredicate.java | 11 ++++++----- .../primitive/CharcoalPileIgniterMachine.java | 1 - 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/XorPredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/XorPredicate.java index bb5257a7372..e1634f2d248 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/XorPredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/XorPredicate.java @@ -103,7 +103,6 @@ public boolean testGlobalMin(PredicateContext ctx) { return predicate.testGlobalMin(ctx); } - public boolean testSliceMin(PredicateContext ctx) { return predicate.testSliceMin(ctx); } diff --git a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/TestablePredicate.java b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/TestablePredicate.java index 50c7202fe5f..132ee3f0519 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/TestablePredicate.java +++ b/src/main/java/com/gregtechceu/gtceu/api/multiblock/predicates/TestablePredicate.java @@ -1,13 +1,11 @@ package com.gregtechceu.gtceu.api.multiblock.predicates; -import brachy.modularui.api.drawable.Text; import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; import com.gregtechceu.gtceu.api.mui.MultiblockSchemaInfo; import com.gregtechceu.gtceu.api.multiblock.PredicateContext; import com.gregtechceu.gtceu.api.multiblock.error.PatternStringError; import com.gregtechceu.gtceu.api.multiblock.error.SimplePatternError; import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; -import com.gregtechceu.gtceu.data.lang.LangHandler; import net.minecraft.client.Camera; import net.minecraft.client.renderer.MultiBufferSource; @@ -18,6 +16,7 @@ import net.minecraft.world.level.Level; import net.minecraftforge.client.event.RenderLevelStageEvent; +import brachy.modularui.api.drawable.Text; import com.mojang.blaze3d.vertex.PoseStack; import org.jetbrains.annotations.Nullable; @@ -71,11 +70,13 @@ public void onError(PredicateContext ctx) { // todo actual lang if (minCount != -1) { tooltips.add(Component.literal(Text.RED + "At least: " + Text.RESET + minCount)); -// tooltips.add(Component.translatable("gtceu.multiblock.pattern.error.limited.min_count", minCount, ctx.getGlobalCount(this))); + // tooltips.add(Component.translatable("gtceu.multiblock.pattern.error.limited.min_count", minCount, + // ctx.getGlobalCount(this))); } if (maxCount != -1) { - tooltips.add(Component.literal( Text.RED + "At most: " + Text.RESET + maxCount)); -// tooltips.add(Component.translatable("gtceu.multiblock.pattern.error.limited.max_count", maxCount, ctx.getGlobalCount(this))); + tooltips.add(Component.literal(Text.RED + "At most: " + Text.RESET + maxCount)); + // tooltips.add(Component.translatable("gtceu.multiblock.pattern.error.limited.max_count", maxCount, + // ctx.getGlobalCount(this))); } } tooltips.forEach(c -> ctx.appendError(PatternStringError.component(c))); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java index 81a91282468..281cd5f2cb1 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/primitive/CharcoalPileIgniterMachine.java @@ -22,7 +22,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.tags.BlockTags;