diff --git a/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/IrisProbeChunkGenerator.java b/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/IrisProbeChunkGenerator.java
new file mode 100644
index 000000000..c38ea4c9e
--- /dev/null
+++ b/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/IrisProbeChunkGenerator.java
@@ -0,0 +1,101 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2026 Arcane Arts (Volmit Software)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package art.arcane.iris.core;
+
+import org.bukkit.HeightMap;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.generator.BiomeProvider;
+import org.bukkit.generator.BlockPopulator;
+import org.bukkit.generator.ChunkGenerator;
+import org.bukkit.generator.WorldInfo;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Random;
+
+/**
+ * Answer to a generator-plugin discovery probe.
+ *
+ * Multiverse-Core calls {@code getDefaultWorldGenerator} with an empty dimension id and the name of
+ * an already loaded world purely to find out whether a plugin is a generator plugin, then throws the
+ * returned instance away. A non-null answer keeps Iris in {@code /mv generators} and in Multiverse's
+ * generator tab-completion without Multiverse logging a warning block on every boot.
+ *
+ * Nothing here can build terrain: every generation entry point refuses, so an instance that escapes
+ * the probe fails loudly instead of silently producing vanilla chunks.
+ */
+final class IrisProbeChunkGenerator extends ChunkGenerator {
+ private final String worldName;
+
+ IrisProbeChunkGenerator(String worldName) {
+ this.worldName = Objects.requireNonNull(worldName, "worldName");
+ }
+
+ @Override
+ public void generateNoise(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
+ throw refusal();
+ }
+
+ @Override
+ public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
+ throw refusal();
+ }
+
+ @Override
+ public void generateBedrock(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
+ throw refusal();
+ }
+
+ @Override
+ public void generateCaves(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
+ throw refusal();
+ }
+
+ @Override
+ public ChunkData generateChunkData(@NotNull World world, @NotNull Random random, int x, int z, @NotNull BiomeGrid biome) {
+ throw refusal();
+ }
+
+ @Override
+ public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) {
+ throw refusal();
+ }
+
+ @Override
+ public int getBaseHeight(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull HeightMap heightMap) {
+ throw refusal();
+ }
+
+ @Override
+ public List getDefaultPopulators(@NotNull World world) {
+ throw refusal();
+ }
+
+ @Override
+ public Location getFixedSpawnLocation(@NotNull World world, @NotNull Random random) {
+ throw refusal();
+ }
+
+ private IllegalStateException refusal() {
+ return new IllegalStateException("Iris generator-discovery probe for '" + worldName
+ + "' was asked to generate terrain. Iris worlds are created with /iris create.");
+ }
+}
diff --git a/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/IrisWorldGeneratorResolver.java b/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/IrisWorldGeneratorResolver.java
index 445749a8f..222ec94bc 100644
--- a/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/IrisWorldGeneratorResolver.java
+++ b/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/IrisWorldGeneratorResolver.java
@@ -33,15 +33,19 @@ import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisWorld;
import art.arcane.iris.engine.platform.BukkitChunkGenerator;
import art.arcane.iris.util.common.plugin.VolmitPlugin;
+import art.arcane.volmlib.util.bukkit.WorldIdentity;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
+import org.bukkit.World;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@@ -56,6 +60,7 @@ import java.util.function.Supplier;
public final class IrisWorldGeneratorResolver {
private static final int VALIDATION_STABILITY_ATTEMPTS = 2;
private static final Object SNAPSHOT_VALIDATION_LOCK = new Object();
+ private static final String IRIS_DIMENSION_NAMESPACE = "iris";
private final VolmitPlugin plugin;
@@ -278,6 +283,10 @@ public final class IrisWorldGeneratorResolver {
}
public ChunkGenerator resolveDefaultWorldGenerator(String worldName, String id) {
+ if (isGeneratorDiscoveryProbe(worldName, id)) {
+ Iris.debug("Generator discovery probe for loaded world " + worldName);
+ return new IrisProbeChunkGenerator(worldName);
+ }
IrisStartupValidation.requireWorldCreationReady();
ChunkGenerator stagedGenerator = WorldLifecycleStaging.consumeGenerator(worldName);
if (stagedGenerator != null) {
@@ -288,6 +297,11 @@ public final class IrisWorldGeneratorResolver {
if (id == null || id.isEmpty()) id = IrisSettings.get().getGenerator().getDefaultWorldType();
Iris.debug("Generator ID: " + id + " requested by bukkit/plugin");
+ File levelRoot = IrisWorldStorage.levelRoot();
+ NamespacedKey worldKey = configuredWorldKey(worldName, levelRoot.getName());
+ requireWorldKeyAvailable(worldName, worldKey);
+ requireOwnedWorld(worldName, levelRoot, worldKey);
+
try {
return resolveFrozenWorldGenerator(worldName, id);
} catch (RuntimeException failure) {
@@ -298,6 +312,66 @@ public final class IrisWorldGeneratorResolver {
}
}
+ /**
+ * Multiverse-Core probes every enabled plugin by asking for a generator with an empty dimension
+ * id and the name of a world that is already loaded. Bukkit never creates a world that is
+ * already loaded, so that pair only ever means discovery, never generation.
+ */
+ private static boolean isGeneratorDiscoveryProbe(String worldName, String id) {
+ return id != null && id.isEmpty() && Bukkit.getWorld(worldName) != null;
+ }
+
+ /**
+ * Refuses a second generator for a world key that is already live. Multiverse imports accept a
+ * world name that maps onto a loaded Iris key, which would otherwise start a second engine on
+ * the same storage with a different seed.
+ */
+ private static void requireWorldKeyAvailable(String worldName, NamespacedKey worldKey) {
+ World loaded = WorldIdentity.resolve(worldKey).orElse(null);
+ if (loaded == null) {
+ return;
+ }
+ throw new IllegalStateException("Refusing to generate '" + worldName + "': " + worldKey
+ + " is already loaded as '" + loaded.getName() + "'.");
+ }
+
+ /**
+ * Refuses worlds Iris does not own before the fail-fast path can see them. A world without Iris
+ * storage is somebody else's create or import, and returning null there would silently hand the
+ * caller a vanilla world.
+ *
+ * The {@code iris} dimension namespace is Iris-exclusive, so a directory in it is ownership on
+ * its own. Every server already has {@code dimensions/minecraft/*}, so a vanilla slot counts as
+ * Iris' only once it carries a frozen pack snapshot.
+ */
+ private static void requireOwnedWorld(String worldName, File levelRoot, NamespacedKey worldKey) {
+ File dimensionRoot;
+ try {
+ dimensionRoot = IrisWorldStorage.frozenDimensionRoot(
+ Bukkit.getWorldContainer(),
+ levelRoot,
+ worldName,
+ worldKey
+ ).orElse(null);
+ } catch (RuntimeException unusableStorage) {
+ // Storage exists but cannot be resolved: an owned world, left to the fail-fast path.
+ return;
+ }
+ if (dimensionRoot != null
+ && (IRIS_DIMENSION_NAMESPACE.equals(worldKey.getNamespace()) || hasFrozenPack(dimensionRoot))) {
+ return;
+ }
+ throw new IllegalStateException("'" + worldName + "' (" + worldKey
+ + ") has no Iris world storage, so Iris cannot generate it."
+ + " Create Iris worlds with /iris create " + worldName + " type=;"
+ + " Iris registers them with Multiverse itself.");
+ }
+
+ private static boolean hasFrozenPack(File dimensionRoot) {
+ Path packRoot = dimensionRoot.toPath().toAbsolutePath().normalize().resolve("iris").resolve("pack");
+ return Files.isDirectory(packRoot, LinkOption.NOFOLLOW_LINKS);
+ }
+
private ChunkGenerator resolveFrozenWorldGenerator(String worldName, String id) {
File levelRoot = IrisWorldStorage.levelRoot();
NamespacedKey worldKey = configuredWorldKey(worldName, levelRoot.getName());
diff --git a/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/service/CommandSVC.java b/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/service/CommandSVC.java
index ad40767dc..11c03e553 100644
--- a/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/service/CommandSVC.java
+++ b/adapters/bukkit/plugin/src/main/java/art/arcane/iris/core/service/CommandSVC.java
@@ -234,7 +234,7 @@ public class CommandSVC implements IrisService, CommandExecutor, TabCompleter, D
}
private boolean sendHelpIfRequested(CommandSender sender, String[] args) {
- Optional request = DirectorMiniMenu.resolveHelp(getDirector(), Arrays.asList(args), 17);
+ Optional request = DirectorMiniMenu.resolveHelp(getDirector(), Arrays.asList(args));
if (request.isEmpty()) {
return false;
}
diff --git a/adapters/bukkit/plugin/src/test/java/art/arcane/iris/core/IrisWorldGeneratorResolverTest.java b/adapters/bukkit/plugin/src/test/java/art/arcane/iris/core/IrisWorldGeneratorResolverTest.java
index f94c19bf2..7496dc732 100644
--- a/adapters/bukkit/plugin/src/test/java/art/arcane/iris/core/IrisWorldGeneratorResolverTest.java
+++ b/adapters/bukkit/plugin/src/test/java/art/arcane/iris/core/IrisWorldGeneratorResolverTest.java
@@ -1,5 +1,6 @@
package art.arcane.iris.core;
+import art.arcane.iris.Iris;
import art.arcane.iris.core.pack.BrokenPackException;
import art.arcane.iris.core.pack.PackValidationRegistry;
import art.arcane.iris.core.pack.PackValidationResult;
@@ -7,19 +8,30 @@ import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
+import org.bukkit.Server;
+import org.bukkit.World;
+import org.bukkit.generator.ChunkGenerator;
+import org.bukkit.generator.WorldInfo;
+import org.mockito.MockedStatic;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
+import java.util.Random;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.when;
public class IrisWorldGeneratorResolverTest {
@Rule
@@ -130,22 +142,158 @@ public class IrisWorldGeneratorResolverTest {
}
@Test
- public void configuredWorldSnapshotFailureStopsStartupAndRethrows() throws Exception {
+ public void ownedWorldSnapshotFailureStopsStartupAndRethrows() throws Exception {
String source = Files.readString(Path.of(
"src/main/java/art/arcane/iris/core/IrisWorldGeneratorResolver.java"));
int resolverStart = source.indexOf("public ChunkGenerator resolveDefaultWorldGenerator(");
int resolverEnd = source.indexOf("private ChunkGenerator resolveFrozenWorldGenerator(", resolverStart);
String resolver = source.substring(resolverStart, resolverEnd);
- int failureCapture = resolver.indexOf("catch (RuntimeException failure)");
+ int probe = resolver.indexOf("isGeneratorDiscoveryProbe(worldName, id)");
+ int readiness = resolver.indexOf("IrisStartupValidation.requireWorldCreationReady()");
+ int duplicateGuard = resolver.indexOf("requireWorldKeyAvailable(worldName, worldKey)");
+ int ownership = resolver.indexOf("requireOwnedWorld(worldName, levelRoot, worldKey)");
+ int frozen = resolver.indexOf("return resolveFrozenWorldGenerator(", ownership);
+ int failureCapture = resolver.indexOf("catch (RuntimeException failure)", frozen);
int report = resolver.indexOf("Iris.reportError(", failureCapture);
int shutdown = resolver.indexOf("Bukkit.shutdown()", report);
int rethrow = resolver.indexOf("throw failure", shutdown);
- assertTrue(failureCapture >= 0);
+ assertTrue(probe >= 0);
+ assertTrue(readiness > probe);
+ assertTrue(duplicateGuard > readiness);
+ assertTrue(ownership > duplicateGuard);
+ assertTrue(frozen > ownership);
+ assertTrue(failureCapture > frozen);
assertTrue(report > failureCapture);
assertTrue(shutdown > report);
assertTrue(rethrow > shutdown);
+
+ String shutdownScope = "the fail-fast shutdown must stay scoped to the frozen snapshot of an owned world";
+ assertEquals(shutdownScope, resolverStart + shutdown, source.indexOf("Bukkit.shutdown()"));
+ assertEquals(shutdownScope, resolverStart + shutdown, source.lastIndexOf("Bukkit.shutdown()"));
+ }
+
+ @Test
+ public void discoveryProbeOfLoadedWorldReturnsInertGeneratorQuietly() {
+ try (MockedStatic bukkit = mockStatic(Bukkit.class);
+ MockedStatic iris = mockStatic(Iris.class)) {
+ bukkit.when(() -> Bukkit.getWorld("world")).thenReturn(mock(World.class));
+
+ ChunkGenerator probe = new IrisWorldGeneratorResolver(null)
+ .resolveDefaultWorldGenerator("world", "");
+
+ assertNotNull("Multiverse drops Iris from /mv generators when the probe returns null", probe);
+ bukkit.verify(Bukkit::shutdown, never());
+ IllegalStateException refusal = assertThrows(
+ IllegalStateException.class,
+ () -> probe.generateNoise(mock(WorldInfo.class), new Random(), 0, 0, null));
+ assertTrue(refusal.getMessage(), refusal.getMessage().contains("'world'"));
+ }
+ }
+
+ @Test
+ public void externalCreateWithoutIrisStorageThrowsWithoutShutdown() throws Exception {
+ File worldContainer = temporaryFolder.newFolder("external-create");
+ File levelRoot = new File(worldContainer, "world");
+ assertTrue(levelRoot.mkdirs());
+
+ try (MockedStatic bukkit = mockStatic(Bukkit.class);
+ MockedStatic iris = mockStatic(Iris.class)) {
+ Server server = mock(Server.class);
+ when(server.getLevelDirectory()).thenReturn(levelRoot.toPath());
+ bukkit.when(Bukkit::getServer).thenReturn(server);
+ bukkit.when(Bukkit::getWorldContainer).thenReturn(worldContainer);
+ bukkit.when(Bukkit::getWorlds).thenReturn(List.of());
+
+ IllegalStateException failure = assertThrows(
+ IllegalStateException.class,
+ () -> new IrisWorldGeneratorResolver(null)
+ .resolveDefaultWorldGenerator("mvtest", "overworld"));
+
+ assertTrue(failure.getMessage(), failure.getMessage().contains("mvtest"));
+ assertTrue(failure.getMessage(), failure.getMessage().contains("/iris create"));
+ bukkit.verify(Bukkit::shutdown, never());
+ }
+ }
+
+ @Test
+ public void ownedIrisWorldWithUnusableSnapshotStillStopsTheServer() throws Exception {
+ File worldContainer = temporaryFolder.newFolder("owned-broken");
+ File levelRoot = new File(worldContainer, "world");
+ assertTrue(levelRoot.mkdirs());
+ assertTrue(new File(worldContainer, "world_iris_moon/dimensions/iris/moon").mkdirs());
+
+ try (MockedStatic bukkit = mockStatic(Bukkit.class);
+ MockedStatic iris = mockStatic(Iris.class)) {
+ Server server = mock(Server.class);
+ when(server.getLevelDirectory()).thenReturn(levelRoot.toPath());
+ bukkit.when(Bukkit::getServer).thenReturn(server);
+ bukkit.when(Bukkit::getWorldContainer).thenReturn(worldContainer);
+ bukkit.when(Bukkit::getWorlds).thenReturn(List.of());
+
+ assertThrows(
+ IllegalStateException.class,
+ () -> new IrisWorldGeneratorResolver(null)
+ .resolveDefaultWorldGenerator("world_iris_moon", "overworld"));
+
+ bukkit.verify(Bukkit::shutdown);
+ }
+ }
+
+ @Test
+ public void vanillaDimensionSlotWithoutFrozenPackIsNotOwned() throws Exception {
+ File worldContainer = temporaryFolder.newFolder("vanilla-slot");
+ File levelRoot = new File(worldContainer, "world");
+ assertTrue(new File(levelRoot, "dimensions/minecraft/the_nether").mkdirs());
+
+ try (MockedStatic bukkit = mockStatic(Bukkit.class);
+ MockedStatic iris = mockStatic(Iris.class)) {
+ Server server = mock(Server.class);
+ when(server.getLevelDirectory()).thenReturn(levelRoot.toPath());
+ bukkit.when(Bukkit::getServer).thenReturn(server);
+ bukkit.when(Bukkit::getWorldContainer).thenReturn(worldContainer);
+ bukkit.when(Bukkit::getWorlds).thenReturn(List.of());
+
+ IllegalStateException failure = assertThrows(
+ IllegalStateException.class,
+ () -> new IrisWorldGeneratorResolver(null)
+ .resolveDefaultWorldGenerator("world_nether", "overworld"));
+
+ assertTrue(failure.getMessage(), failure.getMessage().contains("minecraft:the_nether"));
+ assertTrue(failure.getMessage(), failure.getMessage().contains("/iris create"));
+ bukkit.verify(Bukkit::shutdown, never());
+ }
+ }
+
+ @Test
+ public void alreadyLoadedIrisKeyIsRefusedBeforeAnyEngineCanStart() throws Exception {
+ File worldContainer = temporaryFolder.newFolder("duplicate-key");
+ File levelRoot = new File(worldContainer, "world");
+ assertTrue(levelRoot.mkdirs());
+ writeValidPack(new File(levelRoot, "dimensions/iris/irisworld/iris/pack").toPath());
+
+ World loaded = mock(World.class);
+ when(loaded.getKey()).thenReturn(new NamespacedKey("iris", "irisworld"));
+ when(loaded.getName()).thenReturn("world_iris_irisworld");
+
+ try (MockedStatic bukkit = mockStatic(Bukkit.class);
+ MockedStatic iris = mockStatic(Iris.class)) {
+ Server server = mock(Server.class);
+ when(server.getLevelDirectory()).thenReturn(levelRoot.toPath());
+ bukkit.when(Bukkit::getServer).thenReturn(server);
+ bukkit.when(Bukkit::getWorldContainer).thenReturn(worldContainer);
+ bukkit.when(Bukkit::getWorlds).thenReturn(List.of(loaded));
+
+ IllegalStateException failure = assertThrows(
+ IllegalStateException.class,
+ () -> new IrisWorldGeneratorResolver(null)
+ .resolveDefaultWorldGenerator("irisworld", "overworld"));
+
+ assertTrue(failure.getMessage(), failure.getMessage().contains("iris:irisworld"));
+ assertTrue(failure.getMessage(), failure.getMessage().contains("world_iris_irisworld"));
+ bukkit.verify(Bukkit::shutdown, never());
+ }
}
private static void writeValidPack(Path packRoot) throws Exception {
diff --git a/adapters/fabric/logs/latest.log b/adapters/fabric/logs/latest.log
index 3174ceafc..24f32e414 100644
--- a/adapters/fabric/logs/latest.log
+++ b/adapters/fabric/logs/latest.log
@@ -1,3 +1,488 @@
-[15:24:46] [Test worker/INFO]: Iris object undo service ready (bounded to 32 paste(s) per player)
-[15:24:46] [Test worker/INFO]: [STDOUT]: [Iris/INFO] Iris /iris command tree registered
-[15:24:46] [Test worker/INFO]: [STDOUT]: [Iris/INFO] Iris /iris command tree registered
+[19:35:02] [Test worker/WARN]: Iris cannot resolve the biome id for 'minecraft:plains' before the Minecraft server is available; using biome id 0
+[19:35:02] [Test worker/WARN]: Iris cannot enumerate the biome registry before the Minecraft server is available; returning no biomes
+[19:35:02] [Test worker/INFO]: [STDERR]: [Iris/WARN] Can't find block data for minecraft:definitely_not_a_real_block
+[19:35:02] [Test worker/INFO]: [STDERR]: [Iris/WARN] Can't find block data for minecraft:minecraft:definitely_not_a_real_block
+[19:35:02] [Test worker/INFO]: [STDERR]: [Iris/WARN] Block 'minecraft:oak_log' rejected state 'not_a_property=x'; using its default state
+[19:35:02] [Test worker/INFO]: Iris registered custom content provider 'iris_deferred_test'
+[19:35:02] [Test worker/WARN]: Iris persistent dimension registry entry 1 in /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-partial7029509183426900057/iris-dimensions.json is invalid (entry 1 in /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-partial7029509183426900057/iris-dimensions.json has no dimension); kept verbatim: {"id":"iris:broken","pack":"overworld"}
+[19:35:02] [Test worker/ERROR]: Iris persistent dimension registry at /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-corrupt-boot10459791259189814912/iris-dimensions.json is corrupt; quarantining it and continuing boot
+java.lang.IllegalStateException: Iris persistent dimension registry at /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-corrupt-boot10459791259189814912/iris-dimensions.json could not be read; refusing to discard persistent worlds
+ at art.arcane.iris.modded.ModdedDimensionRegistryStore.contents(ModdedDimensionRegistryStore.java:150)
+ at art.arcane.iris.modded.ModdedDimensionRegistryStore.load(ModdedDimensionRegistryStore.java:56)
+ at art.arcane.iris.modded.ModdedDimensionRegistryStore.loadForStartup(ModdedDimensionRegistryStore.java:69)
+ at art.arcane.iris.modded.ModdedDimensionRegistryStoreTest.startupLoadQuarantinesACorruptRegistryInsteadOfFailingBoot(ModdedDimensionRegistryStoreTest.java:99)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
+ at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
+ at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
+ at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
+ at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
+ at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
+ at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
+ at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
+ at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
+ at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
+ at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
+ at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
+ at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
+ at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
+Caused by: art.arcane.volmlib.util.json.JSONException: A JSONObject text must end with '}' at 34 [character 35 line 1]
+ at art.arcane.volmlib.util.json.JSONTokener.syntaxError(JSONTokener.java:414)
+ at art.arcane.volmlib.util.json.JSONObject.(JSONObject.java:145)
+ at art.arcane.volmlib.util.json.JSONTokener.nextValue(JSONTokener.java:345)
+ at art.arcane.volmlib.util.json.JSONArray.(JSONArray.java:111)
+ at art.arcane.volmlib.util.json.JSONTokener.nextValue(JSONTokener.java:348)
+ at art.arcane.volmlib.util.json.JSONObject.(JSONObject.java:159)
+ at art.arcane.volmlib.util.json.JSONObject.(JSONObject.java:260)
+ at art.arcane.iris.modded.ModdedDimensionRegistryStore.contents(ModdedDimensionRegistryStore.java:117)
+ ... 45 more
+[19:35:02] [Test worker/ERROR]: Iris lost 1 persistent dimension(s) from the corrupt registry: iris:lost
+[19:35:02] [Test worker/ERROR]: Iris moved the corrupt persistent dimension registry to /var/folders/l1/g6lr3c5x26z_mdmtfzt9gjbr0000gn/T/iris-dimension-registry-corrupt-boot10459791259189814912/iris-dimensions.json.broken-1787182502612
+[19:35:02] [Test worker/ERROR]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
+java.lang.RuntimeException: second disable failed
+ at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndNeverRethrows(ModdedServiceManagerTest.java:55)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
+ at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
+ at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
+ at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
+ at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
+ at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
+ at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
+ at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
+ at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
+ at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
+ at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
+ at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
+ at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
+ at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
+[19:35:02] [Test worker/ERROR]: Iris service onDisable failed for art.arcane.iris.modded.ModdedServiceManagerTest$FirstService
+java.lang.RuntimeException: first disable failed
+ at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndNeverRethrows(ModdedServiceManagerTest.java:54)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
+ at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
+ at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
+ at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
+ at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
+ at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
+ at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
+ at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
+ at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
+ at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
+ at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
+ at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
+ at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
+ at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
+[19:35:02] [Test worker/ERROR]: Iris disabled all services with 2 failure(s)
+java.lang.RuntimeException: second disable failed
+ at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndNeverRethrows(ModdedServiceManagerTest.java:55)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
+ at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
+ at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
+ at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
+ at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
+ at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
+ at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
+ at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
+ at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
+ at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
+ at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
+ at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
+ at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
+ at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
+ Suppressed: java.lang.RuntimeException: first disable failed
+ at art.arcane.iris.modded.ModdedServiceManagerTest.disableAttemptsEveryServiceInReverseOrderAndNeverRethrows(ModdedServiceManagerTest.java:54)
+ ... 42 more
+[19:35:02] [Test worker/ERROR]: Iris service rollback failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
+java.lang.RuntimeException: cleanup failed
+ at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:32)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
+ at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
+ at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
+ at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
+ at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
+ at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
+ at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
+ at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
+ at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
+ at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
+ at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
+ at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
+ at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
+ at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
+[19:35:02] [Test worker/ERROR]: Iris service onEnable failed for art.arcane.iris.modded.ModdedServiceManagerTest$SecondService
+java.lang.RuntimeException: enable failed
+ at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:31)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
+ at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
+ at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
+ at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
+ at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
+ at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
+ at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
+ at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
+ at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
+ at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
+ at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
+ at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
+ at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
+ at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
+ Suppressed: java.lang.RuntimeException: cleanup failed
+ at art.arcane.iris.modded.ModdedServiceManagerTest.rollsBackEnabledServicesAndPreservesCleanupFailures(ModdedServiceManagerTest.java:32)
+ ... 42 more
+[19:35:02] [Test worker/ERROR]: [worldcheck] server stop request failed
+java.lang.IllegalStateException: stop request failed
+ at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$stopRequestFailureForcesNonzeroResult$1(ModdedWorldCheckTest.java:238)
+ at art.arcane.iris.modded.ModdedWorldCheck.runAndRequestStop(ModdedWorldCheck.java:144)
+ at art.arcane.iris.modded.ModdedWorldCheckTest.stopRequestFailureForcesNonzeroResult(ModdedWorldCheckTest.java:235)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
+ at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
+ at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
+ at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
+ at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
+ at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
+ at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
+ at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
+ at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
+ at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
+ at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
+ at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
+ at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
+ at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
+[19:35:02] [Test worker/ERROR]: [worldcheck] waiting for server shutdown failed
+java.lang.IllegalStateException: shutdown wait failed
+ at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$shutdownWaitFailureForcesNonzeroExit$0(ModdedWorldCheckTest.java:264)
+ at art.arcane.iris.modded.ModdedWorldCheck.awaitStopAndExit(ModdedWorldCheck.java:159)
+ at art.arcane.iris.modded.ModdedWorldCheckTest.shutdownWaitFailureForcesNonzeroExit(ModdedWorldCheckTest.java:262)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
+ at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
+ at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
+ at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
+ at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
+ at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
+ at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
+ at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
+ at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
+ at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
+ at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
+ at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
+ at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
+ at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
+[19:35:02] [Test worker/ERROR]: [worldcheck] check failed
+java.lang.IllegalStateException: check failed
+ at art.arcane.iris.modded.ModdedWorldCheckTest.lambda$thrownCheckStillRequestsStop$0(ModdedWorldCheckTest.java:224)
+ at art.arcane.iris.modded.ModdedWorldCheck.runAndRequestStop(ModdedWorldCheck.java:139)
+ at art.arcane.iris.modded.ModdedWorldCheckTest.thrownCheckStillRequestsStop(ModdedWorldCheckTest.java:222)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
+ at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
+ at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
+ at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
+ at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
+ at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
+ at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
+ at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
+ at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
+ at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
+ at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
+ at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
+ at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
+ at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
+[19:35:02] [Test worker/INFO]: Iris registered custom content provider 'iris_discovery_success'
+[19:35:02] [Test worker/WARN]: Iris custom content provider discovery failed at provider 'iris_discovery_failure' (art.arcane.iris.modded.api.ModdedCustomContentRegistryTest$TestProvider)
+java.lang.RuntimeException: provider init failed
+ at art.arcane.iris.modded.api.ModdedCustomContentRegistryTest.failedDiscoveryPublishesNothingAndPreservesTheCause(ModdedCustomContentRegistryTest.java:39)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
+ at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
+ at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
+ at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
+ at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
+ at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
+ at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
+ at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
+ at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
+ at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
+ at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.runRequest(JUnitTestExecutor.java:175)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:84)
+ at org.gradle.api.internal.tasks.testing.junit.JUnitTestExecutor.accept(JUnitTestExecutor.java:47)
+ at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestDefinitionProcessor.processTestDefinition(AbstractJUnitTestDefinitionProcessor.java:65)
+ at org.gradle.api.internal.tasks.testing.SuiteTestDefinitionProcessor.processTestDefinition(SuiteTestDefinitionProcessor.java:53)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:565)
+ at org.gradle.internal.dispatch.MethodInvocation.invokeOn(MethodInvocation.java:77)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:28)
+ at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:19)
+ at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
+ at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:88)
+ at jdk.proxy1/jdk.proxy1.$Proxy4.processTestDefinition(Unknown Source)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:178)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:126)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
+ at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
+ at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
+ at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
+ at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
+[19:35:02] [Test worker/INFO]: Iris object undo service ready (bounded to 32 paste(s) per player)
+[19:35:02] [Test worker/INFO]: [STDOUT]: [Iris/INFO] Iris /iris command tree registered
+[19:35:02] [Test worker/INFO]: [STDOUT]: [Iris/INFO] Iris /iris command tree registered
diff --git a/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedLifecycleFailureContractTest.java b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedLifecycleFailureContractTest.java
index 6778d04ff..0db67d247 100644
--- a/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedLifecycleFailureContractTest.java
+++ b/adapters/modded-common/src/test/java/art/arcane/iris/modded/ModdedLifecycleFailureContractTest.java
@@ -278,46 +278,75 @@ public class ModdedLifecycleFailureContractTest {
private static String method(String source, String signature) {
int start = requiredIndex(source, signature);
- int openBrace = requiredIndex(source, "{", start);
+ int openBrace = openingBrace(source, start);
return source.substring(start, matchingBrace(source, openBrace) + 1);
}
+ /**
+ * Returns the block of the shallowest catch in the method, i.e. the one attached to the
+ * method's outermost try. Textual first-match would return a nested catch instead, and a
+ * nested catch handles a different failure than the one these contracts pin.
+ */
private static String catchBlock(String source) {
- int catchIndex = requiredIndex(source, "catch (");
- int openBrace = requiredIndex(source, "{", catchIndex);
- return blockAt(source, openBrace);
+ int bodyStart = openingBrace(source, 0);
+ int depth = 0;
+ int bestDepth = Integer.MAX_VALUE;
+ int catchIndex = -1;
+ int i = bodyStart;
+ while (i < source.length()) {
+ int skipped = skipNonCode(source, i);
+ if (skipped > i) {
+ i = skipped;
+ continue;
+ }
+ char current = source.charAt(i);
+ if (current == '{') {
+ depth++;
+ } else if (current == '}') {
+ depth--;
+ if (depth == 0) {
+ break;
+ }
+ } else if (current == 'c' && depth < bestDepth && source.startsWith("catch (", i)) {
+ bestDepth = depth;
+ catchIndex = i;
+ }
+ i++;
+ }
+ assertTrue("Missing source contract token: catch (", catchIndex >= 0);
+ return blockAt(source, openingBrace(source, catchIndex));
}
private static String blockAt(String source, int openBrace) {
return source.substring(openBrace, matchingBrace(source, openBrace) + 1);
}
+ private static int openingBrace(String source, int start) {
+ int i = start;
+ while (i < source.length()) {
+ int skipped = skipNonCode(source, i);
+ if (skipped > i) {
+ i = skipped;
+ continue;
+ }
+ if (source.charAt(i) == '{') {
+ return i;
+ }
+ i++;
+ }
+ throw new IllegalArgumentException("No source block after offset " + start);
+ }
+
private static int matchingBrace(String source, int openBrace) {
int depth = 0;
- boolean quoted = false;
- boolean character = false;
- boolean escaped = false;
- for (int i = openBrace; i < source.length(); i++) {
+ int i = openBrace;
+ while (i < source.length()) {
+ int skipped = skipNonCode(source, i);
+ if (skipped > i) {
+ i = skipped;
+ continue;
+ }
char current = source.charAt(i);
- if (escaped) {
- escaped = false;
- continue;
- }
- if ((quoted || character) && current == '\\') {
- escaped = true;
- continue;
- }
- if (!character && current == '"') {
- quoted = !quoted;
- continue;
- }
- if (!quoted && current == '\'') {
- character = !character;
- continue;
- }
- if (quoted || character) {
- continue;
- }
if (current == '{') {
depth++;
} else if (current == '}') {
@@ -326,10 +355,54 @@ public class ModdedLifecycleFailureContractTest {
return i;
}
}
+ i++;
}
throw new IllegalArgumentException("Unclosed source block");
}
+ /**
+ * Advances past a comment, string, char or text block starting at the index, otherwise returns
+ * the index unchanged. Comments must be skipped: an apostrophe in prose ("generator's") would
+ * otherwise open a char literal and swallow the rest of the file.
+ */
+ private static int skipNonCode(String source, int index) {
+ char current = source.charAt(index);
+ if (current == '/' && index + 1 < source.length()) {
+ char next = source.charAt(index + 1);
+ if (next == '/') {
+ int end = source.indexOf('\n', index);
+ return end < 0 ? source.length() : end + 1;
+ }
+ if (next == '*') {
+ int end = source.indexOf("*/", index + 2);
+ return end < 0 ? source.length() : end + 2;
+ }
+ return index;
+ }
+ if (current == '"' && source.startsWith("\"\"\"", index)) {
+ int end = source.indexOf("\"\"\"", index + 3);
+ return end < 0 ? source.length() : end + 3;
+ }
+ if (current == '"' || current == '\'') {
+ return endOfLiteral(source, index, current);
+ }
+ return index;
+ }
+
+ private static int endOfLiteral(String source, int index, char terminator) {
+ for (int i = index + 1; i < source.length(); i++) {
+ char current = source.charAt(i);
+ if (current == '\\') {
+ i++;
+ continue;
+ }
+ if (current == terminator) {
+ return i + 1;
+ }
+ }
+ return source.length();
+ }
+
private static int occurrences(String source, String needle) {
int count = 0;
int offset = 0;
diff --git a/core/src/main/java/art/arcane/iris/core/IrisWorlds.java b/core/src/main/java/art/arcane/iris/core/IrisWorlds.java
index 48504a39e..0b7dcbd4d 100644
--- a/core/src/main/java/art/arcane/iris/core/IrisWorlds.java
+++ b/core/src/main/java/art/arcane/iris/core/IrisWorlds.java
@@ -35,6 +35,8 @@ import java.util.Optional;
import java.util.stream.Stream;
public class IrisWorlds {
+ private static final String IRIS_GENERATOR_NAME = "iris";
+ private static final String IRIS_GENERATOR_PREFIX = "iris:";
private static final AtomicCache cache = new AtomicCache<>();
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final Type TYPE = TypeToken.getParameterized(KMap.class, String.class, String.class).getType();
@@ -262,16 +264,10 @@ public class IrisWorlds {
if (worlds == null) return new KMap<>();
KMap result = new KMap<>();
+ String defaultWorldType = IrisSettings.get().getGenerator().getDefaultWorldType();
for (String world : worlds.getKeys(false)) {
- String gen = worlds.getString(world + ".generator");
- if (gen == null) continue;
-
- String loadKey;
- if (gen.equalsIgnoreCase("iris")) {
- loadKey = IrisSettings.get().getGenerator().getDefaultWorldType();
- } else if (gen.startsWith("Iris:")) {
- loadKey = gen.substring(5);
- } else continue;
+ String loadKey = generatorLoadKey(worlds.getString(world + ".generator"), defaultWorldType);
+ if (loadKey == null) continue;
result.put(world, loadKey);
}
@@ -279,6 +275,22 @@ public class IrisWorlds {
return filterBukkitWorldsByStorage(levelRoot, result);
}
+ /**
+ * Maps a bukkit.yml generator string onto the Iris pack it selects, or null when the string is
+ * not Iris. Bukkit matches generator plugin names case-insensitively, so the prefix does too.
+ */
+ static String generatorLoadKey(String generator, String defaultWorldType) {
+ if (generator == null) return null;
+ if (generator.equalsIgnoreCase(IRIS_GENERATOR_NAME)) return defaultWorldType;
+
+ int prefixLength = IRIS_GENERATOR_PREFIX.length();
+ if (generator.length() > prefixLength
+ && generator.regionMatches(true, 0, IRIS_GENERATOR_PREFIX, 0, prefixLength)) {
+ return generator.substring(prefixLength);
+ }
+ return null;
+ }
+
private Optional packRoot(String worldIdentity) {
NamespacedKey worldKey = WorldIdentity.parse(worldIdentity);
Path worldContainer = levelRoot.getParent();
diff --git a/core/src/main/resources/languages/de_DE.json b/core/src/main/resources/languages/de_DE.json
index 8f5a91095..e6f32e4a3 100644
--- a/core/src/main/resources/languages/de_DE.json
+++ b/core/src/main/resources/languages/de_DE.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Dieser Befehl kann von diesem Ursprung aus nicht ausgeführt werden.",
"director.runtime.error.unknown_parameter": "Unbekannter Parameterschlüssel: {key}",
"director.runtime.error.unexpected_argument": "Unerwartetes Argument \"{argument}\". Optionale Parameter müssen als Schlüssel angegeben werden, z. B. seed=123",
+ "director.runtime.error.unclosed_group": "Fehlende schließende \"]\" für Parameter {key}",
"director.runtime.error.conversion_failed": "\"{value}\" kann für {parameter} nicht in {type} konvertiert werden",
"director.runtime.error.default_parse_failed": "Der Standardwert für Parameter {parameter} kann nicht gelesen werden",
"director.runtime.error.missing_argument": "Fehlendes Argument \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/es_ES.json b/core/src/main/resources/languages/es_ES.json
index 7983cbaa7..5aead5475 100644
--- a/core/src/main/resources/languages/es_ES.json
+++ b/core/src/main/resources/languages/es_ES.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Este comando no se puede ejecutar desde este origen.",
"director.runtime.error.unknown_parameter": "Clave de parámetro desconocida: {key}",
"director.runtime.error.unexpected_argument": "Argumento inesperado \"{argument}\". Los parámetros opcionales deben especificarse con clave, p. ej. seed=123",
+ "director.runtime.error.unclosed_group": "Falta el corchete de cierre \"]\" para el parámetro {key}",
"director.runtime.error.conversion_failed": "No se puede convertir \"{value}\" a {type} para {parameter}",
"director.runtime.error.default_parse_failed": "No se puede analizar el valor predeterminado del parámetro {parameter}",
"director.runtime.error.missing_argument": "Falta el argumento \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/fi_FI.json b/core/src/main/resources/languages/fi_FI.json
index 4b9577a0a..e009ab8a5 100644
--- a/core/src/main/resources/languages/fi_FI.json
+++ b/core/src/main/resources/languages/fi_FI.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Tätä komentoa ei voi suorittaa tästä lähteestä.",
"director.runtime.error.unknown_parameter": "Tuntematon parametriavain: {key}",
"director.runtime.error.unexpected_argument": "Odottamaton argumentti \"{argument}\". Valinnaiset parametrit on annettava avaimella, esim. seed=123",
+ "director.runtime.error.unclosed_group": "Parametrilta {key} puuttuu sulkeva \"]\"",
"director.runtime.error.conversion_failed": "Arvoa \"{value}\" ei voi muuntaa tyypiksi {type} parametrille {parameter}",
"director.runtime.error.default_parse_failed": "Parametrin {parameter} oletusarvoa ei voi jäsentää",
"director.runtime.error.missing_argument": "Puuttuva argumentti \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/fr_FR.json b/core/src/main/resources/languages/fr_FR.json
index 7dab73106..ebf7508a3 100644
--- a/core/src/main/resources/languages/fr_FR.json
+++ b/core/src/main/resources/languages/fr_FR.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Cette commande ne peut pas être exécutée depuis cette origine.",
"director.runtime.error.unknown_parameter": "Clé de paramètre inconnue : {key}",
"director.runtime.error.unexpected_argument": "Argument inattendu \"{argument}\". Les paramètres facultatifs doivent être nommés, par ex. seed=123",
+ "director.runtime.error.unclosed_group": "Crochet fermant \"]\" manquant pour le paramètre {key}",
"director.runtime.error.conversion_failed": "Impossible de convertir \"{value}\" en {type} pour {parameter}",
"director.runtime.error.default_parse_failed": "Impossible d'analyser la valeur par défaut du paramètre {parameter}",
"director.runtime.error.missing_argument": "Argument manquant \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/he_IL.json b/core/src/main/resources/languages/he_IL.json
index ddde4e232..6c9688837 100644
--- a/core/src/main/resources/languages/he_IL.json
+++ b/core/src/main/resources/languages/he_IL.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "לא ניתן להריץ פקודה זו ממקור זה.",
"director.runtime.error.unknown_parameter": "מפתח פרמטר לא ידוע: {key}",
"director.runtime.error.unexpected_argument": "ארגומנט לא צפוי \"{argument}\". פרמטרים אופציונליים חייבים להינתן עם מפתח, לדוגמה seed=123",
+ "director.runtime.error.unclosed_group": "חסר סוגר מרובע סוגר \"]\" עבור הפרמטר {key}",
"director.runtime.error.conversion_failed": "לא ניתן להמיר את \"{value}\" ל-{type} עבור {parameter}",
"director.runtime.error.default_parse_failed": "לא ניתן לנתח את ערך ברירת המחדל של הפרמטר {parameter}",
"director.runtime.error.missing_argument": "חסר ארגומנט \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/it_IT.json b/core/src/main/resources/languages/it_IT.json
index 07a354a0c..e06719449 100644
--- a/core/src/main/resources/languages/it_IT.json
+++ b/core/src/main/resources/languages/it_IT.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Questo comando non può essere eseguito da questa origine.",
"director.runtime.error.unknown_parameter": "Chiave di parametro sconosciuta: {key}",
"director.runtime.error.unexpected_argument": "Argomento imprevisto \"{argument}\". I parametri opzionali devono essere specificati con una chiave, ad es. seed=123",
+ "director.runtime.error.unclosed_group": "Manca la parentesi quadra di chiusura \"]\" per il parametro {key}",
"director.runtime.error.conversion_failed": "Impossibile convertire \"{value}\" in {type} per {parameter}",
"director.runtime.error.default_parse_failed": "Impossibile analizzare il valore predefinito del parametro {parameter}",
"director.runtime.error.missing_argument": "Argomento mancante \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/ja-JP.json b/core/src/main/resources/languages/ja-JP.json
index e842a357b..57a842e32 100644
--- a/core/src/main/resources/languages/ja-JP.json
+++ b/core/src/main/resources/languages/ja-JP.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "この実行元からはコマンドを実行できません。",
"director.runtime.error.unknown_parameter": "不明なパラメーターキー: {key}",
"director.runtime.error.unexpected_argument": "予期しない引数 \"{argument}\"。オプションのパラメーターはキー付きで指定してください。例: seed=123",
+ "director.runtime.error.unclosed_group": "パラメーター {key} の閉じ角括弧 \"]\" がありません",
"director.runtime.error.conversion_failed": "\"{value}\" を {parameter} 用の {type} に変換できません",
"director.runtime.error.default_parse_failed": "パラメーター {parameter} のデフォルト値を解析できません",
"director.runtime.error.missing_argument": "引数 \"{parameter}\" ({type}) が必要です",
diff --git a/core/src/main/resources/languages/ko_KR.json b/core/src/main/resources/languages/ko_KR.json
index 6f2c3ae7d..b7558331c 100644
--- a/core/src/main/resources/languages/ko_KR.json
+++ b/core/src/main/resources/languages/ko_KR.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "이 실행 위치에서는 이 명령어를 실행할 수 없습니다.",
"director.runtime.error.unknown_parameter": "알 수 없는 매개변수 키: {key}",
"director.runtime.error.unexpected_argument": "예상하지 못한 인수 \"{argument}\". 선택적 매개변수는 키와 함께 지정해야 합니다. 예: seed=123",
+ "director.runtime.error.unclosed_group": "매개변수 {key}에 닫는 대괄호 \"]\"가 없습니다",
"director.runtime.error.conversion_failed": "\"{value}\" 값을 {parameter}용 {type} 형식으로 변환할 수 없습니다",
"director.runtime.error.default_parse_failed": "매개변수 {parameter}의 기본값을 분석할 수 없습니다",
"director.runtime.error.missing_argument": "인수 \"{parameter}\" ({type})가 필요합니다",
diff --git a/core/src/main/resources/languages/lt_LT.json b/core/src/main/resources/languages/lt_LT.json
index 2796b75d3..44d5798fd 100644
--- a/core/src/main/resources/languages/lt_LT.json
+++ b/core/src/main/resources/languages/lt_LT.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Šios komandos negalima vykdyti iš šio šaltinio.",
"director.runtime.error.unknown_parameter": "Nežinomas parametro raktas: {key}",
"director.runtime.error.unexpected_argument": "Netikėtas argumentas \"{argument}\". Pasirenkami parametrai turi būti nurodyti su raktu, pvz. seed=123",
+ "director.runtime.error.unclosed_group": "Parametrui {key} trūksta uždaromojo skliausto \"]\"",
"director.runtime.error.conversion_failed": "Reikšmės \"{value}\" nepavyko konvertuoti į {type} parametrui {parameter}",
"director.runtime.error.default_parse_failed": "Nepavyko nuskaityti parametro {parameter} numatytosios reikšmės",
"director.runtime.error.missing_argument": "Trūksta argumento \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/nl_NL.json b/core/src/main/resources/languages/nl_NL.json
index ef9146cc3..5a45f9e8b 100644
--- a/core/src/main/resources/languages/nl_NL.json
+++ b/core/src/main/resources/languages/nl_NL.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Deze opdracht kan niet vanuit deze bron worden uitgevoerd.",
"director.runtime.error.unknown_parameter": "Onbekende parametersleutel: {key}",
"director.runtime.error.unexpected_argument": "Onverwacht argument \"{argument}\". Optionele parameters moeten met een sleutel worden opgegeven, bijv. seed=123",
+ "director.runtime.error.unclosed_group": "Ontbrekend afsluitend haakje \"]\" voor parameter {key}",
"director.runtime.error.conversion_failed": "Kan \"{value}\" voor {parameter} niet naar {type} converteren",
"director.runtime.error.default_parse_failed": "Kan de standaardwaarde voor parameter {parameter} niet verwerken",
"director.runtime.error.missing_argument": "Ontbrekend argument \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/pl_PL.json b/core/src/main/resources/languages/pl_PL.json
index 64426952d..d3cd67754 100644
--- a/core/src/main/resources/languages/pl_PL.json
+++ b/core/src/main/resources/languages/pl_PL.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Tego polecenia nie można wykonać z tego źródła.",
"director.runtime.error.unknown_parameter": "Nieznany klucz parametru: {key}",
"director.runtime.error.unexpected_argument": "Nieoczekiwany argument \"{argument}\". Parametry opcjonalne muszą mieć klucz, np. seed=123",
+ "director.runtime.error.unclosed_group": "Brak zamykającego nawiasu \"]\" dla parametru {key}",
"director.runtime.error.conversion_failed": "Nie można przekonwertować \"{value}\" na {type} dla {parameter}",
"director.runtime.error.default_parse_failed": "Nie można odczytać wartości domyślnej parametru {parameter}",
"director.runtime.error.missing_argument": "Brak argumentu \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/pt_PT.json b/core/src/main/resources/languages/pt_PT.json
index 92414fe6f..bfe6b1616 100644
--- a/core/src/main/resources/languages/pt_PT.json
+++ b/core/src/main/resources/languages/pt_PT.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Este comando não pode ser executado a partir desta origem.",
"director.runtime.error.unknown_parameter": "Chave de parâmetro desconhecida: {key}",
"director.runtime.error.unexpected_argument": "Argumento inesperado \"{argument}\". Os parâmetros opcionais devem ser indicados por chave, por ex. seed=123",
+ "director.runtime.error.unclosed_group": "Falta o parêntese reto de fecho \"]\" para o parâmetro {key}",
"director.runtime.error.conversion_failed": "Não foi possível converter \"{value}\" em {type} para {parameter}",
"director.runtime.error.default_parse_failed": "Não foi possível interpretar o valor predefinido do parâmetro {parameter}",
"director.runtime.error.missing_argument": "Falta o argumento \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/ru_RU.json b/core/src/main/resources/languages/ru_RU.json
index 2f680468f..c33605e23 100644
--- a/core/src/main/resources/languages/ru_RU.json
+++ b/core/src/main/resources/languages/ru_RU.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Эту команду нельзя выполнить из данного источника.",
"director.runtime.error.unknown_parameter": "Неизвестный ключ параметра: {key}",
"director.runtime.error.unexpected_argument": "Неожиданный аргумент \"{argument}\". Необязательные параметры должны задаваться с ключом, например seed=123",
+ "director.runtime.error.unclosed_group": "Отсутствует закрывающая скобка \"]\" для параметра {key}",
"director.runtime.error.conversion_failed": "Невозможно преобразовать \"{value}\" в {type} для {parameter}",
"director.runtime.error.default_parse_failed": "Невозможно разобрать значение по умолчанию параметра {parameter}",
"director.runtime.error.missing_argument": "Отсутствует аргумент \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/tr_TR.json b/core/src/main/resources/languages/tr_TR.json
index 2c7fe0b50..723c3677b 100644
--- a/core/src/main/resources/languages/tr_TR.json
+++ b/core/src/main/resources/languages/tr_TR.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Bu komut bu kaynaktan çalıştırılamaz.",
"director.runtime.error.unknown_parameter": "Bilinmeyen parametre anahtarı: {key}",
"director.runtime.error.unexpected_argument": "Beklenmeyen bağımsız değişken \"{argument}\". İsteğe bağlı parametreler anahtarla belirtilmelidir, ör. seed=123",
+ "director.runtime.error.unclosed_group": "{key} parametresi için kapanış köşeli parantezi \"]\" eksik",
"director.runtime.error.conversion_failed": "\"{value}\", {parameter} için {type} türüne dönüştürülemiyor",
"director.runtime.error.default_parse_failed": "{parameter} parametresinin varsayılan değeri ayrıştırılamıyor",
"director.runtime.error.missing_argument": "Eksik bağımsız değişken \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/vi_VI.json b/core/src/main/resources/languages/vi_VI.json
index bcd8cdd30..3d2ffa85d 100644
--- a/core/src/main/resources/languages/vi_VI.json
+++ b/core/src/main/resources/languages/vi_VI.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "Không thể chạy lệnh này từ nguồn này.",
"director.runtime.error.unknown_parameter": "Khóa tham số không xác định: {key}",
"director.runtime.error.unexpected_argument": "Đối số không mong đợi \"{argument}\". Các tham số tùy chọn phải được chỉ định bằng khóa, ví dụ seed=123",
+ "director.runtime.error.unclosed_group": "Thiếu dấu ngoặc vuông đóng \"]\" cho tham số {key}",
"director.runtime.error.conversion_failed": "Không thể chuyển \"{value}\" thành {type} cho {parameter}",
"director.runtime.error.default_parse_failed": "Không thể phân tích giá trị mặc định của tham số {parameter}",
"director.runtime.error.missing_argument": "Thiếu đối số \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/zh_CN.json b/core/src/main/resources/languages/zh_CN.json
index 8df60edaf..47a7b0f87 100644
--- a/core/src/main/resources/languages/zh_CN.json
+++ b/core/src/main/resources/languages/zh_CN.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "无法从此来源运行该命令。",
"director.runtime.error.unknown_parameter": "未知参数键: {key}",
"director.runtime.error.unexpected_argument": "意外参数 \"{argument}\"。可选参数必须使用键指定,例如 seed=123",
+ "director.runtime.error.unclosed_group": "参数 {key} 缺少右方括号 \"]\"",
"director.runtime.error.conversion_failed": "无法将 \"{value}\" 转换为 {parameter} 所需的 {type}",
"director.runtime.error.default_parse_failed": "无法解析参数 {parameter} 的默认值",
"director.runtime.error.missing_argument": "缺少参数 \"{parameter}\" ({type})",
diff --git a/core/src/main/resources/languages/zh_TW.json b/core/src/main/resources/languages/zh_TW.json
index 25ec75286..6524911db 100644
--- a/core/src/main/resources/languages/zh_TW.json
+++ b/core/src/main/resources/languages/zh_TW.json
@@ -19,6 +19,7 @@
"director.runtime.error.invalid_origin": "無法從此來源執行該指令。",
"director.runtime.error.unknown_parameter": "未知參數鍵: {key}",
"director.runtime.error.unexpected_argument": "意外參數 \"{argument}\"。選用參數必須使用鍵指定,例如 seed=123",
+ "director.runtime.error.unclosed_group": "參數 {key} 缺少右方括號 \"]\"",
"director.runtime.error.conversion_failed": "無法將 \"{value}\" 轉換為 {parameter} 所需的 {type}",
"director.runtime.error.default_parse_failed": "無法解析參數 {parameter} 的預設值",
"director.runtime.error.missing_argument": "缺少參數 \"{parameter}\" ({type})",
diff --git a/core/src/test/java/art/arcane/iris/core/IrisWorldsTest.java b/core/src/test/java/art/arcane/iris/core/IrisWorldsTest.java
index f1442bec6..32e88c8c0 100644
--- a/core/src/test/java/art/arcane/iris/core/IrisWorldsTest.java
+++ b/core/src/test/java/art/arcane/iris/core/IrisWorldsTest.java
@@ -11,6 +11,7 @@ import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
public class IrisWorldsTest {
@Rule
@@ -53,6 +54,18 @@ public class IrisWorldsTest {
assertEquals(Set.of("archive_iris_foreign"), other.keySet());
}
+ @Test
+ public void bukkitGeneratorStringsAreMatchedCaseInsensitively() {
+ assertEquals("pack", IrisWorlds.generatorLoadKey("Iris:pack", "overworld"));
+ assertEquals("pack", IrisWorlds.generatorLoadKey("iris:pack", "overworld"));
+ assertEquals("pack", IrisWorlds.generatorLoadKey("IRIS:pack", "overworld"));
+ assertEquals("overworld", IrisWorlds.generatorLoadKey("Iris", "overworld"));
+ assertEquals("overworld", IrisWorlds.generatorLoadKey("iris", "overworld"));
+ assertNull(IrisWorlds.generatorLoadKey("VoidGen", "overworld"));
+ assertNull(IrisWorlds.generatorLoadKey("Irissy:pack", "overworld"));
+ assertNull(IrisWorlds.generatorLoadKey(null, "overworld"));
+ }
+
@Test
public void bukkitWorldFilteringRecognizesCurrentCraftBukkitConfiguredStorage() throws Exception {
Path worldContainer = temporaryFolder.newFolder("configured-server").toPath();