From f64a7c67530a213d004c85447904f9251aae630f Mon Sep 17 00:00:00 2001 From: SwiftSwamp Date: Mon, 26 Oct 2026 18:05:45 -0600 Subject: [PATCH] Fixed wandering trader spawning - World injection attaches vanilla event spawners for NORMAL dimension environments - Covers worlds loaded at server start, Studio worlds and Folia worlds - Binding test covers overworld and nether environments --- .../platform/bukkit/nms/BukkitBinding.java | 4 +++ .../bukkit/nms/BukkitBindingTest.java | 35 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/art/arcane/iris/platform/bukkit/nms/BukkitBinding.java b/core/src/main/java/art/arcane/iris/platform/bukkit/nms/BukkitBinding.java index fdb74abaf..7c63ce640 100644 --- a/core/src/main/java/art/arcane/iris/platform/bukkit/nms/BukkitBinding.java +++ b/core/src/main/java/art/arcane/iris/platform/bukkit/nms/BukkitBinding.java @@ -9,6 +9,7 @@ import art.arcane.iris.spi.PlatformGenerationRegistry; import art.arcane.iris.spi.IrisLogging; import art.arcane.iris.structure.nativegen.IrisImportedStructureControl; import art.arcane.iris.structure.nativegen.NativeStructureVolumeIndex; +import art.arcane.iris.world.IrisEnvironment; import art.arcane.iris.world.history.SavedTerrainChunk; import art.arcane.volmlib.nativelib.NativeAdapters; import art.arcane.volmlib.nativelib.terrain.NativeTerrainAccess; @@ -104,6 +105,9 @@ public final class BukkitBinding implements INMSBinding { public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { validateDimension(engine, world, generation.dimension(world)); generation.inject(world, new BukkitGeneratorContext(new BukkitGeneratorContext.Options(seed, engine, world))); + if (engine.getDimension().getEnvironment() == IrisEnvironment.NORMAL) { + generation.attachOverworldSpawners(world); + } } @Override diff --git a/core/src/test/java/art/arcane/iris/platform/bukkit/nms/BukkitBindingTest.java b/core/src/test/java/art/arcane/iris/platform/bukkit/nms/BukkitBindingTest.java index 401be6254..8abb5e561 100644 --- a/core/src/test/java/art/arcane/iris/platform/bukkit/nms/BukkitBindingTest.java +++ b/core/src/test/java/art/arcane/iris/platform/bukkit/nms/BukkitBindingTest.java @@ -1,5 +1,9 @@ package art.arcane.iris.platform.bukkit.nms; +import art.arcane.iris.generation.runtime.Engine; +import art.arcane.iris.generation.terrain.IrisDimension; +import art.arcane.iris.generation.terrain.IrisDimensionRuntimeContract; +import art.arcane.iris.world.IrisEnvironment; import art.arcane.volmlib.nativelib.terrain.NativeGenerationRegistry; import art.arcane.volmlib.nativelib.terrain.NativeTerrainAccess; import art.arcane.volmlib.nativelib.terrain.NativeTerrainSnapshots; @@ -7,8 +11,12 @@ import art.arcane.volmlib.nativelib.terrain.NativeWorldGeneration; import art.arcane.volmlib.nativelib.terrain.NativeWorldLifecycleFactory; import org.bukkit.World; import org.junit.Test; + +import java.util.Locale; + import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -37,13 +45,38 @@ public class BukkitBindingTest { verify(fixture.lifecycle).releasePluginClassLoaderClose(); } + @Test + public void injectAttachesVanillaSpawnersOnlyToOverworldEnvironments() throws NoSuchFieldException, IllegalAccessException { + Fixture fixture = new Fixture(); + World overworld = injectedWorld(fixture, IrisEnvironment.NORMAL); + World nether = injectedWorld(fixture, IrisEnvironment.NETHER); + verify(fixture.generation).attachOverworldSpawners(overworld); + verify(fixture.generation, never()).attachOverworldSpawners(nether); + } + + private static World injectedWorld(Fixture fixture, IrisEnvironment environment) throws NoSuchFieldException, IllegalAccessException { + IrisDimension dimension = new IrisDimension(); + dimension.setLoadKey(environment.name().toLowerCase(Locale.ROOT)); + dimension.setEnvironment(environment); + IrisDimensionRuntimeContract contract = IrisDimensionRuntimeContract.expected(dimension, "iris"); + Engine engine = mock(Engine.class); + when(engine.getDimension()).thenReturn(dimension); + World world = mock(World.class); + when(world.getMinHeight()).thenReturn(contract.minHeight()); + when(world.getMaxHeight()).thenReturn(contract.minHeight() + contract.height()); + when(fixture.generation.dimension(world)).thenReturn(new NativeWorldGeneration.Dimension(contract.typeKey(), + contract.minHeight(), contract.height(), contract.logicalHeight(), contract.minHeight(), contract.height())); + fixture.binding.inject(1L, engine, world); + return world; + } + private static final class Fixture { private final NativeTerrainAccess terrain = mock(NativeTerrainAccess.class); + private final NativeWorldGeneration generation = mock(NativeWorldGeneration.class); private final NativeWorldLifecycleFactory.Controller lifecycle = mock(NativeWorldLifecycleFactory.Controller.class); private final BukkitBinding binding; private Fixture() { - NativeWorldGeneration generation = mock(NativeWorldGeneration.class); when(generation.lifecycle(BukkitWorldLifecyclePolicy.INSTANCE)).thenReturn(lifecycle); binding = new BukkitBinding(new BukkitBinding.Capabilities(terrain, generation, mock(NativeTerrainSnapshots.class), mock(NativeGenerationRegistry.class)));