Skip to content

Commit ce749c7

Browse files
authored
Fix AdjacencyBlockCondition (#3833)
1 parent 3bebc21 commit ce749c7

File tree

6 files changed

+187
-157
lines changed

6 files changed

+187
-157
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,7 @@ Previously, rock breaker recipes used the `addData("fluidA", ...)` methods.
2727

2828
Now, they work by AdjacentFluidConditions, added with the `adjacentFluid(Fluid...)` methods. See [our other condition builder methods](https://github.com/GregTechCEu/GregTech-Modern/blob/1.20.1/src/main/java/com/gregtechceu/gtceu/integration/kjs/recipe/GTRecipeSchema.java#L894).
2929

30+
In a similar vein, recipes that used to have adjacent block requirements, you now need to use `adjacentBlock(Block...)` rather than `addData("blockA")`.
31+
3032
## Recipe Conditions
3133
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.

src/main/java/com/gregtechceu/gtceu/api/recipe/condition/ConditionSerializeUtils.java

Lines changed: 65 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
import net.minecraft.core.Holder;
66
import net.minecraft.core.HolderSet;
7-
import net.minecraft.core.registries.BuiltInRegistries;
7+
import net.minecraft.core.Registry;
88
import net.minecraft.core.registries.Registries;
99
import net.minecraft.resources.ResourceKey;
1010
import net.minecraft.resources.ResourceLocation;
1111
import net.minecraft.tags.TagKey;
12-
import net.minecraft.world.level.material.Fluid;
12+
import net.minecraft.world.level.block.Blocks;
1313
import net.minecraft.world.level.material.Fluids;
1414

1515
import java.util.ArrayList;
@@ -20,16 +20,17 @@
2020
public class ConditionSerializeUtils {
2121

2222
/**
23-
* Encode a list of HolderSet<Fluids> to a string encoding
24-
*
25-
* @param fluids the List<HolderSet<Fluids>> to be encoded
26-
* @return A string, where HolderSets are separated by |'s and elements of the HolderSet are separated by ,
23+
* Encode a List<HolderSet<T>> to a string encoding.
24+
* HolderSets are separated by '|', and elements of a direct HolderSet are separated by ','.
25+
*
26+
* @param items The list of HolderSet<T> to be encoded.
27+
* @return A string encoding.
2728
*/
28-
public static String encodeFluids(List<HolderSet<Fluid>> fluids) {
29+
public static <T> String encodeHolderSets(List<HolderSet<T>> items) {
2930
StringBuilder sb = new StringBuilder();
3031
boolean first = true;
3132

32-
for (HolderSet<Fluid> holderSet : fluids) {
33+
for (HolderSet<T> holderSet : items) {
3334
if (!first) {
3435
sb.append("|");
3536
}
@@ -41,14 +42,14 @@ public static String encodeFluids(List<HolderSet<Fluid>> fluids) {
4142
}
4243

4344
/**
44-
* Encode a HolderSet<Fluids> to a string encoding
45-
* The encoding is a string, where if it's a tag, it's encoded as #+location,
46-
* and if it's a list, elements of the HolderSet are separated by ,
45+
* Encode a single HolderSet<T> to a string.
46+
* If it's a tag, it's encoded as #+location.
47+
* If it's a direct list, elements are separated by ','.
4748
*
48-
* @param holderSet the HolderSet<Fluids> to be encoded
49-
* @return the encoded string
49+
* @param holderSet The HolderSet<T> to be encoded.
50+
* @return The encoded string.
5051
*/
51-
public static String encodeHolderSet(HolderSet<Fluid> holderSet) {
52+
public static <T> String encodeHolderSet(HolderSet<T> holderSet) {
5253
return holderSet.unwrap().map(
5354
// Case 1: Tag
5455
tagKey -> "#" + tagKey.location(),
@@ -59,78 +60,91 @@ public static String encodeHolderSet(HolderSet<Fluid> holderSet) {
5960
}
6061

6162
/**
62-
* Encode a Holder<Fluid> into a String.
63-
*
64-
* @param holder the Holder<Fluid> to be encoded
65-
* @return a string encoding, as # + location if it's a tagkey, or the location if it's a registry entry.
63+
* Encode a Holder<T> into a String.
64+
*
65+
* @param holder The Holder<T> to be encoded.
66+
* @return A string encoding (location or #+tag_location).
67+
* @throws RuntimeException if the holder cannot be serialized.
6668
*/
67-
public static String getStringFromHolder(Holder<Fluid> holder) {
68-
// Case 1: If the holder has a registry key, use it
69-
Optional<ResourceKey<Fluid>> keyOpt = holder.unwrapKey();
69+
public static <T> String getStringFromHolder(Holder<T> holder) {
70+
Optional<ResourceKey<T>> keyOpt = holder.unwrapKey();
7071
if (keyOpt.isPresent()) {
7172
return keyOpt.get().location().toString();
7273
}
7374

74-
// Case 2: If the holder is tagged, return the first tag with a '#' prefix
75-
Optional<TagKey<Fluid>> tagOpt = holder.tags().findFirst();
75+
Optional<TagKey<T>> tagOpt = holder.tags().findFirst();
7676
if (tagOpt.isPresent()) {
77-
return "#" + tagOpt.get().location().toString();
77+
return "#" + tagOpt.get().location();
7878
}
79-
80-
throw new RuntimeException("could not deserialize holder: " + holder);
79+
throw new RuntimeException("Could not serialize holder: " + holder);
8180
}
8281

8382
/**
84-
* Decode a FluidString into a List<HolderSet<Fluid>>
85-
* The encoding is a string, where if it's a tag, it's encoded as #+location,
86-
* and if it's a list, elements of the HolderSet are separated by ,
87-
*
88-
* @param fluidString the string encoding
89-
* @return The decoded list
83+
* Decode a string into a List<HolderSet<T>>.
84+
*
85+
* @param encodedString The string encoding.
86+
* @param registryKey The ResourceKey of the registry.
87+
* @return The decoded list of HolderSet<T>.
9088
*/
91-
public static List<HolderSet<Fluid>> decodeFluids(String fluidString) {
92-
List<HolderSet<Fluid>> result = new ArrayList<>();
93-
for (String token : fluidString.split("\\|")) {
89+
public static <T> List<HolderSet<T>> decodeHolderSets(String encodedString,
90+
ResourceKey<? extends Registry<T>> registryKey) {
91+
List<HolderSet<T>> result = new ArrayList<>();
92+
for (String token : encodedString.split("\\|")) {
9493
if (!token.isBlank()) {
95-
result.add(decodeHolderSet(token));
94+
result.add(decodeSingleHolderSet(token, registryKey));
9695
}
9796
}
9897
return result;
9998
}
10099

101100
/**
102-
* Decode a string into a HolderSet<Fluid>
103-
* The encoding is a string, where if it's a tag, it's encoded as #+location,
104-
* and if it's a list, elements of the HolderSet are separated by ,
105-
*
106-
* @param encodedSet the encoded set
107-
* @return The decoded list
101+
* Decode a string into a HolderSet<T>.
102+
*
103+
* @param encodedSet The encoded set string.
104+
* @param registryKey The ResourceKey of the registry.
105+
* @return The decoded HolderSet<T>.
106+
* @throws RuntimeException if an unknown ID is encountered.
108107
*/
109-
public static HolderSet<Fluid> decodeHolderSet(String encodedSet) {
108+
public static <T> HolderSet<T> decodeSingleHolderSet(String encodedSet,
109+
ResourceKey<? extends Registry<T>> registryKey) {
110110
encodedSet = encodedSet.trim();
111111
if (encodedSet.isEmpty()) {
112112
return HolderSet.direct(List.of());
113113
}
114114

115+
Registry<T> registry = GTRegistries.builtinRegistry().registry(registryKey).get(); // Use the helper
116+
115117
// Case 1: Tag-based holder set
116118
if (encodedSet.startsWith("#")) {
117119
ResourceLocation tagId = new ResourceLocation(encodedSet.substring(1));
118-
TagKey<Fluid> tagKey = TagKey.create(Registries.FLUID, tagId);
119-
return GTRegistries.builtinRegistry().registry(Registries.FLUID).get().getOrCreateTag(tagKey);
120+
TagKey<T> tagKey = TagKey.create(registryKey, tagId);
121+
return registry.getOrCreateTag(tagKey);
120122
}
121123

122-
// Case 2: Direct list of fluids
124+
// Case 2: Direct list of items
123125
String[] parts = encodedSet.split(",");
124-
List<Holder<Fluid>> holders = new ArrayList<>();
126+
List<Holder<T>> holders = new ArrayList<>();
125127
for (String part : parts) {
126128
ResourceLocation rl = new ResourceLocation(part.trim());
127-
Fluid fluid = GTRegistries.builtinRegistry().registry(Registries.FLUID).get().get(rl);
128-
if (fluid != null && fluid != Fluids.EMPTY) {
129-
holders.add(BuiltInRegistries.FLUID.wrapAsHolder(fluid));
129+
T item = registry.get(rl);
130+
if (item != null && item != getDefaultEmptyValue(registryKey)) { // Use a generic default empty check
131+
holders.add(registry.wrapAsHolder(item));
130132
} else {
131-
throw new RuntimeException("Unknown fluid id: " + rl);
133+
throw new RuntimeException("Unknown ID for registry " + registryKey.location() + ": " + rl);
132134
}
133135
}
134136
return HolderSet.direct(holders);
135137
}
138+
139+
// Helper to get the default "empty" value for a registry type
140+
private static <T> T getDefaultEmptyValue(ResourceKey<? extends Registry<T>> registryKey) {
141+
// Compare ResourceLocation directly instead of ResourceKey objects
142+
if (registryKey.location().equals(Registries.FLUID.location())) {
143+
return (T) Fluids.EMPTY;
144+
} else if (registryKey.location().equals(Registries.BLOCK.location())) {
145+
return (T) Blocks.AIR;
146+
}
147+
throw new IllegalArgumentException(
148+
"Unsupported registry type for default value lookup: " + registryKey.location());
149+
}
136150
}

src/main/java/com/gregtechceu/gtceu/common/recipe/condition/AdjacentBlockCondition.java

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,11 @@
99

1010
import net.minecraft.core.BlockPos;
1111
import net.minecraft.core.HolderSet;
12-
import net.minecraft.core.RegistryCodecs;
1312
import net.minecraft.core.registries.BuiltInRegistries;
1413
import net.minecraft.core.registries.Registries;
1514
import net.minecraft.network.chat.Component;
1615
import net.minecraft.resources.ResourceLocation;
1716
import net.minecraft.tags.TagKey;
18-
import net.minecraft.util.ExtraCodecs;
1917
import net.minecraft.world.level.Level;
2018
import net.minecraft.world.level.block.Block;
2119
import net.minecraft.world.level.block.state.BlockState;
@@ -24,35 +22,53 @@
2422
import com.mojang.serialization.codecs.RecordCodecBuilder;
2523
import lombok.Getter;
2624
import lombok.NoArgsConstructor;
27-
import lombok.Setter;
2825
import org.jetbrains.annotations.NotNull;
26+
import org.jetbrains.annotations.Nullable;
2927

3028
import java.util.*;
3129

30+
import static com.gregtechceu.gtceu.api.recipe.condition.ConditionSerializeUtils.decodeHolderSets;
31+
import static com.gregtechceu.gtceu.api.recipe.condition.ConditionSerializeUtils.encodeHolderSets;
32+
3233
@NoArgsConstructor
3334
public class AdjacentBlockCondition extends RecipeCondition {
3435

3536
// spotless:off
36-
private static final Codec<List<HolderSet<Block>>> BLOCK_CODEC = ExtraCodecs.lazyInitializedCodec(
37-
() -> RegistryCodecs.homogeneousList(Registries.BLOCK).listOf()
38-
);
39-
40-
public static final Codec<AdjacentBlockCondition> CODEC = RecordCodecBuilder.create(instance -> RecipeCondition.isReverse(instance).and(
41-
BLOCK_CODEC.fieldOf("blocks").forGetter(AdjacentBlockCondition::getBlocks)
42-
).apply(instance, AdjacentBlockCondition::new));
37+
public static final Codec<AdjacentBlockCondition> CODEC =
38+
RecordCodecBuilder.create(instance -> RecipeCondition.isReverse(instance).and(
39+
Codec.STRING.fieldOf("blockString").forGetter(AdjacentBlockCondition::getBlockString)
40+
).apply(instance, AdjacentBlockCondition::new));
4341
// spotless:on
4442

4543
@Getter
46-
@Setter
47-
private @NotNull List<HolderSet<Block>> blocks = new ArrayList<>();
44+
private @NotNull String blockString = "";
45+
46+
private @Nullable List<HolderSet<Block>> blocks = null;
47+
48+
public void setBlocks(@NotNull List<HolderSet<Block>> blocks) {
49+
this.blocks = blocks;
50+
this.blockString = encodeHolderSets(blocks);
51+
}
52+
53+
public List<HolderSet<Block>> getBlocks() {
54+
if (blocks == null) {
55+
blocks = decodeHolderSets(getBlockString(), Registries.BLOCK);
56+
}
57+
return blocks;
58+
}
4859

4960
public AdjacentBlockCondition(@NotNull List<HolderSet<Block>> blocks) {
50-
this.blocks.addAll(blocks);
61+
setBlocks(blocks);
5162
}
5263

5364
public AdjacentBlockCondition(boolean isReverse, @NotNull List<HolderSet<Block>> blocks) {
5465
super(isReverse);
55-
this.blocks.addAll(blocks);
66+
setBlocks(blocks);
67+
}
68+
69+
public AdjacentBlockCondition(boolean isReverse, String blockString) {
70+
super(isReverse);
71+
this.blockString = blockString;
5672
}
5773

5874
public static AdjacentBlockCondition fromBlocks(Collection<Block> blocks) {
@@ -113,7 +129,7 @@ public boolean testCondition(@NotNull GTRecipe recipe, @NotNull RecipeLogic reci
113129
}
114130

115131
public @NotNull List<HolderSet<Block>> getOrInitBlocks(@NotNull GTRecipe recipe) {
116-
if (this.blocks.isEmpty() || (recipe.data.contains("blockA") && recipe.data.contains("blockB"))) {
132+
if (getBlocks().isEmpty() || (recipe.data.contains("blockA") && recipe.data.contains("blockB"))) {
117133
List<HolderSet<Block>> blocks = new ArrayList<>();
118134

119135
Block blockA = BuiltInRegistries.BLOCK.get(new ResourceLocation(recipe.data.getString("blockA")));
@@ -124,9 +140,9 @@ public boolean testCondition(@NotNull GTRecipe recipe, @NotNull RecipeLogic reci
124140
if (!blockB.defaultBlockState().isAir()) {
125141
blocks.add(HolderSet.direct(blockB.builtInRegistryHolder()));
126142
}
127-
this.blocks = blocks;
143+
setBlocks(blocks);
128144
}
129-
return this.blocks;
145+
return getBlocks();
130146
}
131147

132148
@Override

src/main/java/com/gregtechceu/gtceu/common/recipe/condition/AdjacentFluidCondition.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import net.minecraft.core.BlockPos;
1111
import net.minecraft.core.HolderSet;
1212
import net.minecraft.core.registries.BuiltInRegistries;
13+
import net.minecraft.core.registries.Registries;
1314
import net.minecraft.network.chat.Component;
1415
import net.minecraft.resources.ResourceLocation;
1516
import net.minecraft.tags.TagKey;
@@ -26,8 +27,8 @@
2627

2728
import java.util.*;
2829

29-
import static com.gregtechceu.gtceu.api.recipe.condition.ConditionSerializeUtils.decodeFluids;
30-
import static com.gregtechceu.gtceu.api.recipe.condition.ConditionSerializeUtils.encodeFluids;
30+
import static com.gregtechceu.gtceu.api.recipe.condition.ConditionSerializeUtils.decodeHolderSets;
31+
import static com.gregtechceu.gtceu.api.recipe.condition.ConditionSerializeUtils.encodeHolderSets;
3132

3233
@NoArgsConstructor
3334
public class AdjacentFluidCondition extends RecipeCondition {
@@ -46,12 +47,12 @@ public class AdjacentFluidCondition extends RecipeCondition {
4647

4748
public void setFluids(@NotNull List<HolderSet<Fluid>> fluids) {
4849
this.fluids = fluids;
49-
this.fluidString = encodeFluids(fluids);
50+
this.fluidString = encodeHolderSets(fluids);
5051
}
5152

5253
public List<HolderSet<Fluid>> getFluids() {
5354
if (fluids == null) {
54-
fluids = decodeFluids(getFluidString());
55+
fluids = decodeHolderSets(getFluidString(), Registries.FLUID);
5556
}
5657
return fluids;
5758
}

src/test/java/com/gregtechceu/gtceu/api/cover/MonitorCoverTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public static void testEnergyPlaceholders(GameTestHelper helper) {
3333
"energy",
3434
"energyCapacity"));
3535
cover.setUpdateInterval(1);
36-
helper.runAtTickTime(2, () -> {
36+
helper.runAtTickTime(5, () -> {
3737
TestUtils.assertEqual(helper, cover.getText(),
3838
"Energy: 0/" + machine.energyContainer.getEnergyCapacity() + " EU");
3939
helper.succeed();
@@ -49,7 +49,7 @@ public static void testCombinePlaceholder(GameTestHelper helper) {
4949
cover.getFormatStringLines()
5050
.add("{if 1 {combine test 1 2 3 lol {repeat 5 \"a \"}} \"if placeholder failed somehow\"}");
5151
cover.setUpdateInterval(1);
52-
helper.runAtTickTime(2, () -> {
52+
helper.runAtTickTime(5, () -> {
5353
TestUtils.assertEqual(helper, cover.getText(), "test 1 2 3 lol a a a a a ");
5454
helper.succeed();
5555
});

0 commit comments

Comments
 (0)