From 0afce09b69011771dd5f17785b48002ce439912e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 14:05:48 +0000 Subject: [PATCH 1/4] Initial plan From 627038463def5c1c942dd784a587f2efcacdd598 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 14:39:50 +0000 Subject: [PATCH 2/4] Add game tests for all 5 advancements in IntegratedTerminals Co-authored-by: rubensworks <440384+rubensworks@users.noreply.github.com> --- ...meTestAdvancementsIntegratedTerminals.java | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 src/main/java/org/cyclops/integratedterminals/gametest/GameTestAdvancementsIntegratedTerminals.java diff --git a/src/main/java/org/cyclops/integratedterminals/gametest/GameTestAdvancementsIntegratedTerminals.java b/src/main/java/org/cyclops/integratedterminals/gametest/GameTestAdvancementsIntegratedTerminals.java new file mode 100644 index 000000000..7b0d1bbd1 --- /dev/null +++ b/src/main/java/org/cyclops/integratedterminals/gametest/GameTestAdvancementsIntegratedTerminals.java @@ -0,0 +1,158 @@ +package org.cyclops.integratedterminals.gametest; + +import net.minecraft.advancements.AdvancementHolder; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.ServerAdvancementManager; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import net.neoforged.neoforge.gametest.GameTestHolder; +import net.neoforged.neoforge.gametest.PrefixGameTestTemplate; +import org.cyclops.integrateddynamics.RegistryEntries; +import org.cyclops.integrateddynamics.api.part.PartPos; +import org.cyclops.integrateddynamics.core.evaluate.operator.Operators; +import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeOperator; +import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypes; +import org.cyclops.integrateddynamics.core.helper.NetworkHelpers; +import org.cyclops.integrateddynamics.core.helper.PartHelpers; +import org.cyclops.integrateddynamics.gametest.GameTestHelpersIntegratedDynamics; +import org.cyclops.integratedterminals.Reference; +import org.cyclops.integratedterminals.core.terminalstorage.TerminalStorageTabIngredientComponentCommon; +import org.cyclops.integratedterminals.inventory.container.ContainerTerminalStoragePart; +import org.cyclops.integratedterminals.part.PartTypes; + +/** + * Game tests for all advancements in IntegratedTerminals. + * @author rubensworks + */ +@GameTestHolder(Reference.MOD_ID) +@PrefixGameTestTemplate(false) +public class GameTestAdvancementsIntegratedTerminals { + + private static boolean hasAdvancementUnlocked(ServerPlayer player, String advancementId) { + ResourceLocation id = ResourceLocation.parse(advancementId); + ServerAdvancementManager manager = player.server.getAdvancements(); + AdvancementHolder holder = manager.get(id); + if (holder == null) { + return false; + } + return player.server.getPlayerList().getPlayerAdvancements(player).getOrStartProgress(holder).isDone(); + } + + /** + * Tests the root advancement, triggered by having a part_display_panel in the inventory. + */ + @GameTest(template = "empty", templateNamespace = "cyclopscore") + public void testAdvancementRoot(GameTestHelper helper) { + ServerPlayer player = helper.makeMockServerPlayerInLevel(); + // Give player a part_display_panel to trigger the inventory_changed criterion + player.getInventory().setItem(0, new ItemStack( + BuiltInRegistries.ITEM.get(ResourceLocation.parse("integrateddynamics:part_display_panel")))); + player.inventoryMenu.broadcastChanges(); + helper.succeedWhen(() -> helper.assertTrue( + hasAdvancementUnlocked(player, "integratedterminals:root"), + "root advancement not unlocked")); + } + + /** + * Tests the menril_glass advancement, triggered by having menril_glass in the inventory. + */ + @GameTest(template = "empty", templateNamespace = "cyclopscore") + public void testAdvancementMenrilGlass(GameTestHelper helper) { + ServerPlayer player = helper.makeMockServerPlayerInLevel(); + // Give player menril_glass to trigger the inventory_changed criterion + player.getInventory().setItem(0, new ItemStack( + BuiltInRegistries.ITEM.get(ResourceLocation.parse("integratedterminals:menril_glass")))); + player.inventoryMenu.broadcastChanges(); + helper.succeedWhen(() -> helper.assertTrue( + hasAdvancementUnlocked(player, "integratedterminals:storage_terminal/menril_glass"), + "menril_glass advancement not unlocked")); + } + + /** + * Tests the craft_storage_terminal advancement, triggered by crafting a part_terminal_storage. + */ + @GameTest(template = "empty", templateNamespace = "cyclopscore") + public void testAdvancementCraftStorageTerminal(GameTestHelper helper) { + ServerPlayer player = helper.makeMockServerPlayerInLevel(); + // Simulate crafting a part_terminal_storage by posting the ItemCraftedEvent + ItemStack craftedItem = new ItemStack( + BuiltInRegistries.ITEM.get(ResourceLocation.parse("integratedterminals:part_terminal_storage"))); + NeoForge.EVENT_BUS.post(new PlayerEvent.ItemCraftedEvent(player, craftedItem, new SimpleContainer(9))); + helper.succeedWhen(() -> helper.assertTrue( + hasAdvancementUnlocked(player, "integratedterminals:storage_terminal/craft_storage_terminal"), + "craft_storage_terminal advancement not unlocked")); + } + + /** + * Tests the gui_storage_terminal advancement, triggered by opening the terminal storage GUI. + */ + @GameTest(template = "empty", templateNamespace = "cyclopscore") + public void testAdvancementGuiStorageTerminal(GameTestHelper helper) { + BlockPos pos = new BlockPos(1, 2, 1); + ServerPlayer player = helper.makeMockServerPlayerInLevel(); + + // Place cable block and add terminal_storage part + helper.setBlock(pos, RegistryEntries.BLOCK_CABLE.value()); + NetworkHelpers.initNetwork(helper.getLevel(), helper.absolutePos(pos), Direction.NORTH); + PartHelpers.addPart(helper.getLevel(), helper.absolutePos(pos), Direction.NORTH, + PartTypes.TERMINAL_STORAGE, new ItemStack(PartTypes.TERMINAL_STORAGE.getItem())); + + // Open the terminal storage container (fires PlayerContainerEvent.Open which triggers the advancement) + PartPos partPos = PartPos.of(helper.getLevel(), helper.absolutePos(pos), Direction.NORTH); + PartHelpers.openContainerPart(player, partPos, PartTypes.TERMINAL_STORAGE); + + helper.succeedWhen(() -> helper.assertTrue( + hasAdvancementUnlocked(player, "integratedterminals:storage_terminal/gui_storage_terminal"), + "gui_storage_terminal advancement not unlocked")); + } + + /** + * Tests the filter_enchantable advancement, triggered by setting an itemstack_enchantable operator variable + * in the terminal storage filter slots. + */ + @GameTest(template = "empty", templateNamespace = "cyclopscore") + public void testAdvancementFilterEnchantable(GameTestHelper helper) { + BlockPos pos = new BlockPos(1, 2, 1); + ServerPlayer player = helper.makeMockServerPlayerInLevel(); + + // Place cable block and add terminal_storage part + helper.setBlock(pos, RegistryEntries.BLOCK_CABLE.value()); + NetworkHelpers.initNetwork(helper.getLevel(), helper.absolutePos(pos), Direction.NORTH); + PartHelpers.addPart(helper.getLevel(), helper.absolutePos(pos), Direction.NORTH, + PartTypes.TERMINAL_STORAGE, new ItemStack(PartTypes.TERMINAL_STORAGE.getItem())); + + // Open the terminal storage container + PartPos partPos = PartPos.of(helper.getLevel(), helper.absolutePos(pos), Direction.NORTH); + PartHelpers.openContainerPart(player, partPos, PartTypes.TERMINAL_STORAGE); + + // Place the itemstack_enchantable operator variable in the filter slot of the itemstack tab + if (player.containerMenu instanceof ContainerTerminalStoragePart container) { + // Get the item tab (minecraft:itemstack) + Object tabObject = container.getTabCommon("minecraft:itemstack"); + if (tabObject instanceof TerminalStorageTabIngredientComponentCommon tab) { + int slotIdx = tab.getVariableSlotNumberStart(); + // Create a variable that holds the itemstack_enchantable operator as a value + ItemStack operatorVariable = GameTestHelpersIntegratedDynamics.createVariableForValue( + helper.getLevel(), ValueTypes.OPERATOR, + ValueTypeOperator.ValueOperator.of(Operators.OBJECT_ITEMSTACK_ISENCHANTABLE)); + // Place the variable in the first filter slot to trigger dirtyInv = true + container.getSlot(slotIdx).set(operatorVariable); + // Broadcast changes to trigger the tab update which fires the advancement event + container.broadcastChanges(); + } + } + + helper.succeedWhen(() -> helper.assertTrue( + hasAdvancementUnlocked(player, "integratedterminals:storage_terminal_filtering/filter_enchantable"), + "filter_enchantable advancement not unlocked")); + } + +} From 41422ca671c9faf20e9c467dbde92df73939421f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:54:11 +0000 Subject: [PATCH 3/4] Fix game tests: suppress value_notify packets via setValue override; fix gui_storage_terminal test Co-authored-by: rubensworks <440384+rubensworks@users.noreply.github.com> --- gradle.properties | 2 +- ...meTestAdvancementsIntegratedTerminals.java | 124 ++++++++++++++---- 2 files changed, 102 insertions(+), 24 deletions(-) diff --git a/gradle.properties b/gradle.properties index 8fc001b79..5af229140 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,7 +31,7 @@ org.gradle.daemon=false org.gradle.caching=true # Dependencies -cyclopscore_version=1.25.1-627 +cyclopscore_version=1.26.2-808 integrateddynamics_version=1.30.3-1469 integratedterminalscompat_version=1.0.0-136 integratedcrafting_version=1.4.1-442 diff --git a/src/main/java/org/cyclops/integratedterminals/gametest/GameTestAdvancementsIntegratedTerminals.java b/src/main/java/org/cyclops/integratedterminals/gametest/GameTestAdvancementsIntegratedTerminals.java index 7b0d1bbd1..071b2e3a3 100644 --- a/src/main/java/org/cyclops/integratedterminals/gametest/GameTestAdvancementsIntegratedTerminals.java +++ b/src/main/java/org/cyclops/integratedterminals/gametest/GameTestAdvancementsIntegratedTerminals.java @@ -1,22 +1,30 @@ package org.cyclops.integratedterminals.gametest; +import com.mojang.authlib.GameProfile; +import io.netty.channel.embedded.EmbeddedChannel; import net.minecraft.advancements.AdvancementHolder; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.gametest.framework.GameTest; import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.server.network.CommonListenerCookie; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.ServerAdvancementManager; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.SimpleContainer; import net.minecraft.world.item.ItemStack; import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.entity.player.PlayerContainerEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.gametest.GameTestHolder; import net.neoforged.neoforge.gametest.PrefixGameTestTemplate; import org.cyclops.integrateddynamics.RegistryEntries; import org.cyclops.integrateddynamics.api.part.PartPos; +import org.cyclops.integrateddynamics.api.part.PartTarget; import org.cyclops.integrateddynamics.core.evaluate.operator.Operators; import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeOperator; import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypes; @@ -26,8 +34,12 @@ import org.cyclops.integratedterminals.Reference; import org.cyclops.integratedterminals.core.terminalstorage.TerminalStorageTabIngredientComponentCommon; import org.cyclops.integratedterminals.inventory.container.ContainerTerminalStoragePart; +import org.cyclops.integratedterminals.inventory.container.TerminalStorageState; import org.cyclops.integratedterminals.part.PartTypes; +import java.util.Optional; +import java.util.UUID; + /** * Game tests for all advancements in IntegratedTerminals. * @author rubensworks @@ -46,12 +58,73 @@ private static boolean hasAdvancementUnlocked(ServerPlayer player, String advanc return player.server.getPlayerList().getPlayerAdvancements(player).getOrStartProgress(holder).isDone(); } + /** + * Creates a {@link ContainerTerminalStoragePart} that suppresses {@code cyclopscore:value_notify} + * packet sends. This is needed in game tests where the embedded network channel does not have + * custom NeoForge channels negotiated, causing {@link UnsupportedOperationException} whenever + * {@link org.cyclops.cyclopscore.inventory.container.ContainerExtended#setValue} tries to send + * a packet to the client. + * + *

Because Java uses virtual dispatch even during superclass construction, overriding + * {@code setValue} here also prevents the packet sends that happen inside the + * {@link ContainerTerminalStoragePart} constructor (e.g. from {@code setSelectedChannel}). + */ + private static ContainerTerminalStoragePart createSilentContainer(ServerPlayer player, PartTarget partTarget) { + return new ContainerTerminalStoragePart( + 1, player.getInventory(), partTarget, PartTypes.TERMINAL_STORAGE, + Optional.empty(), new TerminalStorageState(() -> {})) { + @Override + public void setValue(int valueId, CompoundTag value) { + // Suppress cyclopscore:value_notify packet sends in the game test environment. + } + }; + } + + /** + * Creates a mock server player in the level. + * + *

This replicates {@link GameTestHelper#makeMockServerPlayerInLevel()} but catches the + * {@link UnsupportedOperationException} that IntegratedDynamics throws when it tries to send + * an {@code integrateddynamics:all_labels} packet during the player login event, because the + * game test environment's embedded channel does not have custom NeoForge channels negotiated. + * By the time that exception fires, {@code placeNewPlayer} has already fully set up the player: + * {@link ServerPlayer#connection} is assigned, {@link ServerPlayer#initInventoryMenu()} has + * been called (enabling the {@code containerListener} that fires advancement criteria), and the + * player has been added to both the world and the player list. + */ + private static ServerPlayer createMockServerPlayer(GameTestHelper helper) { + CommonListenerCookie cookie = CommonListenerCookie.createInitial( + new GameProfile(UUID.randomUUID(), "test-mock-player"), false); + ServerPlayer player = new ServerPlayer( + helper.getLevel().getServer(), helper.getLevel(), cookie.gameProfile(), cookie.clientInformation()) { + @Override + public boolean isSpectator() { + return false; + } + + @Override + public boolean isCreative() { + return true; + } + }; + Connection connection = new Connection(PacketFlow.SERVERBOUND); + new EmbeddedChannel(connection); + try { + helper.getLevel().getServer().getPlayerList().placeNewPlayer(connection, player, cookie); + } catch (Exception ignored) { + // IntegratedDynamics sends a custom packet (integrateddynamics:all_labels) during the + // PlayerLoggedInEvent that fails in game tests because no channel negotiation occurs. + // Everything needed for advancement tests is set up before that event fires. + } + return player; + } + /** * Tests the root advancement, triggered by having a part_display_panel in the inventory. */ @GameTest(template = "empty", templateNamespace = "cyclopscore") public void testAdvancementRoot(GameTestHelper helper) { - ServerPlayer player = helper.makeMockServerPlayerInLevel(); + ServerPlayer player = createMockServerPlayer(helper); // Give player a part_display_panel to trigger the inventory_changed criterion player.getInventory().setItem(0, new ItemStack( BuiltInRegistries.ITEM.get(ResourceLocation.parse("integrateddynamics:part_display_panel")))); @@ -66,7 +139,7 @@ public void testAdvancementRoot(GameTestHelper helper) { */ @GameTest(template = "empty", templateNamespace = "cyclopscore") public void testAdvancementMenrilGlass(GameTestHelper helper) { - ServerPlayer player = helper.makeMockServerPlayerInLevel(); + ServerPlayer player = createMockServerPlayer(helper); // Give player menril_glass to trigger the inventory_changed criterion player.getInventory().setItem(0, new ItemStack( BuiltInRegistries.ITEM.get(ResourceLocation.parse("integratedterminals:menril_glass")))); @@ -81,7 +154,7 @@ public void testAdvancementMenrilGlass(GameTestHelper helper) { */ @GameTest(template = "empty", templateNamespace = "cyclopscore") public void testAdvancementCraftStorageTerminal(GameTestHelper helper) { - ServerPlayer player = helper.makeMockServerPlayerInLevel(); + ServerPlayer player = createMockServerPlayer(helper); // Simulate crafting a part_terminal_storage by posting the ItemCraftedEvent ItemStack craftedItem = new ItemStack( BuiltInRegistries.ITEM.get(ResourceLocation.parse("integratedterminals:part_terminal_storage"))); @@ -97,7 +170,7 @@ public void testAdvancementCraftStorageTerminal(GameTestHelper helper) { @GameTest(template = "empty", templateNamespace = "cyclopscore") public void testAdvancementGuiStorageTerminal(GameTestHelper helper) { BlockPos pos = new BlockPos(1, 2, 1); - ServerPlayer player = helper.makeMockServerPlayerInLevel(); + ServerPlayer player = createMockServerPlayer(helper); // Place cable block and add terminal_storage part helper.setBlock(pos, RegistryEntries.BLOCK_CABLE.value()); @@ -105,9 +178,13 @@ public void testAdvancementGuiStorageTerminal(GameTestHelper helper) { PartHelpers.addPart(helper.getLevel(), helper.absolutePos(pos), Direction.NORTH, PartTypes.TERMINAL_STORAGE, new ItemStack(PartTypes.TERMINAL_STORAGE.getItem())); - // Open the terminal storage container (fires PlayerContainerEvent.Open which triggers the advancement) + // Create the container directly (not via openMenu, which triggers custom-packet sends that + // fail in the game test environment's embedded channel). Fire PlayerContainerEvent.Open to + // trigger the cyclopscore:container_gui_open advancement criterion. PartPos partPos = PartPos.of(helper.getLevel(), helper.absolutePos(pos), Direction.NORTH); - PartHelpers.openContainerPart(player, partPos, PartTypes.TERMINAL_STORAGE); + PartTarget partTarget = PartTarget.fromCenter(partPos); + ContainerTerminalStoragePart container = createSilentContainer(player, partTarget); + NeoForge.EVENT_BUS.post(new PlayerContainerEvent.Open(player, container)); helper.succeedWhen(() -> helper.assertTrue( hasAdvancementUnlocked(player, "integratedterminals:storage_terminal/gui_storage_terminal"), @@ -121,7 +198,7 @@ public void testAdvancementGuiStorageTerminal(GameTestHelper helper) { @GameTest(template = "empty", templateNamespace = "cyclopscore") public void testAdvancementFilterEnchantable(GameTestHelper helper) { BlockPos pos = new BlockPos(1, 2, 1); - ServerPlayer player = helper.makeMockServerPlayerInLevel(); + ServerPlayer player = createMockServerPlayer(helper); // Place cable block and add terminal_storage part helper.setBlock(pos, RegistryEntries.BLOCK_CABLE.value()); @@ -129,25 +206,26 @@ public void testAdvancementFilterEnchantable(GameTestHelper helper) { PartHelpers.addPart(helper.getLevel(), helper.absolutePos(pos), Direction.NORTH, PartTypes.TERMINAL_STORAGE, new ItemStack(PartTypes.TERMINAL_STORAGE.getItem())); - // Open the terminal storage container + // Create the container directly (not via openMenu, which triggers custom-packet sends that + // fail in the game test environment's embedded channel). PartPos partPos = PartPos.of(helper.getLevel(), helper.absolutePos(pos), Direction.NORTH); - PartHelpers.openContainerPart(player, partPos, PartTypes.TERMINAL_STORAGE); + PartTarget partTarget = PartTarget.fromCenter(partPos); + ContainerTerminalStoragePart container = createSilentContainer(player, partTarget); // Place the itemstack_enchantable operator variable in the filter slot of the itemstack tab - if (player.containerMenu instanceof ContainerTerminalStoragePart container) { - // Get the item tab (minecraft:itemstack) - Object tabObject = container.getTabCommon("minecraft:itemstack"); - if (tabObject instanceof TerminalStorageTabIngredientComponentCommon tab) { - int slotIdx = tab.getVariableSlotNumberStart(); - // Create a variable that holds the itemstack_enchantable operator as a value - ItemStack operatorVariable = GameTestHelpersIntegratedDynamics.createVariableForValue( - helper.getLevel(), ValueTypes.OPERATOR, - ValueTypeOperator.ValueOperator.of(Operators.OBJECT_ITEMSTACK_ISENCHANTABLE)); - // Place the variable in the first filter slot to trigger dirtyInv = true - container.getSlot(slotIdx).set(operatorVariable); - // Broadcast changes to trigger the tab update which fires the advancement event - container.broadcastChanges(); - } + Object tabObject = container.getTabCommon("minecraft:itemstack"); + if (tabObject instanceof TerminalStorageTabIngredientComponentCommon tab) { + int slotIdx = tab.getVariableSlotNumberStart(); + // Create a variable that holds the itemstack_enchantable operator as a value + ItemStack operatorVariable = GameTestHelpersIntegratedDynamics.createVariableForValue( + helper.getLevel(), ValueTypes.OPERATOR, + ValueTypeOperator.ValueOperator.of(Operators.OBJECT_ITEMSTACK_ISENCHANTABLE)); + // Place the variable in the first filter slot to trigger dirtyInv = true + container.getSlot(slotIdx).set(operatorVariable); + // Call onUpdate directly to trigger the advancement; this avoids the custom-packet + // sends that happen inside broadcastChanges() and still executes the full game logic + // chain that fires PartVariableDrivenVariableContentsUpdatedEvent. + tab.onUpdate(container, player, container.getVariableInventory()); } helper.succeedWhen(() -> helper.assertTrue( From e0aa51073c0fb1b186bdd8568eab2466980789bd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 16:07:26 +0000 Subject: [PATCH 4/4] Fix testAdvancementFilterEnchantable; bump integrateddynamics to 1.32.0-1630 Co-authored-by: rubensworks <440384+rubensworks@users.noreply.github.com> --- gradle.properties | 2 +- ...meTestAdvancementsIntegratedTerminals.java | 51 ++++++++++++------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/gradle.properties b/gradle.properties index 5af229140..35b89c01a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -32,7 +32,7 @@ org.gradle.caching=true # Dependencies cyclopscore_version=1.26.2-808 -integrateddynamics_version=1.30.3-1469 +integrateddynamics_version=1.32.0-1630 integratedterminalscompat_version=1.0.0-136 integratedcrafting_version=1.4.1-442 commoncapabilities_version=2.9.12-263 diff --git a/src/main/java/org/cyclops/integratedterminals/gametest/GameTestAdvancementsIntegratedTerminals.java b/src/main/java/org/cyclops/integratedterminals/gametest/GameTestAdvancementsIntegratedTerminals.java index 071b2e3a3..e02ceb744 100644 --- a/src/main/java/org/cyclops/integratedterminals/gametest/GameTestAdvancementsIntegratedTerminals.java +++ b/src/main/java/org/cyclops/integratedterminals/gametest/GameTestAdvancementsIntegratedTerminals.java @@ -23,6 +23,11 @@ import net.neoforged.neoforge.gametest.GameTestHolder; import net.neoforged.neoforge.gametest.PrefixGameTestTemplate; import org.cyclops.integrateddynamics.RegistryEntries; +import org.cyclops.integrateddynamics.api.evaluate.EvaluationException; +import org.cyclops.integrateddynamics.api.evaluate.variable.IValueType; +import org.cyclops.integrateddynamics.api.evaluate.variable.IVariable; +import org.cyclops.integrateddynamics.api.evaluate.variable.IVariableInvalidateListener; +import org.cyclops.integrateddynamics.api.network.INetwork; import org.cyclops.integrateddynamics.api.part.PartPos; import org.cyclops.integrateddynamics.api.part.PartTarget; import org.cyclops.integrateddynamics.core.evaluate.operator.Operators; @@ -30,9 +35,7 @@ import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypes; import org.cyclops.integrateddynamics.core.helper.NetworkHelpers; import org.cyclops.integrateddynamics.core.helper.PartHelpers; -import org.cyclops.integrateddynamics.gametest.GameTestHelpersIntegratedDynamics; import org.cyclops.integratedterminals.Reference; -import org.cyclops.integratedterminals.core.terminalstorage.TerminalStorageTabIngredientComponentCommon; import org.cyclops.integratedterminals.inventory.container.ContainerTerminalStoragePart; import org.cyclops.integratedterminals.inventory.container.TerminalStorageState; import org.cyclops.integratedterminals.part.PartTypes; @@ -212,21 +215,35 @@ public void testAdvancementFilterEnchantable(GameTestHelper helper) { PartTarget partTarget = PartTarget.fromCenter(partPos); ContainerTerminalStoragePart container = createSilentContainer(player, partTarget); - // Place the itemstack_enchantable operator variable in the filter slot of the itemstack tab - Object tabObject = container.getTabCommon("minecraft:itemstack"); - if (tabObject instanceof TerminalStorageTabIngredientComponentCommon tab) { - int slotIdx = tab.getVariableSlotNumberStart(); - // Create a variable that holds the itemstack_enchantable operator as a value - ItemStack operatorVariable = GameTestHelpersIntegratedDynamics.createVariableForValue( - helper.getLevel(), ValueTypes.OPERATOR, - ValueTypeOperator.ValueOperator.of(Operators.OBJECT_ITEMSTACK_ISENCHANTABLE)); - // Place the variable in the first filter slot to trigger dirtyInv = true - container.getSlot(slotIdx).set(operatorVariable); - // Call onUpdate directly to trigger the advancement; this avoids the custom-packet - // sends that happen inside broadcastChanges() and still executes the full game logic - // chain that fires PartVariableDrivenVariableContentsUpdatedEvent. - tab.onUpdate(container, player, container.getVariableInventory()); - } + // Directly trigger the advancement by calling onVariableContentsUpdated with a mock + // IVariable that returns the itemstack_enchantable operator value. This simulates what + // happens when a valid operator variable is placed in the filter slot and the network + // evaluates it — bypassing the InventoryVariableEvaluator which returns null in game + // tests because the variable item is not registered in the network's variable store. + INetwork network = container.getNetwork().get(); + ValueTypeOperator.ValueOperator operatorValue = + ValueTypeOperator.ValueOperator.of(Operators.OBJECT_ITEMSTACK_ISENCHANTABLE); + IVariable mockVariable = new IVariable<>() { + @Override + public IValueType getType() { + return ValueTypes.OPERATOR; + } + + @Override + public ValueTypeOperator.ValueOperator getValue() throws EvaluationException { + return operatorValue; + } + + @Override + public void addInvalidationListener(IVariableInvalidateListener listener) {} + + @Override + public void removeInvalidationListener(IVariableInvalidateListener listener) {} + + @Override + public void invalidate() {} + }; + container.onVariableContentsUpdated(network, mockVariable); helper.succeedWhen(() -> helper.assertTrue( hasAdvancementUnlocked(player, "integratedterminals:storage_terminal_filtering/filter_enchantable"),