Skip to content

Commit de5dd7a

Browse files
authored
Recipe Condition Documentation (#3841)
1 parent 590aafa commit de5dd7a

3 files changed

Lines changed: 147 additions & 2 deletions

File tree

docs/content/Modpacks/Changes/v7.2.0.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ Now, they work by AdjacentFluidConditions, added with the `adjacentFluid(Fluid..
3030
In a similar vein, recipes that used to have adjacent block requirements, you now need to use `adjacentBlock(Block...)` rather than `addData("blockA")`.
3131

3232
## Recipe Conditions
33-
We have moved away from the .serialize, .deserialize, .toNetwork and .fromNetwork calls on the RecipeCondition, and we now exclusively use the codecs registered in GTRecipeConditions.
33+
We have moved away from the .serialize, .deserialize, .toNetwork and .fromNetwork calls on the RecipeCondition, and we now exclusively use the recipeCondition's codec.
34+
See the [Recipe Conditions Page](../Other-Topics/Recipe-Conditions.md)
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
---
2+
title: Recipe Conditions
3+
---
4+
5+
!!! Warning
6+
Custom recipe conditions are only supported in Java. Therefore, this page will only contain Java examples.
7+
8+
Recipe conditions are custom conditions for your recipe, like biome, machine tier, or anything else you can think of.
9+
10+
!!! Note
11+
The condition is run after recipe matching and before recipe execution. If the recipe condition doesn't match, the machine will be suspended and won't be updated again until something in the inputs/outputs changes.
12+
13+
They are registered using
14+
```java
15+
@Mod(ExampleMod.MOD_ID)
16+
public class ExampleMod {
17+
18+
public ExampleMod(FMLJavaModLoadingContext context) {
19+
var bus = context.getModEventBus();
20+
bus.addGenericListener(RecipeConditionType.class, this::registerConditions);
21+
}
22+
23+
public static RecipeConditionType<ExampleCondition> EXAMPLE_CONDITION;
24+
25+
public void registerConditions(GTCEuAPI.RegisterEvent<String, RecipeConditionType<?>> event) {
26+
EXAMPLE_CONDITION = GTRegistries.RECIPE_CONDITIONS.register("example_condition",
27+
new RecipeConditionType<>(
28+
ExampleCondition::new,
29+
ExampleCondition.CODEC
30+
)
31+
);
32+
}
33+
}
34+
```
35+
36+
We will set up a condition that requires that the power buffer of the machine is above a certain Y level.
37+
```java
38+
public class ExampleCondition extends RecipeCondition {
39+
40+
public int height;
41+
42+
public static final Codec<ExampleCondition> CODEC = RecordCodecBuilder
43+
.create(instance -> RecipeCondition.isReverse(instance)
44+
.and(Codec.INT.fieldOf("height").forGetter(val -> val.height))
45+
.apply(instance, ExampleCondition::new));
46+
47+
48+
public ExampleCondition(boolean isReverse, int height) {
49+
this.isReverse = isReverse;
50+
this.height = height;
51+
}
52+
53+
public ExampleCondition(int height) {
54+
this(false, height);
55+
}
56+
57+
@Override
58+
public RecipeConditionType<?> getType() {
59+
return ExampleMod.EXAMPLE_CONDITION;
60+
}
61+
62+
@Override
63+
public Component getTooltips() {
64+
return Component.literal("Should be ran at least at height %d", height);
65+
}
66+
67+
@Override
68+
protected boolean testCondition(@NotNull GTRecipe recipe, @NotNull RecipeLogic recipeLogic) {
69+
return recipeLogic.getMachine().getHolder().getCurrentPos().getY() >= height;
70+
}
71+
72+
@Override
73+
public RecipeCondition createTemplate() {
74+
return new ExampleCondition(0);
75+
}
76+
}
77+
```
78+
79+
Lets step through this example. This will not be in order as it is in the file, but rather in the order that makes most sense.
80+
81+
Starting with:
82+
```java
83+
@Override
84+
public RecipeConditionType<?> getType() {
85+
return ExampleMod.EXAMPLE_CONDITION;
86+
}
87+
88+
@Override
89+
public Component getTooltips() {
90+
return Component.literal("Should be ran at least at height %d", height);
91+
}
92+
```
93+
This part is quite simple, and just returns the type and tooltip for the condition. The tooltip is what gets added in the recipe viewer's screen if this condition is present.
94+
95+
```java
96+
public ExampleCondition(boolean isReverse, int height) {
97+
this.isReverse = isReverse;
98+
this.height = height;
99+
}
100+
101+
public ExampleCondition(int height) {
102+
this(false, height);
103+
}
104+
105+
```
106+
These are the constructors. We need the `isReverse`, as it is part of the overarching `RecipeCondition` type. `isReverse` means that if the condition is met, your recipe won't be run.
107+
108+
```java
109+
@Override
110+
public RecipeCondition createTemplate() {
111+
return new ExampleCondition(0);
112+
}
113+
```
114+
115+
This creates the basic "template" that might be used for serialization. This should return a default version of your condition.
116+
117+
```java
118+
@Override
119+
protected boolean testCondition(@NotNull GTRecipe recipe, @NotNull RecipeLogic recipeLogic) {
120+
return recipeLogic.getMachine().getHolder().getCurrentPos().getY() >= height;
121+
}
122+
```
123+
124+
This is the actual condition.
125+
126+
```java
127+
public int height;
128+
129+
public static final Codec<ExampleCondition> CODEC = RecordCodecBuilder
130+
.create(instance -> RecipeCondition.isReverse(instance)
131+
.and(Codec.INT.fieldOf("height").forGetter(val -> val.height))
132+
.apply(instance, ExampleCondition::new));
133+
```
134+
135+
The CODEC is how java knows how to serialize/deserialize your condition. This is needed for syncing between client/server, and storing it to json to load when the world loads.
136+
It consists of a few parts:
137+
138+
- `RecordCodecBuilder.create(instance -> ` means we will start a RecordCodecBuilder, or a builder that only consists of simple types.
139+
- `RecipeCondition.isReverse(instance)` is a helper codec that serializes the isReverse boolean of your codec.
140+
- `.and(` means this is the next field in the record.
141+
- `Codec.INT.fieldOf("height").forGetter(val -> val.height)` means we want to serialize an INT, we want to call it "height" in the json, and to get the value you call `.height`.
142+
- `.apply(instance, ExampleCondition::new)` means when deserializing back to an object, you apply these steps to get the values (in this case `bool isReverse, int height`) and call the constructor with those arguments.
143+
In this case, this would call our `new ExampleCondition(isReverse, height)` constructor we have defined earlier.
144+
145+
With this, you should have everything you need to make a custom RecipeCondition.

docs/content/index.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,3 @@ You can download an offline version of this wiki here:
2424

2525
## Want to Contribute?
2626
If you want to contribute to this documentation site, feel free to read [the instructions](https://github.com/GregTechCEu/GregTech-Modern/blob/1.20.1/docs/CONTRIBUTING.md) and open a pull request on the [GitHub repository](https://github.com/GregTechCEu/GregTech-Modern).
27-
```

0 commit comments

Comments
 (0)