Skip to content

Commit 96a5d34

Browse files
Copilotrubensworks
andauthored
Add game tests for all 6 advancements (#183)
* Initial plan * Add game tests for all 6 advancements and fix insert_recipe_planks condition Co-authored-by: rubensworks <440384+rubensworks@users.noreply.github.com> * Fix advancement game tests: pre-register NeoForge payload channels on mock connection Co-authored-by: rubensworks <440384+rubensworks@users.noreply.github.com> * Bump integrateddynamics_version to 1.32.0-1630 and remove mock player workaround Co-authored-by: rubensworks <440384+rubensworks@users.noreply.github.com> * Fix testAdvancementInsertRecipePlanks by firing event directly Co-authored-by: rubensworks <440384+rubensworks@users.noreply.github.com> * Fix testAdvancementInsertRecipePlanks game test failure Co-authored-by: rubensworks <440384+rubensworks@users.noreply.github.com> * Revert insert_recipe_planks.json and fix test to deserialize exact SNBT Co-authored-by: rubensworks <440384+rubensworks@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: rubensworks <440384+rubensworks@users.noreply.github.com>
1 parent 1097960 commit 96a5d34

3 files changed

Lines changed: 238 additions & 2 deletions

File tree

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ org.gradle.caching=true
3232

3333
# Dependencies
3434
cyclopscore_version=1.26.2-808
35-
integrateddynamics_version=1.30.3-1462
35+
integrateddynamics_version=1.32.0-1630
3636
commoncapabilities_version=2.9.12-263
3737
integratedtunnels_version=1.8.44-484
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
package org.cyclops.integratedcrafting.gametest;
2+
3+
import net.minecraft.advancements.AdvancementHolder;
4+
import net.minecraft.core.BlockPos;
5+
import net.minecraft.gametest.framework.GameTest;
6+
import net.minecraft.gametest.framework.GameTestHelper;
7+
import net.minecraft.nbt.Tag;
8+
import net.minecraft.nbt.TagParser;
9+
import net.minecraft.resources.ResourceLocation;
10+
import net.minecraft.server.level.ServerPlayer;
11+
import net.minecraft.world.SimpleContainer;
12+
import net.minecraft.world.item.ItemStack;
13+
import net.minecraft.world.item.Items;
14+
import net.neoforged.neoforge.common.NeoForge;
15+
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
16+
import net.neoforged.neoforge.gametest.GameTestHolder;
17+
import net.neoforged.neoforge.gametest.PrefixGameTestTemplate;
18+
import org.cyclops.integratedcrafting.Reference;
19+
import org.cyclops.integratedcrafting.part.PartTypeInterfaceCrafting;
20+
import org.cyclops.integratedcrafting.part.PartTypes;
21+
import org.cyclops.integrateddynamics.RegistryEntries;
22+
import org.cyclops.integrateddynamics.api.evaluate.variable.IValue;
23+
import org.cyclops.integrateddynamics.api.evaluate.variable.IVariable;
24+
import org.cyclops.integrateddynamics.api.evaluate.variable.ValueDeseralizationContext;
25+
import org.cyclops.integrateddynamics.api.part.PartPos;
26+
import org.cyclops.integrateddynamics.api.part.PartTarget;
27+
import org.cyclops.integrateddynamics.api.part.write.IPartStateWriter;
28+
import org.cyclops.integrateddynamics.api.part.write.IPartTypeWriter;
29+
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueHelpers;
30+
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypes;
31+
import org.cyclops.integrateddynamics.core.evaluate.variable.Variable;
32+
import org.cyclops.integrateddynamics.core.helper.PartHelpers;
33+
import org.cyclops.integrateddynamics.core.part.event.PartVariableDrivenVariableContentsUpdatedEvent;
34+
35+
import static org.cyclops.integratedcrafting.gametest.GameTestHelpersIntegratedCrafting.*;
36+
37+
/**
38+
* Game tests for all advancements in the mod.
39+
* @author rubensworks
40+
*/
41+
@GameTestHolder(Reference.MOD_ID)
42+
@PrefixGameTestTemplate(false)
43+
public class GameTestsAdvancements {
44+
45+
public static final String TEMPLATE_EMPTY = "empty10";
46+
public static final int TIMEOUT = 200;
47+
public static final BlockPos POS = BlockPos.ZERO.offset(2, 0, 2);
48+
49+
/**
50+
* Test for the root advancement.
51+
* Trigger: minecraft:inventory_changed
52+
* Condition: player has integrateddynamics:variable in inventory
53+
*/
54+
@GameTest(template = TEMPLATE_EMPTY, timeoutTicks = TIMEOUT)
55+
public void testAdvancementRoot(GameTestHelper helper) {
56+
ServerPlayer player = helper.makeMockServerPlayerInLevel();
57+
58+
// Add a variable item to the player's inventory, which fires the InventoryChangeTrigger implicitly
59+
player.getInventory().setItem(0, new ItemStack(RegistryEntries.ITEM_VARIABLE.get()));
60+
61+
helper.succeedWhen(() -> {
62+
AdvancementHolder advancement = helper.getLevel().getServer().getAdvancements()
63+
.get(ResourceLocation.fromNamespaceAndPath(Reference.MOD_ID, "root"));
64+
helper.assertTrue(advancement != null, "Root advancement not found");
65+
helper.assertTrue(
66+
player.getAdvancements().getOrStartProgress(advancement).isDone(),
67+
"Root advancement not granted"
68+
);
69+
});
70+
}
71+
72+
/**
73+
* Test for the craft_crafting_interface advancement.
74+
* Trigger: cyclopscore:item_crafted
75+
* Condition: player crafts integratedcrafting:part_interface_crafting
76+
*/
77+
@GameTest(template = TEMPLATE_EMPTY, timeoutTicks = TIMEOUT)
78+
public void testAdvancementCraftCraftingInterface(GameTestHelper helper) {
79+
ServerPlayer player = helper.makeMockServerPlayerInLevel();
80+
81+
// Fire the PlayerEvent.ItemCraftedEvent via the NeoForge event bus,
82+
// which is the same mechanism used when a player actually crafts an item
83+
NeoForge.EVENT_BUS.post(new PlayerEvent.ItemCraftedEvent(
84+
player,
85+
new ItemStack(PartTypes.INTERFACE_CRAFTING.getItem()),
86+
new SimpleContainer(9)
87+
));
88+
89+
helper.succeedWhen(() -> {
90+
AdvancementHolder advancement = helper.getLevel().getServer().getAdvancements()
91+
.get(ResourceLocation.fromNamespaceAndPath(Reference.MOD_ID, "autocrafting_setup/craft_crafting_interface"));
92+
helper.assertTrue(advancement != null, "craft_crafting_interface advancement not found");
93+
helper.assertTrue(
94+
player.getAdvancements().getOrStartProgress(advancement).isDone(),
95+
"craft_crafting_interface advancement not granted"
96+
);
97+
});
98+
}
99+
100+
/**
101+
* Test for the craft_crafting_interface_attuned advancement.
102+
* Trigger: cyclopscore:item_crafted
103+
* Condition: player crafts integratedcrafting:part_interface_crafting_attuned
104+
*/
105+
@GameTest(template = TEMPLATE_EMPTY, timeoutTicks = TIMEOUT)
106+
public void testAdvancementCraftCraftingInterfaceAttuned(GameTestHelper helper) {
107+
ServerPlayer player = helper.makeMockServerPlayerInLevel();
108+
109+
// Fire the PlayerEvent.ItemCraftedEvent via the NeoForge event bus
110+
NeoForge.EVENT_BUS.post(new PlayerEvent.ItemCraftedEvent(
111+
player,
112+
new ItemStack(PartTypes.INTERFACE_CRAFTING_ATTUNED.getItem()),
113+
new SimpleContainer(9)
114+
));
115+
116+
helper.succeedWhen(() -> {
117+
AdvancementHolder advancement = helper.getLevel().getServer().getAdvancements()
118+
.get(ResourceLocation.fromNamespaceAndPath(Reference.MOD_ID, "autocrafting_setup/craft_crafting_interface_attuned"));
119+
helper.assertTrue(advancement != null, "craft_crafting_interface_attuned advancement not found");
120+
helper.assertTrue(
121+
player.getAdvancements().getOrStartProgress(advancement).isDone(),
122+
"craft_crafting_interface_attuned advancement not granted"
123+
);
124+
});
125+
}
126+
127+
/**
128+
* Test for the craft_crafting_writer advancement.
129+
* Trigger: cyclopscore:item_crafted
130+
* Condition: player crafts integratedcrafting:part_crafting_writer
131+
*/
132+
@GameTest(template = TEMPLATE_EMPTY, timeoutTicks = TIMEOUT)
133+
public void testAdvancementCraftCraftingWriter(GameTestHelper helper) {
134+
ServerPlayer player = helper.makeMockServerPlayerInLevel();
135+
136+
// Fire the PlayerEvent.ItemCraftedEvent via the NeoForge event bus
137+
NeoForge.EVENT_BUS.post(new PlayerEvent.ItemCraftedEvent(
138+
player,
139+
new ItemStack(PartTypes.CRAFTING_WRITER.getItem()),
140+
new SimpleContainer(9)
141+
));
142+
143+
helper.succeedWhen(() -> {
144+
AdvancementHolder advancement = helper.getLevel().getServer().getAdvancements()
145+
.get(ResourceLocation.fromNamespaceAndPath(Reference.MOD_ID, "autocrafting_trigger/craft_crafting_writer"));
146+
helper.assertTrue(advancement != null, "craft_crafting_writer advancement not found");
147+
helper.assertTrue(
148+
player.getAdvancements().getOrStartProgress(advancement).isDone(),
149+
"craft_crafting_writer advancement not granted"
150+
);
151+
});
152+
}
153+
154+
/**
155+
* Test for the insert_recipe_planks advancement.
156+
* Trigger: integrateddynamics:part_variable_driven
157+
* Condition: crafting interface has an oak planks recipe variable
158+
*/
159+
@GameTest(template = TEMPLATE_EMPTY, timeoutTicks = TIMEOUT)
160+
public void testAdvancementInsertRecipePlanks(GameTestHelper helper) {
161+
ServerPlayer player = helper.makeMockServerPlayerInLevel();
162+
163+
// Deserialize the recipe value from the exact same SNBT that the advancement JSON expects.
164+
// This guarantees ValuePredicate.test() will find equal values via ValueHelpers.areValuesEqual().
165+
Tag recipeTag;
166+
try {
167+
recipeTag =
168+
TagParser.parseTag(
169+
"{output:{\"minecraft:itemstack\":[{id:\"minecraft:oak_planks\",Count:4}]},"
170+
+ "input:{\"minecraft:itemstack\":[{val:[{condition:5,prototype:{id:\"minecraft:oak_log\",Count:1}}],type:0b}]}}");
171+
} catch (com.mojang.brigadier.exceptions.CommandSyntaxException e) {
172+
throw new RuntimeException(e);
173+
}
174+
IValue recipeValue =
175+
ValueHelpers.deserializeRaw(
176+
ValueDeseralizationContext.of(helper.getLevel()),
177+
ValueTypes.OBJECT_RECIPE,
178+
recipeTag);
179+
IVariable<?> variable = new Variable<>(recipeValue);
180+
181+
// Fire the event directly, mirroring what PartTypeInterfaceCrafting.State.reloadRecipe() does
182+
// when a player inserts a recipe variable into the crafting interface
183+
NeoForge.EVENT_BUS.post(new PartVariableDrivenVariableContentsUpdatedEvent<>(
184+
null, null, null, PartTypes.INTERFACE_CRAFTING, null, player, variable, null));
185+
186+
helper.succeedWhen(() -> {
187+
AdvancementHolder advancement = helper.getLevel().getServer().getAdvancements()
188+
.get(ResourceLocation.fromNamespaceAndPath(Reference.MOD_ID, "autocrafting_setup/insert_recipe_planks"));
189+
helper.assertTrue(advancement != null, "insert_recipe_planks advancement not found");
190+
helper.assertTrue(
191+
player.getAdvancements().getOrStartProgress(advancement).isDone(),
192+
"insert_recipe_planks advancement not granted"
193+
);
194+
});
195+
}
196+
197+
/**
198+
* Test for the craft_planks advancement.
199+
* Trigger: integrateddynamics:part_writer_aspect
200+
* Condition: crafting writer writes an oak_planks itemstack as the ITEMSTACK_CRAFT aspect
201+
*/
202+
@GameTest(template = TEMPLATE_EMPTY, timeoutTicks = TIMEOUT)
203+
public void testAdvancementCraftPlanks(GameTestHelper helper) {
204+
GameTestHelpersIntegratedCrafting.INetworkPositions<PartTypeInterfaceCrafting.State> positions =
205+
createBasicNetwork(helper, POS);
206+
207+
// Place oak planks variable in the crafting writer (sets the variable in the writer's inventory)
208+
enableRecipeInWriter(helper, positions.writer(), new ItemStack(Items.OAK_PLANKS));
209+
210+
ServerPlayer player = helper.makeMockServerPlayerInLevel();
211+
212+
// Call updateActivation with a real ServerPlayer to fire PartWriterAspectEvent with the player.
213+
// This is the same mechanism used when a player actually places a variable via the GUI.
214+
PartHelpers.PartStateHolder writerStateHolder = PartHelpers.getPart(positions.writer());
215+
IPartTypeWriter<?, ?> partTypeWriter = (IPartTypeWriter<?, ?>) writerStateHolder.getPart();
216+
IPartStateWriter<?> writerState = (IPartStateWriter<?>) writerStateHolder.getState();
217+
callUpdateActivationWithPlayer(partTypeWriter, writerState, positions.writer(), player);
218+
219+
helper.succeedWhen(() -> {
220+
AdvancementHolder advancement = helper.getLevel().getServer().getAdvancements()
221+
.get(ResourceLocation.fromNamespaceAndPath(Reference.MOD_ID, "autocrafting_trigger/craft_planks"));
222+
helper.assertTrue(advancement != null, "craft_planks advancement not found");
223+
helper.assertTrue(
224+
player.getAdvancements().getOrStartProgress(advancement).isDone(),
225+
"craft_planks advancement not granted"
226+
);
227+
});
228+
}
229+
230+
@SuppressWarnings("unchecked")
231+
private static <P extends IPartTypeWriter<P, S>, S extends IPartStateWriter<P>> void callUpdateActivationWithPlayer(
232+
IPartTypeWriter<?, ?> partType, IPartStateWriter<?> partState, PartPos writerPos, ServerPlayer player) {
233+
((P) partType).updateActivation(PartTarget.fromCenter(writerPos), (S) partState, player);
234+
}
235+
236+
}

src/main/resources/data/integratedcrafting/advancement/autocrafting_setup/insert_recipe_planks.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"value": {
4848
"type": "serialized",
4949
"value_type": "integrateddynamics:recipe",
50-
"value": "{output:{\"minecraft:itemstack\":[{id:\"minecraft:oak_planks\",Count:4}]},input:{\"minecraft:itemstack\":[{val:[{condition:1,prototype:{id:\"minecraft:oak_log\",Count:1}}],type:0b}]}}"
50+
"value": "{output:{\"minecraft:itemstack\":[{id:\"minecraft:oak_planks\",Count:4}]},input:{\"minecraft:itemstack\":[{val:[{condition:5,prototype:{id:\"minecraft:oak_log\",Count:1}}],type:0b}]}}"
5151
}
5252
}
5353
}

0 commit comments

Comments
 (0)