mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-25 13:30:08 +00:00
World Changes
This commit is contained in:
1 parent
e42ab6fae6
commit
cd05fd1bca
58 files changed
+668
-313
No files matched your search
@@ -10,9 +10,9 @@ dependencies {
|
|||||||
compileOnly(volmLibCoordinate) {
|
compileOnly(volmLibCoordinate) {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
compileOnly(libs.spigot)
|
compileOnly(libs.paper.api)
|
||||||
testImplementation('junit:junit:4.13.2')
|
testImplementation('junit:junit:4.13.2')
|
||||||
testImplementation(libs.spigot)
|
testImplementation(libs.paper.api)
|
||||||
testImplementation(libs.bstats)
|
testImplementation(libs.bstats)
|
||||||
testImplementation(libs.sentry)
|
testImplementation(libs.sentry)
|
||||||
testImplementation(project(':core'))
|
testImplementation(project(':core'))
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import art.arcane.iris.engine.IrisWorldManager;
|
|||||||
import art.arcane.iris.engine.framework.EngineWorldManagerProvider;
|
import art.arcane.iris.engine.framework.EngineWorldManagerProvider;
|
||||||
import art.arcane.iris.core.splash.IrisSplashComposer;
|
import art.arcane.iris.core.splash.IrisSplashComposer;
|
||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
|
import art.arcane.iris.core.IrisWorldStorage;
|
||||||
import art.arcane.iris.core.IrisWorlds;
|
import art.arcane.iris.core.IrisWorlds;
|
||||||
import art.arcane.iris.core.ServerConfigurator;
|
import art.arcane.iris.core.ServerConfigurator;
|
||||||
import art.arcane.iris.core.datapack.DatapackIngestService;
|
import art.arcane.iris.core.datapack.DatapackIngestService;
|
||||||
@@ -61,6 +62,7 @@ import art.arcane.iris.spi.IrisPlatforms;
|
|||||||
import art.arcane.iris.spi.IrisServices;
|
import art.arcane.iris.spi.IrisServices;
|
||||||
import art.arcane.iris.spi.LogLevel;
|
import art.arcane.iris.spi.LogLevel;
|
||||||
import art.arcane.volmlib.integration.ReloadAware;
|
import art.arcane.volmlib.integration.ReloadAware;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import art.arcane.volmlib.util.collection.KList;
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
import art.arcane.volmlib.util.collection.KMap;
|
import art.arcane.volmlib.util.collection.KMap;
|
||||||
import art.arcane.volmlib.util.exceptions.IrisException;
|
import art.arcane.volmlib.util.exceptions.IrisException;
|
||||||
@@ -88,6 +90,7 @@ import lombok.NonNull;
|
|||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.WorldCreator;
|
import org.bukkit.WorldCreator;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
@@ -590,6 +593,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void enable() {
|
private void enable() {
|
||||||
|
alreadyDrained.set(false);
|
||||||
PaperLibBootstrap.install();
|
PaperLibBootstrap.install();
|
||||||
SimdSupport.install();
|
SimdSupport.install();
|
||||||
services = new KMap<>();
|
services = new KMap<>();
|
||||||
@@ -646,7 +650,6 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
J.ar(this::checkConfigHotload, 60);
|
J.ar(this::checkConfigHotload, 60);
|
||||||
J.sr(this::tickQueue, 0);
|
J.sr(this::tickQueue, 0);
|
||||||
J.s(this::setupPapi);
|
J.s(this::setupPapi);
|
||||||
J.a(ServerConfigurator::configureIfDeferred, 20);
|
|
||||||
J.a(DatapackIngestService::autoIngestOnStartup, 60);
|
J.a(DatapackIngestService::autoIngestOnStartup, 60);
|
||||||
|
|
||||||
autoStartStudio();
|
autoStartStudio();
|
||||||
@@ -668,17 +671,22 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
shutdownHook = new Thread(() -> {
|
shutdownHook = new Thread(() -> {
|
||||||
Bukkit.getWorlds()
|
if (alreadyDrained.compareAndSet(false, true)) {
|
||||||
.stream()
|
try {
|
||||||
.map(IrisToolbelt::access)
|
Bukkit.getWorlds()
|
||||||
.filter(Objects::nonNull)
|
.stream()
|
||||||
.forEach(PlatformChunkGenerator::close);
|
.map(World::getGenerator)
|
||||||
|
.filter(PlatformChunkGenerator.class::isInstance)
|
||||||
|
.map(PlatformChunkGenerator.class::cast)
|
||||||
|
.forEach(PlatformChunkGenerator::close);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.reportError("Failed to close Iris world generators from the JVM shutdown hook.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MultiBurst.burst.close();
|
MultiBurst.burst.close();
|
||||||
MultiBurst.ioBurst.close();
|
MultiBurst.ioBurst.close();
|
||||||
if (services != null) {
|
IrisServices.clear();
|
||||||
services.clear();
|
|
||||||
}
|
|
||||||
}, "Iris-ShutdownHook");
|
}, "Iris-ShutdownHook");
|
||||||
try {
|
try {
|
||||||
Runtime.getRuntime().addShutdownHook(shutdownHook);
|
Runtime.getRuntime().addShutdownHook(shutdownHook);
|
||||||
@@ -692,15 +700,16 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
KList<String> deferredStartupWorlds = new KList<>();
|
KList<String> deferredStartupWorlds = new KList<>();
|
||||||
IrisWorlds.readBukkitWorlds().forEach((s, generator) -> {
|
IrisWorlds.readBukkitWorlds().forEach((s, generator) -> {
|
||||||
try {
|
try {
|
||||||
if (Bukkit.getWorld(s) != null || !filter.test(s)) return;
|
NamespacedKey worldKey = IrisWorldStorage.keyFromLegacyName(s);
|
||||||
|
if (WorldIdentity.resolve(worldKey).isPresent() || !filter.test(s)) return;
|
||||||
|
|
||||||
Iris.info("Loading World: %s | Generator: %s", s, generator);
|
Iris.info("Loading World: %s | Generator: %s", s, generator);
|
||||||
var gen = getDefaultWorldGenerator(s, generator);
|
ChunkGenerator gen = getDefaultWorldGenerator(s, generator);
|
||||||
var dim = loadDimension(s, generator);
|
IrisDimension dim = loadDimension(s, generator);
|
||||||
assert dim != null && gen != null;
|
assert dim != null && gen != null;
|
||||||
|
|
||||||
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
|
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
|
||||||
WorldCreator c = new WorldCreator(s)
|
WorldCreator c = WorldCreator.ofKey(worldKey)
|
||||||
.generator(gen)
|
.generator(gen)
|
||||||
.environment(dim.getEnvironment());
|
.environment(dim.getEnvironment());
|
||||||
Long stagedSeed = IrisWorlds.readBukkitWorldSeed(s);
|
Long stagedSeed = IrisWorlds.readBukkitWorldSeed(s);
|
||||||
@@ -786,7 +795,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LinkedHashMap<String, String> queue = loadPendingWorldDeleteMap();
|
LinkedHashMap<String, String> queue = loadPendingWorldDeleteMap();
|
||||||
for (String transientStudioWorld : TransientWorldCleanupSupport.collectTransientStudioWorldNames(Bukkit.getWorldContainer())) {
|
for (String transientStudioWorld : TransientWorldCleanupSupport.collectTransientStudioWorldNames(IrisWorldStorage.levelRoot())) {
|
||||||
queue.putIfAbsent(transientStudioWorld.toLowerCase(Locale.ROOT), transientStudioWorld);
|
queue.putIfAbsent(transientStudioWorld.toLowerCase(Locale.ROOT), transientStudioWorld);
|
||||||
}
|
}
|
||||||
if (queue.isEmpty()) {
|
if (queue.isEmpty()) {
|
||||||
@@ -800,7 +809,8 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
org.bukkit.World loaded = Bukkit.getWorld(worldName);
|
NamespacedKey worldKey = IrisWorldStorage.keyFromLegacyName(worldName);
|
||||||
|
World loaded = WorldIdentity.resolve(worldKey).orElse(null);
|
||||||
if (loaded != null) {
|
if (loaded != null) {
|
||||||
if (TransientWorldCleanupSupport.isTransientStudioWorldName(worldName)) {
|
if (TransientWorldCleanupSupport.isTransientStudioWorldName(worldName)) {
|
||||||
try {
|
try {
|
||||||
@@ -815,7 +825,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
Iris.reportError("Failed to unload leftover studio world \"" + worldName + "\".", e);
|
Iris.reportError("Failed to unload leftover studio world \"" + worldName + "\".", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Bukkit.getWorld(worldName) != null) {
|
if (WorldIdentity.resolve(worldKey).isPresent()) {
|
||||||
Iris.warn("Studio world \"" + worldName + "\" is still loaded after unload; will retry next startup.");
|
Iris.warn("Studio world \"" + worldName + "\" is still loaded after unload; will retry next startup.");
|
||||||
remaining.put(worldName.toLowerCase(Locale.ROOT), worldName);
|
remaining.put(worldName.toLowerCase(Locale.ROOT), worldName);
|
||||||
continue;
|
continue;
|
||||||
@@ -830,7 +840,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
boolean foundAny = false;
|
boolean foundAny = false;
|
||||||
boolean deletedAll = true;
|
boolean deletedAll = true;
|
||||||
for (String familyWorldName : TransientWorldCleanupSupport.worldFamilyNames(worldName)) {
|
for (String familyWorldName : TransientWorldCleanupSupport.worldFamilyNames(worldName)) {
|
||||||
File worldFolder = new File(Bukkit.getWorldContainer(), familyWorldName);
|
File worldFolder = IrisWorldStorage.dimensionRoot(familyWorldName);
|
||||||
if (!worldFolder.exists()) {
|
if (!worldFolder.exists()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -975,7 +985,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
|
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
if (IrisSafeguard.isForceShutdown()) return;
|
if (IrisSafeguard.isForceShutdown()) return;
|
||||||
if (!alreadyDrained.get()) {
|
if (alreadyDrained.compareAndSet(false, true)) {
|
||||||
drainWorldGenerators("onDisable", 30L);
|
drainWorldGenerators("onDisable", 30L);
|
||||||
}
|
}
|
||||||
if (services != null) {
|
if (services != null) {
|
||||||
@@ -1202,12 +1212,14 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Iris.debug("Assuming IrisDimension: " + dim.getName());
|
Iris.debug("Assuming IrisDimension: " + dim.getName());
|
||||||
|
NamespacedKey worldKey = IrisWorldStorage.keyFromLegacyName(worldName);
|
||||||
|
|
||||||
IrisWorld w = IrisWorld.builder()
|
IrisWorld w = IrisWorld.builder()
|
||||||
|
.key(worldKey)
|
||||||
.name(worldName)
|
.name(worldName)
|
||||||
.seed(1337)
|
.seed(1337)
|
||||||
.environment(dim.getEnvironment())
|
.environment(dim.getEnvironment())
|
||||||
.worldFolder(new File(Bukkit.getWorldContainer(), worldName))
|
.worldFolder(IrisWorldStorage.dimensionRoot(worldKey))
|
||||||
.minHeight(dim.getMinHeight())
|
.minHeight(dim.getMinHeight())
|
||||||
.maxHeight(dim.getMaxHeight())
|
.maxHeight(dim.getMaxHeight())
|
||||||
.build();
|
.build();
|
||||||
@@ -1215,7 +1227,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
Iris.debug("Generator Config: " + w.toString());
|
Iris.debug("Generator Config: " + w.toString());
|
||||||
|
|
||||||
File ff = new File(w.worldFolder(), "iris/pack");
|
File ff = new File(w.worldFolder(), "iris/pack");
|
||||||
var files = ff.listFiles();
|
File[] files = ff.listFiles();
|
||||||
if (files == null || files.length == 0)
|
if (files == null || files.length == 0)
|
||||||
IO.delete(ff);
|
IO.delete(ff);
|
||||||
|
|
||||||
@@ -1263,8 +1275,8 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static IrisDimension loadDimension(@NonNull String worldName, @NonNull String id) {
|
public static IrisDimension loadDimension(@NonNull String worldName, @NonNull String id) {
|
||||||
File pack = new File(Bukkit.getWorldContainer(), String.join(File.separator, worldName, "iris", "pack"));
|
File pack = IrisWorldStorage.packRoot(IrisWorldStorage.keyFromLegacyName(worldName));
|
||||||
var dimension = pack.isDirectory() ? IrisData.get(pack).getDimensionLoader().load(id) : null;
|
IrisDimension dimension = pack.isDirectory() ? IrisData.get(pack).getDimensionLoader().load(id) : null;
|
||||||
if (dimension == null) dimension = IrisData.loadAnyDimension(id, null);
|
if (dimension == null) dimension = IrisData.loadAnyDimension(id, null);
|
||||||
if (dimension == null) {
|
if (dimension == null) {
|
||||||
Iris.warn("Unable to find dimension type " + id + " Looking for online packs...");
|
Iris.warn("Unable to find dimension type " + id + " Looking for online packs...");
|
||||||
|
|||||||
+24
-12
@@ -31,15 +31,19 @@ import art.arcane.iris.util.common.director.DirectorExecutor;
|
|||||||
import art.arcane.iris.util.common.director.specialhandlers.ObjectHandler;
|
import art.arcane.iris.util.common.director.specialhandlers.ObjectHandler;
|
||||||
import art.arcane.iris.util.common.director.specialhandlers.StructureHandler;
|
import art.arcane.iris.util.common.director.specialhandlers.StructureHandler;
|
||||||
import art.arcane.iris.util.common.format.C;
|
import art.arcane.iris.util.common.format.C;
|
||||||
|
import art.arcane.iris.util.common.plugin.VolmitSender;
|
||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
import art.arcane.volmlib.util.collection.KList;
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
import art.arcane.volmlib.util.director.DirectorOrigin;
|
import art.arcane.volmlib.util.director.DirectorOrigin;
|
||||||
import art.arcane.volmlib.util.director.annotations.Director;
|
import art.arcane.volmlib.util.director.annotations.Director;
|
||||||
import art.arcane.volmlib.util.director.annotations.Param;
|
import art.arcane.volmlib.util.director.annotations.Param;
|
||||||
|
import io.papermc.paper.registry.RegistryAccess;
|
||||||
|
import io.papermc.paper.registry.RegistryKey;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.Registry;
|
import org.bukkit.Registry;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.generator.structure.Structure;
|
||||||
import org.bukkit.util.StructureSearchResult;
|
import org.bukkit.util.StructureSearchResult;
|
||||||
|
|
||||||
@Director(name = "find", origin = DirectorOrigin.PLAYER, description = "Iris Find commands", aliases = "goto")
|
@Director(name = "find", origin = DirectorOrigin.PLAYER, description = "Iris Find commands", aliases = "goto")
|
||||||
@@ -99,10 +103,16 @@ public class CommandFind implements DirectorExecutor {
|
|||||||
@Param(description = "The structure to look for (e.g. minecraft:village_plains, minecraft:stronghold, minecraft_ancient_city)", customHandler = StructureHandler.class)
|
@Param(description = "The structure to look for (e.g. minecraft:village_plains, minecraft:stronghold, minecraft_ancient_city)", customHandler = StructureHandler.class)
|
||||||
String structure
|
String structure
|
||||||
) {
|
) {
|
||||||
|
VolmitSender commandSender = sender();
|
||||||
|
if (commandSender == null) {
|
||||||
|
Iris.reportError("Structure lookup started without a command sender context.", new IllegalStateException("Missing command sender context"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Engine e = engine();
|
Engine e = engine();
|
||||||
|
|
||||||
if (e == null) {
|
if (e == null) {
|
||||||
sender().sendMessage(C.GOLD + "Not in an Iris World!");
|
commandSender.sendMessage(C.GOLD + "Not in an Iris World!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,43 +123,45 @@ public class CommandFind implements DirectorExecutor {
|
|||||||
|
|
||||||
Player target = player();
|
Player target = player();
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
sender().sendMessage(C.GOLD + "Run this in-game to teleport to a structure.");
|
commandSender.sendMessage(C.GOLD + "Run this in-game to teleport to a structure.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sender().sendMessage(C.GRAY + "Locating " + structure + "...");
|
commandSender.sendMessage(C.GRAY + "Locating " + structure + "...");
|
||||||
J.s(() -> {
|
J.s(() -> {
|
||||||
try {
|
try {
|
||||||
org.bukkit.generator.structure.Structure match = null;
|
Registry<Structure> structureRegistry = RegistryAccess.registryAccess().getRegistry(RegistryKey.STRUCTURE);
|
||||||
for (org.bukkit.generator.structure.Structure s : Registry.STRUCTURE) {
|
Structure match = null;
|
||||||
NamespacedKey key = s.getKey();
|
for (Structure candidate : structureRegistry) {
|
||||||
|
NamespacedKey key = structureRegistry.getKey(candidate);
|
||||||
if (key != null && key.toString().equalsIgnoreCase(structure)) {
|
if (key != null && key.toString().equalsIgnoreCase(structure)) {
|
||||||
match = s;
|
match = candidate;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (match == null) {
|
if (match == null) {
|
||||||
sender().sendMessage(C.RED + "Unknown structure: " + structure);
|
commandSender.sendMessage(C.RED + "Unknown structure: " + structure);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!StructureReachability.isReachable(e, structure)) {
|
if (!StructureReachability.isReachable(e, structure)) {
|
||||||
KList<String> miss = StructureReachability.missingBiomeKeys(e, structure);
|
KList<String> miss = StructureReachability.missingBiomeKeys(e, structure);
|
||||||
sender().sendMessage(C.YELLOW + structure + " cannot generate in this world (its required biomes are not produced by this pack"
|
commandSender.sendMessage(C.YELLOW + structure + " cannot generate in this world (its required biomes are not produced by this pack"
|
||||||
+ (miss.isEmpty() ? "" : ": needs " + String.join("/", miss)) + ").");
|
+ (miss.isEmpty() ? "" : ": needs " + String.join("/", miss)) + ").");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
StructureSearchResult result = target.getWorld().locateNearestStructure(target.getLocation(), match, 100, true);
|
StructureSearchResult result = target.getWorld().locateNearestStructure(target.getLocation(), match, 100, true);
|
||||||
if (result == null || result.getLocation() == null) {
|
if (result == null || result.getLocation() == null) {
|
||||||
sender().sendMessage(C.YELLOW + "No " + structure + " found within range of you.");
|
commandSender.sendMessage(C.YELLOW + "No " + structure + " found within range of you.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Location at = result.getLocation();
|
Location at = result.getLocation();
|
||||||
int y = target.getWorld().getHighestBlockYAt(at.getBlockX(), at.getBlockZ()) + 2;
|
int y = target.getWorld().getHighestBlockYAt(at.getBlockX(), at.getBlockZ()) + 2;
|
||||||
Location dest = new Location(target.getWorld(), at.getBlockX() + 0.5, y, at.getBlockZ() + 0.5);
|
Location dest = new Location(target.getWorld(), at.getBlockX() + 0.5, y, at.getBlockZ() + 0.5);
|
||||||
BukkitPlatform.teleportAsync(target, dest);
|
BukkitPlatform.teleportAsync(target, dest);
|
||||||
sender().sendMessage(C.GREEN + "Teleported to " + structure + " @ " + at.getBlockX() + ", " + at.getBlockZ());
|
commandSender.sendMessage(C.GREEN + "Teleported to " + structure + " @ " + at.getBlockX() + ", " + at.getBlockZ());
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
sender().sendMessage(C.RED + "Could not locate " + structure + ": " + t.getClass().getSimpleName());
|
commandSender.sendMessage(C.RED + "Could not locate " + structure + ": " + t.getClass().getSimpleName());
|
||||||
|
Iris.reportError("Could not locate structure '" + structure + "'.", t);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-18
@@ -21,6 +21,7 @@ package art.arcane.iris.core.commands;
|
|||||||
import art.arcane.iris.Iris;
|
import art.arcane.iris.Iris;
|
||||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
|
import art.arcane.iris.core.IrisWorldStorage;
|
||||||
import art.arcane.iris.core.IrisWorlds;
|
import art.arcane.iris.core.IrisWorlds;
|
||||||
import art.arcane.iris.core.ServerConfigurator;
|
import art.arcane.iris.core.ServerConfigurator;
|
||||||
import art.arcane.iris.core.lifecycle.WorldLifecycleService;
|
import art.arcane.iris.core.lifecycle.WorldLifecycleService;
|
||||||
@@ -30,6 +31,7 @@ import art.arcane.iris.core.tools.IrisToolbelt;
|
|||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
import art.arcane.iris.engine.object.IrisDimension;
|
import art.arcane.iris.engine.object.IrisDimension;
|
||||||
import art.arcane.volmlib.util.collection.KList;
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import art.arcane.volmlib.util.director.DirectorParameterHandler;
|
import art.arcane.volmlib.util.director.DirectorParameterHandler;
|
||||||
import art.arcane.iris.util.common.director.DirectorExecutor;
|
import art.arcane.iris.util.common.director.DirectorExecutor;
|
||||||
import art.arcane.volmlib.util.director.DirectorOrigin;
|
import art.arcane.volmlib.util.director.DirectorOrigin;
|
||||||
@@ -44,6 +46,7 @@ import art.arcane.iris.util.common.plugin.VolmitSender;
|
|||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
@@ -55,6 +58,7 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@@ -108,7 +112,7 @@ public class CommandIris implements DirectorExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new File(Bukkit.getWorldContainer(), name).exists()) {
|
if (IrisWorldStorage.dimensionRoot(name).exists()) {
|
||||||
sender().sendMessage(C.RED + "That folder already exists!");
|
sender().sendMessage(C.RED + "That folder already exists!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -161,29 +165,44 @@ public class CommandIris implements DirectorExecutor {
|
|||||||
|
|
||||||
private boolean updateMainWorld(String newName) {
|
private boolean updateMainWorld(String newName) {
|
||||||
try {
|
try {
|
||||||
File worlds = Bukkit.getWorldContainer();
|
File oldLevelRoot = IrisWorldStorage.levelRoot();
|
||||||
var data = ServerProperties.DATA;
|
File worldContainer = oldLevelRoot.getParentFile();
|
||||||
try (var in = new FileInputStream(ServerProperties.SERVER_PROPERTIES)) {
|
Properties data = ServerProperties.DATA;
|
||||||
|
try (FileInputStream in = new FileInputStream(ServerProperties.SERVER_PROPERTIES)) {
|
||||||
data.load(in);
|
data.load(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
File oldWorldFolder = new File(worlds, ServerProperties.LEVEL_NAME);
|
File sourceDimensionRoot = IrisWorldStorage.dimensionRoot(IrisWorldStorage.keyFromLegacyName(newName));
|
||||||
File newWorldFolder = new File(worlds, newName);
|
if (!sourceDimensionRoot.isDirectory()) {
|
||||||
if (!newWorldFolder.exists() && !newWorldFolder.mkdirs()) {
|
throw new IllegalStateException("Source dimension folder does not exist: " + sourceDimensionRoot.getAbsolutePath());
|
||||||
Iris.warn("Could not create target main world folder: " + newWorldFolder.getAbsolutePath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String sub : List.of("datapacks", "playerdata", "advancements", "stats")) {
|
File newLevelRoot = new File(worldContainer, newName);
|
||||||
File source = new File(oldWorldFolder, sub);
|
if (!newLevelRoot.exists() && !newLevelRoot.mkdirs()) {
|
||||||
|
throw new IllegalStateException("Could not create target level folder: " + newLevelRoot.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String sub : List.of("data", "datapacks", "players")) {
|
||||||
|
File source = new File(oldLevelRoot, sub);
|
||||||
if (!source.exists()) {
|
if (!source.exists()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
IO.copyDirectory(source.toPath(), new File(newWorldFolder, sub).toPath());
|
IO.copyDirectory(source.toPath(), new File(newLevelRoot, sub).toPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File targetDimensionRoot = IrisWorldStorage.dimensionRoot(newLevelRoot, NamespacedKey.minecraft("overworld"));
|
||||||
|
IO.copyDirectory(sourceDimensionRoot.toPath(), targetDimensionRoot.toPath());
|
||||||
|
|
||||||
|
World sourceWorld = WorldIdentity.resolve(IrisWorldStorage.keyFromLegacyName(newName)).orElse(null);
|
||||||
|
Long stagedSeed = IrisWorlds.readBukkitWorldSeed(newName);
|
||||||
|
if (sourceWorld == null && stagedSeed == null) {
|
||||||
|
throw new IllegalStateException("Cannot determine the promoted world's seed.");
|
||||||
|
}
|
||||||
|
long promotedSeed = sourceWorld == null ? stagedSeed : sourceWorld.getSeed();
|
||||||
data.setProperty("level-name", newName);
|
data.setProperty("level-name", newName);
|
||||||
try (var out = new FileOutputStream(ServerProperties.SERVER_PROPERTIES)) {
|
data.setProperty("level-seed", Long.toString(promotedSeed));
|
||||||
|
try (FileOutputStream out = new FileOutputStream(ServerProperties.SERVER_PROPERTIES)) {
|
||||||
data.store(out, null);
|
data.store(out, null);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -198,7 +217,7 @@ public class CommandIris implements DirectorExecutor {
|
|||||||
sender().sendMessage(C.YELLOW + "Runtime world creation is disabled on Folia.");
|
sender().sendMessage(C.YELLOW + "Runtime world creation is disabled on Folia.");
|
||||||
sender().sendMessage(C.YELLOW + "Preparing world files and bukkit.yml for next startup...");
|
sender().sendMessage(C.YELLOW + "Preparing world files and bukkit.yml for next startup...");
|
||||||
|
|
||||||
File worldFolder = new File(Bukkit.getWorldContainer(), name);
|
File worldFolder = IrisWorldStorage.dimensionRoot(name);
|
||||||
IrisDimension installed = Iris.service(StudioSVC.class).installIntoWorld(sender(), dimension, worldFolder);
|
IrisDimension installed = Iris.service(StudioSVC.class).installIntoWorld(sender(), dimension, worldFolder);
|
||||||
if (installed == null) {
|
if (installed == null) {
|
||||||
sender().sendMessage(C.RED + "Failed to stage world files for dimension \"" + dimension.getLoadKey() + "\".");
|
sender().sendMessage(C.RED + "Failed to stage world files for dimension \"" + dimension.getLoadKey() + "\".");
|
||||||
@@ -497,7 +516,6 @@ public class CommandIris implements DirectorExecutor {
|
|||||||
@Param(description = "The name of the world to load")
|
@Param(description = "The name of the world to load")
|
||||||
String world
|
String world
|
||||||
) {
|
) {
|
||||||
World worldloaded = Bukkit.getWorld(world);
|
|
||||||
worldNameToCheck = world;
|
worldNameToCheck = world;
|
||||||
boolean worldExists = doesWorldExist(worldNameToCheck);
|
boolean worldExists = doesWorldExist(worldNameToCheck);
|
||||||
WorldEngine = world;
|
WorldEngine = world;
|
||||||
@@ -507,8 +525,7 @@ public class CommandIris implements DirectorExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String pathtodim = world + File.separator +"iris"+File.separator +"pack"+File.separator +"dimensions"+File.separator;
|
File directory = new File(IrisWorldStorage.packRoot(IrisWorldStorage.keyFromLegacyName(world)), "dimensions");
|
||||||
File directory = new File(Bukkit.getWorldContainer(), pathtodim);
|
|
||||||
|
|
||||||
String dimension = null;
|
String dimension = null;
|
||||||
if (directory.exists() && directory.isDirectory()) {
|
if (directory.exists() && directory.isDirectory()) {
|
||||||
@@ -562,8 +579,7 @@ public class CommandIris implements DirectorExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean doesWorldExist(String worldName) {
|
boolean doesWorldExist(String worldName) {
|
||||||
File worldContainer = Bukkit.getWorldContainer();
|
File worldDirectory = IrisWorldStorage.dimensionRoot(worldName);
|
||||||
File worldDirectory = new File(worldContainer, worldName);
|
|
||||||
return worldDirectory.exists() && worldDirectory.isDirectory();
|
return worldDirectory.exists() && worldDirectory.isDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -42,6 +42,8 @@ import art.arcane.volmlib.util.director.annotations.Param;
|
|||||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||||
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
||||||
import art.arcane.volmlib.util.math.RNG;
|
import art.arcane.volmlib.util.math.RNG;
|
||||||
|
import io.papermc.paper.registry.RegistryAccess;
|
||||||
|
import io.papermc.paper.registry.RegistryKey;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
@@ -49,6 +51,7 @@ import org.bukkit.Registry;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.generator.structure.Structure;
|
||||||
import org.bukkit.util.StructureSearchResult;
|
import org.bukkit.util.StructureSearchResult;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -139,8 +142,9 @@ public class CommandStructure implements DirectorExecutor {
|
|||||||
int irisPlaced = 0;
|
int irisPlaced = 0;
|
||||||
KList<String> notFound = new KList<>();
|
KList<String> notFound = new KList<>();
|
||||||
KList<String> cannotGenerate = new KList<>();
|
KList<String> cannotGenerate = new KList<>();
|
||||||
for (org.bukkit.generator.structure.Structure structure : Registry.STRUCTURE) {
|
Registry<Structure> structureRegistry = RegistryAccess.registryAccess().getRegistry(RegistryKey.STRUCTURE);
|
||||||
NamespacedKey key = structure.getKey();
|
for (Structure structure : structureRegistry) {
|
||||||
|
NamespacedKey key = structureRegistry.getKey(structure);
|
||||||
String keyName = key == null ? structure.toString() : key.toString();
|
String keyName = key == null ? structure.toString() : key.toString();
|
||||||
boolean isIrisPlaced = engine != null && IrisStructureLocator.suppressesVanilla(engine, keyName);
|
boolean isIrisPlaced = engine != null && IrisStructureLocator.suppressesVanilla(engine, keyName);
|
||||||
boolean isReachable = engine != null && reachable.contains(keyName.toLowerCase());
|
boolean isReachable = engine != null && reachable.contains(keyName.toLowerCase());
|
||||||
|
|||||||
+2
-2
@@ -389,7 +389,7 @@ public class IrisEngineSVC implements IrisService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PregeneratorJob pregeneratorJob = PregeneratorJob.getInstance();
|
PregeneratorJob pregeneratorJob = PregeneratorJob.getInstance();
|
||||||
return pregeneratorJob != null && pregeneratorJob.targetsWorldName(engine.getWorld().name());
|
return pregeneratorJob != null && pregeneratorJob.targetsWorldIdentity(engine.getWorld().identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private int activeTectonicLimit(Engine engine) {
|
private int activeTectonicLimit(Engine engine) {
|
||||||
@@ -446,7 +446,7 @@ public class IrisEngineSVC implements IrisService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PregeneratorJob pregeneratorJob = PregeneratorJob.getInstance();
|
PregeneratorJob pregeneratorJob = PregeneratorJob.getInstance();
|
||||||
boolean pregeneratorTargetsWorld = pregeneratorJob != null && pregeneratorJob.targetsWorldName(world.getName());
|
boolean pregeneratorTargetsWorld = pregeneratorJob != null && pregeneratorJob.targetsWorld(world);
|
||||||
return shouldSkipMantleReductionForMaintenance(maintenanceActive, pregeneratorTargetsWorld);
|
return shouldSkipMantleReductionForMaintenance(maintenanceActive, pregeneratorTargetsWorld);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -32,6 +32,7 @@ import art.arcane.iris.spi.IrisServices;
|
|||||||
import art.arcane.iris.spi.protocol.IrisProtocol;
|
import art.arcane.iris.spi.protocol.IrisProtocol;
|
||||||
import art.arcane.iris.util.common.plugin.IrisService;
|
import art.arcane.iris.util.common.plugin.IrisService;
|
||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -167,7 +168,7 @@ public class IrisProtocolService implements IrisService, PluginMessageListener,
|
|||||||
world.getSeed(), engine.getMinHeight(), engine.getMaxHeight(), true);
|
world.getSeed(), engine.getMinHeight(), engine.getMaxHeight(), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
protocol.sendDimensionStatus(sessionId, world.getName(), "", world.getSeed(), world.getMinHeight(), world.getMaxHeight(), false);
|
protocol.sendDimensionStatus(sessionId, WorldIdentity.serialize(world), "", world.getSeed(), world.getMinHeight(), world.getMaxHeight(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Engine resolveEngine(String sessionId) {
|
private static Engine resolveEngine(String sessionId) {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.bukkit.Location;
|
|||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Particle;
|
import org.bukkit.Particle;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.World;
|
||||||
import art.arcane.iris.Iris;
|
import art.arcane.iris.Iris;
|
||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
import art.arcane.iris.core.edit.DustRevealer;
|
import art.arcane.iris.core.edit.DustRevealer;
|
||||||
@@ -32,6 +33,7 @@ import art.arcane.iris.core.wand.WandSelection;
|
|||||||
import art.arcane.iris.engine.object.IrisObject;
|
import art.arcane.iris.engine.object.IrisObject;
|
||||||
import art.arcane.iris.util.project.matter.WorldMatter;
|
import art.arcane.iris.util.project.matter.WorldMatter;
|
||||||
import art.arcane.volmlib.util.collection.KList;
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import art.arcane.volmlib.util.data.Cuboid;
|
import art.arcane.volmlib.util.data.Cuboid;
|
||||||
import art.arcane.iris.util.common.format.C;
|
import art.arcane.iris.util.common.format.C;
|
||||||
import art.arcane.volmlib.util.math.M;
|
import art.arcane.volmlib.util.math.M;
|
||||||
@@ -210,7 +212,9 @@ public class WandSVC implements IrisService {
|
|||||||
if (f.length != 2) return null;
|
if (f.length != 2) return null;
|
||||||
String[] g = f[0].split("\\Q,\\E");
|
String[] g = f[0].split("\\Q,\\E");
|
||||||
if (g.length != 3) return null;
|
if (g.length != 3) return null;
|
||||||
return new Location(Bukkit.getWorld(f[1]), Integer.parseInt(g[0]), Integer.parseInt(g[1]), Integer.parseInt(g[2]));
|
World world = WorldIdentity.resolve(f[1]).orElse(null);
|
||||||
|
if (world == null) return null;
|
||||||
|
return new Location(world, Integer.parseInt(g[0]), Integer.parseInt(g[1]), Integer.parseInt(g[2]));
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
return null;
|
return null;
|
||||||
@@ -228,7 +232,7 @@ public class WandSVC implements IrisService {
|
|||||||
return "<#>";
|
return "<#>";
|
||||||
}
|
}
|
||||||
|
|
||||||
return loc.getBlockX() + "," + loc.getBlockY() + "," + loc.getBlockZ() + " in " + loc.getWorld().getName();
|
return loc.getBlockX() + "," + loc.getBlockY() + "," + loc.getBlockZ() + " in " + WorldIdentity.serialize(loc.getWorld());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -532,7 +536,7 @@ public class WandSVC implements IrisService {
|
|||||||
Location[] f = getCuboidFromItem(item);
|
Location[] f = getCuboidFromItem(item);
|
||||||
Location other = left ? f[1] : f[0];
|
Location other = left ? f[1] : f[0];
|
||||||
|
|
||||||
if (other != null && !other.getWorld().getName().equals(a.getWorld().getName())) {
|
if (other != null && !WorldIdentity.key(other.getWorld()).equals(WorldIdentity.key(a.getWorld()))) {
|
||||||
other = null;
|
other = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ public final class ModdedParityProbe {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IrisWorld world = IrisWorld.builder()
|
IrisWorld world = IrisWorld.builder()
|
||||||
|
.platformIdentity("iris:parity")
|
||||||
.name("parity")
|
.name("parity")
|
||||||
.seed(SEED)
|
.seed(SEED)
|
||||||
.worldFolder(new File(workRoot, "world"))
|
.worldFolder(new File(workRoot, "world"))
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ public final class ModdedWorldEngines {
|
|||||||
long seed = seedOverride == Long.MIN_VALUE ? level.getSeed() : seedOverride;
|
long seed = seedOverride == Long.MIN_VALUE ? level.getSeed() : seedOverride;
|
||||||
File worldFolder = DimensionType.getStorageFolder(level.dimension(), level.getServer().getWorldPath(LevelResource.ROOT)).toFile();
|
File worldFolder = DimensionType.getStorageFolder(level.dimension(), level.getServer().getWorldPath(LevelResource.ROOT)).toFile();
|
||||||
IrisWorld world = IrisWorld.builder()
|
IrisWorld world = IrisWorld.builder()
|
||||||
|
.platformIdentity(level.dimension().identifier().toString())
|
||||||
.name(level.dimension().identifier().toString().replace(':', '_'))
|
.name(level.dimension().identifier().toString().replace(':', '_'))
|
||||||
.seed(seed)
|
.seed(seed)
|
||||||
.worldFolder(worldFolder)
|
.worldFolder(worldFolder)
|
||||||
|
|||||||
@@ -641,7 +641,7 @@ public final class ModdedWorldManager implements EngineWorldManager {
|
|||||||
|
|
||||||
private boolean isPregenActive() {
|
private boolean isPregenActive() {
|
||||||
PregeneratorJob job = PregeneratorJob.getInstance();
|
PregeneratorJob job = PregeneratorJob.getInstance();
|
||||||
return job != null && job.targetsWorldName(engine.getWorld().name());
|
return job != null && job.targetsWorldIdentity(engine.getWorld().identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean markerSystemEnabled() {
|
private static boolean markerSystemEnabled() {
|
||||||
|
|||||||
+3
-3
@@ -106,8 +106,8 @@ public final class ModdedRegen {
|
|||||||
|
|
||||||
private void run() {
|
private void run() {
|
||||||
long startedAt = M.ms();
|
long startedAt = M.ms();
|
||||||
String worldName = engine.getWorld() == null ? null : engine.getWorld().name();
|
String worldIdentity = engine.getWorld() == null ? null : engine.getWorld().identity();
|
||||||
WorldMaintenance.beginWorldMaintenance(worldName, "regen");
|
WorldMaintenance.beginWorldMaintenance(worldIdentity, "regen");
|
||||||
try {
|
try {
|
||||||
resetMantleMargin();
|
resetMantleMargin();
|
||||||
List<int[]> targets = ChunkSpiral.centerOut(centerX, centerZ, radius);
|
List<int[]> targets = ChunkSpiral.centerOut(centerX, centerZ, radius);
|
||||||
@@ -120,7 +120,7 @@ public final class ModdedRegen {
|
|||||||
LOGGER.error("Iris regen failed", e);
|
LOGGER.error("Iris regen failed", e);
|
||||||
fail("Regen failed: " + e);
|
fail("Regen failed: " + e);
|
||||||
} finally {
|
} finally {
|
||||||
WorldMaintenance.endWorldMaintenance(worldName, "regen");
|
WorldMaintenance.endWorldMaintenance(worldIdentity, "regen");
|
||||||
ACTIVE.set(false);
|
ACTIVE.set(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -127,7 +127,7 @@ public final class ModdedChunkUpdateService implements ModdedTickableService {
|
|||||||
|
|
||||||
private boolean isPregenActive(Engine engine) {
|
private boolean isPregenActive(Engine engine) {
|
||||||
PregeneratorJob job = PregeneratorJob.getInstance();
|
PregeneratorJob job = PregeneratorJob.getInstance();
|
||||||
return job != null && job.targetsWorldName(engine.getWorld().name());
|
return job != null && job.targetsWorldIdentity(engine.getWorld().identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateNearPlayers(Engine engine, ServerLevel level) {
|
private void updateNearPlayers(Engine engine, ServerLevel level) {
|
||||||
|
|||||||
+2
-2
@@ -169,7 +169,7 @@ public final class ModdedEngineMaintenanceService implements ModdedTickableServi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldSkipForMaintenance(Engine engine) {
|
private boolean shouldSkipForMaintenance(Engine engine) {
|
||||||
if (engine.getWorld() == null || !WorldMaintenance.isWorldMaintenanceActive(engine.getWorld().name())) {
|
if (engine.getWorld() == null || !WorldMaintenance.isWorldMaintenanceActive(engine.getWorld().identity())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return !pregenTargets(engine);
|
return !pregenTargets(engine);
|
||||||
@@ -180,7 +180,7 @@ public final class ModdedEngineMaintenanceService implements ModdedTickableServi
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
PregeneratorJob job = PregeneratorJob.getInstance();
|
PregeneratorJob job = PregeneratorJob.getInstance();
|
||||||
return job != null && job.targetsWorldName(engine.getWorld().name());
|
return job != null && job.targetsWorldIdentity(engine.getWorld().identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private int activeTectonicLimit(Engine engine, int share) {
|
private int activeTectonicLimit(Engine engine, int share) {
|
||||||
|
|||||||
+1
-1
@@ -139,7 +139,7 @@ public final class ModdedStudioHotloadService implements ModdedTickableService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
PregeneratorJob job = PregeneratorJob.getInstance();
|
PregeneratorJob job = PregeneratorJob.getInstance();
|
||||||
return job != null && job.targetsWorldName(engine.getWorld().name());
|
return job != null && job.targetsWorldIdentity(engine.getWorld().identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void poll(String dimensionId, Watch watch, IrisModdedChunkGenerator generator, Engine engine) {
|
private void poll(String dimensionId, Watch watch, IrisModdedChunkGenerator generator, Engine engine) {
|
||||||
|
|||||||
+1
-1
@@ -81,7 +81,7 @@ String forgeConsumerPath = "${consumerLocation}/forge-mod-consumers/dropins/mods
|
|||||||
String neoForgeConsumerPath = "${consumerLocation}/neoforge-mod-consumers/dropins/mods"
|
String neoForgeConsumerPath = "${consumerLocation}/neoforge-mod-consumers/dropins/mods"
|
||||||
|
|
||||||
def nmsBindings = [
|
def nmsBindings = [
|
||||||
v26_2_R1: '26.2.build.25-alpha',
|
v26_2_R1: '26.2.build.60-beta',
|
||||||
]
|
]
|
||||||
Class nmsTypeClass = Class.forName('NMSBinding$Type')
|
Class nmsTypeClass = Class.forName('NMSBinding$Type')
|
||||||
nmsBindings.each { key, value ->
|
nmsBindings.each { key, value ->
|
||||||
|
|||||||
+3
-3
@@ -62,7 +62,7 @@ dependencies {
|
|||||||
api(project(':spi'))
|
api(project(':spi'))
|
||||||
|
|
||||||
// Provided or Classpath
|
// Provided or Classpath
|
||||||
compileOnly(libs.spigot)
|
compileOnly(libs.paper.api)
|
||||||
compileOnly(libs.log4j.api)
|
compileOnly(libs.log4j.api)
|
||||||
compileOnly(libs.log4j.core)
|
compileOnly(libs.log4j.core)
|
||||||
|
|
||||||
@@ -120,8 +120,8 @@ dependencies {
|
|||||||
|
|
||||||
testImplementation('junit:junit:4.13.2')
|
testImplementation('junit:junit:4.13.2')
|
||||||
testImplementation('org.mockito:mockito-core:5.16.1')
|
testImplementation('org.mockito:mockito-core:5.16.1')
|
||||||
testImplementation(libs.spigot)
|
testImplementation(libs.paper.api)
|
||||||
testRuntimeOnly(libs.spigot)
|
testRuntimeOnly(libs.paper.api)
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
|
|||||||
@@ -254,7 +254,6 @@ public class IrisSettings {
|
|||||||
public boolean adjustVanillaHeight = false;
|
public boolean adjustVanillaHeight = false;
|
||||||
public boolean autoIngestDatapacks = true;
|
public boolean autoIngestDatapacks = true;
|
||||||
public boolean autoImportDatapackStructures = true;
|
public boolean autoImportDatapackStructures = true;
|
||||||
public String forceMainWorld = "";
|
|
||||||
public int spinh = -20;
|
public int spinh = -20;
|
||||||
public int spins = 7;
|
public int spins = 7;
|
||||||
public int spinb = 8;
|
public int spinb = 8;
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package art.arcane.iris.core;
|
||||||
|
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.generator.WorldInfo;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public final class IrisWorldStorage {
|
||||||
|
private IrisWorldStorage() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File levelRoot() {
|
||||||
|
return Bukkit.getServer().getLevelDirectory().toAbsolutePath().normalize().toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File levelRoot(File dimensionRoot) {
|
||||||
|
Path current = Objects.requireNonNull(dimensionRoot, "dimensionRoot").toPath().toAbsolutePath().normalize();
|
||||||
|
while (current != null) {
|
||||||
|
Path fileName = current.getFileName();
|
||||||
|
if (fileName != null && "dimensions".equals(fileName.toString())) {
|
||||||
|
Path parent = current.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
return parent.toFile();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current = current.getParent();
|
||||||
|
}
|
||||||
|
return dimensionRoot.getAbsoluteFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NamespacedKey keyFromLegacyName(String worldName) {
|
||||||
|
return keyFromLegacyName(worldName, levelRoot().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
static NamespacedKey keyFromLegacyName(String worldName, String levelName) {
|
||||||
|
String name = Objects.requireNonNull(worldName, "worldName").trim();
|
||||||
|
String mainLevelName = Objects.requireNonNull(levelName, "levelName").trim();
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("World name cannot be empty.");
|
||||||
|
}
|
||||||
|
if (name.equals(mainLevelName)) {
|
||||||
|
return NamespacedKey.minecraft("overworld");
|
||||||
|
}
|
||||||
|
if (name.equals(mainLevelName + "_nether")) {
|
||||||
|
return NamespacedKey.minecraft("the_nether");
|
||||||
|
}
|
||||||
|
if (name.equals(mainLevelName + "_the_end")) {
|
||||||
|
return NamespacedKey.minecraft("the_end");
|
||||||
|
}
|
||||||
|
|
||||||
|
String key = name.toLowerCase(Locale.ENGLISH).replace(' ', '_');
|
||||||
|
return NamespacedKey.minecraft(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File dimensionRoot(String worldName) {
|
||||||
|
return dimensionRoot(keyFromLegacyName(worldName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File dimensionRoot(WorldInfo world) {
|
||||||
|
NamespacedKey key = WorldIdentity.key(world);
|
||||||
|
Optional<World> loadedWorld = WorldIdentity.resolve(key);
|
||||||
|
if (loadedWorld.isPresent()) {
|
||||||
|
return loadedWorld.get().getWorldFolder().getAbsoluteFile();
|
||||||
|
}
|
||||||
|
return dimensionRoot(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File dimensionRoot(NamespacedKey key) {
|
||||||
|
return dimensionRoot(levelRoot(), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File dimensionRoot(File levelRoot, NamespacedKey key) {
|
||||||
|
Path dimensionsRoot = Objects.requireNonNull(levelRoot, "levelRoot")
|
||||||
|
.toPath()
|
||||||
|
.toAbsolutePath()
|
||||||
|
.normalize()
|
||||||
|
.resolve("dimensions");
|
||||||
|
NamespacedKey worldKey = Objects.requireNonNull(key, "key");
|
||||||
|
Path namespaceRoot = dimensionsRoot.resolve(worldKey.getNamespace()).normalize();
|
||||||
|
Path dimensionRoot = namespaceRoot.resolve(worldKey.getKey()).normalize();
|
||||||
|
if (!dimensionRoot.startsWith(namespaceRoot)) {
|
||||||
|
throw new IllegalArgumentException("World key escapes its namespace storage root: " + worldKey);
|
||||||
|
}
|
||||||
|
return dimensionRoot.toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<NamespacedKey> keyFromDimensionRoot(File levelRoot, File dimensionRoot) {
|
||||||
|
Path dimensionsPath = Objects.requireNonNull(levelRoot, "levelRoot")
|
||||||
|
.toPath()
|
||||||
|
.toAbsolutePath()
|
||||||
|
.normalize()
|
||||||
|
.resolve("dimensions");
|
||||||
|
Path worldPath = Objects.requireNonNull(dimensionRoot, "dimensionRoot")
|
||||||
|
.toPath()
|
||||||
|
.toAbsolutePath()
|
||||||
|
.normalize();
|
||||||
|
if (!worldPath.startsWith(dimensionsPath)) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Path relative = dimensionsPath.relativize(worldPath);
|
||||||
|
if (relative.getNameCount() < 2) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
String namespace = relative.getName(0).toString();
|
||||||
|
StringBuilder key = new StringBuilder();
|
||||||
|
for (int i = 1; i < relative.getNameCount(); i++) {
|
||||||
|
if (!key.isEmpty()) {
|
||||||
|
key.append('/');
|
||||||
|
}
|
||||||
|
key.append(relative.getName(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.ofNullable(NamespacedKey.fromString(namespace + ":" + key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File packRoot(NamespacedKey key) {
|
||||||
|
return new File(dimensionRoot(key), "iris/pack");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,20 @@
|
|||||||
package art.arcane.iris.core;
|
package art.arcane.iris.core;
|
||||||
|
|
||||||
|
import art.arcane.iris.core.loader.IrisData;
|
||||||
|
import art.arcane.iris.core.service.StudioSVC;
|
||||||
|
import art.arcane.iris.engine.data.cache.AtomicCache;
|
||||||
|
import art.arcane.iris.engine.object.IrisDimension;
|
||||||
|
import art.arcane.iris.spi.IrisLogging;
|
||||||
|
import art.arcane.iris.spi.IrisPlatforms;
|
||||||
|
import art.arcane.iris.spi.IrisServices;
|
||||||
|
import art.arcane.iris.util.common.misc.ServerProperties;
|
||||||
|
import art.arcane.iris.util.common.plugin.VolmitSender;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
|
import art.arcane.volmlib.util.collection.KMap;
|
||||||
|
import art.arcane.volmlib.util.io.IO;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import art.arcane.iris.spi.IrisLogging;
|
|
||||||
import art.arcane.iris.spi.IrisPlatforms;
|
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
|
||||||
import art.arcane.iris.engine.data.cache.AtomicCache;
|
|
||||||
import art.arcane.iris.engine.object.IrisDimension;
|
|
||||||
import art.arcane.volmlib.util.collection.KMap;
|
|
||||||
import art.arcane.volmlib.util.io.IO;
|
|
||||||
import art.arcane.iris.util.common.misc.ServerProperties;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
@@ -30,8 +34,15 @@ public class IrisWorlds {
|
|||||||
private volatile boolean dirty = false;
|
private volatile boolean dirty = false;
|
||||||
|
|
||||||
private IrisWorlds(KMap<String, String> worlds) {
|
private IrisWorlds(KMap<String, String> worlds) {
|
||||||
this.worlds = worlds;
|
this.worlds = new KMap<>();
|
||||||
readBukkitWorlds().forEach(this::put0);
|
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));
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,20 +67,23 @@ public class IrisWorlds {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void put(String name, String type) {
|
public void put(String identity, String type) {
|
||||||
put0(name, type);
|
put0(identity, type);
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void put0(String name, String type) {
|
private void put0(String identity, String type) {
|
||||||
String old = worlds.put(name, type);
|
String canonicalIdentity = WorldIdentity.parse(identity).toString();
|
||||||
|
String old = worlds.put(canonicalIdentity, type);
|
||||||
if (!type.equals(old))
|
if (!type.equals(old))
|
||||||
dirty = true;
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KMap<String, String> getWorlds() {
|
public KMap<String, String> getWorlds() {
|
||||||
clean();
|
clean();
|
||||||
return readBukkitWorlds().put(worlds);
|
KMap<String, String> result = new KMap<>();
|
||||||
|
readBukkitWorlds().forEach((name, type) -> result.put(IrisWorldStorage.keyFromLegacyName(name).toString(), type));
|
||||||
|
return result.put(worlds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream<IrisData> getPacks() {
|
public Stream<IrisData> getPacks() {
|
||||||
@@ -87,7 +101,15 @@ public class IrisWorlds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void clean() {
|
public void clean() {
|
||||||
dirty = worlds.entrySet().removeIf(entry -> !new File(Bukkit.getWorldContainer(), entry.getKey() + "/iris/pack/dimensions/" + entry.getValue() + ".json").exists());
|
boolean removed = worlds.entrySet().removeIf(entry -> {
|
||||||
|
try {
|
||||||
|
File packRoot = IrisWorldStorage.packRoot(WorldIdentity.parse(entry.getKey()));
|
||||||
|
return !new File(packRoot, "dimensions/" + entry.getValue() + ".json").exists();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dirty = dirty || removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void save() {
|
public synchronized void save() {
|
||||||
@@ -114,13 +136,13 @@ public class IrisWorlds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static KMap<String, String> readBukkitWorlds() {
|
public static KMap<String, String> readBukkitWorlds() {
|
||||||
var bukkit = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML);
|
YamlConfiguration bukkit = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML);
|
||||||
var worlds = bukkit.getConfigurationSection("worlds");
|
ConfigurationSection worlds = bukkit.getConfigurationSection("worlds");
|
||||||
if (worlds == null) return new KMap<>();
|
if (worlds == null) return new KMap<>();
|
||||||
|
|
||||||
var result = new KMap<String, String>();
|
KMap<String, String> result = new KMap<>();
|
||||||
for (String world : worlds.getKeys(false)) {
|
for (String world : worlds.getKeys(false)) {
|
||||||
var gen = worlds.getString(world + ".generator");
|
String gen = worlds.getString(world + ".generator");
|
||||||
if (gen == null) continue;
|
if (gen == null) continue;
|
||||||
|
|
||||||
String loadKey;
|
String loadKey;
|
||||||
@@ -136,20 +158,28 @@ public class IrisWorlds {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static art.arcane.iris.engine.object.IrisDimension loadDimension(String worldName, String id) {
|
private static IrisDimension loadDimension(String worldIdentity, String id) {
|
||||||
java.io.File pack = new java.io.File(org.bukkit.Bukkit.getWorldContainer(), String.join(java.io.File.separator, worldName, "iris", "pack"));
|
File pack = IrisWorldStorage.packRoot(WorldIdentity.parse(worldIdentity));
|
||||||
art.arcane.iris.engine.object.IrisDimension dimension = pack.isDirectory() ? art.arcane.iris.core.loader.IrisData.get(pack).getDimensionLoader().load(id) : null;
|
IrisDimension dimension = pack.isDirectory() ? IrisData.get(pack).getDimensionLoader().load(id) : null;
|
||||||
if (dimension == null) {
|
if (dimension == null) {
|
||||||
dimension = art.arcane.iris.core.loader.IrisData.loadAnyDimension(id, null);
|
dimension = IrisData.loadAnyDimension(id, null);
|
||||||
}
|
}
|
||||||
if (dimension == null) {
|
if (dimension == null) {
|
||||||
IrisLogging.warn("Unable to find dimension type " + id + " Looking for online packs...");
|
IrisLogging.warn("Unable to find dimension type " + id + " Looking for online packs...");
|
||||||
art.arcane.iris.spi.IrisServices.get(art.arcane.iris.core.service.StudioSVC.class).downloadSearch(new art.arcane.iris.util.common.plugin.VolmitSender(org.bukkit.Bukkit.getConsoleSender()), id, false);
|
IrisServices.get(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, false);
|
||||||
dimension = art.arcane.iris.core.loader.IrisData.loadAnyDimension(id, null);
|
dimension = IrisData.loadAnyDimension(id, null);
|
||||||
if (dimension != null) {
|
if (dimension != null) {
|
||||||
IrisLogging.info("Resolved missing dimension, proceeding.");
|
IrisLogging.info("Resolved missing dimension, proceeding.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dimension;
|
return dimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String migrateLoadedIdentity(String identity) {
|
||||||
|
try {
|
||||||
|
return WorldIdentity.parse(identity).toString();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return IrisWorldStorage.keyFromLegacyName(identity).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -36,6 +36,7 @@ import art.arcane.iris.util.common.plugin.VolmitSender;
|
|||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.configuration.InvalidConfigurationException;
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
@@ -46,6 +47,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -58,8 +60,6 @@ import java.util.concurrent.atomic.AtomicIntegerArray;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class ServerConfigurator {
|
public class ServerConfigurator {
|
||||||
private static volatile boolean deferredInstallPending = false;
|
|
||||||
|
|
||||||
public static void configure() {
|
public static void configure() {
|
||||||
IrisSettings.IrisSettingsAutoconfiguration s = IrisSettings.get().getAutoConfiguration();
|
IrisSettings.IrisSettingsAutoconfiguration s = IrisSettings.get().getAutoConfiguration();
|
||||||
if (s.isConfigureSpigotTimeoutTime()) {
|
if (s.isConfigureSpigotTimeoutTime()) {
|
||||||
@@ -70,26 +70,9 @@ public class ServerConfigurator {
|
|||||||
J.attempt(ServerConfigurator::increasePaperWatchdog);
|
J.attempt(ServerConfigurator::increasePaperWatchdog);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldDeferInstallUntilWorldsReady()) {
|
|
||||||
deferredInstallPending = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
deferredInstallPending = false;
|
|
||||||
installDataPacks(true);
|
installDataPacks(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void configureIfDeferred() {
|
|
||||||
if (!deferredInstallPending) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
configure();
|
|
||||||
if (deferredInstallPending) {
|
|
||||||
J.a(ServerConfigurator::configureIfDeferred, 20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void increaseKeepAliveSpigot() throws IOException, InvalidConfigurationException {
|
private static void increaseKeepAliveSpigot() throws IOException, InvalidConfigurationException {
|
||||||
File spigotConfig = new File("spigot.yml");
|
File spigotConfig = new File("spigot.yml");
|
||||||
FileConfiguration f = new YamlConfiguration();
|
FileConfiguration f = new YamlConfiguration();
|
||||||
@@ -122,20 +105,7 @@ public class ServerConfigurator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static KList<File> getDatapacksFolder() {
|
public static KList<File> getDatapacksFolder() {
|
||||||
if (!IrisSettings.get().getGeneral().forceMainWorld.isEmpty()) {
|
return new KList<File>().qadd(new File(IrisWorldStorage.levelRoot(), "datapacks"));
|
||||||
return new KList<File>().qadd(new File(Bukkit.getWorldContainer(), IrisSettings.get().getGeneral().forceMainWorld + "/datapacks"));
|
|
||||||
}
|
|
||||||
KList<File> worlds = new KList<>();
|
|
||||||
Bukkit.getServer().getWorlds().forEach(w -> {
|
|
||||||
File folder = resolveDatapacksFolder(w.getWorldFolder());
|
|
||||||
if (!worlds.contains(folder)) {
|
|
||||||
worlds.add(folder);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (worlds.isEmpty()) {
|
|
||||||
worlds.add(new File(Bukkit.getWorldContainer(), ServerProperties.LEVEL_NAME + "/datapacks"));
|
|
||||||
}
|
|
||||||
return worlds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean installDataPacks(boolean fullInstall) {
|
public static boolean installDataPacks(boolean fullInstall) {
|
||||||
@@ -250,15 +220,6 @@ public class ServerConfigurator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean shouldDeferInstallUntilWorldsReady() {
|
|
||||||
String forcedMainWorld = IrisSettings.get().getGeneral().forceMainWorld;
|
|
||||||
if (forcedMainWorld != null && !forcedMainWorld.isBlank()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Bukkit.getServer().getWorlds().isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File resolveDatapacksFolder(File worldFolder) {
|
public static File resolveDatapacksFolder(File worldFolder) {
|
||||||
File rootFolder = resolveWorldRootFolder(worldFolder);
|
File rootFolder = resolveWorldRootFolder(worldFolder);
|
||||||
return new File(rootFolder, "datapacks");
|
return new File(rootFolder, "datapacks");
|
||||||
@@ -266,22 +227,9 @@ public class ServerConfigurator {
|
|||||||
|
|
||||||
static File resolveWorldRootFolder(File worldFolder) {
|
static File resolveWorldRootFolder(File worldFolder) {
|
||||||
if (worldFolder == null) {
|
if (worldFolder == null) {
|
||||||
return new File(Bukkit.getWorldContainer(), ServerProperties.LEVEL_NAME);
|
return IrisWorldStorage.levelRoot();
|
||||||
}
|
}
|
||||||
|
return IrisWorldStorage.levelRoot(worldFolder);
|
||||||
File current = worldFolder.getAbsoluteFile();
|
|
||||||
while (current != null) {
|
|
||||||
if ("dimensions".equals(current.getName())) {
|
|
||||||
File parent = current.getParentFile();
|
|
||||||
if (parent != null) {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
current = current.getParentFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
return worldFolder.getAbsoluteFile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean verifyDataPacksPost(boolean allowRestarting) {
|
private static boolean verifyDataPacksPost(boolean allowRestarting) {
|
||||||
@@ -401,13 +349,19 @@ public class ServerConfigurator {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String getWorld(@NonNull IrisData data) {
|
public static String getWorld(@NonNull IrisData data) {
|
||||||
String worldContainer = Bukkit.getWorldContainer().getAbsolutePath();
|
Path packPath = data.getDataFolder().toPath().toAbsolutePath().normalize();
|
||||||
if (!worldContainer.endsWith(File.separator)) worldContainer += File.separator;
|
Path irisPath = packPath.getParent();
|
||||||
|
if (irisPath == null || !"pack".equals(packPath.getFileName().toString()) || !"iris".equals(irisPath.getFileName().toString())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
String path = data.getDataFolder().getAbsolutePath();
|
Path dimensionPath = irisPath.getParent();
|
||||||
if (!path.startsWith(worldContainer)) return null;
|
if (dimensionPath == null) {
|
||||||
int l = path.endsWith(File.separator) ? 11 : 10;
|
return null;
|
||||||
return path.substring(worldContainer.length(), path.length() - l);
|
}
|
||||||
|
File dimensionRoot = dimensionPath.toFile();
|
||||||
|
NamespacedKey key = IrisWorldStorage.keyFromDimensionRoot(IrisWorldStorage.levelRoot(), dimensionRoot).orElse(null);
|
||||||
|
return key == null ? null : key.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DimensionHeight {
|
public static class DimensionHeight {
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ import art.arcane.volmlib.util.mantle.runtime.Mantle;
|
|||||||
import art.arcane.volmlib.util.math.Position2;
|
import art.arcane.volmlib.util.math.Position2;
|
||||||
import art.arcane.volmlib.util.scheduling.ChronoLatch;
|
import art.arcane.volmlib.util.scheduling.ChronoLatch;
|
||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
|
import org.bukkit.generator.WorldInfo;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
@@ -216,13 +218,20 @@ public class PregeneratorJob implements PregenListener, PregenRenderSource {
|
|||||||
return engine.getWorld().name();
|
return engine.getWorld().name();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean targetsWorldName(String worldName) {
|
public boolean targetsWorld(WorldInfo world) {
|
||||||
if (worldName == null || engine == null || engine.getWorld() == null) {
|
if (world == null || engine == null || engine.getWorld() == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String targetName = engine.getWorld().name();
|
return WorldIdentity.key(world).equals(engine.getWorld().key());
|
||||||
return targetName != null && targetName.equalsIgnoreCase(worldName);
|
}
|
||||||
|
|
||||||
|
public boolean targetsWorldIdentity(String worldIdentity) {
|
||||||
|
if (worldIdentity == null || engine == null || engine.getWorld() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return worldIdentity.equals(engine.getWorld().identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Color parseColor(String c) {
|
private static Color parseColor(String c) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package art.arcane.iris.core.lifecycle;
|
package art.arcane.iris.core.lifecycle;
|
||||||
|
|
||||||
import art.arcane.iris.core.nms.INMS;
|
import art.arcane.iris.core.nms.INMS;
|
||||||
import org.bukkit.Bukkit;
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.WorldCreator;
|
import org.bukkit.WorldCreator;
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ final class BukkitPublicBackend implements WorldLifecycleBackend {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<World> create(WorldLifecycleRequest request) {
|
public CompletableFuture<World> create(WorldLifecycleRequest request) {
|
||||||
World existing = Bukkit.getWorld(request.worldName());
|
World existing = WorldIdentity.resolve(request.worldKey()).orElse(null);
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
return CompletableFuture.completedFuture(existing);
|
return CompletableFuture.completedFuture(existing);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package art.arcane.iris.core.lifecycle;
|
package art.arcane.iris.core.lifecycle;
|
||||||
|
|
||||||
import art.arcane.iris.spi.IrisLogging;
|
import art.arcane.iris.spi.IrisLogging;
|
||||||
import org.bukkit.Bukkit;
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -31,7 +31,7 @@ final class PaperLikeRuntimeBackend implements WorldLifecycleBackend {
|
|||||||
public CompletableFuture<World> create(WorldLifecycleRequest request) {
|
public CompletableFuture<World> create(WorldLifecycleRequest request) {
|
||||||
Object legacyStorageAccess = null;
|
Object legacyStorageAccess = null;
|
||||||
try {
|
try {
|
||||||
World existing = Bukkit.getWorld(request.worldName());
|
World existing = WorldIdentity.resolve(request.worldKey()).orElse(null);
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
return CompletableFuture.completedFuture(existing);
|
return CompletableFuture.completedFuture(existing);
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ final class PaperLikeRuntimeBackend implements WorldLifecycleBackend {
|
|||||||
+ ", backend=paper_like_runtime, flavor=" + capabilities.paperLikeFlavor().name().toLowerCase(Locale.ROOT)
|
+ ", backend=paper_like_runtime, flavor=" + capabilities.paperLikeFlavor().name().toLowerCase(Locale.ROOT)
|
||||||
+ ", registrySource=" + WorldLifecycleSupport.runtimeLevelStemRegistrySource(request));
|
+ ", registrySource=" + WorldLifecycleSupport.runtimeLevelStemRegistrySource(request));
|
||||||
Object levelStem = WorldLifecycleSupport.resolveRuntimeLevelStem(capabilities, request);
|
Object levelStem = WorldLifecycleSupport.resolveRuntimeLevelStem(capabilities, request);
|
||||||
Object stemKey = WorldLifecycleSupport.createRuntimeLevelStemKey(request.worldName());
|
Object stemKey = WorldLifecycleSupport.createRuntimeLevelStemKey(request.worldKey());
|
||||||
|
|
||||||
if (capabilities.paperLikeFlavor() == CapabilitySnapshot.PaperLikeFlavor.CURRENT_INFO_AND_DATA) {
|
if (capabilities.paperLikeFlavor() == CapabilitySnapshot.PaperLikeFlavor.CURRENT_INFO_AND_DATA) {
|
||||||
Object dimensionKey = WorldLifecycleSupport.createDimensionKey(stemKey);
|
Object dimensionKey = WorldLifecycleSupport.createDimensionKey(stemKey);
|
||||||
@@ -55,18 +55,18 @@ final class PaperLikeRuntimeBackend implements WorldLifecycleBackend {
|
|||||||
Object worldLoadingInfo = capabilities.worldLoadingInfoConstructor().newInstance(request.environment(), stemKey, dimensionKey, !request.studio());
|
Object worldLoadingInfo = capabilities.worldLoadingInfoConstructor().newInstance(request.environment(), stemKey, dimensionKey, !request.studio());
|
||||||
Object worldLoadingInfoAndData = capabilities.worldLoadingInfoAndDataConstructor().newInstance(worldLoadingInfo, loadedWorldData);
|
Object worldLoadingInfoAndData = capabilities.worldLoadingInfoAndDataConstructor().newInstance(worldLoadingInfo, loadedWorldData);
|
||||||
Object worldDataAndGenSettings = WorldLifecycleSupport.createCurrentWorldDataAndSettings(capabilities, request.worldName());
|
Object worldDataAndGenSettings = WorldLifecycleSupport.createCurrentWorldDataAndSettings(capabilities, request.worldName());
|
||||||
if (!WorldLifecycleSupport.hasExistingWorldData(request.worldName())) {
|
if (!WorldLifecycleSupport.hasExistingWorldData(request.worldKey())) {
|
||||||
worldDataAndGenSettings = WorldLifecycleSupport.applySeedToWorldDataAndGenSettings(worldDataAndGenSettings, request.seed());
|
worldDataAndGenSettings = WorldLifecycleSupport.applySeedToWorldDataAndGenSettings(worldDataAndGenSettings, request.seed());
|
||||||
}
|
}
|
||||||
capabilities.createLevelMethod().invoke(capabilities.minecraftServer(), levelStem, worldLoadingInfoAndData, worldDataAndGenSettings);
|
capabilities.createLevelMethod().invoke(capabilities.minecraftServer(), levelStem, worldLoadingInfoAndData, worldDataAndGenSettings);
|
||||||
} else {
|
} else {
|
||||||
legacyStorageAccess = WorldLifecycleSupport.createLegacyStorageAccess(capabilities, request.worldName());
|
legacyStorageAccess = WorldLifecycleSupport.createLegacyStorageAccess(capabilities);
|
||||||
Object primaryLevelData = WorldLifecycleSupport.createLegacyPrimaryLevelData(capabilities, legacyStorageAccess, request.worldName());
|
Object primaryLevelData = WorldLifecycleSupport.createLegacyPrimaryLevelData(capabilities, legacyStorageAccess, request.worldName());
|
||||||
Object worldLoadingInfo = capabilities.worldLoadingInfoConstructor().newInstance(0, request.worldName(), request.environment().name().toLowerCase(Locale.ROOT), stemKey, !request.studio());
|
Object worldLoadingInfo = capabilities.worldLoadingInfoConstructor().newInstance(0, request.worldName(), request.environment().name().toLowerCase(Locale.ROOT), stemKey, !request.studio());
|
||||||
capabilities.createLevelMethod().invoke(capabilities.minecraftServer(), levelStem, worldLoadingInfo, legacyStorageAccess, primaryLevelData);
|
capabilities.createLevelMethod().invoke(capabilities.minecraftServer(), levelStem, worldLoadingInfo, legacyStorageAccess, primaryLevelData);
|
||||||
}
|
}
|
||||||
|
|
||||||
World loadedWorld = Bukkit.getWorld(request.worldName());
|
World loadedWorld = WorldIdentity.resolve(request.worldKey()).orElse(null);
|
||||||
if (loadedWorld == null) {
|
if (loadedWorld == null) {
|
||||||
return CompletableFuture.failedFuture(new IllegalStateException("Paper-like runtime backend did not load world \"" + request.worldName() + "\"."));
|
return CompletableFuture.failedFuture(new IllegalStateException("Paper-like runtime backend did not load world \"" + request.worldName() + "\"."));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package art.arcane.iris.core.lifecycle;
|
package art.arcane.iris.core.lifecycle;
|
||||||
|
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.WorldCreator;
|
import org.bukkit.WorldCreator;
|
||||||
import org.bukkit.WorldType;
|
import org.bukkit.WorldType;
|
||||||
@@ -8,6 +9,7 @@ import org.bukkit.generator.ChunkGenerator;
|
|||||||
|
|
||||||
public record WorldLifecycleRequest(
|
public record WorldLifecycleRequest(
|
||||||
String worldName,
|
String worldName,
|
||||||
|
NamespacedKey worldKey,
|
||||||
World.Environment environment,
|
World.Environment environment,
|
||||||
ChunkGenerator generator,
|
ChunkGenerator generator,
|
||||||
BiomeProvider biomeProvider,
|
BiomeProvider biomeProvider,
|
||||||
@@ -22,6 +24,7 @@ public record WorldLifecycleRequest(
|
|||||||
public static WorldLifecycleRequest fromCreator(WorldCreator creator, boolean studio, boolean benchmark, WorldLifecycleCaller callerKind) {
|
public static WorldLifecycleRequest fromCreator(WorldCreator creator, boolean studio, boolean benchmark, WorldLifecycleCaller callerKind) {
|
||||||
return new WorldLifecycleRequest(
|
return new WorldLifecycleRequest(
|
||||||
creator.name(),
|
creator.name(),
|
||||||
|
creator.key(),
|
||||||
creator.environment(),
|
creator.environment(),
|
||||||
creator.generator(),
|
creator.generator(),
|
||||||
creator.biomeProvider(),
|
creator.biomeProvider(),
|
||||||
@@ -36,7 +39,7 @@ public record WorldLifecycleRequest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public WorldCreator toWorldCreator() {
|
public WorldCreator toWorldCreator() {
|
||||||
WorldCreator creator = new WorldCreator(worldName)
|
WorldCreator creator = WorldCreator.ofKey(worldKey)
|
||||||
.environment(environment)
|
.environment(environment)
|
||||||
.generateStructures(generateStructures)
|
.generateStructures(generateStructures)
|
||||||
.hardcore(hardcore)
|
.hardcore(hardcore)
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package art.arcane.iris.core.lifecycle;
|
|||||||
|
|
||||||
import art.arcane.iris.spi.IrisLogging;
|
import art.arcane.iris.spi.IrisLogging;
|
||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -18,7 +20,7 @@ public final class WorldLifecycleService {
|
|||||||
private final PaperLikeRuntimeBackend paperLikeRuntimeBackend;
|
private final PaperLikeRuntimeBackend paperLikeRuntimeBackend;
|
||||||
private final BukkitPublicBackend bukkitPublicBackend;
|
private final BukkitPublicBackend bukkitPublicBackend;
|
||||||
private final List<WorldLifecycleBackend> backends;
|
private final List<WorldLifecycleBackend> backends;
|
||||||
private final Map<String, String> worldBackendByName;
|
private final Map<String, String> worldBackendByKey;
|
||||||
|
|
||||||
public WorldLifecycleService(CapabilitySnapshot capabilities) {
|
public WorldLifecycleService(CapabilitySnapshot capabilities) {
|
||||||
this.capabilities = capabilities;
|
this.capabilities = capabilities;
|
||||||
@@ -26,7 +28,7 @@ public final class WorldLifecycleService {
|
|||||||
this.paperLikeRuntimeBackend = new PaperLikeRuntimeBackend(capabilities);
|
this.paperLikeRuntimeBackend = new PaperLikeRuntimeBackend(capabilities);
|
||||||
this.bukkitPublicBackend = new BukkitPublicBackend(capabilities);
|
this.bukkitPublicBackend = new BukkitPublicBackend(capabilities);
|
||||||
this.backends = List.of(worldsProviderBackend, paperLikeRuntimeBackend, bukkitPublicBackend);
|
this.backends = List.of(worldsProviderBackend, paperLikeRuntimeBackend, bukkitPublicBackend);
|
||||||
this.worldBackendByName = new ConcurrentHashMap<>();
|
this.worldBackendByKey = new ConcurrentHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WorldLifecycleService get() {
|
public static WorldLifecycleService get() {
|
||||||
@@ -74,7 +76,7 @@ public final class WorldLifecycleService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (world != null) {
|
if (world != null) {
|
||||||
worldBackendByName.put(world.getName(), backend.backendName());
|
worldBackendByKey.put(WorldIdentity.serialize(world), backend.backendName());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -104,7 +106,8 @@ public final class WorldLifecycleService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean unloadDirect(World world, boolean save) {
|
private boolean unloadDirect(World world, boolean save) {
|
||||||
WorldLifecycleBackend backend = selectUnloadBackend(world.getName());
|
String worldIdentity = WorldIdentity.serialize(world);
|
||||||
|
WorldLifecycleBackend backend = selectUnloadBackend(worldIdentity);
|
||||||
IrisLogging.info("WorldLifecycle unload: world=%s, backend=%s",
|
IrisLogging.info("WorldLifecycle unload: world=%s, backend=%s",
|
||||||
world.getName(),
|
world.getName(),
|
||||||
backend.backendName());
|
backend.backendName());
|
||||||
@@ -124,13 +127,13 @@ public final class WorldLifecycleService {
|
|||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
if (unloaded) {
|
if (unloaded) {
|
||||||
worldBackendByName.remove(world.getName());
|
worldBackendByKey.remove(worldIdentity);
|
||||||
}
|
}
|
||||||
return unloaded;
|
return unloaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String backendNameForWorld(String worldName) {
|
public String backendNameForWorld(NamespacedKey worldKey) {
|
||||||
return selectUnloadBackend(worldName).backendName();
|
return selectUnloadBackend(worldKey.toString()).backendName();
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldLifecycleBackend selectCreateBackend(WorldLifecycleRequest request) {
|
WorldLifecycleBackend selectCreateBackend(WorldLifecycleRequest request) {
|
||||||
@@ -155,8 +158,8 @@ public final class WorldLifecycleService {
|
|||||||
throw new IllegalStateException("No world lifecycle backend supports request for \"" + request.worldName() + "\".");
|
throw new IllegalStateException("No world lifecycle backend supports request for \"" + request.worldName() + "\".");
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldLifecycleBackend selectUnloadBackend(String worldName) {
|
WorldLifecycleBackend selectUnloadBackend(String worldIdentity) {
|
||||||
String backendName = worldBackendByName.get(worldName);
|
String backendName = worldBackendByKey.get(worldIdentity);
|
||||||
if (backendName == null) {
|
if (backendName == null) {
|
||||||
return bukkitPublicBackend;
|
return bukkitPublicBackend;
|
||||||
}
|
}
|
||||||
@@ -170,7 +173,7 @@ public final class WorldLifecycleService {
|
|||||||
return bukkitPublicBackend;
|
return bukkitPublicBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rememberBackend(String worldName, String backendName) {
|
void rememberBackend(NamespacedKey worldKey, String backendName) {
|
||||||
worldBackendByName.put(worldName, backendName);
|
worldBackendByKey.put(worldKey.toString(), backendName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
package art.arcane.iris.core.lifecycle;
|
package art.arcane.iris.core.lifecycle;
|
||||||
|
|
||||||
|
import art.arcane.iris.core.IrisWorldStorage;
|
||||||
import art.arcane.iris.core.link.Identifier;
|
import art.arcane.iris.core.link.Identifier;
|
||||||
import art.arcane.iris.core.nms.INMS;
|
import art.arcane.iris.core.nms.INMS;
|
||||||
import art.arcane.iris.core.nms.INMSBinding;
|
import art.arcane.iris.core.nms.INMSBinding;
|
||||||
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
@@ -18,7 +21,6 @@ import java.lang.reflect.Field;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.OptionalLong;
|
import java.util.OptionalLong;
|
||||||
@@ -119,10 +121,8 @@ final class WorldLifecycleSupport {
|
|||||||
return lookupMethod.invoke(datapackDimensions, levelStemRegistryKey);
|
return lookupMethod.invoke(datapackDimensions, levelStemRegistryKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object createRuntimeLevelStemKey(String worldName) throws ReflectiveOperationException {
|
static Object createRuntimeLevelStemKey(NamespacedKey worldKey) throws ReflectiveOperationException {
|
||||||
String sanitized = worldName.toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9/_-]", "_");
|
Identifier identifier = new Identifier(worldKey.getNamespace(), worldKey.getKey());
|
||||||
String path = "runtime/" + sanitized;
|
|
||||||
Identifier identifier = new Identifier("iris", path);
|
|
||||||
Object rawIdentifier = Class.forName("net.minecraft.resources.Identifier")
|
Object rawIdentifier = Class.forName("net.minecraft.resources.Identifier")
|
||||||
.getMethod("fromNamespaceAndPath", String.class, String.class)
|
.getMethod("fromNamespaceAndPath", String.class, String.class)
|
||||||
.invoke(null, identifier.namespace(), identifier.key());
|
.invoke(null, identifier.namespace(), identifier.key());
|
||||||
@@ -253,11 +253,13 @@ final class WorldLifecycleSupport {
|
|||||||
setModdedInfoMethod.invoke(worldData, modName, modified);
|
setModdedInfoMethod.invoke(worldData, modName, modified);
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean hasExistingWorldData(String worldName) {
|
static boolean hasExistingWorldData(NamespacedKey worldKey) {
|
||||||
File worldFolder = new File(Bukkit.getWorldContainer(), worldName);
|
File worldFolder = IrisWorldStorage.dimensionRoot(worldKey);
|
||||||
return new File(worldFolder, "level.dat").exists()
|
return new File(worldFolder, "region").exists()
|
||||||
|| new File(worldFolder, "region").exists()
|
|| new File(worldFolder, "entities").exists()
|
||||||
|| new File(worldFolder, "data").exists();
|
|| new File(worldFolder, "poi").exists()
|
||||||
|
|| new File(worldFolder, "data/paper/metadata.dat").exists()
|
||||||
|
|| new File(worldFolder, "paper-world.yml").exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object applySeedToWorldDataAndGenSettings(Object worldDataAndGenSettings, long seed) throws ReflectiveOperationException {
|
static Object applySeedToWorldDataAndGenSettings(Object worldDataAndGenSettings, long seed) throws ReflectiveOperationException {
|
||||||
@@ -386,18 +388,19 @@ final class WorldLifecycleSupport {
|
|||||||
return primaryLevelData;
|
return primaryLevelData;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object createLegacyStorageAccess(CapabilitySnapshot capabilities, String worldName) throws ReflectiveOperationException {
|
static Object createLegacyStorageAccess(CapabilitySnapshot capabilities) throws ReflectiveOperationException {
|
||||||
Class<?> levelStorageSourceClass = Class.forName("net.minecraft.world.level.storage.LevelStorageSource");
|
Class<?> levelStorageSourceClass = Class.forName("net.minecraft.world.level.storage.LevelStorageSource");
|
||||||
Method createDefaultMethod = levelStorageSourceClass.getMethod("createDefault", Path.class);
|
Method createDefaultMethod = levelStorageSourceClass.getMethod("createDefault", Path.class);
|
||||||
Object levelStorageSource = createDefaultMethod.invoke(null, Bukkit.getWorldContainer().toPath());
|
File levelRoot = IrisWorldStorage.levelRoot();
|
||||||
|
Object levelStorageSource = createDefaultMethod.invoke(null, levelRoot.getParentFile().toPath());
|
||||||
Method storageAccessMethod = capabilities.levelStorageAccessMethod();
|
Method storageAccessMethod = capabilities.levelStorageAccessMethod();
|
||||||
if (storageAccessMethod.getParameterCount() == 1) {
|
if (storageAccessMethod.getParameterCount() == 1) {
|
||||||
return storageAccessMethod.invoke(levelStorageSource, worldName);
|
return storageAccessMethod.invoke(levelStorageSource, levelRoot.getName());
|
||||||
}
|
}
|
||||||
Object overworldStemKey = Class.forName("net.minecraft.world.level.dimension.LevelStem")
|
Object overworldStemKey = Class.forName("net.minecraft.world.level.dimension.LevelStem")
|
||||||
.getField("OVERWORLD")
|
.getField("OVERWORLD")
|
||||||
.get(null);
|
.get(null);
|
||||||
return storageAccessMethod.invoke(levelStorageSource, worldName, overworldStemKey);
|
return storageAccessMethod.invoke(levelStorageSource, levelRoot.getName(), overworldStemKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void closeLevelStorageAccess(Object levelStorageAccess) {
|
static void closeLevelStorageAccess(Object levelStorageAccess) {
|
||||||
@@ -437,8 +440,8 @@ final class WorldLifecycleSupport {
|
|||||||
Method getHandleMethod = world.getClass().getMethod("getHandle");
|
Method getHandleMethod = world.getClass().getMethod("getHandle");
|
||||||
Object serverLevel = getHandleMethod.invoke(world);
|
Object serverLevel = getHandleMethod.invoke(world);
|
||||||
closeServerLevel(world, serverLevel);
|
closeServerLevel(world, serverLevel);
|
||||||
detachServerLevel(capabilities, serverLevel, world.getName());
|
detachServerLevel(capabilities, serverLevel, world);
|
||||||
return Bukkit.getWorld(world.getName()) == null;
|
return WorldIdentity.resolve(WorldIdentity.key(world)).isEmpty();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new IllegalStateException("Failed to unload world \"" + world.getName() + "\" through the selected world lifecycle backend.", unwrap(e));
|
throw new IllegalStateException("Failed to unload world \"" + world.getName() + "\" through the selected world lifecycle backend.", unwrap(e));
|
||||||
}
|
}
|
||||||
@@ -527,7 +530,7 @@ final class WorldLifecycleSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
private static void removeWorldFromCraftServerMap(String worldName) throws ReflectiveOperationException {
|
private static void removeWorldFromCraftServerMap(World world) throws ReflectiveOperationException {
|
||||||
Object bukkitServer = Bukkit.getServer();
|
Object bukkitServer = Bukkit.getServer();
|
||||||
if (bukkitServer == null) {
|
if (bukkitServer == null) {
|
||||||
return;
|
return;
|
||||||
@@ -536,16 +539,17 @@ final class WorldLifecycleSupport {
|
|||||||
Field worldsField = CapabilityResolution.resolveField(bukkitServer.getClass(), "worlds");
|
Field worldsField = CapabilityResolution.resolveField(bukkitServer.getClass(), "worlds");
|
||||||
Object rawWorlds = worldsField.get(bukkitServer);
|
Object rawWorlds = worldsField.get(bukkitServer);
|
||||||
if (rawWorlds instanceof Map map) {
|
if (rawWorlds instanceof Map map) {
|
||||||
map.remove(worldName);
|
map.remove(WorldIdentity.key(world));
|
||||||
map.remove(worldName.toLowerCase(Locale.ROOT));
|
map.remove(WorldIdentity.serialize(world));
|
||||||
|
map.remove(world.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void detachServerLevel(CapabilitySnapshot capabilities, Object serverLevel, String worldName) throws Throwable {
|
private static void detachServerLevel(CapabilitySnapshot capabilities, Object serverLevel, World world) throws Throwable {
|
||||||
Runnable detachTask = () -> {
|
Runnable detachTask = () -> {
|
||||||
try {
|
try {
|
||||||
capabilities.removeLevelMethod().invoke(capabilities.minecraftServer(), serverLevel);
|
capabilities.removeLevelMethod().invoke(capabilities.minecraftServer(), serverLevel);
|
||||||
removeWorldFromCraftServerMap(worldName);
|
removeWorldFromCraftServerMap(world);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -558,7 +562,7 @@ final class WorldLifecycleSupport {
|
|||||||
|
|
||||||
CompletableFuture<Void> detachFuture = J.sfut(detachTask);
|
CompletableFuture<Void> detachFuture = J.sfut(detachTask);
|
||||||
if (detachFuture == null) {
|
if (detachFuture == null) {
|
||||||
throw new IllegalStateException("Failed to schedule global detach task for world \"" + worldName + "\".");
|
throw new IllegalStateException("Failed to schedule global detach task for world \"" + world.getName() + "\".");
|
||||||
}
|
}
|
||||||
detachFuture.get(15, TimeUnit.SECONDS);
|
detachFuture.get(15, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
package art.arcane.iris.core.lifecycle;
|
package art.arcane.iris.core.lifecycle;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import art.arcane.iris.core.IrisWorldStorage;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.WorldType;
|
import org.bukkit.WorldType;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@@ -25,7 +24,7 @@ final class WorldsProviderBackend implements WorldLifecycleBackend {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public CompletableFuture<World> create(WorldLifecycleRequest request) {
|
public CompletableFuture<World> create(WorldLifecycleRequest request) {
|
||||||
try {
|
try {
|
||||||
Path worldPath = new File(Bukkit.getWorldContainer(), request.worldName()).toPath();
|
Path worldPath = IrisWorldStorage.dimensionRoot(request.worldKey()).toPath();
|
||||||
Object builder = WorldLifecycleSupport.invokeNamed(capabilities.worldsProvider(), "levelBuilder", new Class[]{Path.class}, worldPath);
|
Object builder = WorldLifecycleSupport.invokeNamed(capabilities.worldsProvider(), "levelBuilder", new Class[]{Path.class}, worldPath);
|
||||||
builder = WorldLifecycleSupport.invokeNamed(builder, "name", new Class[]{String.class}, request.worldName());
|
builder = WorldLifecycleSupport.invokeNamed(builder, "name", new Class[]{String.class}, request.worldName());
|
||||||
builder = WorldLifecycleSupport.invokeNamed(builder, "seed", new Class[]{long.class}, request.seed());
|
builder = WorldLifecycleSupport.invokeNamed(builder, "seed", new Class[]{long.class}, request.seed());
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package art.arcane.iris.core.runtime;
|
package art.arcane.iris.core.runtime;
|
||||||
|
|
||||||
|
import art.arcane.iris.core.IrisWorldStorage;
|
||||||
import art.arcane.iris.spi.IrisLogging;
|
import art.arcane.iris.spi.IrisLogging;
|
||||||
import art.arcane.iris.spi.IrisServices;
|
import art.arcane.iris.spi.IrisServices;
|
||||||
import art.arcane.iris.core.lifecycle.WorldLifecycleService;
|
import art.arcane.iris.core.lifecycle.WorldLifecycleService;
|
||||||
@@ -10,6 +11,7 @@ import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
|||||||
import art.arcane.iris.util.common.plugin.VolmitSender;
|
import art.arcane.iris.util.common.plugin.VolmitSender;
|
||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
import art.arcane.volmlib.util.exceptions.IrisException;
|
import art.arcane.volmlib.util.exceptions.IrisException;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import art.arcane.volmlib.util.io.IO;
|
import art.arcane.volmlib.util.io.IO;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@@ -327,7 +329,7 @@ public final class StudioOpenCoordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (String familyWorldName : TransientWorldCleanupSupport.worldFamilyNames(worldName)) {
|
for (String familyWorldName : TransientWorldCleanupSupport.worldFamilyNames(worldName)) {
|
||||||
World familyWorld = Bukkit.getWorld(familyWorldName);
|
World familyWorld = WorldIdentity.resolve(IrisWorldStorage.keyFromLegacyName(familyWorldName)).orElse(null);
|
||||||
if (familyWorld == null) {
|
if (familyWorld == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -342,10 +344,9 @@ public final class StudioOpenCoordinator {
|
|||||||
return new WorldFamilyDeleteResult(true, false);
|
return new WorldFamilyDeleteResult(true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
File container = Bukkit.getWorldContainer();
|
|
||||||
boolean liveDeleted = true;
|
boolean liveDeleted = true;
|
||||||
for (String familyWorldName : TransientWorldCleanupSupport.worldFamilyNames(worldName)) {
|
for (String familyWorldName : TransientWorldCleanupSupport.worldFamilyNames(worldName)) {
|
||||||
File folder = new File(container, familyWorldName);
|
File folder = IrisWorldStorage.dimensionRoot(familyWorldName);
|
||||||
if (!folder.exists()) {
|
if (!folder.exists()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -378,15 +379,14 @@ public final class StudioOpenCoordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void cleanupStaleTransientWorlds(String worldName) {
|
private void cleanupStaleTransientWorlds(String worldName) {
|
||||||
File container = Bukkit.getWorldContainer();
|
LinkedHashSet<String> staleWorldNames = TransientWorldCleanupSupport.collectTransientStudioWorldNames(IrisWorldStorage.levelRoot());
|
||||||
LinkedHashSet<String> staleWorldNames = TransientWorldCleanupSupport.collectTransientStudioWorldNames(container);
|
|
||||||
String requestedBaseName = TransientWorldCleanupSupport.transientStudioBaseWorldName(worldName);
|
String requestedBaseName = TransientWorldCleanupSupport.transientStudioBaseWorldName(worldName);
|
||||||
if (requestedBaseName != null) {
|
if (requestedBaseName != null) {
|
||||||
staleWorldNames.add(requestedBaseName);
|
staleWorldNames.add(requestedBaseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String staleWorldName : staleWorldNames) {
|
for (String staleWorldName : staleWorldNames) {
|
||||||
if (Bukkit.getWorld(staleWorldName) != null) {
|
if (WorldIdentity.resolve(IrisWorldStorage.keyFromLegacyName(staleWorldName)).isPresent()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,7 +480,7 @@ public final class StudioOpenCoordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (String familyWorldName : TransientWorldCleanupSupport.worldFamilyNames(worldName)) {
|
for (String familyWorldName : TransientWorldCleanupSupport.worldFamilyNames(worldName)) {
|
||||||
if (Bukkit.getWorld(familyWorldName) != null) {
|
if (WorldIdentity.resolve(IrisWorldStorage.keyFromLegacyName(familyWorldName)).isPresent()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,31 +49,38 @@ public final class TransientWorldCleanupSupport {
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LinkedHashSet<String> collectTransientStudioWorldNames(File worldContainer) {
|
public static LinkedHashSet<String> collectTransientStudioWorldNames(File levelRoot) {
|
||||||
LinkedHashSet<String> names = new LinkedHashSet<>();
|
LinkedHashSet<String> names = new LinkedHashSet<>();
|
||||||
if (worldContainer == null) {
|
if (levelRoot == null) {
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
File[] children = worldContainer.listFiles();
|
File namespacesRoot = new File(levelRoot, "dimensions");
|
||||||
if (children == null) {
|
File[] namespaces = namespacesRoot.listFiles(File::isDirectory);
|
||||||
|
if (namespaces == null) {
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (File namespace : namespaces) {
|
||||||
|
collectTransientStudioWorldNames(namespace, names);
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void collectTransientStudioWorldNames(File folder, LinkedHashSet<String> names) {
|
||||||
|
File[] children = folder.listFiles(File::isDirectory);
|
||||||
|
if (children == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (File child : children) {
|
for (File child : children) {
|
||||||
if (child == null || !child.isDirectory()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String baseName = transientStudioBaseWorldName(child.getName());
|
String baseName = transientStudioBaseWorldName(child.getName());
|
||||||
if (baseName == null) {
|
if (baseName != null) {
|
||||||
|
names.add(baseName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
collectTransientStudioWorldNames(child, names);
|
||||||
names.add(baseName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return names;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String normalizeWorldName(String worldName) {
|
private static String normalizeWorldName(String worldName) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package art.arcane.iris.core.safeguard.task;
|
|||||||
import art.arcane.iris.BuildConstants;
|
import art.arcane.iris.BuildConstants;
|
||||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||||
import art.arcane.iris.core.IrisWorlds;
|
import art.arcane.iris.core.IrisWorlds;
|
||||||
|
import art.arcane.iris.core.IrisWorldStorage;
|
||||||
import art.arcane.iris.core.nms.INMS;
|
import art.arcane.iris.core.nms.INMS;
|
||||||
import art.arcane.iris.core.nms.v1X.NMSBinding1X;
|
import art.arcane.iris.core.nms.v1X.NMSBinding1X;
|
||||||
import art.arcane.iris.core.safeguard.Mode;
|
import art.arcane.iris.core.safeguard.Mode;
|
||||||
@@ -137,7 +138,7 @@ public final class Tasks {
|
|||||||
});
|
});
|
||||||
|
|
||||||
private static final Task DISK_SPACE = Task.of("diskSpace", () -> {
|
private static final Task DISK_SPACE = Task.of("diskSpace", () -> {
|
||||||
double freeGiB = server().getWorldContainer().getFreeSpace() / (double) 0x4000_0000;
|
double freeGiB = IrisWorldStorage.levelRoot().getFreeSpace() / (double) 0x4000_0000;
|
||||||
if (freeGiB > 3.0) {
|
if (freeGiB > 3.0) {
|
||||||
return withDiagnostics(Mode.STABLE);
|
return withDiagnostics(Mode.STABLE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package art.arcane.iris.core.service;
|
package art.arcane.iris.core.service;
|
||||||
|
|
||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
|
import art.arcane.iris.core.IrisWorldStorage;
|
||||||
import art.arcane.iris.core.pregenerator.cache.PregenCache;
|
import art.arcane.iris.core.pregenerator.cache.PregenCache;
|
||||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import art.arcane.volmlib.util.collection.KMap;
|
import art.arcane.volmlib.util.collection.KMap;
|
||||||
import art.arcane.iris.util.common.plugin.IrisService;
|
import art.arcane.iris.util.common.plugin.IrisService;
|
||||||
import art.arcane.volmlib.util.scheduling.Looper;
|
import art.arcane.volmlib.util.scheduling.Looper;
|
||||||
@@ -64,7 +66,7 @@ public class GlobalCacheSVC implements IrisService {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public PregenCache get(@NonNull World world) {
|
public PregenCache get(@NonNull World world) {
|
||||||
return globalCache.get(world.getName());
|
return globalCache.get(WorldIdentity.serialize(world));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -80,7 +82,7 @@ public class GlobalCacheSVC implements IrisService {
|
|||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR)
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
public void on(WorldUnloadEvent event) {
|
public void on(WorldUnloadEvent event) {
|
||||||
var cache = globalCache.remove(event.getWorld().getName());
|
PregenCache cache = globalCache.remove(WorldIdentity.serialize(event.getWorld()));
|
||||||
if (cache == null) return;
|
if (cache == null) return;
|
||||||
cache.write();
|
cache.write();
|
||||||
}
|
}
|
||||||
@@ -94,7 +96,8 @@ public class GlobalCacheSVC implements IrisService {
|
|||||||
|
|
||||||
private void createCache(World world) {
|
private void createCache(World world) {
|
||||||
if (!IrisToolbelt.isIrisWorld(world)) return;
|
if (!IrisToolbelt.isIrisWorld(world)) return;
|
||||||
globalCache.computeIfAbsent(world.getName(), GlobalCacheSVC::createDefault);
|
String worldIdentity = WorldIdentity.serialize(world);
|
||||||
|
globalCache.computeIfAbsent(worldIdentity, GlobalCacheSVC::createDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDisabled() {
|
private boolean isDisabled() {
|
||||||
@@ -116,25 +119,26 @@ public class GlobalCacheSVC implements IrisService {
|
|||||||
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static PregenCache createCache(@NonNull String worldName, @NonNull Function<String, PregenCache> provider) {
|
public static PregenCache createCache(@NonNull String worldIdentity, @NonNull Function<String, PregenCache> provider) {
|
||||||
PregenCache[] holder = new PregenCache[1];
|
PregenCache[] holder = new PregenCache[1];
|
||||||
REFERENCE_CACHE.compute(worldName, (name, ref) -> {
|
REFERENCE_CACHE.compute(worldIdentity, (identity, ref) -> {
|
||||||
if (ref != null) {
|
if (ref != null) {
|
||||||
if ((holder[0] = ref.get()) != null)
|
if ((holder[0] = ref.get()) != null)
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
return new WeakReference<>(holder[0] = provider.apply(worldName));
|
return new WeakReference<>(holder[0] = provider.apply(worldIdentity));
|
||||||
});
|
});
|
||||||
return holder[0];
|
return holder[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static PregenCache createDefault(@NonNull String worldName) {
|
public static PregenCache createDefault(@NonNull String worldIdentity) {
|
||||||
return createCache(worldName, GlobalCacheSVC::createDefault0);
|
return createCache(worldIdentity, GlobalCacheSVC::createDefault0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PregenCache createDefault0(String worldName) {
|
private static PregenCache createDefault0(String worldIdentity) {
|
||||||
if (disabled) return PregenCache.EMPTY;
|
if (disabled) return PregenCache.EMPTY;
|
||||||
return PregenCache.create(new File(Bukkit.getWorldContainer(), String.join(File.separator, worldName, "iris", "pregen"))).sync();
|
File dimensionRoot = IrisWorldStorage.dimensionRoot(WorldIdentity.parse(worldIdentity));
|
||||||
|
return PregenCache.create(new File(dimensionRoot, "iris/pregen")).sync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,6 +22,7 @@ import com.google.gson.JsonSyntaxException;
|
|||||||
import art.arcane.iris.spi.IrisLogging;
|
import art.arcane.iris.spi.IrisLogging;
|
||||||
import art.arcane.iris.spi.IrisServices;
|
import art.arcane.iris.spi.IrisServices;
|
||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
|
import art.arcane.iris.core.IrisWorldStorage;
|
||||||
import art.arcane.iris.core.ServerConfigurator;
|
import art.arcane.iris.core.ServerConfigurator;
|
||||||
import art.arcane.iris.core.lifecycle.WorldLifecycleService;
|
import art.arcane.iris.core.lifecycle.WorldLifecycleService;
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
import art.arcane.iris.core.loader.IrisData;
|
||||||
@@ -86,7 +87,7 @@ public class StudioSVC implements IrisService {
|
|||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
IrisLogging.debug("Studio Mode Active: Closing Projects");
|
IrisLogging.debug("Studio Mode Active: Closing Projects");
|
||||||
boolean stopping = IrisToolbelt.isServerStopping();
|
boolean stopping = IrisToolbelt.isServerStopping();
|
||||||
LinkedHashSet<String> worldNamesToDelete = new LinkedHashSet<>(TransientWorldCleanupSupport.collectTransientStudioWorldNames(Bukkit.getWorldContainer()));
|
LinkedHashSet<String> worldNamesToDelete = new LinkedHashSet<>(TransientWorldCleanupSupport.collectTransientStudioWorldNames(IrisWorldStorage.levelRoot()));
|
||||||
|
|
||||||
if (activeProject != null) {
|
if (activeProject != null) {
|
||||||
PlatformChunkGenerator activeProvider = activeProject.getActiveProvider();
|
PlatformChunkGenerator activeProvider = activeProject.getActiveProvider();
|
||||||
@@ -425,9 +426,8 @@ public class StudioSVC implements IrisService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
File container = Bukkit.getWorldContainer();
|
|
||||||
for (String familyWorldName : TransientWorldCleanupSupport.worldFamilyNames(worldName)) {
|
for (String familyWorldName : TransientWorldCleanupSupport.worldFamilyNames(worldName)) {
|
||||||
File folder = new File(container, familyWorldName);
|
File folder = IrisWorldStorage.dimensionRoot(familyWorldName);
|
||||||
if (!folder.exists()) {
|
if (!folder.exists()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.core.structure;
|
package art.arcane.iris.core.structure;
|
||||||
|
|
||||||
|
import art.arcane.iris.core.IrisWorldStorage;
|
||||||
import art.arcane.iris.spi.IrisLogging;
|
import art.arcane.iris.spi.IrisLogging;
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
import art.arcane.iris.core.loader.IrisData;
|
||||||
import art.arcane.iris.core.nms.INMS;
|
import art.arcane.iris.core.nms.INMS;
|
||||||
@@ -28,6 +29,7 @@ import art.arcane.iris.util.common.format.C;
|
|||||||
import art.arcane.iris.util.common.plugin.VolmitSender;
|
import art.arcane.iris.util.common.plugin.VolmitSender;
|
||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
import art.arcane.volmlib.util.collection.KList;
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import art.arcane.volmlib.util.io.IO;
|
import art.arcane.volmlib.util.io.IO;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@@ -293,11 +295,11 @@ public final class FeatureImporter {
|
|||||||
|
|
||||||
static World createScratchWorld(VolmitSender sender) {
|
static World createScratchWorld(VolmitSender sender) {
|
||||||
try {
|
try {
|
||||||
World existing = Bukkit.getWorld(SCRATCH_WORLD_NAME);
|
World existing = WorldIdentity.resolve(IrisWorldStorage.keyFromLegacyName(SCRATCH_WORLD_NAME)).orElse(null);
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
WorldCreator creator = new WorldCreator(SCRATCH_WORLD_NAME)
|
WorldCreator creator = WorldCreator.ofKey(IrisWorldStorage.keyFromLegacyName(SCRATCH_WORLD_NAME))
|
||||||
.environment(World.Environment.NORMAL)
|
.environment(World.Environment.NORMAL)
|
||||||
.type(WorldType.FLAT)
|
.type(WorldType.FLAT)
|
||||||
.generateStructures(false);
|
.generateStructures(false);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import art.arcane.iris.spi.IrisServices;
|
|||||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||||
import art.arcane.iris.core.link.MultiverseCoreLink;
|
import art.arcane.iris.core.link.MultiverseCoreLink;
|
||||||
import art.arcane.iris.core.IrisRuntimeSchedulerMode;
|
import art.arcane.iris.core.IrisRuntimeSchedulerMode;
|
||||||
|
import art.arcane.iris.core.IrisWorldStorage;
|
||||||
import art.arcane.iris.core.IrisWorlds;
|
import art.arcane.iris.core.IrisWorlds;
|
||||||
import art.arcane.iris.core.IrisSettings;
|
import art.arcane.iris.core.IrisSettings;
|
||||||
import art.arcane.iris.core.ServerConfigurator;
|
import art.arcane.iris.core.ServerConfigurator;
|
||||||
@@ -50,7 +51,6 @@ import org.bukkit.WorldCreator;
|
|||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@@ -166,7 +166,7 @@ public class IrisCreator {
|
|||||||
|
|
||||||
reportStudioProgress(0.16D, "prepare_world_pack");
|
reportStudioProgress(0.16D, "prepare_world_pack");
|
||||||
if (!studio() || benchmark) {
|
if (!studio() || benchmark) {
|
||||||
d = IrisServices.get(StudioSVC.class).installIntoWorld(sender, d, new File(Bukkit.getWorldContainer(), name()));
|
d = IrisServices.get(StudioSVC.class).installIntoWorld(sender, d, IrisWorldStorage.dimensionRoot(name()));
|
||||||
if (d == null) {
|
if (d == null) {
|
||||||
throw new IrisException("Failed to install dimension pack for " + dimension());
|
throw new IrisException("Failed to install dimension pack for " + dimension());
|
||||||
}
|
}
|
||||||
@@ -188,7 +188,7 @@ public class IrisCreator {
|
|||||||
.studio(studio)
|
.studio(studio)
|
||||||
.create();
|
.create();
|
||||||
if (!studio()) {
|
if (!studio()) {
|
||||||
IrisWorlds.get().put(name(), dimension());
|
IrisWorlds.get().put(wc.key().toString(), dimension());
|
||||||
}
|
}
|
||||||
ServerConfigurator.installDataPacksIfChanged(!studio());
|
ServerConfigurator.installDataPacksIfChanged(!studio());
|
||||||
IrisLogging.debug("[Studio timing] create.packPrep + datapacks = " + (System.currentTimeMillis() - createStart) + "ms (cumulative in create)");
|
IrisLogging.debug("[Studio timing] create.packPrep + datapacks = " + (System.currentTimeMillis() - createStart) + "ms (cumulative in create)");
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package art.arcane.iris.core.tools;
|
package art.arcane.iris.core.tools;
|
||||||
|
|
||||||
|
|
||||||
|
import art.arcane.iris.core.IrisWorldStorage;
|
||||||
import art.arcane.iris.spi.IrisLogging;
|
import art.arcane.iris.spi.IrisLogging;
|
||||||
import art.arcane.iris.spi.IrisPlatforms;
|
import art.arcane.iris.spi.IrisPlatforms;
|
||||||
import art.arcane.iris.core.lifecycle.WorldLifecycleService;
|
import art.arcane.iris.core.lifecycle.WorldLifecycleService;
|
||||||
@@ -9,12 +10,13 @@ import art.arcane.iris.engine.framework.Engine;
|
|||||||
import art.arcane.iris.engine.object.IrisDimension;
|
import art.arcane.iris.engine.object.IrisDimension;
|
||||||
import art.arcane.volmlib.util.collection.KList;
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
import art.arcane.volmlib.util.collection.KMap;
|
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.exceptions.IrisException;
|
||||||
import art.arcane.volmlib.util.format.Form;
|
import art.arcane.volmlib.util.format.Form;
|
||||||
import art.arcane.volmlib.util.io.IO;
|
import art.arcane.volmlib.util.io.IO;
|
||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.World;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
@@ -47,9 +49,9 @@ public class IrisPackBenchmarking {
|
|||||||
.name("PackBenchmarking")
|
.name("PackBenchmarking")
|
||||||
.start(() -> {
|
.start(() -> {
|
||||||
IrisLogging.info("Setting up benchmark environment ");
|
IrisLogging.info("Setting up benchmark environment ");
|
||||||
IO.delete(new File(Bukkit.getWorldContainer(), "benchmark"));
|
IO.delete(IrisWorldStorage.dimensionRoot("benchmark"));
|
||||||
createBenchmark();
|
createBenchmark();
|
||||||
while (!IrisToolbelt.isIrisWorld(Bukkit.getWorld("benchmark"))) {
|
while (!IrisToolbelt.isIrisWorld(benchmarkWorld())) {
|
||||||
J.sleep(1000);
|
J.sleep(1000);
|
||||||
IrisLogging.debug("Iris PackBenchmark: Waiting...");
|
IrisLogging.debug("Iris PackBenchmark: Waiting...");
|
||||||
}
|
}
|
||||||
@@ -63,7 +65,11 @@ public class IrisPackBenchmarking {
|
|||||||
public void finishedBenchmark(KList<Integer> cps) {
|
public void finishedBenchmark(KList<Integer> cps) {
|
||||||
try {
|
try {
|
||||||
String time = Form.duration((long) stopwatch.getMilliseconds());
|
String time = Form.duration((long) stopwatch.getMilliseconds());
|
||||||
Engine engine = IrisToolbelt.access(Bukkit.getWorld("benchmark")).getEngine();
|
World benchmarkWorld = benchmarkWorld();
|
||||||
|
if (benchmarkWorld == null) {
|
||||||
|
throw new IllegalStateException("Benchmark world is not loaded.");
|
||||||
|
}
|
||||||
|
Engine engine = IrisToolbelt.access(benchmarkWorld).getEngine();
|
||||||
IrisLogging.info("-----------------");
|
IrisLogging.info("-----------------");
|
||||||
IrisLogging.info("Results:");
|
IrisLogging.info("Results:");
|
||||||
IrisLogging.info("- Total time: " + time);
|
IrisLogging.info("- Total time: " + time);
|
||||||
@@ -101,7 +107,7 @@ public class IrisPackBenchmarking {
|
|||||||
}
|
}
|
||||||
|
|
||||||
J.s(() -> {
|
J.s(() -> {
|
||||||
org.bukkit.World world = Bukkit.getWorld("benchmark");
|
World world = benchmarkWorld();
|
||||||
if (world == null) return;
|
if (world == null) return;
|
||||||
IrisToolbelt.evacuate(world);
|
IrisToolbelt.evacuate(world);
|
||||||
WorldLifecycleService.get().unload(world, true);
|
WorldLifecycleService.get().unload(world, true);
|
||||||
@@ -136,13 +142,17 @@ public class IrisPackBenchmarking {
|
|||||||
.gui(gui)
|
.gui(gui)
|
||||||
.radiusX(radius)
|
.radiusX(radius)
|
||||||
.radiusZ(radius)
|
.radiusZ(radius)
|
||||||
.build(), Bukkit.getWorld("benchmark")
|
.build(), benchmarkWorld()
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
instance.remove();
|
instance.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static World benchmarkWorld() {
|
||||||
|
return WorldIdentity.resolve(IrisWorldStorage.keyFromLegacyName("benchmark")).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
private double calculateAverage(KList<Integer> list) {
|
private double calculateAverage(KList<Integer> list) {
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
for (int num : list) {
|
for (int num : list) {
|
||||||
|
|||||||
@@ -37,10 +37,12 @@ import art.arcane.iris.core.service.GlobalCacheSVC;
|
|||||||
import art.arcane.iris.core.service.StudioSVC;
|
import art.arcane.iris.core.service.StudioSVC;
|
||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
import art.arcane.iris.engine.object.IrisDimension;
|
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.engine.platform.BukkitChunkGenerator;
|
||||||
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
import art.arcane.iris.util.common.plugin.VolmitSender;
|
import art.arcane.iris.util.common.plugin.VolmitSender;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import io.papermc.lib.PaperLib;
|
import io.papermc.lib.PaperLib;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@@ -222,14 +224,14 @@ public class IrisToolbelt {
|
|||||||
return ((PlatformChunkGenerator) world.getGenerator());
|
return ((PlatformChunkGenerator) world.getGenerator());
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioSVC studioService = IrisServices.get(StudioSVC.class);
|
StudioSVC studioService = IrisServices.getOrNull(StudioSVC.class);
|
||||||
if (studioService != null && studioService.isProjectOpen()) {
|
if (studioService != null && studioService.isProjectOpen()) {
|
||||||
IrisProject activeProject = studioService.getActiveProject();
|
IrisProject activeProject = studioService.getActiveProject();
|
||||||
if (activeProject != null) {
|
if (activeProject != null) {
|
||||||
PlatformChunkGenerator activeProvider = activeProject.getActiveProvider();
|
PlatformChunkGenerator activeProvider = activeProject.getActiveProvider();
|
||||||
if (activeProvider != null) {
|
if (activeProvider != null) {
|
||||||
World activeWorld = activeProvider.getTarget().getWorld().realWorld();
|
World activeWorld = activeProvider.getTarget().getWorld().realWorld();
|
||||||
if (activeWorld != null && activeWorld.getName().equals(world.getName())) {
|
if (activeWorld != null && WorldIdentity.key(activeWorld).equals(WorldIdentity.key(world))) {
|
||||||
if (activeProvider instanceof BukkitChunkGenerator bukkit) {
|
if (activeProvider instanceof BukkitChunkGenerator bukkit) {
|
||||||
bukkit.touch(world);
|
bukkit.touch(world);
|
||||||
}
|
}
|
||||||
@@ -267,14 +269,18 @@ public class IrisToolbelt {
|
|||||||
IrisRuntimeSchedulerMode runtimeSchedulerMode = IrisRuntimeSchedulerMode.resolve(IrisSettings.get().getPregen());
|
IrisRuntimeSchedulerMode runtimeSchedulerMode = IrisRuntimeSchedulerMode.resolve(IrisSettings.get().getPregen());
|
||||||
useCachedWrapper = runtimeSchedulerMode != IrisRuntimeSchedulerMode.FOLIA;
|
useCachedWrapper = runtimeSchedulerMode != IrisRuntimeSchedulerMode.FOLIA;
|
||||||
}
|
}
|
||||||
return new PregeneratorJob(task, useCachedWrapper ? new CachedPregenMethod(method, resolvePregenCache(engine.getWorld().name()), task) : method, engine);
|
return new PregeneratorJob(task, useCachedWrapper ? new CachedPregenMethod(method, resolvePregenCache(engine.getWorld()), task) : method, engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PregenCache resolvePregenCache(String worldName) {
|
private static PregenCache resolvePregenCache(IrisWorld world) {
|
||||||
PregenCache cache = IrisServices.get(GlobalCacheSVC.class).get(worldName);
|
String worldIdentity = world.key() == null ? null : world.key().toString();
|
||||||
|
if (worldIdentity == null) {
|
||||||
|
throw new IllegalStateException("Pregeneration requires a namespaced world identity.");
|
||||||
|
}
|
||||||
|
PregenCache cache = IrisServices.get(GlobalCacheSVC.class).get(worldIdentity);
|
||||||
if (cache == null) {
|
if (cache == null) {
|
||||||
IrisLogging.debug("Could not find existing cache for " + worldName + " creating fallback");
|
IrisLogging.debug("Could not find existing cache for " + worldIdentity + " creating fallback");
|
||||||
cache = GlobalCacheSVC.createDefault(worldName);
|
cache = GlobalCacheSVC.createDefault(worldIdentity);
|
||||||
}
|
}
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
@@ -351,7 +357,7 @@ public class IrisToolbelt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (World i : Bukkit.getWorlds()) {
|
for (World i : Bukkit.getWorlds()) {
|
||||||
if (!i.getName().equals(world.getName())) {
|
if (!WorldIdentity.key(i).equals(WorldIdentity.key(world))) {
|
||||||
for (Player j : new ArrayList<>(world.getPlayers())) {
|
for (Player j : new ArrayList<>(world.getPlayers())) {
|
||||||
new VolmitSender(j, BukkitPlatform.volmitPlugin().getTag()).sendMessage("You have been evacuated from this world.");
|
new VolmitSender(j, BukkitPlatform.volmitPlugin().getTag()).sendMessage("You have been evacuated from this world.");
|
||||||
Location target = i.getSpawnLocation();
|
Location target = i.getSpawnLocation();
|
||||||
@@ -381,7 +387,7 @@ public class IrisToolbelt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (World i : Bukkit.getWorlds()) {
|
for (World i : Bukkit.getWorlds()) {
|
||||||
if (!i.getName().equals(world.getName())) {
|
if (!WorldIdentity.key(i).equals(WorldIdentity.key(world))) {
|
||||||
for (Player j : new ArrayList<>(world.getPlayers())) {
|
for (Player j : new ArrayList<>(world.getPlayers())) {
|
||||||
new VolmitSender(j, BukkitPlatform.volmitPlugin().getTag()).sendMessage("You have been evacuated from this world. " + m);
|
new VolmitSender(j, BukkitPlatform.volmitPlugin().getTag()).sendMessage("You have been evacuated from this world. " + m);
|
||||||
Location target = i.getSpawnLocation();
|
Location target = i.getSpawnLocation();
|
||||||
@@ -460,7 +466,7 @@ public class IrisToolbelt {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
beginWorldMaintenance(world.getName(), reason, bypassMantleStages);
|
beginWorldMaintenance(WorldIdentity.serialize(world), reason, bypassMantleStages);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void beginWorldMaintenance(String worldName, String reason) {
|
public static void beginWorldMaintenance(String worldName, String reason) {
|
||||||
@@ -476,7 +482,7 @@ public class IrisToolbelt {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
endWorldMaintenance(world.getName(), reason);
|
endWorldMaintenance(WorldIdentity.serialize(world), reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void endWorldMaintenance(String worldName, String reason) {
|
public static void endWorldMaintenance(String worldName, String reason) {
|
||||||
@@ -484,7 +490,7 @@ public class IrisToolbelt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isWorldMaintenanceActive(World world) {
|
public static boolean isWorldMaintenanceActive(World world) {
|
||||||
return world != null && isWorldMaintenanceActive(world.getName());
|
return world != null && isWorldMaintenanceActive(WorldIdentity.serialize(world));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isWorldMaintenanceActive(String worldName) {
|
public static boolean isWorldMaintenanceActive(String worldName) {
|
||||||
@@ -492,7 +498,7 @@ public class IrisToolbelt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isWorldMaintenanceBypassingMantleStages(World world) {
|
public static boolean isWorldMaintenanceBypassingMantleStages(World world) {
|
||||||
return world != null && isWorldMaintenanceBypassingMantleStages(world.getName());
|
return world != null && isWorldMaintenanceBypassingMantleStages(WorldIdentity.serialize(world));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isWorldMaintenanceBypassingMantleStages(String worldName) {
|
public static boolean isWorldMaintenanceBypassingMantleStages(String worldName) {
|
||||||
|
|||||||
@@ -18,11 +18,12 @@
|
|||||||
|
|
||||||
package art.arcane.iris.core.tools;
|
package art.arcane.iris.core.tools;
|
||||||
|
|
||||||
|
import art.arcane.iris.core.IrisWorldStorage;
|
||||||
import art.arcane.iris.core.loader.IrisData;
|
import art.arcane.iris.core.loader.IrisData;
|
||||||
import art.arcane.iris.engine.object.IrisDimension;
|
import art.arcane.iris.engine.object.IrisDimension;
|
||||||
import art.arcane.iris.engine.object.IrisWorld;
|
import art.arcane.iris.engine.object.IrisWorld;
|
||||||
import art.arcane.iris.engine.platform.BukkitChunkGenerator;
|
import art.arcane.iris.engine.platform.BukkitChunkGenerator;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.WorldCreator;
|
import org.bukkit.WorldCreator;
|
||||||
import org.bukkit.generator.ChunkGenerator;
|
import org.bukkit.generator.ChunkGenerator;
|
||||||
@@ -74,13 +75,15 @@ public class IrisWorldCreator {
|
|||||||
|
|
||||||
public WorldCreator create() {
|
public WorldCreator create() {
|
||||||
IrisDimension dim = dimension == null ? IrisData.loadAnyDimension(dimensionName, null) : dimension;
|
IrisDimension dim = dimension == null ? IrisData.loadAnyDimension(dimensionName, null) : dimension;
|
||||||
|
NamespacedKey worldKey = IrisWorldStorage.keyFromLegacyName(name);
|
||||||
|
|
||||||
IrisWorld w = IrisWorld.builder()
|
IrisWorld w = IrisWorld.builder()
|
||||||
|
.key(worldKey)
|
||||||
.name(name)
|
.name(name)
|
||||||
.minHeight(dim.getMinHeight())
|
.minHeight(dim.getMinHeight())
|
||||||
.maxHeight(dim.getMaxHeight())
|
.maxHeight(dim.getMaxHeight())
|
||||||
.seed(seed)
|
.seed(seed)
|
||||||
.worldFolder(new File(Bukkit.getWorldContainer(), name))
|
.worldFolder(IrisWorldStorage.dimensionRoot(worldKey))
|
||||||
.environment(findEnvironment())
|
.environment(findEnvironment())
|
||||||
.build();
|
.build();
|
||||||
ChunkGenerator g = new BukkitChunkGenerator(w, studio, studio
|
ChunkGenerator g = new BukkitChunkGenerator(w, studio, studio
|
||||||
@@ -88,7 +91,7 @@ public class IrisWorldCreator {
|
|||||||
new File(w.worldFolder(), "iris/pack"), dimensionName);
|
new File(w.worldFolder(), "iris/pack"), dimensionName);
|
||||||
|
|
||||||
|
|
||||||
return new WorldCreator(name)
|
return WorldCreator.ofKey(worldKey)
|
||||||
.environment(w.environment())
|
.environment(w.environment())
|
||||||
.generateStructures(true)
|
.generateStructures(true)
|
||||||
.generator(g).seed(seed);
|
.generator(g).seed(seed);
|
||||||
|
|||||||
@@ -650,7 +650,7 @@ public class IrisEngine implements Engine {
|
|||||||
|
|
||||||
private boolean isPregeneratorActiveForThisWorld() {
|
private boolean isPregeneratorActiveForThisWorld() {
|
||||||
PregeneratorJob pregeneratorJob = PregeneratorJob.getInstance();
|
PregeneratorJob pregeneratorJob = PregeneratorJob.getInstance();
|
||||||
return pregeneratorJob != null && pregeneratorJob.targetsWorldName(getWorld().name());
|
return pregeneratorJob != null && pregeneratorJob.targetsWorldIdentity(getWorld().identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void savePrefetchOnce() {
|
private void savePrefetchOnce() {
|
||||||
|
|||||||
@@ -574,7 +574,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return job.targetsWorldName(world.getName());
|
return job.targetsWorld(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Position2[] getLoadedChunkPositionsSnapshot(World world) {
|
private Position2[] getLoadedChunkPositionsSnapshot(World world) {
|
||||||
|
|||||||
@@ -691,11 +691,11 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
if (world == null) {
|
if (world == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String worldName = world.name();
|
String worldIdentity = world.identity();
|
||||||
if (!WorldMaintenance.isWorldMaintenanceActive(worldName)) {
|
if (!WorldMaintenance.isWorldMaintenanceActive(worldIdentity)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
PregeneratorJob pregeneratorJob = PregeneratorJob.getInstance();
|
PregeneratorJob pregeneratorJob = PregeneratorJob.getInstance();
|
||||||
return pregeneratorJob == null || !pregeneratorJob.targetsWorldName(worldName);
|
return pregeneratorJob == null || !pregeneratorJob.targetsWorldIdentity(worldIdentity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,13 +96,13 @@ public interface EngineMode extends Staged {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldDisableContextCacheForMaintenance() {
|
private boolean shouldDisableContextCacheForMaintenance() {
|
||||||
boolean maintenanceActive = WorldMaintenance.isWorldMaintenanceActive(getEngine().getWorld().name());
|
boolean maintenanceActive = WorldMaintenance.isWorldMaintenanceActive(getEngine().getWorld().identity());
|
||||||
if (!maintenanceActive) {
|
if (!maintenanceActive) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PregeneratorJob pregeneratorJob = PregeneratorJob.getInstance();
|
PregeneratorJob pregeneratorJob = PregeneratorJob.getInstance();
|
||||||
boolean pregeneratorTargetsWorld = pregeneratorJob != null && pregeneratorJob.targetsWorldName(getEngine().getWorld().name());
|
boolean pregeneratorTargetsWorld = pregeneratorJob != null && pregeneratorJob.targetsWorldIdentity(getEngine().getWorld().identity());
|
||||||
return shouldDisableContextCacheForMaintenance(maintenanceActive, pregeneratorTargetsWorld);
|
return shouldDisableContextCacheForMaintenance(maintenanceActive, pregeneratorTargetsWorld);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
|
|||||||
this.z = z;
|
this.z = z;
|
||||||
|
|
||||||
final boolean foliaMaintenance = J.isFolia()
|
final boolean foliaMaintenance = J.isFolia()
|
||||||
&& WorldMaintenance.isWorldMaintenanceActive(engineMantle.getEngine().getWorld().name());
|
&& WorldMaintenance.isWorldMaintenanceActive(engineMantle.getEngine().getWorld().identity());
|
||||||
final int parallelism = foliaMaintenance ? 1 : (multicore ? Runtime.getRuntime().availableProcessors() / 2 : 4);
|
final int parallelism = foliaMaintenance ? 1 : (multicore ? Runtime.getRuntime().availableProcessors() / 2 : 4);
|
||||||
if (foliaMaintenance && IrisSettings.get().getGeneral().isDebug()) {
|
if (foliaMaintenance && IrisSettings.get().getGeneral().isDebug()) {
|
||||||
IrisLogging.info("MantleWriter using sequential chunk prefetch for maintenance regen at " + x + "," + z + ".");
|
IrisLogging.info("MantleWriter using sequential chunk prefetch for maintenance regen at " + x + "," + z + ".");
|
||||||
|
|||||||
@@ -18,8 +18,10 @@
|
|||||||
|
|
||||||
package art.arcane.iris.engine.object;
|
package art.arcane.iris.engine.object;
|
||||||
|
|
||||||
|
import art.arcane.iris.core.IrisWorldStorage;
|
||||||
import art.arcane.iris.core.tools.IrisToolbelt;
|
import art.arcane.iris.core.tools.IrisToolbelt;
|
||||||
import art.arcane.iris.spi.IrisLogging;
|
import art.arcane.iris.spi.IrisLogging;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import art.arcane.volmlib.util.collection.KList;
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
@@ -27,8 +29,8 @@ import lombok.Data;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -44,6 +46,8 @@ import java.util.List;
|
|||||||
public class IrisWorld {
|
public class IrisWorld {
|
||||||
private static final KList<Player> NO_PLAYERS = new KList<>();
|
private static final KList<Player> NO_PLAYERS = new KList<>();
|
||||||
private static final KList<? extends Entity> NO_ENTITIES = new KList<>();
|
private static final KList<? extends Entity> NO_ENTITIES = new KList<>();
|
||||||
|
private NamespacedKey key;
|
||||||
|
private String platformIdentity;
|
||||||
private String name;
|
private String name;
|
||||||
private File worldFolder;
|
private File worldFolder;
|
||||||
|
|
||||||
@@ -60,7 +64,8 @@ public class IrisWorld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static IrisWorld bindWorld(IrisWorld iw, World world) {
|
private static IrisWorld bindWorld(IrisWorld iw, World world) {
|
||||||
return iw.name(world.getName())
|
return iw.key(WorldIdentity.key(world))
|
||||||
|
.name(world.getName())
|
||||||
.worldFolder(world.getWorldFolder())
|
.worldFolder(world.getWorldFolder())
|
||||||
.minHeight(world.getMinHeight())
|
.minHeight(world.getMinHeight())
|
||||||
.maxHeight(world.getMaxHeight())
|
.maxHeight(world.getMaxHeight())
|
||||||
@@ -72,6 +77,10 @@ public class IrisWorld {
|
|||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String identity() {
|
||||||
|
return key == null ? platformIdentity : key.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public void setRawWorldSeed(long seed) {
|
public void setRawWorldSeed(long seed) {
|
||||||
this.seed = seed;
|
this.seed = seed;
|
||||||
}
|
}
|
||||||
@@ -81,7 +90,11 @@ public class IrisWorld {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
World w = Bukkit.getWorld(name);
|
if (key == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
World w = WorldIdentity.resolve(key).orElse(null);
|
||||||
|
|
||||||
if (w != null) {
|
if (w != null) {
|
||||||
realWorld = w;
|
realWorld = w;
|
||||||
@@ -111,8 +124,8 @@ public class IrisWorld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void bind(WorldInfo worldInfo) {
|
public void bind(WorldInfo worldInfo) {
|
||||||
name(worldInfo.getName())
|
key(WorldIdentity.key(worldInfo))
|
||||||
.worldFolder(new File(Bukkit.getWorldContainer(), worldInfo.getName()))
|
.worldFolder(IrisWorldStorage.dimensionRoot(worldInfo))
|
||||||
.minHeight(worldInfo.getMinHeight())
|
.minHeight(worldInfo.getMinHeight())
|
||||||
.maxHeight(worldInfo.getMaxHeight())
|
.maxHeight(worldInfo.getMaxHeight())
|
||||||
.environment(worldInfo.getEnvironment());
|
.environment(worldInfo.getEnvironment());
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import art.arcane.iris.spi.IrisLogging;
|
|||||||
import art.arcane.iris.spi.IrisPlatforms;
|
import art.arcane.iris.spi.IrisPlatforms;
|
||||||
import art.arcane.iris.spi.PlatformBiome;
|
import art.arcane.iris.spi.PlatformBiome;
|
||||||
import art.arcane.iris.util.common.format.C;
|
import art.arcane.iris.util.common.format.C;
|
||||||
|
import art.arcane.volmlib.util.bukkit.WorldIdentity;
|
||||||
import art.arcane.volmlib.util.collection.KList;
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
import art.arcane.volmlib.util.math.M;
|
import art.arcane.volmlib.util.math.M;
|
||||||
import art.arcane.iris.util.project.hunk.Hunk;
|
import art.arcane.iris.util.project.hunk.Hunk;
|
||||||
@@ -77,6 +78,7 @@ import java.io.File;
|
|||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@@ -136,8 +138,9 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public void onWorldInit(WorldInitEvent event) {
|
public void onWorldInit(WorldInitEvent event) {
|
||||||
if (!world.name().equals(event.getWorld().getName())) return;
|
if (!Objects.equals(world.key(), WorldIdentity.key(event.getWorld()))) return;
|
||||||
BukkitPlatform.volmitPlugin().unregisterListener(this);
|
BukkitPlatform.volmitPlugin().unregisterListener(this);
|
||||||
|
world.bind(event.getWorld());
|
||||||
world.setRawWorldSeed(event.getWorld().getSeed());
|
world.setRawWorldSeed(event.getWorld().getSeed());
|
||||||
if (initialize(event.getWorld())) return;
|
if (initialize(event.getWorld())) return;
|
||||||
|
|
||||||
@@ -165,7 +168,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
}
|
}
|
||||||
spawnChunks.complete(INMS.get().getSpawnChunkCount(world));
|
spawnChunks.complete(INMS.get().getSpawnChunkCount(world));
|
||||||
BukkitPlatform.volmitPlugin().unregisterListener(this);
|
BukkitPlatform.volmitPlugin().unregisterListener(this);
|
||||||
IrisWorlds.get().put(world.getName(), dimensionKey);
|
IrisWorlds.get().put(WorldIdentity.serialize(world), dimensionKey);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -524,7 +527,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
|
|
||||||
World realWorld = this.world.realWorld();
|
World realWorld = this.world.realWorld();
|
||||||
PregeneratorJob pregeneratorJob = PregeneratorJob.getInstance();
|
PregeneratorJob pregeneratorJob = PregeneratorJob.getInstance();
|
||||||
return realWorld != null && pregeneratorJob != null && pregeneratorJob.targetsWorldName(realWorld.getName());
|
return realWorld != null && pregeneratorJob != null && pregeneratorJob.targetsWorld(realWorld);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -10,12 +10,13 @@ import io.github.slimjar.logging.ProcessLogger;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class SlimJar {
|
public class SlimJar {
|
||||||
private static final boolean DEBUG = Boolean.getBoolean("iris.debug-slimjar");
|
private static final boolean DEBUG = Boolean.getBoolean("iris.debug-slimjar");
|
||||||
private static final boolean DISABLE_REMAPPER = Boolean.getBoolean("iris.disable-remapper");
|
|
||||||
|
|
||||||
private static final ReentrantLock lock = new ReentrantLock();
|
private static final ReentrantLock lock = new ReentrantLock();
|
||||||
private static final AtomicBoolean loaded = new AtomicBoolean();
|
private static final AtomicBoolean loaded = new AtomicBoolean();
|
||||||
@@ -26,16 +27,15 @@ public class SlimJar {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (loaded.getAndSet(true)) return;
|
if (loaded.getAndSet(true)) return;
|
||||||
final VolmitPlugin plugin = BukkitPlatform.volmitPlugin();
|
VolmitPlugin plugin = BukkitPlatform.volmitPlugin();
|
||||||
final var downloadPath = plugin.getDataFolder("cache", "libraries").toPath();
|
Path downloadPath = plugin.getDataFolder("cache", "libraries").toPath();
|
||||||
final var logger = plugin.getLogger();
|
Logger logger = plugin.getLogger();
|
||||||
|
|
||||||
logger.info("Loading libraries...");
|
logger.info("Loading libraries...");
|
||||||
try {
|
try {
|
||||||
new SpigotApplicationBuilder(plugin)
|
new SpigotApplicationBuilder(plugin)
|
||||||
.downloadDirectoryPath(downloadPath)
|
.downloadDirectoryPath(downloadPath)
|
||||||
.debug(DEBUG)
|
.debug(DEBUG)
|
||||||
.remap(!DISABLE_REMAPPER)
|
|
||||||
.build();
|
.build();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
IrisLogging.warn("Failed to inject the library loader, falling back to application builder");
|
IrisLogging.warn("Failed to inject the library loader, falling back to application builder");
|
||||||
|
|||||||
@@ -138,8 +138,8 @@ public class NBTWorld {
|
|||||||
Map<Biome, Integer> biomeIds = new KMap<>();
|
Map<Biome, Integer> biomeIds = new KMap<>();
|
||||||
|
|
||||||
for (Biome biome : Registry.BIOME) {
|
for (Biome biome : Registry.BIOME) {
|
||||||
NamespacedKey key = biome.getKeyOrNull();
|
NamespacedKey key = biome.getKey();
|
||||||
if (key != null && !key.getKey().equals("custom")) {
|
if (!key.getKey().equals("custom")) {
|
||||||
biomeIds.put(biome, INMS.get().getBiomeId(biome));
|
biomeIds.put(biome, INMS.get().getBiomeId(biome));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package art.arcane.iris.util.common.plugin;
|
package art.arcane.iris.util.common.plugin;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.permissions.Permission;
|
import org.bukkit.permissions.Permission;
|
||||||
@@ -63,6 +64,12 @@ public class CommandDummy implements CommandSender {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Component name() {
|
||||||
|
return Component.empty();
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Spigot spigot() {
|
public Spigot spigot() {
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.permissions.Permission;
|
import org.bukkit.permissions.Permission;
|
||||||
import org.bukkit.permissions.PermissionAttachment;
|
import org.bukkit.permissions.PermissionAttachment;
|
||||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -507,6 +508,12 @@ public class VolmitSender implements CommandSender {
|
|||||||
return s.getName();
|
return s.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Component name() {
|
||||||
|
return s.name();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Spigot spigot() {
|
public Spigot spigot() {
|
||||||
return s.spigot();
|
return s.spigot();
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package art.arcane.iris.core;
|
||||||
|
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertThrows;
|
||||||
|
|
||||||
|
public class IrisWorldStorageTest {
|
||||||
|
@Rule
|
||||||
|
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void derivesPaperDimensionRootFromNamespacedKey() throws Exception {
|
||||||
|
File levelRoot = temporaryFolder.newFolder("world");
|
||||||
|
NamespacedKey key = new NamespacedKey("iris", "runtime/studio");
|
||||||
|
|
||||||
|
File dimensionRoot = IrisWorldStorage.dimensionRoot(levelRoot, key);
|
||||||
|
|
||||||
|
assertEquals(new File(levelRoot, "dimensions/iris/runtime/studio").getAbsoluteFile(), dimensionRoot);
|
||||||
|
assertEquals(key, IrisWorldStorage.keyFromDimensionRoot(levelRoot, dimensionRoot).orElseThrow());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void separatesLevelRootFromDimensionRoot() throws Exception {
|
||||||
|
File levelRoot = temporaryFolder.newFolder("world");
|
||||||
|
File dimensionRoot = new File(levelRoot, "dimensions/minecraft/overworld");
|
||||||
|
|
||||||
|
assertEquals(levelRoot.getAbsoluteFile(), IrisWorldStorage.levelRoot(dimensionRoot));
|
||||||
|
}
|
||||||
|
|
||||||
|
@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"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rejectsKeysThatEscapeNamespaceStorage() throws Exception {
|
||||||
|
File levelRoot = temporaryFolder.newFolder("world");
|
||||||
|
NamespacedKey key = NamespacedKey.minecraft("../outside");
|
||||||
|
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> IrisWorldStorage.dimensionRoot(levelRoot, key));
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
package art.arcane.iris.core.lifecycle;
|
package art.arcane.iris.core.lifecycle;
|
||||||
|
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -15,7 +16,7 @@ public class WorldLifecycleDiagnosticsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void studioCreateSelectionFailurePrintsFullStacktrace() {
|
public void studioCreateSelectionFailurePrintsFullStacktrace() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PAPER, false, false, false));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PAPER, false, false, false));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
||||||
|
|
||||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||||
PrintStream originalErr = System.err;
|
PrintStream originalErr = System.err;
|
||||||
|
|||||||
+2
@@ -5,6 +5,7 @@ import art.arcane.iris.core.nms.INMSBinding;
|
|||||||
import art.arcane.iris.engine.framework.Engine;
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
import art.arcane.iris.engine.framework.EngineTarget;
|
import art.arcane.iris.engine.framework.EngineTarget;
|
||||||
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.generator.ChunkGenerator;
|
import org.bukkit.generator.ChunkGenerator;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -26,6 +27,7 @@ public class WorldLifecycleRuntimeLevelStemTest {
|
|||||||
CapabilitySnapshot capabilities = CapabilitySnapshot.forTestingRuntimeRegistries(ServerFamily.PURPUR, false, datapackDimensions, serverRegistryAccess);
|
CapabilitySnapshot capabilities = CapabilitySnapshot.forTestingRuntimeRegistries(ServerFamily.PURPUR, false, datapackDimensions, serverRegistryAccess);
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest(
|
WorldLifecycleRequest request = new WorldLifecycleRequest(
|
||||||
"studio",
|
"studio",
|
||||||
|
NamespacedKey.minecraft("studio"),
|
||||||
World.Environment.NORMAL,
|
World.Environment.NORMAL,
|
||||||
new TestingPlatformChunkGenerator(),
|
new TestingPlatformChunkGenerator(),
|
||||||
null,
|
null,
|
||||||
|
|||||||
+12
-11
@@ -1,5 +1,6 @@
|
|||||||
package art.arcane.iris.core.lifecycle;
|
package art.arcane.iris.core.lifecycle;
|
||||||
|
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
@Test
|
@Test
|
||||||
public void studioSelectsPaperLikeBackendOnPaper() {
|
public void studioSelectsPaperLikeBackendOnPaper() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PAPER, false, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PAPER, false, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
||||||
|
|
||||||
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
||||||
}
|
}
|
||||||
@@ -17,7 +18,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
@Test
|
@Test
|
||||||
public void studioSelectsPaperLikeBackendOnPurpur() {
|
public void studioSelectsPaperLikeBackendOnPurpur() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PURPUR, false, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PURPUR, false, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
||||||
|
|
||||||
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
||||||
}
|
}
|
||||||
@@ -25,7 +26,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
@Test
|
@Test
|
||||||
public void studioSelectsPaperLikeBackendOnCanvas() {
|
public void studioSelectsPaperLikeBackendOnCanvas() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.CANVAS, true, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.CANVAS, true, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
||||||
|
|
||||||
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
||||||
}
|
}
|
||||||
@@ -33,7 +34,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
@Test
|
@Test
|
||||||
public void studioSelectsPaperLikeBackendOnFolia() {
|
public void studioSelectsPaperLikeBackendOnFolia() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.FOLIA, true, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.FOLIA, true, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
||||||
|
|
||||||
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
||||||
}
|
}
|
||||||
@@ -41,7 +42,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
@Test
|
@Test
|
||||||
public void studioSelectsBukkitBackendOnSpigot() {
|
public void studioSelectsBukkitBackendOnSpigot() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.SPIGOT, false, false, false));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.SPIGOT, false, false, false));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("studio", NamespacedKey.minecraft("studio"), World.Environment.NORMAL, null, null, null, true, false, 1337L, true, false, WorldLifecycleCaller.STUDIO);
|
||||||
|
|
||||||
assertEquals("bukkit_public", service.selectCreateBackend(request).backendName());
|
assertEquals("bukkit_public", service.selectCreateBackend(request).backendName());
|
||||||
}
|
}
|
||||||
@@ -49,7 +50,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
@Test
|
@Test
|
||||||
public void persistentCreatePrefersBukkitBackendOnPaperLikeServers() {
|
public void persistentCreatePrefersBukkitBackendOnPaperLikeServers() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PURPUR, false, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PURPUR, false, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", NamespacedKey.minecraft("persistent"), World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
||||||
|
|
||||||
assertEquals("bukkit_public", service.selectCreateBackend(request).backendName());
|
assertEquals("bukkit_public", service.selectCreateBackend(request).backendName());
|
||||||
}
|
}
|
||||||
@@ -57,7 +58,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
@Test
|
@Test
|
||||||
public void persistentCreateSelectsPaperLikeBackendOnFolia() {
|
public void persistentCreateSelectsPaperLikeBackendOnFolia() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.FOLIA, true, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.FOLIA, true, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", NamespacedKey.minecraft("persistent"), World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
||||||
|
|
||||||
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
||||||
}
|
}
|
||||||
@@ -65,7 +66,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
@Test
|
@Test
|
||||||
public void persistentCreateSelectsPaperLikeBackendOnCanvas() {
|
public void persistentCreateSelectsPaperLikeBackendOnCanvas() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.CANVAS, true, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.CANVAS, true, false, true));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", NamespacedKey.minecraft("persistent"), World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
||||||
|
|
||||||
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
assertEquals("paper_like_runtime", service.selectCreateBackend(request).backendName());
|
||||||
}
|
}
|
||||||
@@ -73,7 +74,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
@Test
|
@Test
|
||||||
public void persistentCreateFallsBackToBukkitBackendOnFoliaWithoutRuntime() {
|
public void persistentCreateFallsBackToBukkitBackendOnFoliaWithoutRuntime() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.FOLIA, true, false, false));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.FOLIA, true, false, false));
|
||||||
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
WorldLifecycleRequest request = new WorldLifecycleRequest("persistent", NamespacedKey.minecraft("persistent"), World.Environment.NORMAL, null, null, null, true, false, 1337L, false, false, WorldLifecycleCaller.CREATE);
|
||||||
|
|
||||||
assertEquals("bukkit_public", service.selectCreateBackend(request).backendName());
|
assertEquals("bukkit_public", service.selectCreateBackend(request).backendName());
|
||||||
}
|
}
|
||||||
@@ -82,7 +83,7 @@ public class WorldLifecycleSelectionTest {
|
|||||||
public void unloadUsesRememberedBackendFamily() {
|
public void unloadUsesRememberedBackendFamily() {
|
||||||
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PURPUR, false, false, true));
|
WorldLifecycleService service = new WorldLifecycleService(CapabilitySnapshot.forTesting(ServerFamily.PURPUR, false, false, true));
|
||||||
|
|
||||||
service.rememberBackend("studio", "paper_like_runtime");
|
service.rememberBackend(NamespacedKey.minecraft("studio"), "paper_like_runtime");
|
||||||
assertEquals("paper_like_runtime", service.selectUnloadBackend("studio").backendName());
|
assertEquals("paper_like_runtime", service.selectUnloadBackend("minecraft:studio").backendName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+7
-4
@@ -39,10 +39,11 @@ public class TransientWorldCleanupSupportTest {
|
|||||||
public void collectsOnlyTransientStudioWorldFamiliesFromContainer() throws IOException {
|
public void collectsOnlyTransientStudioWorldFamiliesFromContainer() throws IOException {
|
||||||
File container = Files.createTempDirectory("transient-world-cleanup-test").toFile();
|
File container = Files.createTempDirectory("transient-world-cleanup-test").toFile();
|
||||||
String baseName = "iris-123e4567-e89b-12d3-a456-426614174000";
|
String baseName = "iris-123e4567-e89b-12d3-a456-426614174000";
|
||||||
File baseFolder = new File(container, baseName);
|
File namespace = new File(container, "dimensions/minecraft");
|
||||||
File netherFolder = new File(container, baseName + "_nether");
|
File baseFolder = new File(namespace, baseName);
|
||||||
File smokeFolder = new File(container, "iris-smoke-studio-deadbeef");
|
File netherFolder = new File(namespace, baseName + "_nether");
|
||||||
File regularFolder = new File(container, "overworld");
|
File smokeFolder = new File(namespace, "iris-smoke-studio-deadbeef");
|
||||||
|
File regularFolder = new File(namespace, "overworld");
|
||||||
baseFolder.mkdirs();
|
baseFolder.mkdirs();
|
||||||
netherFolder.mkdirs();
|
netherFolder.mkdirs();
|
||||||
smokeFolder.mkdirs();
|
smokeFolder.mkdirs();
|
||||||
@@ -57,6 +58,8 @@ public class TransientWorldCleanupSupportTest {
|
|||||||
Files.deleteIfExists(netherFolder.toPath());
|
Files.deleteIfExists(netherFolder.toPath());
|
||||||
Files.deleteIfExists(smokeFolder.toPath());
|
Files.deleteIfExists(smokeFolder.toPath());
|
||||||
Files.deleteIfExists(regularFolder.toPath());
|
Files.deleteIfExists(regularFolder.toPath());
|
||||||
|
Files.deleteIfExists(namespace.toPath());
|
||||||
|
Files.deleteIfExists(namespace.getParentFile().toPath());
|
||||||
Files.deleteIfExists(container.toPath());
|
Files.deleteIfExists(container.toPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,24 @@
|
|||||||
package art.arcane.iris.core.tools;
|
package art.arcane.iris.core.tools;
|
||||||
|
|
||||||
|
import art.arcane.iris.core.service.StudioSVC;
|
||||||
|
import art.arcane.iris.spi.IrisServices;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class IrisToolbeltPackReferenceTest {
|
public class IrisToolbeltPackReferenceTest {
|
||||||
|
@After
|
||||||
|
public void cleanServices() {
|
||||||
|
IrisServices.remove(StudioSVC.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void plainPackUsesMatchingDimensionKey() {
|
public void plainPackUsesMatchingDimensionKey() {
|
||||||
IrisToolbelt.PackReference reference = IrisToolbelt.parsePackReference("overworld");
|
IrisToolbelt.PackReference reference = IrisToolbelt.parsePackReference("overworld");
|
||||||
@@ -34,4 +45,16 @@ public class IrisToolbeltPackReferenceTest {
|
|||||||
assertNull(IrisToolbelt.parsePackReference("pack:"));
|
assertNull(IrisToolbelt.parsePackReference("pack:"));
|
||||||
assertNull(IrisToolbelt.parsePackReference(":dimension"));
|
assertNull(IrisToolbelt.parsePackReference(":dimension"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void accessReturnsNullAfterStudioServiceIsRemoved() {
|
||||||
|
IrisServices.remove(StudioSVC.class);
|
||||||
|
World world = (World) Proxy.newProxyInstance(
|
||||||
|
World.class.getClassLoader(),
|
||||||
|
new Class<?>[]{World.class},
|
||||||
|
(proxy, method, args) -> null
|
||||||
|
);
|
||||||
|
|
||||||
|
assertNull(IrisToolbelt.access(world));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package art.arcane.iris.engine.object;
|
||||||
|
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class IrisWorldIdentityTest {
|
||||||
|
@Test
|
||||||
|
public void usesBukkitKeyBeforePlatformIdentity() {
|
||||||
|
IrisWorld world = IrisWorld.builder()
|
||||||
|
.key(new NamespacedKey("iris", "bukkit"))
|
||||||
|
.platformIdentity("iris:modded")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertEquals("iris:bukkit", world.identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void usesPlatformIdentityWithoutBukkitKey() {
|
||||||
|
IrisWorld world = IrisWorld.builder()
|
||||||
|
.platformIdentity("minecraft:the_nether")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertEquals("minecraft:the_nether", world.identity());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ grgit = "5.3.2" # https://github.com/ajoberstar/grgit
|
|||||||
# Core Libraries
|
# Core Libraries
|
||||||
lombok = "1.18.44"
|
lombok = "1.18.44"
|
||||||
spigot = "26.2-R0.1-SNAPSHOT" # https://hub.spigotmc.org/nexus/repository/snapshots/org/spigotmc/spigot-api/maven-metadata.xml
|
spigot = "26.2-R0.1-SNAPSHOT" # https://hub.spigotmc.org/nexus/repository/snapshots/org/spigotmc/spigot-api/maven-metadata.xml
|
||||||
|
paper-api = "26.2.build.60-beta"
|
||||||
log4j = "2.19.0" # https://central.sonatype.com/artifact/org.apache.logging.log4j/log4j-api
|
log4j = "2.19.0" # https://central.sonatype.com/artifact/org.apache.logging.log4j/log4j-api
|
||||||
adventure-api = "5.1.1" # https://github.com/KyoriPowered/adventure
|
adventure-api = "5.1.1" # https://github.com/KyoriPowered/adventure
|
||||||
adventure-platform = "4.4.1" # https://github.com/KyoriPowered/adventure-platform
|
adventure-platform = "4.4.1" # https://github.com/KyoriPowered/adventure-platform
|
||||||
@@ -71,6 +72,7 @@ fabricApi-keyMapping = "2.0.5+e2bdee789e"
|
|||||||
# Core Libraries
|
# Core Libraries
|
||||||
lombok = { module = "org.projectlombok:lombok", version.ref ="lombok" }
|
lombok = { module = "org.projectlombok:lombok", version.ref ="lombok" }
|
||||||
spigot = { module = "org.spigotmc:spigot-api", version.ref = "spigot" }
|
spigot = { module = "org.spigotmc:spigot-api", version.ref = "spigot" }
|
||||||
|
paper-api = { module = "io.papermc.paper:paper-api", version.ref = "paper-api" }
|
||||||
log4j-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j" }
|
log4j-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j" }
|
||||||
log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" }
|
log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" }
|
||||||
annotations = { module = "org.jetbrains:annotations", version.ref = "annotations" }
|
annotations = { module = "org.jetbrains:annotations", version.ref = "annotations" }
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ public final class GenerationProbe {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IrisWorld world = IrisWorld.builder()
|
IrisWorld world = IrisWorld.builder()
|
||||||
|
.platformIdentity("iris:probe")
|
||||||
.name("probe")
|
.name("probe")
|
||||||
.seed(SEED)
|
.seed(SEED)
|
||||||
.worldFolder(new File(workRoot, "world"))
|
.worldFolder(new File(workRoot, "world"))
|
||||||
|
|||||||
Reference in new issue
Block a user