mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-26 05:50:39 +00:00
Fixed Structure Crash
- Don't carash anymore when you disable structures in the server.properties.
This commit is contained in:
1 parent
65ae3f1b45
commit
ee5aaec87c
6 files changed
+12
-74
No files matched your search
-32
@@ -195,8 +195,6 @@ public final class IrisModdedChunkGenerator implements NativeGeneratorOwner, Nat
|
|||||||
if (!nativeGenerator.represents(level)) {
|
if (!nativeGenerator.represents(level)) {
|
||||||
throw new IllegalArgumentException("NativeWorld does not use Iris generator '" + dimensionKey + "'");
|
throw new IllegalArgumentException("NativeWorld does not use Iris generator '" + dimensionKey + "'");
|
||||||
}
|
}
|
||||||
requireGlobalStructureGeneration(
|
|
||||||
NativeModdedServer.forWorld(level).generateStructures(), dimensionKey);
|
|
||||||
Engine activeEngine = engineIfBound();
|
Engine activeEngine = engineIfBound();
|
||||||
Engine replacement = ModdedWorldEngines.prepareReplacement(
|
Engine replacement = ModdedWorldEngines.prepareReplacement(
|
||||||
level,
|
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
|
// 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.
|
// history verification on every chunk call and fail the same way.
|
||||||
engineBinding.throwIfFailed(dimensionKey);
|
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.
|
// Cache the owning level so hot paths never scan the level map to find themselves.
|
||||||
boundLevel = level;
|
boundLevel = level;
|
||||||
Engine cached = engine;
|
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
|
* 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.
|
* engine is refused, unloading or stopping throws, so no stage can mistake it for an unbound generator.
|
||||||
|
|||||||
-11
@@ -122,17 +122,6 @@ final class ModdedNativeStructurePolicy implements NativeModdedStructureStage.Po
|
|||||||
return ((IrisMaterialPalette) source).get(rng, x, y, z, generator.engine().getData());
|
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
|
@Override
|
||||||
public String generationLabel(String structureId) {
|
public String generationLabel(String structureId) {
|
||||||
return "Iris native structure " + structureId;
|
return "Iris native structure " + structureId;
|
||||||
|
|||||||
+8
-3
@@ -57,8 +57,11 @@ public class ModdedBindFailureTest {
|
|||||||
when(server.generateStructures()).thenReturn(false);
|
when(server.generateStructures()).thenReturn(false);
|
||||||
|
|
||||||
try (MockedStatic<NativeModdedServer> servers = mockStatic(NativeModdedServer.class);
|
try (MockedStatic<NativeModdedServer> servers = mockStatic(NativeModdedServer.class);
|
||||||
|
MockedStatic<ModdedWorldEngines> engines = mockStatic(ModdedWorldEngines.class);
|
||||||
MockedStatic<ModdedIrisLog> log = mockStatic(ModdedIrisLog.class)) {
|
MockedStatic<ModdedIrisLog> log = mockStatic(ModdedIrisLog.class)) {
|
||||||
servers.when(() -> NativeModdedServer.forWorld(level)).thenReturn(server);
|
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 recorded = assertThrows(IllegalStateException.class, () -> generator.bindLevel(level));
|
||||||
IllegalStateException second = assertThrows(IllegalStateException.class, generator::engine);
|
IllegalStateException second = assertThrows(IllegalStateException.class, generator::engine);
|
||||||
@@ -66,9 +69,9 @@ public class ModdedBindFailureTest {
|
|||||||
|
|
||||||
assertSame(recorded, second.getCause());
|
assertSame(recorded, second.getCause());
|
||||||
assertSame(recorded, third.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: ")
|
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<ModdedWorldEngines> engines = mockStatic(ModdedWorldEngines.class);
|
MockedStatic<ModdedWorldEngines> engines = mockStatic(ModdedWorldEngines.class);
|
||||||
MockedStatic<ModdedIrisLog> log = mockStatic(ModdedIrisLog.class)) {
|
MockedStatic<ModdedIrisLog> log = mockStatic(ModdedIrisLog.class)) {
|
||||||
servers.when(() -> NativeModdedServer.forWorld(level)).thenReturn(server);
|
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));
|
IllegalStateException first = assertThrows(IllegalStateException.class, () -> generator.bindLevel(level));
|
||||||
generator.unbindEngine(level);
|
generator.unbindEngine(level);
|
||||||
IllegalStateException second = assertThrows(IllegalStateException.class, () -> generator.bindLevel(level));
|
IllegalStateException second = assertThrows(IllegalStateException.class, () -> generator.bindLevel(level));
|
||||||
|
|
||||||
assertNotSame(first, second.getCause());
|
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));
|
engines.verify(() -> ModdedWorldEngines.evictOrThrow(level));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -37,7 +37,7 @@ public class ModdedStructureBindingOrderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void initialBindingPublishesReadyEngineBeforeStartingStructureSearches() throws Exception {
|
public void disabledStructuresAllowInitialBindingBeforeStartingStructureSearches() throws Exception {
|
||||||
NativeModdedChunkGenerator<?, ?, ?> nativeGenerator = mock(NativeModdedChunkGenerator.class);
|
NativeModdedChunkGenerator<?, ?, ?> nativeGenerator = mock(NativeModdedChunkGenerator.class);
|
||||||
ModdedEngineBinding<Engine> binding = new ModdedEngineBinding<>(1L, TimeUnit.MILLISECONDS);
|
ModdedEngineBinding<Engine> binding = new ModdedEngineBinding<>(1L, TimeUnit.MILLISECONDS);
|
||||||
IrisModdedChunkGenerator generator = generator(nativeGenerator, binding);
|
IrisModdedChunkGenerator generator = generator(nativeGenerator, binding);
|
||||||
@@ -45,7 +45,7 @@ public class ModdedStructureBindingOrderTest {
|
|||||||
NativeModdedServer server = mock(NativeModdedServer.class);
|
NativeModdedServer server = mock(NativeModdedServer.class);
|
||||||
Engine engine = readyEngine();
|
Engine engine = readyEngine();
|
||||||
when(nativeGenerator.represents(world)).thenReturn(true);
|
when(nativeGenerator.represents(world)).thenReturn(true);
|
||||||
when(server.generateStructures()).thenReturn(true);
|
when(server.generateStructures()).thenReturn(false);
|
||||||
doAnswer(invocation -> {
|
doAnswer(invocation -> {
|
||||||
assertSame(engine, generator.awaitStructureEngine());
|
assertSame(engine, generator.awaitStructureEngine());
|
||||||
assertSame(engine, binding.await("overworld"));
|
assertSame(engine, binding.await("overworld"));
|
||||||
@@ -88,7 +88,7 @@ public class ModdedStructureBindingOrderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void repointPublishesReplacementBindingBeforeStartingStructureSearches() throws Exception {
|
public void disabledStructuresAllowReplacementBindingBeforeStartingStructureSearches() throws Exception {
|
||||||
NativeModdedChunkGenerator<?, ?, ?> nativeGenerator = mock(NativeModdedChunkGenerator.class);
|
NativeModdedChunkGenerator<?, ?, ?> nativeGenerator = mock(NativeModdedChunkGenerator.class);
|
||||||
ModdedEngineBinding<Engine> binding = new ModdedEngineBinding<>(1L, TimeUnit.MILLISECONDS);
|
ModdedEngineBinding<Engine> binding = new ModdedEngineBinding<>(1L, TimeUnit.MILLISECONDS);
|
||||||
IrisModdedChunkGenerator generator = generator(nativeGenerator, binding);
|
IrisModdedChunkGenerator generator = generator(nativeGenerator, binding);
|
||||||
@@ -96,7 +96,7 @@ public class ModdedStructureBindingOrderTest {
|
|||||||
NativeModdedServer server = mock(NativeModdedServer.class);
|
NativeModdedServer server = mock(NativeModdedServer.class);
|
||||||
Engine replacement = readyEngine();
|
Engine replacement = readyEngine();
|
||||||
when(nativeGenerator.represents(world)).thenReturn(true);
|
when(nativeGenerator.represents(world)).thenReturn(true);
|
||||||
when(server.generateStructures()).thenReturn(true);
|
when(server.generateStructures()).thenReturn(false);
|
||||||
doAnswer(invocation -> {
|
doAnswer(invocation -> {
|
||||||
assertSame(replacement, generator.awaitStructureEngine());
|
assertSame(replacement, generator.awaitStructureEngine());
|
||||||
assertSame(replacement, binding.await("overworld"));
|
assertSame(replacement, binding.await("overworld"));
|
||||||
|
|||||||
-16
@@ -7,7 +7,6 @@ import org.junit.BeforeClass;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertSame;
|
import static org.junit.Assert.assertSame;
|
||||||
import static org.junit.Assert.assertThrows;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class NativeStructureFailureContractTest {
|
public class NativeStructureFailureContractTest {
|
||||||
@@ -17,21 +16,6 @@ public class NativeStructureFailureContractTest {
|
|||||||
Bootstrap.bootStrap();
|
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
|
@Test
|
||||||
public void structureFailurePreservesPhaseIdentityChunkAndCause() {
|
public void structureFailurePreservesPhaseIdentityChunkAndCause() {
|
||||||
IllegalArgumentException cause = new IllegalArgumentException("broken placement");
|
IllegalArgumentException cause = new IllegalArgumentException("broken placement");
|
||||||
|
|||||||
@@ -118,14 +118,6 @@ public final class BukkitStructureStagePolicy implements StructureStagePolicy<
|
|||||||
return ((IrisMaterialPalette) source).get(rng, x, y, z, engine.getData());
|
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
|
@Override
|
||||||
public String generationLabel(String structureId) {
|
public String generationLabel(String structureId) {
|
||||||
return "Iris native structure " + structureId;
|
return "Iris native structure " + structureId;
|
||||||
|
|||||||
Reference in new issue
Block a user