This commit is contained in:
Brian Neumann-Fopiano
2026-07-18 21:48:52 -04:00
parent 1d194e880b
commit d76dadec30
13 changed files with 160 additions and 68 deletions
@@ -13,6 +13,8 @@ import java.util.Objects;
import java.util.Optional;
public final class IrisWorldStorage {
private static final String IRIS_NAMESPACE = "iris";
private IrisWorldStorage() {
}
@@ -36,11 +38,11 @@ public final class IrisWorldStorage {
return dimensionRoot.getAbsoluteFile();
}
public static NamespacedKey keyFromLegacyName(String worldName) {
return keyFromLegacyName(worldName, levelRoot().getName());
public static NamespacedKey keyFromName(String worldName) {
return keyFromName(worldName, levelRoot().getName());
}
static NamespacedKey keyFromLegacyName(String worldName, String levelName) {
static NamespacedKey keyFromName(String worldName, String levelName) {
String name = Objects.requireNonNull(worldName, "worldName").trim();
String mainLevelName = Objects.requireNonNull(levelName, "levelName").trim();
if (name.isEmpty()) {
@@ -57,11 +59,34 @@ public final class IrisWorldStorage {
}
String key = name.toLowerCase(Locale.ENGLISH).replace(' ', '_');
return NamespacedKey.minecraft(key);
return new NamespacedKey(IRIS_NAMESPACE, key);
}
public static String logicalName(WorldInfo world) {
return logicalName(WorldIdentity.key(world));
}
public static String logicalName(NamespacedKey key) {
return logicalName(key, levelRoot().getName());
}
static String logicalName(NamespacedKey key, String levelName) {
NamespacedKey worldKey = Objects.requireNonNull(key, "key");
String mainLevelName = Objects.requireNonNull(levelName, "levelName").trim();
if (NamespacedKey.minecraft("overworld").equals(worldKey)) {
return mainLevelName;
}
if (NamespacedKey.minecraft("the_nether").equals(worldKey)) {
return mainLevelName + "_nether";
}
if (NamespacedKey.minecraft("the_end").equals(worldKey)) {
return mainLevelName + "_the_end";
}
return worldKey.getKey();
}
public static File dimensionRoot(String worldName) {
return dimensionRoot(keyFromLegacyName(worldName));
return dimensionRoot(keyFromName(worldName));
}
public static File dimensionRoot(WorldInfo world) {
@@ -35,14 +35,8 @@ public class IrisWorlds {
private IrisWorlds(KMap<String, String> worlds) {
this.worlds = new KMap<>();
worlds.forEach((identity, type) -> {
String normalizedIdentity = migrateLoadedIdentity(identity);
this.worlds.put(normalizedIdentity, type);
if (!normalizedIdentity.equals(identity)) {
dirty = true;
}
});
readBukkitWorlds().forEach((name, type) -> put0(IrisWorldStorage.keyFromLegacyName(name).toString(), type));
worlds.forEach((identity, type) -> this.worlds.put(WorldIdentity.parse(identity).toString(), type));
readBukkitWorlds().forEach((name, type) -> put0(IrisWorldStorage.keyFromName(name).toString(), type));
save();
}
@@ -82,7 +76,7 @@ public class IrisWorlds {
public KMap<String, String> getWorlds() {
clean();
KMap<String, String> result = new KMap<>();
readBukkitWorlds().forEach((name, type) -> result.put(IrisWorldStorage.keyFromLegacyName(name).toString(), type));
readBukkitWorlds().forEach((name, type) -> result.put(IrisWorldStorage.keyFromName(name).toString(), type));
return result.put(worlds);
}
@@ -174,12 +168,4 @@ public class IrisWorlds {
}
return dimension;
}
private static String migrateLoadedIdentity(String identity) {
try {
return WorldIdentity.parse(identity).toString();
} catch (IllegalArgumentException e) {
return IrisWorldStorage.keyFromLegacyName(identity).toString();
}
}
}
@@ -76,7 +76,9 @@ public final class StudioOpenCoordinator {
}
World world = BukkitWorldBinding.world(provider.getTarget().getWorld());
String worldName = world == null ? provider.getTarget().getWorld().name() : world.getName();
String worldName = world == null
? IrisWorldStorage.logicalName(WorldIdentity.parse(provider.getTarget().getWorld().identity()))
: IrisWorldStorage.logicalName(world);
try {
return closeWorld(provider, worldName, world, true, project);
} catch (Throwable e) {
@@ -330,7 +332,7 @@ public final class StudioOpenCoordinator {
}
for (String familyWorldName : TransientWorldCleanupSupport.worldFamilyNames(worldName)) {
World familyWorld = WorldIdentity.resolve(IrisWorldStorage.keyFromLegacyName(familyWorldName)).orElse(null);
World familyWorld = WorldIdentity.resolve(IrisWorldStorage.keyFromName(familyWorldName)).orElse(null);
if (familyWorld == null) {
continue;
}
@@ -387,7 +389,7 @@ public final class StudioOpenCoordinator {
}
for (String staleWorldName : staleWorldNames) {
if (WorldIdentity.resolve(IrisWorldStorage.keyFromLegacyName(staleWorldName)).isPresent()) {
if (WorldIdentity.resolve(IrisWorldStorage.keyFromName(staleWorldName)).isPresent()) {
continue;
}
@@ -481,7 +483,7 @@ public final class StudioOpenCoordinator {
}
for (String familyWorldName : TransientWorldCleanupSupport.worldFamilyNames(worldName)) {
if (WorldIdentity.resolve(IrisWorldStorage.keyFromLegacyName(familyWorldName)).isPresent()) {
if (WorldIdentity.resolve(IrisWorldStorage.keyFromName(familyWorldName)).isPresent()) {
return true;
}
}
@@ -39,6 +39,7 @@ import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
import art.arcane.iris.platform.bukkit.BukkitPlatform;
import art.arcane.volmlib.util.collection.KMap;
import art.arcane.volmlib.util.bukkit.WorldIdentity;
import art.arcane.volmlib.util.exceptions.IrisException;
import art.arcane.volmlib.util.io.IO;
import art.arcane.volmlib.util.json.JSONException;
@@ -93,7 +94,8 @@ public class StudioSVC implements IrisService {
if (activeProject != null) {
PlatformChunkGenerator activeProvider = activeProject.getActiveProvider();
if (activeProvider != null) {
String activeWorldName = activeProvider.getTarget().getWorld().name();
String activeWorldName = IrisWorldStorage.logicalName(
WorldIdentity.parse(activeProvider.getTarget().getWorld().identity()));
if (activeWorldName != null && !activeWorldName.isBlank()) {
worldNamesToDelete.add(activeWorldName);
}
@@ -105,7 +107,7 @@ public class StudioSVC implements IrisService {
continue;
}
worldNamesToDelete.add(i.getName());
worldNamesToDelete.add(IrisWorldStorage.logicalName(i));
PlatformChunkGenerator generator = IrisToolbelt.access(i);
if (!stopping) {
destroyStudioWorld(i, generator);
@@ -422,7 +424,7 @@ public class StudioSVC implements IrisService {
IrisLogging.reportError("Failed to unload studio world \"" + world.getName() + "\" during shutdown cleanup.", e);
}
deleteTransientStudioFolders(world.getName());
deleteTransientStudioFolders(IrisWorldStorage.logicalName(world));
}
private void deleteTransientStudioFolders(String worldName) {
@@ -294,11 +294,11 @@ public final class FeatureImporter {
static World createScratchWorld(VolmitSender sender) {
try {
World existing = WorldIdentity.resolve(IrisWorldStorage.keyFromLegacyName(SCRATCH_WORLD_NAME)).orElse(null);
World existing = WorldIdentity.resolve(IrisWorldStorage.keyFromName(SCRATCH_WORLD_NAME)).orElse(null);
if (existing != null) {
return existing;
}
WorldCreator creator = WorldCreator.ofKey(IrisWorldStorage.keyFromLegacyName(SCRATCH_WORLD_NAME))
WorldCreator creator = WorldCreator.ofKey(IrisWorldStorage.keyFromName(SCRATCH_WORLD_NAME))
.environment(World.Environment.NORMAL)
.type(WorldType.FLAT)
.generateStructures(false);
@@ -155,6 +155,7 @@ public class IrisCreator {
if (Bukkit.isPrimaryThread()) {
throw new IrisException("You cannot invoke create() on the main thread.");
}
name = IrisWorldStorage.logicalName(IrisWorldStorage.keyFromName(name));
long createStart = System.currentTimeMillis();
reportStudioProgress(0.02D, "resolve_dimension");
@@ -323,7 +324,7 @@ public class IrisCreator {
IrisLogging.reportError("World \"" + world.getName()
+ "\" was created, but automatic teleport failed for player \"" + player.getName() + "\".", throwable);
J.runEntity(player, () -> new VolmitSender(player).sendMessage(C.YELLOW
+ "The world was created, but automatic teleport failed. Try /iris teleport world=" + world.getName()));
+ "The world was created, but automatic teleport failed. Try /iris teleport world=" + IrisWorldStorage.logicalName(world)));
}
private void reportStudioProgress(double progress, String stage) {
@@ -150,7 +150,7 @@ public class IrisPackBenchmarking {
}
private static World benchmarkWorld() {
return WorldIdentity.resolve(IrisWorldStorage.keyFromLegacyName("benchmark")).orElse(null);
return WorldIdentity.resolve(IrisWorldStorage.keyFromName("benchmark")).orElse(null);
}
private double calculateAverage(KList<Integer> list) {
@@ -25,6 +25,7 @@ import art.arcane.iris.spi.IrisPlatforms;
import art.arcane.iris.platform.bukkit.BukkitPlatform;
import art.arcane.iris.core.IrisRuntimeSchedulerMode;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.core.IrisWorldStorage;
import art.arcane.iris.core.gui.PregeneratorJob;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.core.pregenerator.PregenPerformanceProfile;
@@ -531,7 +532,7 @@ public class IrisToolbelt {
}
public static boolean removeWorld(World world) throws IOException {
return IrisCreator.removeFromBukkitYml(world.getName());
return IrisCreator.removeFromBukkitYml(IrisWorldStorage.logicalName(world));
}
record PackReference(String pack, String dimension, boolean explicitDimension) {
@@ -76,7 +76,7 @@ public class IrisWorldCreator {
public WorldCreator create() {
IrisDimension dim = dimension == null ? IrisData.loadAnyDimension(dimensionName, null) : dimension;
NamespacedKey worldKey = IrisWorldStorage.keyFromLegacyName(name);
NamespacedKey worldKey = IrisWorldStorage.keyFromName(name);
World.Environment environment = findEnvironment();
IrisWorld w = IrisWorld.builder()
@@ -34,11 +34,19 @@ public class IrisWorldStorageTest {
}
@Test
public void mapsLegacyBukkitNamesToPaperKeys() {
assertEquals(NamespacedKey.minecraft("overworld"), IrisWorldStorage.keyFromLegacyName("world", "world"));
assertEquals(NamespacedKey.minecraft("the_nether"), IrisWorldStorage.keyFromLegacyName("world_nether", "world"));
assertEquals(NamespacedKey.minecraft("the_end"), IrisWorldStorage.keyFromLegacyName("world_the_end", "world"));
assertEquals(NamespacedKey.minecraft("iris_world"), IrisWorldStorage.keyFromLegacyName("Iris World", "world"));
public void mapsIrisWorldNamesToOwnedPaperKeys() {
assertEquals(NamespacedKey.minecraft("overworld"), IrisWorldStorage.keyFromName("world", "world"));
assertEquals(NamespacedKey.minecraft("the_nether"), IrisWorldStorage.keyFromName("world_nether", "world"));
assertEquals(NamespacedKey.minecraft("the_end"), IrisWorldStorage.keyFromName("world_the_end", "world"));
assertEquals(new NamespacedKey("iris", "iris_world"), IrisWorldStorage.keyFromName("Iris World", "world"));
}
@Test
public void mapsOwnedPaperKeysBackToLogicalWorldNames() {
assertEquals("world", IrisWorldStorage.logicalName(NamespacedKey.minecraft("overworld"), "world"));
assertEquals("world_nether", IrisWorldStorage.logicalName(NamespacedKey.minecraft("the_nether"), "world"));
assertEquals("world_the_end", IrisWorldStorage.logicalName(NamespacedKey.minecraft("the_end"), "world"));
assertEquals("iris_world", IrisWorldStorage.logicalName(new NamespacedKey("iris", "iris_world"), "world"));
}
@Test
@@ -0,0 +1,64 @@
package art.arcane.iris.util.common.director.handlers;
import art.arcane.volmlib.util.director.exceptions.DirectorParsingException;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.junit.Test;
import java.lang.reflect.Proxy;
import java.util.List;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThrows;
public class WorldHandlerTest {
@Test
public void resolvesOwnedIrisWorldByLogicalNameAndCanonicalKey() throws DirectorParsingException {
World world = world("iris_irisworld", new NamespacedKey("iris", "irisworld"));
WorldHandler handler = new TestWorldHandler(List.of(world));
assertSame(world, handler.parse("irisworld", false));
assertSame(world, handler.parse("iris:irisworld", false));
assertThrows(DirectorParsingException.class, () -> handler.parse("minecraft:irisworld", false));
}
private static World world(String name, NamespacedKey key) {
return (World) Proxy.newProxyInstance(
World.class.getClassLoader(),
new Class<?>[]{World.class},
(proxy, method, arguments) -> switch (method.getName()) {
case "getName" -> name;
case "getKey" -> key;
case "equals" -> proxy == arguments[0];
case "hashCode" -> System.identityHashCode(proxy);
default -> defaultValue(method.getReturnType());
}
);
}
private static Object defaultValue(Class<?> type) {
if (!type.isPrimitive()) {
return null;
}
if (type == boolean.class) {
return false;
}
if (type == char.class) {
return '\0';
}
return 0;
}
private static final class TestWorldHandler extends WorldHandler {
private final List<World> worlds;
private TestWorldHandler(List<World> worlds) {
this.worlds = worlds;
}
@Override
protected List<World> worldOptions() {
return worlds;
}
}
}