From 4071b0fa29124e03174617b2c11e082f83bbc424 Mon Sep 17 00:00:00 2001 From: Aintripin <72869676+Aintripin@users.noreply.github.com> Date: Mon, 12 Oct 2026 11:46:31 -0700 Subject: [PATCH] Fix crash when a crafting job completes with the crafting log enabled (#1698) --- .../CraftingCPUClusterFunctionalTest.java | 53 ++++++++++++++++++- .../implementations/CraftingCPUCluster.java | 2 +- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/functionalTest/java/appeng/test/me/crafting/CraftingCPUClusterFunctionalTest.java b/src/functionalTest/java/appeng/test/me/crafting/CraftingCPUClusterFunctionalTest.java index 5b5c8b136..0ee3a2879 100644 --- a/src/functionalTest/java/appeng/test/me/crafting/CraftingCPUClusterFunctionalTest.java +++ b/src/functionalTest/java/appeng/test/me/crafting/CraftingCPUClusterFunctionalTest.java @@ -24,9 +24,12 @@ import appeng.api.networking.crafting.ICraftingGrid; import appeng.api.networking.crafting.ICraftingMedium; import appeng.api.networking.crafting.ICraftingPatternDetails; import appeng.api.networking.energy.IEnergyGrid; +import appeng.api.networking.security.BaseActionSource; import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEStack; import appeng.api.util.WorldCoord; +import appeng.core.AEConfig; +import appeng.core.features.AEFeature; import appeng.helpers.PatternHelper; import appeng.me.cache.CraftingGridCache; import appeng.me.cluster.implementations.CraftingCPUCluster; @@ -169,10 +172,50 @@ public class CraftingCPUClusterFunctionalTest { assertEquals(2, cpu.core.dirtyNotifications, "Notifications outside the update must remain immediate"); } + @Test + void craftingLogDoesNotBreakJobCompletion() { + cpu.prepare(pattern, 64, 128); + cpu.trackFinalOutput(64); + cpu.setStartItemCount(7); + final long[] reportedCount = { -1 }; + cpu.addOnCompleteListener((output, count, elapsedTime) -> reportedCount[0] = count); + tick(); + + withCraftingLog( + () -> cpu.injectItems( + AEItemStack.create(new ItemStack(Blocks.stone)).setStackSize(512), + Actionable.MODULATE, + new BaseActionSource())); + + assertAll( + () -> assertTrue(cpu.completed()), + () -> assertEquals(512, reportedCount[0], "The crafting log must not change the reported output")); + } + + @Test + void craftingLogDoesNotBreakFakeCraftingCompletion() { + cpu.prepare(pattern, 64, 128); + cpu.enableFakeCrafting(64); + + withCraftingLog(this::tick); + + assertTrue(cpu.completed()); + } + private void tick() { cpu.updateCraftingLogic(grid, energy, cache); } + private static void withCraftingLog(Runnable action) { + final boolean wasEnabled = AEConfig.instance.isFeatureEnabled(AEFeature.CraftingLog); + AEConfig.instance.featureFlags.add(AEFeature.CraftingLog); + try { + action.run(); + } finally { + if (!wasEnabled) AEConfig.instance.featureFlags.remove(AEFeature.CraftingLog); + } + } + private static ICraftingPatternDetails processingPattern() { final ItemStack encoded = AEApi.instance().definitions().items().encodedPattern().maybeStack(1).get(); final NBTTagCompound tag = new NBTTagCompound(); @@ -207,8 +250,16 @@ public class CraftingCPUClusterFunctionalTest { Actionable.MODULATE); } - private void enableFakeCrafting(int crafts) { + private void setStartItemCount(long count) { + startItemCount = count; + } + + private void trackFinalOutput(int crafts) { finalOutput.init(AEItemStack.create(new ItemStack(Blocks.stone)).setStackSize(crafts * 8L)); + } + + private void enableFakeCrafting(int crafts) { + trackFinalOutput(crafts); finalOutput.setFakeCrafting(); } diff --git a/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java b/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java index 03c1ab080..05ffd5c5c 100644 --- a/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java +++ b/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java @@ -576,7 +576,7 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU { } if (AELog.isCraftingLogEnabled()) { - final IAEStack logStack = this.finalOutput.get(); + final IAEStack logStack = this.finalOutput.getOriginalOutput().copy(); logStack.setStackSize(this.startItemCount); AELog.crafting(LOG_MARK_AS_COMPLETE, logStack); }