diff --git a/adapters/modded-common/src/main/java/art/arcane/iris/modded/IrisModdedChunkGenerator.java b/adapters/modded-common/src/main/java/art/arcane/iris/modded/IrisModdedChunkGenerator.java index 0bb4e4fc7..165ee583a 100644 --- a/adapters/modded-common/src/main/java/art/arcane/iris/modded/IrisModdedChunkGenerator.java +++ b/adapters/modded-common/src/main/java/art/arcane/iris/modded/IrisModdedChunkGenerator.java @@ -195,8 +195,6 @@ public final class IrisModdedChunkGenerator implements NativeGeneratorOwner, Nat if (!nativeGenerator.represents(level)) { throw new IllegalArgumentException("NativeWorld does not use Iris generator '" + dimensionKey + "'"); } - requireGlobalStructureGeneration( - NativeModdedServer.forWorld(level).generateStructures(), dimensionKey); Engine activeEngine = engineIfBound(); Engine replacement = ModdedWorldEngines.prepareReplacement( level, @@ -462,13 +460,6 @@ public final class IrisModdedChunkGenerator implements NativeGeneratorOwner, Nat // A recorded failure stands until repoint or unbind resets the binding; re-running the bind would repeat the // history verification on every chunk call and fail the same way. engineBinding.throwIfFailed(dimensionKey); - try { - requireGlobalStructureGeneration( - NativeModdedServer.forWorld(level).generateStructures(), dimensionKey); - } catch (RuntimeException error) { - recordBindFailure(level, error); - throw error; - } // Cache the owning level so hot paths never scan the level map to find themselves. boundLevel = level; Engine cached = engine; @@ -575,29 +566,6 @@ public final class IrisModdedChunkGenerator implements NativeGeneratorOwner, Nat } } - static void requireGlobalStructureGeneration(boolean enabled, String dimensionKey) { - if (enabled) { - return; - } - String remedy = integratedEnvironment() - ? "enable 'Generate Structures' for this world; Iris requires it, then deny families through " - + "importedStructures.disabled or complete keys through importedStructures.disabledExact" - : "set generate-structures=true in server.properties, restart the server, " - + "then deny families through importedStructures.disabled or complete keys through " - + "importedStructures.disabledExact"; - throw new IllegalStateException("Iris generator '" + dimensionKey - + "' cannot bind while generate-structures=false; " + remedy); - } - - private static boolean integratedEnvironment() { - try { - return ModdedEngineBootstrap.loader().clientEnvironment(); - } catch (Throwable e) { - // No loader bound (unit tests, very early boot): assume dedicated wording. - return false; - } - } - /** * Null only while no level uses this generator (world creation screens, codec validation). A bound level whose * engine is refused, unloading or stopping throws, so no stage can mistake it for an unbound generator. diff --git a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedNativeStructurePolicy.java b/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedNativeStructurePolicy.java index 080577629..bbaef85c7 100644 --- a/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedNativeStructurePolicy.java +++ b/adapters/modded-common/src/main/java/art/arcane/iris/modded/ModdedNativeStructurePolicy.java @@ -122,17 +122,6 @@ final class ModdedNativeStructurePolicy implements NativeModdedStructureStage.Po return ((IrisMaterialPalette) source).get(rng, x, y, z, generator.engine().getData()); } - @Override - public RuntimeException structuresDisabled(int chunkX, int chunkZ) { - return new IllegalStateException("Iris cannot generate native structures in chunk " - + chunkX + "," + chunkZ - + " because generate-structures=false disables them outside the pack. That flag is fixed when " - + "the world is created (server.properties generate-structures, or the Generate Structures " - + "toggle in singleplayer), so it cannot be changed for this world: create a new world with " - + "structures enabled, then deny families through importedStructures.disabled or complete keys " - + "through importedStructures.disabledExact"); - } - @Override public String generationLabel(String structureId) { return "Iris native structure " + structureId; diff --git a/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedBindFailureTest.java b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedBindFailureTest.java index 40b207410..2848942df 100644 --- a/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedBindFailureTest.java +++ b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedBindFailureTest.java @@ -57,8 +57,11 @@ public class ModdedBindFailureTest { when(server.generateStructures()).thenReturn(false); try (MockedStatic servers = mockStatic(NativeModdedServer.class); + MockedStatic engines = mockStatic(ModdedWorldEngines.class); MockedStatic log = mockStatic(ModdedIrisLog.class)) { servers.when(() -> NativeModdedServer.forWorld(level)).thenReturn(server); + engines.when(() -> ModdedWorldEngines.get(eq(level), any(), any(), anyLong(), any())) + .thenThrow(new IllegalStateException("broken world binding")); IllegalStateException recorded = assertThrows(IllegalStateException.class, () -> generator.bindLevel(level)); IllegalStateException second = assertThrows(IllegalStateException.class, generator::engine); @@ -66,9 +69,9 @@ public class ModdedBindFailureTest { assertSame(recorded, second.getCause()); assertSame(recorded, third.getCause()); - servers.verify(() -> NativeModdedServer.forWorld(level), times(1)); + engines.verify(() -> ModdedWorldEngines.get(eq(level), any(), any(), anyLong(), any()), times(1)); log.verify(() -> ModdedIrisLog.error(argThat((String line) -> line != null && line.startsWith("Cause: ") - && line.contains("generate-structures=false"))), times(1)); + && line.contains("broken world binding"))), times(1)); } } @@ -117,13 +120,15 @@ public class ModdedBindFailureTest { MockedStatic engines = mockStatic(ModdedWorldEngines.class); MockedStatic log = mockStatic(ModdedIrisLog.class)) { servers.when(() -> NativeModdedServer.forWorld(level)).thenReturn(server); + engines.when(() -> ModdedWorldEngines.get(eq(level), any(), any(), anyLong(), any())) + .thenAnswer(invocation -> { throw new IllegalStateException("broken world binding"); }); IllegalStateException first = assertThrows(IllegalStateException.class, () -> generator.bindLevel(level)); generator.unbindEngine(level); IllegalStateException second = assertThrows(IllegalStateException.class, () -> generator.bindLevel(level)); assertNotSame(first, second.getCause()); - servers.verify(() -> NativeModdedServer.forWorld(level), times(2)); + engines.verify(() -> ModdedWorldEngines.get(eq(level), any(), any(), anyLong(), any()), times(2)); engines.verify(() -> ModdedWorldEngines.evictOrThrow(level)); } } diff --git a/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedStructureBindingOrderTest.java b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedStructureBindingOrderTest.java index f9d473c89..02221da19 100644 --- a/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedStructureBindingOrderTest.java +++ b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedStructureBindingOrderTest.java @@ -37,7 +37,7 @@ public class ModdedStructureBindingOrderTest { } @Test - public void initialBindingPublishesReadyEngineBeforeStartingStructureSearches() throws Exception { + public void disabledStructuresAllowInitialBindingBeforeStartingStructureSearches() throws Exception { NativeModdedChunkGenerator nativeGenerator = mock(NativeModdedChunkGenerator.class); ModdedEngineBinding binding = new ModdedEngineBinding<>(1L, TimeUnit.MILLISECONDS); IrisModdedChunkGenerator generator = generator(nativeGenerator, binding); @@ -45,7 +45,7 @@ public class ModdedStructureBindingOrderTest { NativeModdedServer server = mock(NativeModdedServer.class); Engine engine = readyEngine(); when(nativeGenerator.represents(world)).thenReturn(true); - when(server.generateStructures()).thenReturn(true); + when(server.generateStructures()).thenReturn(false); doAnswer(invocation -> { assertSame(engine, generator.awaitStructureEngine()); assertSame(engine, binding.await("overworld")); @@ -88,7 +88,7 @@ public class ModdedStructureBindingOrderTest { } @Test - public void repointPublishesReplacementBindingBeforeStartingStructureSearches() throws Exception { + public void disabledStructuresAllowReplacementBindingBeforeStartingStructureSearches() throws Exception { NativeModdedChunkGenerator nativeGenerator = mock(NativeModdedChunkGenerator.class); ModdedEngineBinding binding = new ModdedEngineBinding<>(1L, TimeUnit.MILLISECONDS); IrisModdedChunkGenerator generator = generator(nativeGenerator, binding); @@ -96,7 +96,7 @@ public class ModdedStructureBindingOrderTest { NativeModdedServer server = mock(NativeModdedServer.class); Engine replacement = readyEngine(); when(nativeGenerator.represents(world)).thenReturn(true); - when(server.generateStructures()).thenReturn(true); + when(server.generateStructures()).thenReturn(false); doAnswer(invocation -> { assertSame(replacement, generator.awaitStructureEngine()); assertSame(replacement, binding.await("overworld")); diff --git a/adapters/modded-common/src/test/java/art/arcane/iris/modded/NativeStructureFailureContractTest.java b/adapters/modded-common/src/test/java/art/arcane/iris/modded/NativeStructureFailureContractTest.java index 7d51a63f0..7cb788523 100644 --- a/adapters/modded-common/src/test/java/art/arcane/iris/modded/NativeStructureFailureContractTest.java +++ b/adapters/modded-common/src/test/java/art/arcane/iris/modded/NativeStructureFailureContractTest.java @@ -7,7 +7,6 @@ import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; public class NativeStructureFailureContractTest { @@ -17,21 +16,6 @@ public class NativeStructureFailureContractTest { Bootstrap.bootStrap(); } - @Test - public void globalStructureDisableRefusesGeneratorBinding() { - IrisModdedChunkGenerator.requireGlobalStructureGeneration(true, "overworld:overworld"); - - IllegalStateException error = assertThrows( - IllegalStateException.class, - () -> IrisModdedChunkGenerator.requireGlobalStructureGeneration( - false, "overworld:overworld")); - - assertTrue(error.getMessage().contains("overworld:overworld")); - assertTrue(error.getMessage().contains("generate-structures=false")); - assertTrue(error.getMessage().contains("importedStructures.disabled")); - assertTrue(error.getMessage().contains("importedStructures.disabledExact")); - } - @Test public void structureFailurePreservesPhaseIdentityChunkAndCause() { IllegalArgumentException cause = new IllegalArgumentException("broken placement"); diff --git a/core/src/main/java/art/arcane/iris/platform/bukkit/nms/BukkitStructureStagePolicy.java b/core/src/main/java/art/arcane/iris/platform/bukkit/nms/BukkitStructureStagePolicy.java index 646cb7784..47f32c9f6 100644 --- a/core/src/main/java/art/arcane/iris/platform/bukkit/nms/BukkitStructureStagePolicy.java +++ b/core/src/main/java/art/arcane/iris/platform/bukkit/nms/BukkitStructureStagePolicy.java @@ -118,14 +118,6 @@ public final class BukkitStructureStagePolicy implements StructureStagePolicy< return ((IrisMaterialPalette) source).get(rng, x, y, z, engine.getData()); } - @Override - public RuntimeException structuresDisabled(int chunkX, int chunkZ) { - return new IllegalStateException("Iris cannot generate native structures in chunk " - + chunkX + "," + chunkZ - + " because structure generation is disabled outside the pack; enable native structure generation " - + "and deny families through importedStructures.disabled or complete keys through importedStructures.disabledExact"); - } - @Override public String generationLabel(String structureId) { return "Iris native structure " + structureId;