Predicates
MultiPredicates are the main system of turning some potential block in a multiblock IBlockPattern into a valid or invalid state.
Predicate Helpers
There are several helper methods to make various MultiPredicates:
MultiPredicate any(); // (1)
MultiPredicate air(); // (2)
MultiPredicate controller(MultiblockMachineDefinition def); // (3)
MultiPredicate machines(MachineDefinition... definitions); // (4)
MultiPredicate blocksDebug(String debugName, Block... blocks); // (5)
MultiPredicate blocks(Block... blocks); // (6)
MultiPredicate statesDebug(String debugName, BlockState... allowedStates); // (7)
MultiPredicate states(BlockState... allowedStates); // (8)
MultiPredicate fluidsDebug(String debugName, Fluid... fluids); // (9)
MultiPredicate fluids(Fluid... fluids); // (10)
MultiPredicate blockTag(TagKey<Block> tag); // (11)
MultiPredicate fluidTag(TagKey<Fluid> tag); // (12)
MultiPredicate abilities(PartAbility... abilities); // (13)
MultiPredicate ability(PartAbility ability, int... tiers); // (14)
MultiPredicate autoAbilities(GTRecipeType[] recipeType,
boolean checkEnergyIn, boolean checkEnergyOut,
boolean checkItemIn, boolean checkItemOut,
boolean checkFluidIn, boolean checkFluidOut); // (15)
MultiPredicate autoAbilities(GTRecipeType... recipeType); // (16)
MultiPredicate autoAbilities(boolean checkMaintenance, boolean checkMuffler,
boolean checkParallel); // (17)
MultiPredicate heatingCoils(); // (18)
MultiPredicate cleanroomFilters(); // (19)
MultiPredicate powerSubstationBatteries(); // (20)
MultiPredicate dataHatchPredicate(); // (21)
MultiPredicate frames(Material... frameMaterials); // (22)
-
Any block matches, returns no error.
-
Only AIR can exist here.
-
Shortcut for
blocks(definition.getBlock())and sets the controller to that specific predicate. -
Must match any of these machines.
-
Must match any of these blocks.
-
Must match any of these blocks.
-
Must match any of these block states.
-
Must match any of these block states.
-
Must match any of these fluids.
-
Must match any of these fluids.
-
Must match the block tag.
-
Must match the fluid tag.
-
Must be one of the blocks in the
PartAbility(see Part Abilities) -
Must be one of the blocks in the
PartAbility(see Part Abilities) with one of those tier values. -
Fills predicate with the EU, Item and Fluid PartAbilities based on the RecipeType's recipe capability max values.
-
Fills predicate with any of those RecipeType's recipe capabilities, see // (15)
-
Fills predicate with Maintenance, Muffler and ParallelHatch PartAbilities.
-
Fills predicate with CoilBlocks (used in Electric Blast Furnace, Cracking Unit, Rotary Hearth, etc.)
-
Fills predicate with Cleanroom Filter casings.
-
Fills predicate with PowerSubstation batteries.
-
Fills predicate with Data Access and Optical Reception part abilities.
-
Fills predicate with any GT frame matching those materials or any pipe with one of those frame box materials.
Combining Predicates
Predicates can be joined in different ways. There's 3 main ways to join predicates:
predicate1.or(predicate2)- Multiblock forms if the minimum and maximum limits for any of the predicates are satisfied.predicate1.and(predicate2)- Multiblock forms if the minimum and maximum limits for all the predicates are satisfied.predicate1.xor(predicate2)- Multiblock forms if the minimum and maximum limits for exactly one of the predicates are satisfied.
Generally speaking, you want .and(...) so that all limits that you set are respected.
Do note that this only affects the limits. For example, dirtPred.and(stonePred) does not require a block to be both dirt and stone.
MultiPredicate myCustomPredicate = Predicates.blocks(GTBlocks.PLASCRETE)
.and(Predicates.blocks(Blocks.DIRT))
.and(Predicates.frames(GTMaterials.Steel).setExactLimit(20))
.and(Predicates.autoAbilities(true, false, true));
Mutations return the mutated predicate
Mutations on predicates return the edited copy, so you can't do a = Predicates.blocks(Blocks.DIRT); a.setMinLimit(2);, since the predicate with the limit would be the return value of the .setMinLimit call.
Instead, do e.g. a = Predicates.blocks(Blocks.DIRT); a = a.setMinLimit(2); or
a = Predicates.blocks(Blocks.DIRT).setMinLimit(2);
Setting limits on composite predicates
Setting a limit on a predicate sets the limit on all its children and predicates. It is currently not possible to do e.g.
existingPredicate1.or(existingPredicate2).setMinLimit(4) to mean "4 of combined either predicate",
this instead means "either 4 of predicate 1 or 4 of predicate 2".
This is possible with e.g. simple blocks by creating one predicate with all the blocks like Predicates.blocks(Blocks.DIRT, Blocks.STONE).setMinLimit(4)
Predicate Internals
MultiPredicates can be composed of one or more BasePredicates and other MultiPredicates which means any, all or one of those predicates can succeed for the MultiPredicate to succeed (returning no PatternError).
BasePredicates are composed of a few values,
-
The
Predicate<BlockInfo, PatternError> predicateErrorwhich runs for each block state this predicate is assigned to and returns that specific error. -
The
List<BlockInfo> candidateswhich are all the valid blocks for that predicate. -
Optionally, a global min and max value, which causes specific
PatternErrors if there are too much or not enough of that predicate match succeeding.
Custom Predicates
public static MultiPredicate customPredicate() {
return new MultiPredicate("MyDebugName", // (1)
(blockInfo) -> { // (2)
BlockState state = blockInfo.getBlockState();
if (state.getBlock() == Blocks.OAK_WOOD) {
return null; // (3)
}
return new BlockMatchingError(blockInfo.getBlockPos(), Blocks.OAK_WOOD); // (4)
}, new BlockInfo(Blocks.OAK_WOOD)); // (5)
}
-
Debug name of the predicate (used in the terminal preview), optional.
-
The condition for if the MultiPredicate matches.
-
If the predicate succeeds it MUST return null;
-
If the predicate fails it will return some
PatternError(see Pattern Errors) -
The list of all valid candidates for this predicate (used for terminal previewing and autobuilding).