From 2ddd33220a4cc00484958a91038d9a86f5fb9d41 Mon Sep 17 00:00:00 2001 From: Ruben Taelman Date: Fri, 4 Sep 2026 19:06:13 +0000 Subject: [PATCH] Expose the machine that a crafting interface targets Crafting interfaces know which block they are targeting, but only exposed their own (center) position through getPosition(). Callers that want the machine had to look the part up again and re-derive its target, which duplicates the logic that decides where a part points at. Add ICraftingInterface#getTargetMachineItem(), which the part state answers from the target it already holds. It is a default method returning an empty stack, so other implementations keep working. Needed by CyclopsMC/IntegratedTerminals#181, to show the crafting machine in the storage terminal's tooltips. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01RM86uiqD4soLkMyjC9Eeid --- .../api/crafting/ICraftingInterface.java | 9 +++ .../part/PartTypeInterfaceCraftingBase.java | 16 +++++ ...meTestsCraftingInterfaceTargetMachine.java | 59 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 src/main/java/org/cyclops/integratedcrafting/gametest/GameTestsCraftingInterfaceTargetMachine.java diff --git a/src/main/java/org/cyclops/integratedcrafting/api/crafting/ICraftingInterface.java b/src/main/java/org/cyclops/integratedcrafting/api/crafting/ICraftingInterface.java index 2bda7f00..a6585037 100644 --- a/src/main/java/org/cyclops/integratedcrafting/api/crafting/ICraftingInterface.java +++ b/src/main/java/org/cyclops/integratedcrafting/api/crafting/ICraftingInterface.java @@ -3,6 +3,7 @@ import org.cyclops.commoncapabilities.api.capability.recipehandler.IRecipeDefinition; import org.cyclops.commoncapabilities.api.ingredient.IPrototypedIngredient; import org.cyclops.commoncapabilities.api.ingredient.IngredientComponent; +import net.minecraft.world.item.ItemStack; import org.cyclops.commoncapabilities.api.ingredient.storage.IIngredientComponentStorage; import org.cyclops.integratedcrafting.api.network.ICraftingNetwork; import org.cyclops.integrateddynamics.api.part.PrioritizedPartPos; @@ -101,6 +102,14 @@ public interface ICraftingInterface { */ public PrioritizedPartPos getPosition(); + /** + * @return An item representation of the machine that this interface is targeting, + * or an empty stack if the machine is unknown or its position is not loaded. + */ + public default ItemStack getTargetMachineItem() { + return ItemStack.EMPTY; + } + public static Comparator createComparator() { return Comparator.comparing(ICraftingInterface::getPosition); } diff --git a/src/main/java/org/cyclops/integratedcrafting/core/part/PartTypeInterfaceCraftingBase.java b/src/main/java/org/cyclops/integratedcrafting/core/part/PartTypeInterfaceCraftingBase.java index f2ff716b..06d19eb1 100644 --- a/src/main/java/org/cyclops/integratedcrafting/core/part/PartTypeInterfaceCraftingBase.java +++ b/src/main/java/org/cyclops/integratedcrafting/core/part/PartTypeInterfaceCraftingBase.java @@ -9,7 +9,9 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; import org.cyclops.commoncapabilities.api.capability.recipehandler.IRecipeDefinition; +import org.cyclops.cyclopscore.datastructure.DimPos; import org.cyclops.commoncapabilities.api.ingredient.IPrototypedIngredient; import org.cyclops.commoncapabilities.api.ingredient.IngredientComponent; import org.cyclops.commoncapabilities.api.ingredient.IngredientInstanceWrapper; @@ -394,6 +396,20 @@ public PrioritizedPartPos getPosition() { return PrioritizedPartPos.of(getTarget().getCenter(), getPriority()); } + @Override + public ItemStack getTargetMachineItem() { + PartTarget target = getTarget(); + if (target == null) { + return ItemStack.EMPTY; + } + DimPos dimPos = target.getTarget().getPos(); + if (!dimPos.isLoaded()) { + return ItemStack.EMPTY; + } + Level level = dimPos.getLevel(false); + return new ItemStack(level.getBlockState(dimPos.getBlockPos()).getBlock()); + } + public CraftingJobHandler getCraftingJobHandler() { return craftingJobHandler; } diff --git a/src/main/java/org/cyclops/integratedcrafting/gametest/GameTestsCraftingInterfaceTargetMachine.java b/src/main/java/org/cyclops/integratedcrafting/gametest/GameTestsCraftingInterfaceTargetMachine.java new file mode 100644 index 00000000..c059fdc4 --- /dev/null +++ b/src/main/java/org/cyclops/integratedcrafting/gametest/GameTestsCraftingInterfaceTargetMachine.java @@ -0,0 +1,59 @@ +package org.cyclops.integratedcrafting.gametest; + +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.neoforged.neoforge.gametest.GameTestHolder; +import net.neoforged.neoforge.gametest.PrefixGameTestTemplate; +import org.cyclops.integratedcrafting.Reference; +import org.cyclops.integratedcrafting.core.part.PartTypeInterfaceCraftingBase; + +import static org.cyclops.integratedcrafting.gametest.GameTestHelpersIntegratedCrafting.*; + +/** + * Game tests for the machine that crafting interfaces are targeting. + * @author rubensworks + */ +@GameTestHolder(Reference.MOD_ID) +@PrefixGameTestTemplate(false) +public class GameTestsCraftingInterfaceTargetMachine { + + public static final String TEMPLATE_EMPTY = "empty10"; + public static final int TIMEOUT = 2000; + public static final BlockPos POS = BlockPos.ZERO.offset(2, 0, 2); + + protected void testTargetMachineItem(GameTestHelper helper, boolean attuned, Block crafter, Item expectedItem) { + INetworkPositions> positions = createBasicNetwork(helper, POS, attuned, crafter); + + helper.succeedWhen(() -> { + ItemStack machineItem = positions.interfaceStates().get(0).getTargetMachineItem(); + helper.assertValueEqual(machineItem.getItem(), expectedItem, "Target machine item is incorrect"); + }); + } + + @GameTest(template = TEMPLATE_EMPTY, timeoutTicks = TIMEOUT) + public void testTargetMachineItemCraftingTable(GameTestHelper helper) { + testTargetMachineItem(helper, false, Blocks.CRAFTING_TABLE, Items.CRAFTING_TABLE); + } + + @GameTest(template = TEMPLATE_EMPTY, timeoutTicks = TIMEOUT) + public void testTargetMachineItemFurnace(GameTestHelper helper) { + testTargetMachineItem(helper, false, Blocks.FURNACE, Items.FURNACE); + } + + @GameTest(template = TEMPLATE_EMPTY, timeoutTicks = TIMEOUT) + public void testTargetMachineItemAttunedCraftingTable(GameTestHelper helper) { + testTargetMachineItem(helper, true, Blocks.CRAFTING_TABLE, Items.CRAFTING_TABLE); + } + + @GameTest(template = TEMPLATE_EMPTY, timeoutTicks = TIMEOUT) + public void testTargetMachineItemAttunedFurnace(GameTestHelper helper) { + testTargetMachineItem(helper, true, Blocks.FURNACE, Items.FURNACE); + } + +}