diff --git a/build.gradle.kts b/build.gradle.kts index 6b52129b2..3c275b9ca 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -215,6 +215,7 @@ allprojects { maven("https://mvn.lumine.io/repository/maven-public/") // mythic maven("https://nexus.phoenixdevt.fr/repository/maven-public/") //MMOItems maven("https://repo.onarandombox.com/content/groups/public/") //Multiverse Core + maven("https://repo.thenextlvl.net/releases") //Worlds } dependencies { diff --git a/core/build.gradle.kts b/core/build.gradle.kts index a91d4c72f..a587f6c2a 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -65,6 +65,7 @@ dependencies { isTransitive = false } compileOnly(libs.multiverseCore) + compileOnly(libs.worlds) // Shaded implementation(slimjarHelper("spigot")) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index dd4b0e51d..e9455150a 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -490,8 +490,13 @@ public class Iris extends VolmitPlugin implements Listener { WorldCreator c = new WorldCreator(s) .generator(gen) .environment(dim.getEnvironment()); - INMS.get().createWorld(c); - Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"); + INMS.get().createWorldAsync(c) + .thenAccept(w -> Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!")) + .exceptionally(e -> { + Iris.error("Failed to load world " + s + "!"); + e.printStackTrace(); + return null; + }); } catch (Throwable e) { Iris.error("Failed to load world " + s + "!"); e.printStackTrace(); diff --git a/core/src/main/java/com/volmit/iris/core/link/FoliaWorldsLink.java b/core/src/main/java/com/volmit/iris/core/link/FoliaWorldsLink.java new file mode 100644 index 000000000..f21ac8a78 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/link/FoliaWorldsLink.java @@ -0,0 +1,68 @@ +package com.volmit.iris.core.link; + +import lombok.NonNull; +import net.thenextlvl.worlds.api.WorldsProvider; +import net.thenextlvl.worlds.api.generator.GeneratorType; +import net.thenextlvl.worlds.api.generator.LevelStem; +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.WorldCreator; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.concurrent.CompletableFuture; + +public class FoliaWorldsLink { + private static FoliaWorldsLink instance; + private final Object provider; + + private FoliaWorldsLink(Object provider) { + this.provider = provider; + } + + public static FoliaWorldsLink get() { + if(instance == null) { + synchronized (FoliaWorldsLink.class) { + try { + Server.class.getDeclaredMethod("isGlobalTickThread"); + instance = new FoliaWorldsLink(Bukkit.getServicesManager().load(WorldsProvider.class)); + } catch (Throwable e) { + instance = new FoliaWorldsLink(null); + } + } + } + + return instance; + } + + public boolean isActive() { + return provider != null; + } + + @Nullable + public CompletableFuture createWorld(@NonNull WorldCreator creator) { + if (provider == null) return null; + return ((WorldsProvider) provider) + .levelBuilder(new File(Bukkit.getWorldContainer(), creator.name()).toPath()) + .name(creator.name()) + .seed(creator.seed()) + .levelStem(switch (creator.environment()) { + case CUSTOM, NORMAL -> LevelStem.OVERWORLD; + case NETHER -> LevelStem.NETHER; + case THE_END -> LevelStem.END; + }) + .chunkGenerator(creator.generator()) + .biomeProvider(creator.biomeProvider()) + .generatorType(switch (creator.type()) { + case NORMAL -> GeneratorType.NORMAL; + case FLAT -> GeneratorType.FLAT; + case LARGE_BIOMES -> GeneratorType.LARGE_BIOMES; + case AMPLIFIED -> GeneratorType.AMPLIFIED; + }) + .structures(creator.generateStructures()) + .hardcore(creator.hardcore()) + .build() + .createAsync(); + } +} diff --git a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java index 29fa4e37d..ccc27d72d 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java +++ b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java @@ -18,6 +18,7 @@ package com.volmit.iris.core.nms; +import com.volmit.iris.core.link.FoliaWorldsLink; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.engine.framework.Engine; @@ -39,6 +40,7 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; import java.awt.Color; +import java.util.concurrent.CompletableFuture; public interface INMSBinding { boolean hasTile(Material material); @@ -96,6 +98,15 @@ public interface INMSBinding { return c.createWorld(); } + default CompletableFuture createWorldAsync(WorldCreator c) { + try { + var link = FoliaWorldsLink.get(); + return link.isActive() ? link.createWorld(c) : CompletableFuture.completedFuture(createWorld(c)); + } catch (Throwable e) { + return CompletableFuture.failedFuture(e); + } + } + int countCustomBiomes(); void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk); diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java index 2c1eed0f3..c7d877d8d 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java @@ -44,6 +44,8 @@ import java.io.IOException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.function.IntSupplier; import java.util.function.Supplier; import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML; @@ -128,11 +130,7 @@ public class IrisCreator { Iris.service(StudioSVC.class).installIntoWorld(sender, d.getLoadKey(), new File(Bukkit.getWorldContainer(), name())); } - PlatformChunkGenerator access; - AtomicReference world = new AtomicReference<>(); AtomicDouble pp = new AtomicDouble(0); - O done = new O<>(); - done.set(false); WorldCreator wc = new IrisWorldCreator() .dimension(dimension) .name(name) @@ -141,28 +139,32 @@ public class IrisCreator { .create(); ServerConfigurator.installDataPacks(false); - access = (PlatformChunkGenerator) wc.generator(); - PlatformChunkGenerator finalAccess1 = access; + PlatformChunkGenerator access = (PlatformChunkGenerator) wc.generator(); + if (access == null) throw new IrisException("Access is null. Something bad happened."); - J.a(() -> - { - Supplier g = () -> { - if (finalAccess1 == null || finalAccess1.getEngine() == null) { + AtomicBoolean failed = new AtomicBoolean(false); + J.a(() -> { + IntSupplier g = () -> { + if (access.getEngine() == null) { return 0; } - return finalAccess1.getEngine().getGenerated(); + return access.getEngine().getGenerated(); }; if(!benchmark) { - if (finalAccess1 == null) return; - int req = finalAccess1.getSpawnChunks().join(); + int req = access.getSpawnChunks().join(); - while (g.get() < req) { - double v = (double) g.get() / (double) req; + while (g.getAsInt() < req) { + if (failed.get()) { + sender.sendMessage(C.RED + "Failed to create world!"); + return; + } + + double v = (double) g.getAsInt() / (double) req; if (sender.isPlayer()) { sender.sendProgress(v, "Generating"); J.sleep(16); } else { - sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - g.get()) + " Left)"))); + sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - g.getAsInt()) + " Left)"))); J.sleep(1000); } } @@ -170,37 +172,33 @@ public class IrisCreator { }); + final World world; try { - J.sfut(() -> { - world.set(INMS.get().createWorld(wc)); - }).get(); + world = J.sfut(() -> INMS.get().createWorldAsync(wc)) + .thenCompose(Function.identity()) + .get(); } catch (Throwable e) { - e.printStackTrace(); + failed.set(true); + throw new IrisException("Failed to create world!", e); } - if (access == null) { - throw new IrisException("Access is null. Something bad happened."); - } - - done.set(true); - if (sender.isPlayer() && !benchmark) { - J.s(() -> Iris.platform.teleportAsync(sender.player(), new Location(world.get(), 0, world.get().getHighestBlockYAt(0, 0), 0))); + J.s(() -> Iris.platform.teleportAsync(sender.player(), new Location(world, 0, world.getHighestBlockYAt(0, 0), 0))); } if (studio || benchmark) { J.s(() -> { - Iris.linkMultiverseCore.removeFromConfig(world.get()); + Iris.linkMultiverseCore.removeFromConfig(world); if (IrisSettings.get().getStudio().isDisableTimeAndWeather()) { - world.get().setGameRule(GameRule.DO_WEATHER_CYCLE, false); - world.get().setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false); - world.get().setTime(6000); + world.setGameRule(GameRule.DO_WEATHER_CYCLE, false); + world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false); + world.setTime(6000); } }); } else { addToBukkitYml(); - J.s(() -> Iris.linkMultiverseCore.updateWorld(world.get(), dimension)); + J.s(() -> Iris.linkMultiverseCore.updateWorld(world, dimension)); } if (pregen != null) { @@ -231,7 +229,7 @@ public class IrisCreator { e.printStackTrace(); } } - return world.get(); + return world; } private void addToBukkitYml() { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a2753148c..46aac93b3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -50,6 +50,7 @@ mythic = "5.9.5" mythic-chrucible = "2.1.0" kgenerators = "7.3" # https://repo.codemc.io/repository/maven-public/me/kryniowesegryderiusz/kgenerators-core/maven-metadata.xml multiverseCore = "5.1.0" +worlds = "3.2.5" # https://modrinth.com/plugin/worlds-1 [libraries] # Core Libraries @@ -96,6 +97,7 @@ mythic = { module = "io.lumine:Mythic-Dist", version.ref = "mythic" } mythicChrucible = { module = "io.lumine:MythicCrucible-Dist", version.ref = "mythic-chrucible" } kgenerators = { module = "me.kryniowesegryderiusz:kgenerators-core", version.ref = "kgenerators" } multiverseCore = { module = "org.mvplugins.multiverse.core:multiverse-core", version.ref = "multiverseCore" } +worlds = { module = "net.thenextlvl:worlds", version.ref = "worlds" } [plugins] shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }