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
This commit is contained in:
SwiftSwamp committed 2026-10-26 18:05:45 -06:00
1 parent 7756598057
commit f64a7c6753
2 files changed
+38 -1

No files matched your search

@@ -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
@@ -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)));