diff --git a/README.md b/README.md index df89fcade..fadd56ffe 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Consider supporting our development by buying Iris on spigot! We work hard to ma 4. Use `CTRL + X`, then Press `Y`, Then `ENTER` 5. Quit & Reopen Terminal and verify with `echo $JAVA_HOME`. It should print a directory 3. If this is your first time building Iris for MC 1.18+ run `gradlew setup` inside the root Iris project folder. - Otherwise, skip this step. Grab a coffee, this may take up to 5 minutes depending on your cpu & internet connection. + Otherwise, skip this step. Grab a coffee, this may take up to 45 minutes depending on your cpu & internet connection. 4. Once the project has setup, run `gradlew iris` 5. The Iris jar will be placed in `Iris/build/Iris-XXX-XXX.jar` Enjoy! Consider supporting us by buying it on spigot! diff --git a/build.gradle b/build.gradle index 94ecba786..4305b4aa7 100644 --- a/build.gradle +++ b/build.gradle @@ -21,12 +21,12 @@ import java.util.function.Consumer plugins { id 'java' id 'java-library' - id "com.github.johnrengelman.shadow" version "7.1.2" + id "io.github.goooler.shadow" version "8.1.7" id "de.undercouch.download" version "5.0.1" } version '3.2.6-1.19.2-1.20.4' -def specialSourceVersion = '1.11.0' //[NMS] +def specialSourceVersion = '1.11.4' //[NMS] // ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED // ======================== WINDOWS ============================= @@ -43,8 +43,8 @@ registerCustomOutputTaskUnix('CyberpwnLT', '/Users/danielmills/development/serve registerCustomOutputTaskUnix('PsychoLT', '/Volumes/PRO-G40/Minecraft/MinecraftDevelopment/Server/plugins') // ============================================================== - def NMS_BINDINGS = Map.of( + "v1_20_R4", "1.20.6-R0.1-SNAPSHOT", "v1_20_R3", "1.20.4-R0.1-SNAPSHOT", "v1_20_R2", "1.20.2-R0.1-SNAPSHOT", "v1_20_R1", "1.20.1-R0.1-SNAPSHOT", @@ -52,11 +52,15 @@ def NMS_BINDINGS = Map.of( "v1_19_R2", "1.19.3-R0.1-SNAPSHOT", "v1_19_R1", "1.19.2-R0.1-SNAPSHOT" ) +def JVM_VERSION = Map.of( + "v1_20_R4", 21, +) NMS_BINDINGS.each { def key = it.key def value = it.value def nms = value.split("-")[0]; project(":nms:${key}") { + apply plugin: 'java' apply plugin: 'java-library' apply plugin: 'de.undercouch.download' @@ -65,9 +69,10 @@ NMS_BINDINGS.each { compileOnly "org.spigotmc:spigot-api:${value}" compileOnly "org.bukkit:craftbukkit:${value}:remapped-mojang" //[NMS] } - def buildToolsJar = new File(rootProject.buildDir, "tools/BuildTools.jar") - def specialSourceJar = new File(rootProject.buildDir, "tools/SpecialSource.jar") + def buildToolsJar = new File(rootProject.layout.buildDirectory.asFile.get(), "tools/BuildTools.jar") + def specialSourceJar = new File(rootProject.layout.buildDirectory.asFile.get(), "tools/SpecialSource.jar") + def buildDir = layout.buildDirectory.asFile.get(); def buildToolsFolder = new File(buildDir, "buildtools") def specialSourceFolder = new File(buildDir, "specialsource") def buildToolsHint = new File(buildDir, "buildtools/craftbukkit-" + nms + ".jar") @@ -82,6 +87,22 @@ NMS_BINDINGS.each { def m2s = m2.getAbsolutePath(); // ======================== Building Mapped Jars ============================= + def targetJavaVersion = JVM_VERSION.getOrDefault(key, 17) + def javaVersion = JavaVersion.toVersion(targetJavaVersion) + def javaLanguageVersion = JavaLanguageVersion.of(targetJavaVersion) + project.java.sourceCompatibility = javaVersion + project.java.targetCompatibility = javaVersion + project.java.toolchain.languageVersion = javaLanguageVersion + def launcher = javaToolchains.launcherFor(java.toolchain).get() + def javaHome = launcher.executablePath.getAsFile().parentFile.parentFile.getAbsolutePath() + + tasks.withType(JavaCompile).configureEach { + options.release.set(targetJavaVersion) + } + + tasks.withType(JavaExec).configureEach { + javaLauncher.set(launcher) + } ext { executeBuildTools = new Runnable() { @@ -99,6 +120,7 @@ NMS_BINDINGS.each { if (!buildToolsHint.exists()) { buildToolsFolder.mkdirs() project.javaexec { + executable = launcher.executablePath classpath = files(buildToolsJar) workingDir = buildToolsFolder args = [ @@ -108,16 +130,14 @@ NMS_BINDINGS.each { "craftbukkit", "--remap" ] + def env = new HashMap(environment) + env.put("JAVA_HOME", javaHome) + environment = env } } } } } - tasks.register("executeBuildTools") { - doLast { - property("executeBuildTools").run(); - } - } tasks.build.doLast { //Download @@ -137,6 +157,7 @@ NMS_BINDINGS.each { //obfuscate javaexec { + executable = launcher.executablePath workingDir = specialSourceFolder classpath = files(specialSourceJar, new File(m2s + "/org/spigotmc/spigot/" + value + "/spigot-" + value + "-remapped-mojang.jar")) @@ -151,10 +172,14 @@ NMS_BINDINGS.each { m2s + "/org/spigotmc/minecraft-server/" + value + "/minecraft-server-" + value + "-maps-mojang.txt", "--reverse", ] + def env = new HashMap(environment) + env.put("JAVA_HOME", javaHome) + environment = env } //remap javaexec { + executable = launcher.executablePath workingDir = specialSourceFolder classpath = files(specialSourceJar, new File(m2s + "/org/spigotmc/spigot/" + value + "/spigot-" + value + "-remapped-obf.jar")) @@ -168,6 +193,9 @@ NMS_BINDINGS.each { "-m", m2s + "/org/spigotmc/minecraft-server/" + value + "/minecraft-server-" + value + "-maps-spigot.csrg" ] + def env = new HashMap(environment) + env.put("JAVA_HOME", javaHome) + environment = env } //copy copy { @@ -182,6 +210,10 @@ NMS_BINDINGS.each { } shadowJar { + NMS_BINDINGS.each { + dependsOn(":nms:${it.key}:build") + from("${project(":nms:${it.key}").layout.buildDirectory.asFile.get()}/libs/${it.key}.jar") + } NMS_BINDINGS.each {dependsOn(":nms:${it.key}:build")} dependsOn(':com.volmit.gui:build') @@ -195,9 +227,6 @@ shadowJar { dependencies { implementation project(':core') - NMS_BINDINGS.each { - implementation project(":nms:${it.key}") - } } configurations.configureEach { @@ -230,7 +259,6 @@ allprojects { dependencies { // Provided or Classpath - // implementation project(':com.volmit.gui') compileOnly 'org.projectlombok:lombok:1.18.24' annotationProcessor 'org.projectlombok:lombok:1.18.24' @@ -240,6 +268,8 @@ allprojects { implementation "net.kyori:adventure-text-minimessage:4.13.1" implementation 'net.kyori:adventure-platform-bukkit:4.3.2' implementation 'net.kyori:adventure-api:4.13.1' + //implementation 'org.bytedeco:javacpp:1.5.10' + //implementation 'org.bytedeco:cuda-platform:12.3-8.9-1.5.10' compileOnly 'io.lumine:Mythic-Dist:5.2.1' // Dynamically Loaded @@ -289,8 +319,8 @@ if (JavaVersion.current().toString() != "17") { task iris(type: Copy) { group "iris" - from new File(buildDir, "libs/Iris-${version}.jar") - into buildDir + from new File(layout.buildDirectory.asFile.get(), "libs/Iris-${version}.jar") + into layout.buildDirectory.asFile.get() dependsOn(build) } @@ -313,7 +343,9 @@ NMS_BINDINGS.keySet().forEach { tasks.register("setup-${nms}") { group "iris" dependsOn(":nms:${nms}:clean") - dependsOn(":nms:${nms}:executeBuildTools") + doLast { + project(":nms:${nms}").property("executeBuildTools").run(); + } } } diff --git a/core/build.gradle b/core/build.gradle index b15995f34..d1c25950d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -19,7 +19,7 @@ plugins { id 'java' id 'java-library' - id "io.freefair.lombok" version "6.3.0" + id "io.freefair.lombok" version "8.6" } def apiVersion = '1.19' @@ -35,6 +35,7 @@ compileJava { repositories { maven { url 'https://nexus.phoenixdevt.fr/repository/maven-public/'} + maven { url 'https://repo.auxilor.io/repository/maven-public/' } } /** @@ -66,6 +67,7 @@ dependencies { compileOnly 'com.github.PlaceholderAPI:placeholderapi:2.11.3' compileOnly 'com.github.Ssomar-Developement:SCore:4.23.10.8' compileOnly 'net.Indyuce:MMOItems-API:6.9.5-SNAPSHOT' + compileOnly 'com.willfp:EcoItems:5.44.0' //implementation files('libs/CustomItems.jar') } diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index f916d9501..2a710e83e 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -92,6 +92,7 @@ import java.lang.management.OperatingSystemMXBean; import java.net.URL; import java.util.Date; import java.util.Map; +import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -457,7 +458,6 @@ public class Iris extends VolmitPlugin implements Listener { instance = this; InitializeSafeguard(); ByteBuddyAgent.install(); - boolean configured; services = new KMap<>(); setupAudience(); initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class) i.getClass(), (IrisService) i)); @@ -473,7 +473,7 @@ public class Iris extends VolmitPlugin implements Listener { configWatcher = new FileWatcher(getDataFile("settings.json")); services.values().forEach(IrisService::onEnable); services.values().forEach(this::registerListener); - configured = ServerConfigurator.postConfigure(); + installMainDimension(); if (!IrisSafeguard.instance.acceptUnstable && IrisSafeguard.instance.unstablemode) { Iris.info(C.RED + "World loading has been disabled until the incompatibility is resolved."); Iris.info(C.DARK_RED + "Alternatively, go to plugins/iris/settings.json and set ignoreBootMode to true."); @@ -486,7 +486,7 @@ public class Iris extends VolmitPlugin implements Listener { J.ar(this::checkConfigHotload, 60); J.sr(this::tickQueue, 0); J.s(this::setupPapi); - if (!configured) J.a(ServerConfigurator::configure, 20); + J.a(ServerConfigurator::configure, 20); splash(); UtilsSFG.splash(); autoStartStudio(); @@ -686,6 +686,48 @@ public class Iris extends VolmitPlugin implements Listener { s.sendMessage(C.IRIS + "[" + C.DARK_GRAY + "Iris" + C.IRIS + "]" + C.GRAY + ": " + msg); } + private void installMainDimension() { + try { + Properties props = new Properties(); + props.load(new FileInputStream("server.properties")); + String world = props.getProperty("level-name"); + if (world == null) return; + + FileConfiguration fc = new YamlConfiguration(); + fc.load(new File("bukkit.yml")); + String id = fc.getString("worlds." + world + ".generator"); + if (id.startsWith("Iris:")) { + id = id.split("\\Q:\\E")[1]; + } else if (id.equalsIgnoreCase("Iris")) { + id = IrisSettings.get().getGenerator().getDefaultWorldType(); + } else { + return; + } + + IrisDimension dim; + if (id == null || id.isEmpty()) { + dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType()); + } else { + dim = IrisData.loadAnyDimension(id); + } + + File w = new File(Bukkit.getWorldContainer(), world); + File packFolder = new File(w, "/iris/pack"); + if (!packFolder.exists() || packFolder.listFiles().length == 0) { + packFolder.mkdirs(); + service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w); + } + if (packFolder.exists()) { + IrisDimension worldDim = IrisData.get(packFolder).getDimensionLoader().load(id); + if (worldDim != null) dim = worldDim; + } + + INMS.get().registerDimension("overworld", dim); + } catch (Throwable e) { + + } + } + @Nullable @Override public BiomeProvider getDefaultBiomeProvider(@NotNull String worldName, @Nullable String id) { diff --git a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java index f3dafea22..dc75b46df 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -19,33 +19,15 @@ package com.volmit.iris.core; import com.volmit.iris.Iris; -import com.volmit.iris.core.loader.IrisData; -import com.volmit.iris.core.nms.INMS; -import com.volmit.iris.engine.object.IrisBiome; -import com.volmit.iris.engine.object.IrisBiomeCustom; -import com.volmit.iris.engine.object.IrisDimension; -import com.volmit.iris.engine.object.IrisRange; -import com.volmit.iris.util.collection.KList; -import com.volmit.iris.util.collection.KSet; -import com.volmit.iris.util.format.C; -import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; -import org.bukkit.Bukkit; -import org.bukkit.World; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.util.List; -import java.util.Properties; import java.util.concurrent.TimeUnit; -import static org.bukkit.Bukkit.getServer; - public class ServerConfigurator { public static void configure() { IrisSettings.IrisSettingsAutoconfiguration s = IrisSettings.get().getAutoConfiguration(); @@ -56,16 +38,6 @@ public class ServerConfigurator { if (s.isConfigurePaperWatchdogDelay()) { J.attempt(ServerConfigurator::increasePaperWatchdog); } - - installDataPacks(true); - } - - public static boolean postConfigure() { - if(postVerifyDataPacks(true)) { - configure(); - return true; - } - return false; } private static void increaseKeepAliveSpigot() throws IOException, InvalidConfigurationException { @@ -81,6 +53,7 @@ public class ServerConfigurator { f.save(spigotConfig); } } + private static void increasePaperWatchdog() throws IOException, InvalidConfigurationException { File spigotConfig = new File("config/paper-global.yml"); FileConfiguration f = new YamlConfiguration(); @@ -94,191 +67,4 @@ public class ServerConfigurator { f.save(spigotConfig); } } - - private static List getDatapacksFolder() { - if (!IrisSettings.get().getGeneral().forceMainWorld.isEmpty()) { - return new KList().qadd(new File(Bukkit.getWorldContainer(), IrisSettings.get().getGeneral().forceMainWorld + "/datapacks")); - } - KList worlds = new KList<>(); - Bukkit.getServer().getWorlds().forEach(w -> worlds.add(new File(w.getWorldFolder(), "datapacks"))); - if (worlds.isEmpty()) { - worlds.add(new File(getMainWorldFolder(), "datapacks")); - } - return worlds; - } - - private static File getMainWorldFolder() { - try { - Properties prop = new Properties(); - prop.load(new FileInputStream("server.properties")); - String world = prop.getProperty("level-name"); - return new File(Bukkit.getWorldContainer(), world); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - private static boolean postVerifyDataPacks(boolean fast) { - try { - File datapacksFolder = new File(getMainWorldFolder(), "datapacks"); - File IrisDatapacks = new File(datapacksFolder, "iris"); - if (!datapacksFolder.exists() || !IrisDatapacks.exists()) { - return (true); - } - } catch (Exception e) { - e.printStackTrace(); - } - return false; - } - - public static void installDataPacks(boolean fullInstall) { - Iris.info("Checking Data Packs..."); - File packs = new File("plugins/Iris/packs"); - if (packs.exists()) { - for (File i : packs.listFiles()) { - if (i.isDirectory()) { - Iris.verbose("Checking Pack: " + i.getPath()); - IrisData data = IrisData.get(i); - File dims = new File(i, "dimensions"); - - if (dims.exists()) { - for (File j : dims.listFiles()) { - if (j.getName().endsWith(".json")) { - IrisDimension dim = data.getDimensionLoader().load(j.getName().split("\\Q.\\E")[0]); - - if (dim == null) { - continue; - } - - Iris.verbose(" Checking Dimension " + dim.getLoadFile().getPath()); - for (File dpack : getDatapacksFolder()) { - dim.installDataPack(() -> data, dpack); - } - } - } - } - } - } - } - - Iris.info("Data Packs Setup!"); - - if (fullInstall) - verifyDataPacksPost(IrisSettings.get().getAutoConfiguration().isAutoRestartOnCustomBiomeInstall()); - } - - private static void verifyDataPacksPost(boolean allowRestarting) { - File packs = new File("plugins/Iris/packs"); - - boolean bad = false; - if (packs.exists()) { - for (File i : packs.listFiles()) { - if (i.isDirectory()) { - Iris.verbose("Checking Pack: " + i.getPath()); - IrisData data = IrisData.get(i); - File dims = new File(i, "dimensions"); - - if (dims.exists()) { - for (File j : dims.listFiles()) { - if (j.getName().endsWith(".json")) { - IrisDimension dim = data.getDimensionLoader().load(j.getName().split("\\Q.\\E")[0]); - - if (dim == null) { - Iris.error("Failed to load " + j.getPath() + " "); - continue; - } - - if (!verifyDataPackInstalled(dim)) { - bad = true; - } - } - } - } - } - } - } - - if (bad) { - // Iris.info(""); - Iris.info( "Hotloading all Datapacks!"); - if (INMS.get().supportsDataPacks()) { - for (File folder : getDatapacksFolder()) { - INMS.get().loadDatapack(folder, false); - } - Iris.info("Datapacks Hotloaded!"); - Iris.info(C.YELLOW + "============================================================================"); - Iris.info(C.ITALIC + "" + C.YELLOW + "To ensure the stability of custom biome generation, a server restart is necessary."); - Iris.info(C.ITALIC + "" + C.YELLOW + "While datapacks have been hotloaded, a complete restart is advised."); - Iris.info(C.YELLOW + "----------------------------------------------------------------------------"); - Iris.info(C.UNDERLINE + "" + C.YELLOW + "IT IS HIGHLY RECOMMENDED YOU RESTART THE SERVER BEFORE GENERATING!"); - Iris.info(C.YELLOW + "============================================================================"); - - for (Player i : Bukkit.getOnlinePlayers()) { - if (i.isOp() || i.hasPermission("iris.all")) { - VolmitSender sender = new VolmitSender(i, Iris.instance.getTag("WARNING")); - sender.sendMessage("There are some Iris Packs that have custom biomes in them"); - sender.sendMessage("You need to restart your server to use these packs."); - } - } - - J.sleep(3000); - } - } - } - - public static void restart() { - J.s(() -> { - Iris.warn("New data pack entries have been installed in Iris! Restarting server!"); - Iris.warn("This will only happen when your pack changes (updates/first time setup)"); - Iris.warn("(You can disable this auto restart in iris settings)"); - J.s(() -> { - Iris.warn("Looks like the restart command didn't work. Stopping the server instead!"); - Bukkit.shutdown(); - }, 100); - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart"); - }); - } - - public static boolean verifyDataPackInstalled(IrisDimension dimension) { - IrisData idm = IrisData.get(Iris.instance.getDataFolder("packs", dimension.getLoadKey())); - KSet keys = new KSet<>(); - boolean warn = false; - - for (IrisBiome i : dimension.getAllBiomes(() -> idm)) { - if (i.isCustom()) { - for (IrisBiomeCustom j : i.getCustomDerivitives()) { - keys.add(dimension.getLoadKey() + ":" + j.getId()); - } - } - } - - if (!INMS.get().supportsDataPacks()) { - if (!keys.isEmpty()) { - Iris.warn("==================================================================================="); - Iris.warn("Pack " + dimension.getLoadKey() + " has " + keys.size() + " custom biome(s). "); - Iris.warn("Your server version does not yet support datapacks for iris."); - Iris.warn("The world will generate these biomes as backup biomes."); - Iris.warn("===================================================================================="); - } - - return true; - } - - for (String i : keys) { - Object o = INMS.get().getCustomBiomeBaseFor(i); - - if (o == null) { - Iris.warn("The Biome " + i + " is not registered on the server."); - warn = true; - } - } - - if (warn) { - Iris.error("The Pack " + dimension.getLoadKey() + " is INCAPABLE of generating custom biomes"); - Iris.error("Queued for Datapack Hotload."); - } - - return !warn; - } } diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java index cc26c7a04..6dac2f2fa 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java @@ -19,8 +19,10 @@ package com.volmit.iris.core.commands; import com.volmit.iris.Iris; +import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.INMS; +import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.core.nms.v1X.NMSBinding1X; import com.volmit.iris.core.pregenerator.ChunkUpdater; import com.volmit.iris.core.service.IrisEngineSVC; @@ -152,10 +154,12 @@ public class CommandDeveloper implements DecreeExecutor { @Param(description = "The pack to bench", aliases = {"pack"}) IrisDimension dimension, @Param(description = "Headless", defaultValue = "false") - boolean headless + boolean headless, + @Param(description = "GUI", defaultValue = "false") + boolean gui ) { Iris.info("test"); - IrisPackBenchmarking benchmark = new IrisPackBenchmarking(dimension, 1, headless); + IrisPackBenchmarking benchmark = new IrisPackBenchmarking(dimension, 1, headless, gui); } diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java index 6e282777b..7b7a24ea7 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java @@ -20,7 +20,9 @@ package com.volmit.iris.core.commands; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.core.pregenerator.ChunkUpdater; import com.volmit.iris.core.safeguard.IrisSafeguard; import com.volmit.iris.core.service.StudioSVC; diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java b/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java index 15bf87b76..830068de7 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java @@ -35,6 +35,7 @@ import com.volmit.iris.util.decree.specialhandlers.ObjectHandler; import com.volmit.iris.util.format.C; import com.volmit.iris.util.math.Direction; import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.misc.E; import com.volmit.iris.util.scheduling.Queue; import org.bukkit.*; import org.bukkit.block.Block; @@ -52,7 +53,7 @@ import java.util.*; @Decree(name = "object", aliases = "o", origin = DecreeOrigin.PLAYER, studio = true, description = "Iris object manipulation") public class CommandObject implements DecreeExecutor { - private static final Set skipBlocks = Set.of(Material.GRASS, Material.SNOW, Material.VINE, Material.TORCH, Material.DEAD_BUSH, + private static final Set skipBlocks = Set.of(E.getOrDefault(Material.class, "GRASS", "SHORT_GRASS"), Material.SNOW, Material.VINE, Material.TORCH, Material.DEAD_BUSH, Material.POPPY, Material.DANDELION); public static IObjectPlacer createPlacer(World world, Map futureBlockChanges) { diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java index 2188485c0..095e28406 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java @@ -20,21 +20,16 @@ package com.volmit.iris.core.commands; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; -import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.gui.NoiseExplorerGUI; import com.volmit.iris.core.gui.VisionGUI; -import com.volmit.iris.core.loader.IrisData; -import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.project.IrisProject; import com.volmit.iris.core.service.ConversionSVC; import com.volmit.iris.core.service.StudioSVC; -import com.volmit.iris.core.tools.IrisConverter; import com.volmit.iris.core.tools.IrisNoiseBenchmark; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.platform.PlatformChunkGenerator; -import com.volmit.iris.engine.platform.studio.StudioGenerator; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KSet; @@ -43,30 +38,23 @@ import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeOrigin; import com.volmit.iris.util.decree.annotations.Decree; import com.volmit.iris.util.decree.annotations.Param; -import com.volmit.iris.util.decree.specialhandlers.NullablePlayerHandler; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; import com.volmit.iris.util.function.Function2; -import com.volmit.iris.util.function.NoiseProvider; -import com.volmit.iris.util.interpolation.InterpolationMethod; -import com.volmit.iris.util.io.IO; import com.volmit.iris.util.json.JSONArray; import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.Spiraler; -import com.volmit.iris.util.noise.CNG; import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.O; -import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.jobs.QueueJob; import io.papermc.lib.PaperLib; import org.bukkit.*; -import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.util.BlockVector; @@ -85,7 +73,6 @@ import java.util.Date; import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; @Decree(name = "studio", aliases = {"std", "s"}, description = "Studio Commands", studio = true) @@ -286,7 +273,7 @@ public class CommandStudio implements DecreeExecutor { } @Decree(description = "Hotload a studio", aliases = {"reload", "h"}) - public void hotload(@Param(defaultValue = "false") boolean reloadDataPack) { + public void hotload() { if (!Iris.service(StudioSVC.class).isProjectOpen()) { sender().sendMessage(C.RED + "No studio world open!"); return; @@ -294,15 +281,6 @@ public class CommandStudio implements DecreeExecutor { var provider = Iris.service(StudioSVC.class).getActiveProject().getActiveProvider(); provider.getEngine().hotload(); sender().sendMessage(C.GREEN + "Hotloaded"); - if (reloadDataPack) { - var world = provider.getTarget().getWorld().realWorld(); - if (world == null) { - sender().sendMessage(C.RED + "Failed to reload datapacks."); - return; - } - boolean success = INMS.get().loadDatapack(new File(world.getWorldFolder(), "datapacks"), true); - sender().sendMessage(success ? C.GREEN + "Reloaded datapacks." : C.RED + "Failed to reload datapacks."); - } } @Decree(description = "Show loot if a chest were right here", origin = DecreeOrigin.PLAYER, sync = true) diff --git a/core/src/main/java/com/volmit/iris/core/link/EcoItemsDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/EcoItemsDataProvider.java new file mode 100644 index 000000000..615256e66 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/link/EcoItemsDataProvider.java @@ -0,0 +1,71 @@ +package com.volmit.iris.core.link; + +import com.volmit.iris.Iris; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.reflect.WrappedField; +import com.willfp.ecoitems.items.EcoItem; +import com.willfp.ecoitems.items.EcoItems; +import org.bukkit.NamespacedKey; +import org.bukkit.block.data.BlockData; +import org.bukkit.inventory.ItemStack; + +import java.util.MissingResourceException; + +public class EcoItemsDataProvider extends ExternalDataProvider { + private WrappedField itemStack; + private WrappedField id; + + public EcoItemsDataProvider() { + super("EcoItems"); + } + + @Override + public void init() { + Iris.info("Setting up EcoItems Link..."); + itemStack = new WrappedField<>(EcoItem.class, "_itemStack"); + if (this.itemStack.hasFailed()) { + Iris.error("Failed to set up EcoItems Link: Unable to fetch ItemStack field!"); + } + id = new WrappedField<>(EcoItem.class, "id"); + if (this.id.hasFailed()) { + Iris.error("Failed to set up EcoItems Link: Unable to fetch id field!"); + } + } + + @Override + public BlockData getBlockData(Identifier blockId) throws MissingResourceException { + throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); + } + + @Override + public ItemStack getItemStack(Identifier itemId) throws MissingResourceException { + EcoItem item = EcoItems.INSTANCE.getByID(itemId.key()); + if (item == null) throw new MissingResourceException("Failed to find Item!", itemId.namespace(), itemId.key()); + return itemStack.get(item).clone(); + } + + @Override + public Identifier[] getBlockTypes() { + return new Identifier[0]; + } + + @Override + public Identifier[] getItemTypes() { + KList names = new KList<>(); + for (EcoItem item : EcoItems.INSTANCE.values()) { + try { + Identifier key = Identifier.fromNamespacedKey(id.get(item)); + if (getItemStack(key) != null) + names.add(key); + } catch (MissingResourceException ignored) { + } + } + + return names.toArray(new Identifier[0]); + } + + @Override + public boolean isValidProvider(Identifier id, boolean isItem) { + return id.namespace().equalsIgnoreCase("ecoitems") && isItem; + } +} diff --git a/core/src/main/java/com/volmit/iris/core/link/Identifier.java b/core/src/main/java/com/volmit/iris/core/link/Identifier.java index 4059016d0..3969b174b 100644 --- a/core/src/main/java/com/volmit/iris/core/link/Identifier.java +++ b/core/src/main/java/com/volmit/iris/core/link/Identifier.java @@ -6,6 +6,10 @@ public record Identifier(String namespace, String key) { private static final String DEFAULT_NAMESPACE = "minecraft"; + public static Identifier fromNamespacedKey(NamespacedKey key) { + return new Identifier(key.getNamespace(), key.getKey()); + } + public static Identifier fromString(String id) { String[] strings = id.split(":", 2); if (strings.length == 1) { diff --git a/core/src/main/java/com/volmit/iris/core/nms/IHeadless.java b/core/src/main/java/com/volmit/iris/core/nms/IHeadless.java index 7b32a79ca..2b7accdc1 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/IHeadless.java +++ b/core/src/main/java/com/volmit/iris/core/nms/IHeadless.java @@ -9,9 +9,9 @@ import java.io.Closeable; public interface IHeadless extends Closeable { - void saveAll(); + void save(); - @RegionCoordinates + @ChunkCoordinates boolean exists(int x, int z); @RegionCoordinates diff --git a/core/src/main/java/com/volmit/iris/core/nms/INMS.java b/core/src/main/java/com/volmit/iris/core/nms/INMS.java index dcb5e8dce..85b3778e9 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/INMS.java +++ b/core/src/main/java/com/volmit/iris/core/nms/INMS.java @@ -23,7 +23,13 @@ import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.nms.v1X.NMSBinding1X; import org.bukkit.Bukkit; +import java.util.Map; + public class INMS { + private static final Map REVISION = Map.of( + "1.20.5", "v1_20_R4", + "1.20.6", "v1_20_R4" + ); //@done private static final INMSBinding binding = bind(); @@ -37,7 +43,12 @@ public class INMS { } try { - return Bukkit.getServer().getClass().getCanonicalName().split("\\Q.\\E")[3]; + String name = Bukkit.getServer().getClass().getCanonicalName(); + if (name.equals("org.bukkit.craftbukkit.CraftServer")) { + return REVISION.getOrDefault(Bukkit.getServer().getBukkitVersion().split("-")[0], "BUKKIT"); + } else { + return name.split("\\Q.\\E")[3]; + } } catch (Throwable e) { Iris.reportError(e); Iris.error("Failed to determine server nms version!"); 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 6c22368aa..7f72c84d7 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,11 +18,12 @@ package com.volmit.iris.core.nms; +import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.object.IrisBiomeCustom; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; -import com.volmit.iris.util.documentation.RegionCoordinates; import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer; @@ -40,8 +41,6 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; -import java.io.File; - public interface INMSBinding { boolean hasTile(Location l); @@ -115,10 +114,14 @@ public interface INMSBinding { Entity spawnEntity(Location location, EntityType type, CreatureSpawnEvent.SpawnReason reason); - boolean loadDatapack(File datapackFolder, boolean replace); + default DataVersion getDataVersion() { + return DataVersion.V1192; + } boolean registerDimension(String name, IrisDimension dimension); + boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace); + void injectBukkit(); default IHeadless createHeadless(Engine engine) { diff --git a/core/src/main/java/com/volmit/iris/core/nms/datapack/DataVersion.java b/core/src/main/java/com/volmit/iris/core/nms/datapack/DataVersion.java new file mode 100644 index 000000000..7185b693d --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/nms/datapack/DataVersion.java @@ -0,0 +1,40 @@ +package com.volmit.iris.core.nms.datapack; + +import com.volmit.iris.core.nms.INMS; +import com.volmit.iris.core.nms.datapack.v1192.DataFixerV1192; +import com.volmit.iris.core.nms.datapack.v1206.DataFixerV1206; +import com.volmit.iris.util.collection.KMap; +import lombok.AccessLevel; +import lombok.Getter; + +import java.util.function.Supplier; + +//https://minecraft.wiki/w/Pack_format +@Getter +public enum DataVersion { + V1192("1.19.2", 10, DataFixerV1192::new), + V1205("1.20.6", 41, DataFixerV1206::new); + private static final KMap cache = new KMap<>(); + @Getter(AccessLevel.NONE) + private final Supplier constructor; + private final String version; + private final int packFormat; + + DataVersion(String version, int packFormat, Supplier constructor) { + this.constructor = constructor; + this.packFormat = packFormat; + this.version = version; + } + + public IDataFixer get() { + return cache.computeIfAbsent(this, k -> constructor.get()); + } + + public static IDataFixer getDefault() { + return INMS.get().getDataVersion().get(); + } + + public static DataVersion getLatest() { + return values()[values().length - 1]; + } +} diff --git a/core/src/main/java/com/volmit/iris/core/nms/datapack/IDataFixer.java b/core/src/main/java/com/volmit/iris/core/nms/datapack/IDataFixer.java new file mode 100644 index 000000000..76a30f6e0 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/nms/datapack/IDataFixer.java @@ -0,0 +1,11 @@ +package com.volmit.iris.core.nms.datapack; + +import com.volmit.iris.engine.object.IrisBiomeCustom; +import com.volmit.iris.util.json.JSONObject; + +public interface IDataFixer { + + JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json); + + JSONObject fixDimension(JSONObject json); +} diff --git a/core/src/main/java/com/volmit/iris/core/nms/datapack/v1192/DataFixerV1192.java b/core/src/main/java/com/volmit/iris/core/nms/datapack/v1192/DataFixerV1192.java new file mode 100644 index 000000000..c6bd59359 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/nms/datapack/v1192/DataFixerV1192.java @@ -0,0 +1,18 @@ +package com.volmit.iris.core.nms.datapack.v1192; + +import com.volmit.iris.core.nms.datapack.IDataFixer; +import com.volmit.iris.engine.object.IrisBiomeCustom; +import com.volmit.iris.util.json.JSONObject; + +public class DataFixerV1192 implements IDataFixer { + + @Override + public JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) { + return json; + } + + @Override + public JSONObject fixDimension(JSONObject json) { + return json; + } +} diff --git a/core/src/main/java/com/volmit/iris/core/nms/datapack/v1206/DataFixerV1206.java b/core/src/main/java/com/volmit/iris/core/nms/datapack/v1206/DataFixerV1206.java new file mode 100644 index 000000000..48883bfa5 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/nms/datapack/v1206/DataFixerV1206.java @@ -0,0 +1,54 @@ +package com.volmit.iris.core.nms.datapack.v1206; + +import com.volmit.iris.core.nms.datapack.IDataFixer; +import com.volmit.iris.engine.object.IrisBiomeCustom; +import com.volmit.iris.engine.object.IrisBiomeCustomSpawn; +import com.volmit.iris.engine.object.IrisBiomeCustomSpawnType; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.json.JSONArray; +import com.volmit.iris.util.json.JSONObject; + +import java.util.Locale; + +public class DataFixerV1206 implements IDataFixer { + @Override + public JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) { + int spawnRarity = biome.getSpawnRarity(); + if (spawnRarity > 0) { + json.put("creature_spawn_probability", Math.min(spawnRarity/20d, 0.9999999)); + } + + var spawns = biome.getSpawns(); + if (spawns != null && spawns.isNotEmpty()) { + JSONObject spawners = new JSONObject(); + KMap groups = new KMap<>(); + + for (IrisBiomeCustomSpawn i : spawns) { + JSONArray g = groups.computeIfAbsent(i.getGroup(), (k) -> new JSONArray()); + JSONObject o = new JSONObject(); + o.put("type", "minecraft:" + i.getType().name().toLowerCase()); + o.put("weight", i.getWeight()); + o.put("minCount", Math.min(i.getMinCount()/20d, 0)); + o.put("maxCount", Math.min(i.getMaxCount()/20d, 0.9999999)); + g.put(o); + } + + for (IrisBiomeCustomSpawnType i : groups.k()) { + spawners.put(i.name().toLowerCase(Locale.ROOT), groups.get(i)); + } + + json.put("spawners", spawners); + } + return json; + } + + @Override + public JSONObject fixDimension(JSONObject json) { + if (!(json.get("monster_spawn_light_level") instanceof JSONObject lightLevel)) + return json; + var value = (JSONObject) lightLevel.remove("value"); + lightLevel.put("max_inclusive", value.get("max_inclusive")); + lightLevel.put("min_inclusive", value.get("min_inclusive")); + return json; + } +} diff --git a/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java b/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java index 42a5e2507..d54ee7f6a 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java +++ b/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java @@ -23,6 +23,7 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.core.nms.container.BlockPos; import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.object.IrisBiomeCustom; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; @@ -108,12 +109,12 @@ public class NMSBinding1X implements INMSBinding { } @Override - public boolean loadDatapack(File datapackFolder, boolean replace) { + public boolean registerDimension(String name, IrisDimension dimension) { return false; } @Override - public boolean registerDimension(String name, IrisDimension dimension) { + public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) { return false; } diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java index 80b0a3dfd..495454f22 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java @@ -82,11 +82,8 @@ public class AsyncPregenMethod implements PregeneratorMethod { private void completeChunk(int x, int z, PregenListener listener) { try { future.add(PaperLib.getChunkAtAsync(world, x, z, true).thenApply((i) -> { - if (i == null) { - - } - Chunk c = Bukkit.getWorld(world.getUID()).getChunkAt(x, z); - lastUse.put(c, M.ms()); + if (i == null) return 0; + lastUse.put(i, M.ms()); listener.onChunkGenerated(x, z); listener.onChunkCleaned(x, z); return 0; diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/HeadlessPregenMethod.java b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/HeadlessPregenMethod.java index e1298da23..7196032fa 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/HeadlessPregenMethod.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/HeadlessPregenMethod.java @@ -1,30 +1,29 @@ package com.volmit.iris.core.pregenerator.methods; import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.nms.IHeadless; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.pregenerator.PregenListener; import com.volmit.iris.core.pregenerator.PregeneratorMethod; import com.volmit.iris.engine.framework.Engine; -import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.parallel.MultiBurst; import java.io.IOException; -import java.util.Objects; -import java.util.concurrent.Future; +import java.util.concurrent.Semaphore; public class HeadlessPregenMethod implements PregeneratorMethod { private final Engine engine; private final IHeadless headless; - private final MultiBurst burst; - private final KList> futures; + private final Semaphore semaphore; + private final int max; public HeadlessPregenMethod(Engine engine) { + this.max = IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism()); this.engine = engine; this.headless = INMS.get().createHeadless(engine); - this.burst = new MultiBurst("Iris Headless", Thread.MAX_PRIORITY); - this.futures = new KList<>(); + this.semaphore = new Semaphore(max); } @Override @@ -32,9 +31,10 @@ public class HeadlessPregenMethod implements PregeneratorMethod { @Override public void close() { - waitForChunksPartial(0); - burst.close(); - headless.saveAll(); + try { + semaphore.acquire(max); + } catch (InterruptedException ignored) {} + headless.save(); try { headless.close(); } catch (IOException e) { @@ -45,7 +45,7 @@ public class HeadlessPregenMethod implements PregeneratorMethod { @Override public void save() { - headless.saveAll(); + headless.save(); } @Override @@ -63,34 +63,25 @@ public class HeadlessPregenMethod implements PregeneratorMethod { @Override public void generateChunk(int x, int z, PregenListener listener) { - futures.removeIf(Future::isDone); - waitForChunksPartial(512); - futures.add(burst.complete(() -> { - listener.onChunkGenerating(x, z); - headless.generateChunk(x, z); - listener.onChunkGenerated(x, z); - })); + try { + semaphore.acquire(); + } catch (InterruptedException ignored) { + semaphore.release(); + return; + } + MultiBurst.burst.complete(() -> { + try { + listener.onChunkGenerating(x, z); + headless.generateChunk(x, z); + listener.onChunkGenerated(x, z); + } finally { + semaphore.release(); + } + }); } @Override public Mantle getMantle() { return engine.getMantle().getMantle(); } - - private void waitForChunksPartial(int maxWaiting) { - futures.removeWhere(Objects::isNull); - while (futures.size() > maxWaiting) { - try { - Future i = futures.remove(0); - - if (i == null) { - continue; - } - - i.get(); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } } diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/MedievalPregenMethod.java b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/MedievalPregenMethod.java index 2ebfb64b2..cdecf2bcc 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/MedievalPregenMethod.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/MedievalPregenMethod.java @@ -119,8 +119,7 @@ public class MedievalPregenMethod implements PregeneratorMethod { listener.onChunkGenerating(x, z); futures.add(J.sfut(() -> { - world.getChunkAt(x, z); - Chunk c = Bukkit.getWorld(world.getUID()).getChunkAt(x, z); + Chunk c = world.getChunkAt(x, z); lastUse.put(c, M.ms()); listener.onChunkGenerated(x, z); listener.onChunkCleaned(x, z); diff --git a/core/src/main/java/com/volmit/iris/core/safeguard/ServerBootSFG.java b/core/src/main/java/com/volmit/iris/core/safeguard/ServerBootSFG.java index 853ca91ba..0d7842588 100644 --- a/core/src/main/java/com/volmit/iris/core/safeguard/ServerBootSFG.java +++ b/core/src/main/java/com/volmit/iris/core/safeguard/ServerBootSFG.java @@ -15,6 +15,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.StringJoiner; @@ -81,7 +82,7 @@ public class ServerBootSFG { severityHigh++; } - if (getJavaVersion() != 17) { + if (!List.of(17, 21).contains(getJavaVersion())) { isJDK17 = false; joiner.add("Unsupported Java version"); severityMedium++; diff --git a/core/src/main/java/com/volmit/iris/core/safeguard/UtilsSFG.java b/core/src/main/java/com/volmit/iris/core/safeguard/UtilsSFG.java index bacb71e2e..2b2bf5c46 100644 --- a/core/src/main/java/com/volmit/iris/core/safeguard/UtilsSFG.java +++ b/core/src/main/java/com/volmit/iris/core/safeguard/UtilsSFG.java @@ -37,7 +37,7 @@ public class UtilsSFG { } if (ServerBootSFG.unsuportedversion) { Iris.safeguard(C.RED + "Server Version"); - Iris.safeguard(C.RED + "- Iris only supports 1.19.2 > 1.20.4"); + Iris.safeguard(C.RED + "- Iris only supports 1.19.2 > 1.20.6"); } if (!ServerBootSFG.passedserversoftware) { Iris.safeguard(C.YELLOW + "Unsupported Server Software"); @@ -53,11 +53,11 @@ public class UtilsSFG { } if (!ServerBootSFG.isJDK17) { Iris.safeguard(C.YELLOW + "Unsupported java version"); - Iris.safeguard(C.YELLOW + "- Please consider using JDK 17 Instead of JDK " + Iris.getJavaVersion()); + Iris.safeguard(C.YELLOW + "- Please consider using JDK 17 (or 21 for 1.20.6) Instead of JDK " + Iris.getJavaVersion()); } if (ServerBootSFG.isJRE) { Iris.safeguard(C.YELLOW + "Unsupported Server JDK"); - Iris.safeguard(C.YELLOW + "- Please consider using JDK 17 Instead of JRE " + Iris.getJavaVersion()); + Iris.safeguard(C.YELLOW + "- Please consider using JDK 17 (or 21 for 1.20.6) Instead of JRE " + Iris.getJavaVersion()); } } } diff --git a/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java b/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java index 00bc519c1..e70e1c1d4 100644 --- a/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/ExternalDataSVC.java @@ -64,6 +64,10 @@ public class ExternalDataSVC implements IrisService { if (Bukkit.getPluginManager().getPlugin("MMOItems") != null) { Iris.info("MMOItems found, loading MMOItemsDataProvider..."); } + providers.add(new EcoItemsDataProvider()); + if (Bukkit.getPluginManager().getPlugin("EcoItems") != null) { + Iris.info("EcoItems found, loading EcoItemsDataProvider..."); + } for (ExternalDataProvider p : providers) { if (p.isReady()) { diff --git a/core/src/main/java/com/volmit/iris/core/service/StudioSVC.java b/core/src/main/java/com/volmit/iris/core/service/StudioSVC.java index 720da652f..519a92b5f 100644 --- a/core/src/main/java/com/volmit/iris/core/service/StudioSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/StudioSVC.java @@ -22,7 +22,6 @@ import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; -import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.pack.IrisPack; import com.volmit.iris.core.project.IrisProject; @@ -296,7 +295,6 @@ public class StudioSVC implements IrisService { } sender.sendMessage("Successfully Aquired " + d.getName()); - ServerConfigurator.installDataPacks(true); } public KMap getListing(boolean cached) { diff --git a/core/src/main/java/com/volmit/iris/core/service/WandSVC.java b/core/src/main/java/com/volmit/iris/core/service/WandSVC.java index 27fc4c87a..e71392c89 100644 --- a/core/src/main/java/com/volmit/iris/core/service/WandSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/WandSVC.java @@ -30,9 +30,11 @@ import com.volmit.iris.util.format.C; import com.volmit.iris.util.math.M; import com.volmit.iris.util.matter.Matter; import com.volmit.iris.util.matter.WorldMatter; +import com.volmit.iris.util.misc.E; import com.volmit.iris.util.plugin.IrisService; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; +import com.volmit.iris.util.scheduling.S; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.enchantments.Enchantment; @@ -53,6 +55,9 @@ import java.util.ArrayList; import java.util.Objects; public class WandSVC implements IrisService { + private static final Particle CRIT_MAGIC = E.getOrDefault(Particle.class, "CRIT_MAGIC", "CRIT"); + private static final Particle REDSTONE = E.getOrDefault(Particle.class, "REDSTONE", "DUST"); + private static ItemStack dust; private static ItemStack wand; @@ -162,11 +167,11 @@ public class WandSVC implements IrisService { */ public static ItemStack createDust() { ItemStack is = new ItemStack(Material.GLOWSTONE_DUST); - is.addUnsafeEnchantment(Enchantment.ARROW_INFINITE, 1); + is.addUnsafeEnchantment(Enchantment.FIRE_ASPECT, 1); ItemMeta im = is.getItemMeta(); im.setDisplayName(C.BOLD + "" + C.YELLOW + "Dust of Revealing"); im.setUnbreakable(true); - im.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_PLACED_ON, ItemFlag.HIDE_POTION_EFFECTS, ItemFlag.HIDE_DESTROYS, ItemFlag.HIDE_ENCHANTS); + im.addItemFlags(ItemFlag.values()); im.setLore(new KList().qadd("Right click on a block to reveal it's placement structure!")); is.setItemMeta(im); @@ -206,11 +211,11 @@ public class WandSVC implements IrisService { */ public static ItemStack createWand(Location a, Location b) { ItemStack is = new ItemStack(Material.BLAZE_ROD); - is.addUnsafeEnchantment(Enchantment.ARROW_INFINITE, 1); + is.addUnsafeEnchantment(Enchantment.FIRE_ASPECT, 1); ItemMeta im = is.getItemMeta(); im.setDisplayName(C.BOLD + "" + C.GOLD + "Wand of Iris"); im.setUnbreakable(true); - im.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_PLACED_ON, ItemFlag.HIDE_POTION_EFFECTS, ItemFlag.HIDE_DESTROYS, ItemFlag.HIDE_ENCHANTS); + im.addItemFlags(ItemFlag.values()); im.setLore(new KList().add(locationToString(a), locationToString(b))); is.setItemMeta(im); @@ -311,7 +316,7 @@ public class WandSVC implements IrisService { */ public void draw(Location[] d, Player p) { Vector gx = Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65); - d[0].getWorld().spawnParticle(Particle.CRIT_MAGIC, d[0], 1, 0.5 + gx.getX(), 0.5 + gx.getY(), 0.5 + gx.getZ(), 0, null, false); + d[0].getWorld().spawnParticle(CRIT_MAGIC, d[0], 1, 0.5 + gx.getX(), 0.5 + gx.getY(), 0.5 + gx.getZ(), 0, null, false); Vector gxx = Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65); d[1].getWorld().spawnParticle(Particle.CRIT, d[1], 1, 0.5 + gxx.getX(), 0.5 + gxx.getY(), 0.5 + gxx.getZ(), 0, null, false); @@ -370,7 +375,7 @@ public class WandSVC implements IrisService { int r = color.getRed(); int g = color.getGreen(); int b = color.getBlue(); - p.spawnParticle(Particle.REDSTONE, lv.getX(), lv.getY(), lv.getZ(), 1, 0, 0, 0, 0, new Particle.DustOptions(org.bukkit.Color.fromRGB(r, g, b), 0.75f)); + p.spawnParticle(REDSTONE, lv.getX(), lv.getY(), lv.getZ(), 1, 0, 0, 0, 0, new Particle.DustOptions(org.bukkit.Color.fromRGB(r, g, b), 0.75f)); } } } 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 73ce06bb5..9f5b58e67 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 @@ -21,13 +21,10 @@ package com.volmit.iris.core.tools; import com.google.common.util.concurrent.AtomicDouble; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; -import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.pregenerator.PregenTask; import com.volmit.iris.core.service.StudioSVC; -import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.platform.PlatformChunkGenerator; -import com.volmit.iris.core.safeguard.UtilsSFG; import com.volmit.iris.util.exceptions.IrisException; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; @@ -144,7 +141,6 @@ public class IrisCreator { .studio(studio) .smartVanillaHeight(smartVanillaHeight) .create(); - ServerConfigurator.installDataPacks(false); access = (PlatformChunkGenerator) wc.generator(); PlatformChunkGenerator finalAccess1 = access; diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java b/core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java index 54f7b3c4f..f473d1f4a 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java @@ -45,15 +45,17 @@ public class IrisPackBenchmarking { private IrisDimension IrisDimension; private int radius; private final boolean headless; + private final boolean gui; private boolean finished = false; private Engine engine; PrecisionStopwatch stopwatch; - public IrisPackBenchmarking(IrisDimension dimension, int r, boolean headless) { + public IrisPackBenchmarking(IrisDimension dimension, int r, boolean headless, boolean gui) { instance = this; this.IrisDimension = dimension; this.radius = r; this.headless = headless; + this.gui = gui; runBenchmark(); } @@ -153,7 +155,7 @@ public class IrisPackBenchmarking { return new IrisEngine(new EngineTarget(world, dim, data), false); } return IrisToolbelt.access(IrisToolbelt.createWorld() - .dimension(IrisDimension.getName()) + .dimension(IrisDimension.getLoadKey()) .name("benchmark") .seed(1337) .studio(false) @@ -169,7 +171,7 @@ public class IrisPackBenchmarking { int z = 0; IrisToolbelt.pregenerate(PregenTask .builder() - .gui(false) + .gui(gui) .center(new Position2(x, z)) .width(5) .height(5) diff --git a/core/src/main/java/com/volmit/iris/core/wand/WandSelection.java b/core/src/main/java/com/volmit/iris/core/wand/WandSelection.java index 94be207d2..e2b99633b 100644 --- a/core/src/main/java/com/volmit/iris/core/wand/WandSelection.java +++ b/core/src/main/java/com/volmit/iris/core/wand/WandSelection.java @@ -21,6 +21,7 @@ package com.volmit.iris.core.wand; import com.volmit.iris.util.data.Cuboid; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.misc.E; import org.bukkit.Location; import org.bukkit.Particle; import org.bukkit.entity.Player; @@ -29,6 +30,7 @@ import org.bukkit.util.Vector; import java.awt.*; public class WandSelection { + private static final Particle REDSTONE = E.getOrDefault(Particle.class, "REDSTONE", "DUST"); private final Cuboid c; private final Player p; @@ -101,7 +103,7 @@ public class WandSelection { int g = color.getGreen(); int b = color.getBlue(); - p.spawnParticle(Particle.REDSTONE, a.getX(), a.getY(), a.getZ(), + p.spawnParticle(REDSTONE, a.getX(), a.getY(), a.getZ(), 1, 0, 0, 0, 0, new Particle.DustOptions(org.bukkit.Color.fromRGB(r, g, b), (float) dist * 3f)); diff --git a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java index 94b4294eb..18b67d056 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -21,8 +21,6 @@ package com.volmit.iris.engine; import com.google.common.util.concurrent.AtomicDouble; import com.google.gson.Gson; import com.volmit.iris.Iris; -import com.volmit.iris.core.IrisSettings; -import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.events.IrisEngineHotloadEvent; import com.volmit.iris.core.gui.PregeneratorJob; import com.volmit.iris.core.nms.container.BlockPos; @@ -53,7 +51,6 @@ import com.volmit.iris.util.scheduling.PrecisionStopwatch; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; -import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; @@ -66,8 +63,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -import java.util.regex.Matcher; -import java.util.regex.Pattern; @Data @EqualsAndHashCode(exclude = "context") @@ -242,11 +237,6 @@ public class IrisEngine implements Engine { getTarget().setDimension(getData().getDimensionLoader().load(getDimension().getLoadKey())); prehotload(); setupEngine(); - J.a(() -> { - synchronized (ServerConfigurator.class) { - ServerConfigurator.installDataPacks(false); - } - }); } @Override diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisBiomeCustom.java b/core/src/main/java/com/volmit/iris/engine/object/IrisBiomeCustom.java index 2b7052db4..f491dff68 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisBiomeCustom.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisBiomeCustom.java @@ -19,6 +19,7 @@ package com.volmit.iris.engine.object; import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; @@ -68,8 +69,10 @@ public class IrisBiomeCustom { @Desc("The biome's category type") private IrisBiomeCustomCategory category = IrisBiomeCustomCategory.plains; + @MinNumber(0) + @MaxNumber(20) @Desc("The spawn rarity of any defined spawners") - private int spawnRarity = -1; + private int spawnRarity = 0; @Desc("The color of the sky, top half of sky. (hex format)") private String skyColor = "#79a8e1"; @@ -155,7 +158,7 @@ public class IrisBiomeCustom { j.put("spawners", spawners); } - return j.toString(4); + return DataVersion.getDefault().fixCustomBiome(this, j).toString(4); } private int parseColor(String c) { diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java b/core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java index fedf5cf0e..98049d32f 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java @@ -18,17 +18,12 @@ package com.volmit.iris.engine.object; -import com.volmit.iris.Iris; -import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.engine.data.cache.AtomicCache; -import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.data.DataProvider; -import com.volmit.iris.util.data.Dimension; -import com.volmit.iris.util.io.IO; import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.RNG; @@ -43,10 +38,6 @@ import org.bukkit.Material; import org.bukkit.World.Environment; import org.bukkit.block.data.BlockData; -import java.io.DataInput; -import java.io.File; -import java.io.IOException; - @Accessors(chain = true) @AllArgsConstructor @NoArgsConstructor @@ -380,56 +371,6 @@ public class IrisDimension extends IrisRegistrant { return landBiomeStyle; } - public boolean installDataPack(DataProvider data, File datapacks) { - boolean write = false; - boolean changed = false; - - IO.delete(new File(datapacks, "iris/data/" + getLoadKey().toLowerCase())); - - for (IrisBiome i : getAllBiomes(data)) { - if (i.isCustom()) { - write = true; - - for (IrisBiomeCustom j : i.getCustomDerivitives()) { - File output = new File(datapacks, "iris/data/" + getLoadKey().toLowerCase() + "/worldgen/biome/" + j.getId() + ".json"); - - if (!output.exists()) { - changed = true; - } - - Iris.verbose(" Installing Data Pack Biome: " + output.getPath()); - output.getParentFile().mkdirs(); - try { - IO.writeAll(output, j.generateJson()); - } catch (IOException e) { - Iris.reportError(e); - e.printStackTrace(); - } - } - } - } - - if (write) { - File mcm = new File(datapacks, "iris/pack.mcmeta"); - try { - IO.writeAll(mcm, """ - { - "pack": { - "description": "Iris Data Pack. This pack contains all installed Iris Packs' resources.", - "pack_format": 10 - } - } - """); - } catch (IOException e) { - Iris.reportError(e); - e.printStackTrace(); - } - Iris.verbose(" Installing Data Pack MCMeta: " + mcm.getPath()); - } - - return changed; - } - @Override public String getFolderName() { return "dimensions"; diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java index 61de43e69..6f732f449 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java @@ -29,6 +29,7 @@ import com.volmit.iris.util.format.C; import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.misc.E; import com.volmit.iris.util.plugin.Chunks; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; @@ -65,6 +66,7 @@ import java.util.concurrent.atomic.AtomicReference; @Data @EqualsAndHashCode(callSuper = false) public class IrisEntity extends IrisRegistrant { + private static final Particle ITEM = E.getOrDefault(Particle.class, "ITEM_CRACK", "ITEM"); @Required @Desc("The type of entity to spawn. To spawn a mythic mob, set this type to unknown and define mythic type.") private EntityType type = EntityType.UNKNOWN; @@ -386,7 +388,7 @@ public class IrisEntity extends IrisRegistrant { if (e.getLocation().getBlock().getType().isSolid() || ((LivingEntity) e).getEyeLocation().getBlock().getType().isSolid()) { e.teleport(start.add(new Vector(0, 0.1, 0))); ItemStack itemCrackData = new ItemStack(((LivingEntity) e).getEyeLocation().clone().subtract(0, 2, 0).getBlock().getBlockData().getMaterial()); - e.getWorld().spawnParticle(Particle.ITEM_CRACK, ((LivingEntity) e).getEyeLocation(), 6, 0.2, 0.4, 0.2, 0.06f, itemCrackData); + e.getWorld().spawnParticle(ITEM, ((LivingEntity) e).getEyeLocation(), 6, 0.2, 0.4, 0.2, 0.06f, itemCrackData); if (M.r(0.2)) { e.getWorld().playSound(e.getLocation(), Sound.BLOCK_CHORUS_FLOWER_GROW, 0.8f, 0.1f); } diff --git a/core/src/main/java/com/volmit/iris/util/data/B.java b/core/src/main/java/com/volmit/iris/util/data/B.java index 59d150357..d67615151 100644 --- a/core/src/main/java/com/volmit/iris/util/data/B.java +++ b/core/src/main/java/com/volmit/iris/util/data/B.java @@ -25,6 +25,7 @@ import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.engine.object.IrisCompat; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.misc.E; import com.volmit.iris.util.scheduling.ChronoLatch; import it.unimi.dsi.fastutil.ints.*; import org.bukkit.Bukkit; @@ -46,6 +47,7 @@ public class B { private static final KMap custom = new KMap<>(); private static final Material AIR_MATERIAL = Material.AIR; + private static final Material SHORT_GRASS = E.getOrDefault(Material.class, "GRASS", "SHORT_GRASS"); private static final BlockData AIR = AIR_MATERIAL.createBlockData(); private static final IntSet foliageCache = buildFoliageCache(); private static final IntSet deepslateCache = buildDeepslateCache(); @@ -85,7 +87,7 @@ public class B { WHITE_TULIP, FERN, LARGE_FERN, - GRASS, + SHORT_GRASS, TALL_GRASS }).forEach((i) -> b.add(i.ordinal())); @@ -143,7 +145,7 @@ public class B { private static IntSet buildDecorantCache() { IntSet b = new IntOpenHashSet(); Arrays.stream(new Material[]{ - GRASS, + SHORT_GRASS, TALL_GRASS, TALL_SEAGRASS, FERN, diff --git a/core/src/main/java/com/volmit/iris/util/data/IrisBlockData.java b/core/src/main/java/com/volmit/iris/util/data/IrisBlockData.java index dce36cd17..b5cd4030c 100644 --- a/core/src/main/java/com/volmit/iris/util/data/IrisBlockData.java +++ b/core/src/main/java/com/volmit/iris/util/data/IrisBlockData.java @@ -15,7 +15,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @Data -public class IrisBlockData implements BlockData{ +public class IrisBlockData implements BlockData { private final @NonNull BlockData base; private final @NotNull Identifier custom; diff --git a/core/src/main/java/com/volmit/iris/util/decree/handlers/DataVersionHandler.java b/core/src/main/java/com/volmit/iris/util/decree/handlers/DataVersionHandler.java new file mode 100644 index 000000000..489590496 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/decree/handlers/DataVersionHandler.java @@ -0,0 +1,36 @@ +package com.volmit.iris.util.decree.handlers; + +import com.volmit.iris.core.nms.datapack.DataVersion; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.decree.DecreeParameterHandler; +import com.volmit.iris.util.decree.exceptions.DecreeParsingException; + +public class DataVersionHandler implements DecreeParameterHandler { + @Override + public KList getPossibilities() { + return new KList<>(DataVersion.values()); + } + + @Override + public String toString(DataVersion version) { + return version.getVersion(); + } + + @Override + public DataVersion parse(String in, boolean force) throws DecreeParsingException { + if (in.equalsIgnoreCase("latest")) { + return DataVersion.getLatest(); + } + for (DataVersion v : DataVersion.values()) { + if (v.getVersion().equalsIgnoreCase(in)) { + return v; + } + } + throw new DecreeParsingException("Unable to parse data version \"" + in + "\""); + } + + @Override + public boolean supports(Class type) { + return DataVersion.class.equals(type); + } +} diff --git a/core/src/main/java/com/volmit/iris/util/inventorygui/UIElement.java b/core/src/main/java/com/volmit/iris/util/inventorygui/UIElement.java index 21344d06f..acadadd37 100644 --- a/core/src/main/java/com/volmit/iris/util/inventorygui/UIElement.java +++ b/core/src/main/java/com/volmit/iris/util/inventorygui/UIElement.java @@ -212,7 +212,7 @@ public class UIElement implements Element { im.setLore(getLore().copy()); if (isEnchanted()) { - im.addEnchant(Enchantment.DURABILITY, 1, true); + im.addEnchant(Enchantment.FIRE_ASPECT, 1, true); } is.setItemMeta(im); diff --git a/core/src/main/java/com/volmit/iris/util/misc/E.java b/core/src/main/java/com/volmit/iris/util/misc/E.java new file mode 100644 index 000000000..473fa2b17 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/misc/E.java @@ -0,0 +1,12 @@ +package com.volmit.iris.util.misc; + +public class E { + + public static > T getOrDefault(Class enumClass, String name, String fallback) { + try { + return Enum.valueOf(enumClass, name); + } catch (Throwable e) { + return Enum.valueOf(enumClass, fallback); + } + } +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2e6e5897b..48c0a02ca 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/CustomBiomeSource.java b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/CustomBiomeSource.java index a24e62d85..5a1f89970 100644 --- a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/CustomBiomeSource.java +++ b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/CustomBiomeSource.java @@ -2,6 +2,7 @@ package com.volmit.iris.core.nms.v1_19_R1; import com.mojang.serialization.Codec; import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMS; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisBiome; @@ -11,6 +12,7 @@ import com.volmit.iris.util.math.RNG; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeSource; @@ -25,6 +27,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.Optional; public class CustomBiomeSource extends BiomeSource { private final long seed; @@ -118,8 +121,28 @@ public class CustomBiomeSource extends BiomeSource { for (IrisBiome i : engine.getAllBiomes()) { if (i.isCustom()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) { - m.put(j.getId(), customRegistry.getHolder(customRegistry.getResourceKey(customRegistry - .get(new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()))).get()).get()); + ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); + Biome biome = customRegistry.get(location); + if (biome == null) { + INMS.get().registerBiome(location.getNamespace(), j, false); + biome = customRegistry.get(location); + if (biome == null) { + Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); + continue; + } + } + Optional> optionalBiomeKey = customRegistry.getResourceKey(biome); + if (optionalBiomeKey.isEmpty()) { + Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); + continue; + } + ResourceKey biomeKey = optionalBiomeKey.get(); + Optional> optionalReferenceHolder = customRegistry.getHolder(biomeKey); + if (optionalReferenceHolder.isEmpty()) { + Iris.error("Cannot find reference to biome " + biomeKey + " for engine " + engine.getName()); + continue; + } + m.put(j.getId(), optionalReferenceHolder.get()); } } } diff --git a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java index 8d01af591..2033666da 100644 --- a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java +++ b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java @@ -5,12 +5,9 @@ import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -26,9 +23,9 @@ import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; import com.mojang.serialization.Lifecycle; +import com.volmit.iris.engine.object.IrisBiomeCustom; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.util.format.C; -import com.volmit.iris.util.io.IO; import it.unimi.dsi.fastutil.objects.Reference2IntMap; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; @@ -587,51 +584,10 @@ public class NMSBinding implements INMSBinding { } @Override - public boolean loadDatapack(File folder, boolean replace) { - var data = new File(folder, "iris/data"); - if (!data.exists() || !data.isDirectory()) return false; - FilenameFilter jsonFilter = (dir, name) -> new File(dir, name).isFile() && name.toLowerCase().endsWith(".json"); - - var files = data.listFiles((dir, name) -> new File(dir, name).isDirectory()); - if (files == null) return false; - for (File file : files) { - var biome = new File(file, "worldgen/biome"); - if (!biome.exists()) continue; - var biomeFiles = biome.listFiles(jsonFilter); - if (biomeFiles == null) continue; - for (File biomeFile : biomeFiles) { - String json = null; - int tries = 10; - while (json == null && tries-- > 0) { - try { - json = IO.readAll(biomeFile); - } catch (IOException e) { - Iris.error("Failed to read biome " + file.getName() + ":" + biomeFile.getName() + " tries left: " + tries); - if (tries == 0) { - e.printStackTrace(); - } - try { - Thread.sleep(100); - } catch (InterruptedException ignored) {} - } - } - if (json == null) continue; - - try { - var value = decode(net.minecraft.world.level.biome.Biome.CODEC, json).map(Holder::value).orElse(null); - register(Registry.BIOME_REGISTRY, from(file.getName(), biomeFile), value, replace); - } catch (Throwable e) { - Iris.error("Failed to register biome " + file.getName() + ":" + biomeFile.getName()); - e.printStackTrace(); - } - } - } - return true; - } - - private ResourceLocation from(String namespace, File file) { - var name = file.getName(); - return new ResourceLocation(namespace, name.substring(0, name.lastIndexOf('.'))); + public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) { + var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null); + if (biomeBase == null) return false; + return register(Registry.BIOME_REGISTRY, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace); } private Optional decode(Codec codec, String json) { diff --git a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/CustomBiomeSource.java b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/CustomBiomeSource.java index 7a82acf42..340c053cd 100644 --- a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/CustomBiomeSource.java +++ b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/CustomBiomeSource.java @@ -2,6 +2,7 @@ package com.volmit.iris.core.nms.v1_19_R2; import com.mojang.serialization.Codec; import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMS; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisBiome; @@ -12,6 +13,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeSource; @@ -26,6 +28,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.Optional; public class CustomBiomeSource extends BiomeSource { @@ -120,8 +123,28 @@ public class CustomBiomeSource extends BiomeSource { for (IrisBiome i : engine.getAllBiomes()) { if (i.isCustom()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) { - m.put(j.getId(), customRegistry.getHolder(customRegistry.getResourceKey(customRegistry - .get(new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()))).get()).get()); + ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); + Biome biome = customRegistry.get(location); + if (biome == null) { + INMS.get().registerBiome(location.getNamespace(), j, false); + biome = customRegistry.get(location); + if (biome == null) { + Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); + continue; + } + } + Optional> optionalBiomeKey = customRegistry.getResourceKey(biome); + if (optionalBiomeKey.isEmpty()) { + Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); + continue; + } + ResourceKey biomeKey = optionalBiomeKey.get(); + Optional> optionalReferenceHolder = customRegistry.getHolder(biomeKey); + if (optionalReferenceHolder.isEmpty()) { + Iris.error("Cannot find reference to biome " + biomeKey + " for engine " + engine.getName()); + continue; + } + m.put(j.getId(), optionalReferenceHolder.get()); } } } diff --git a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java index 59c54c2ad..ed1a4a09e 100644 --- a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java +++ b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java @@ -5,12 +5,9 @@ import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -26,9 +23,9 @@ import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; import com.mojang.serialization.Lifecycle; +import com.volmit.iris.engine.object.IrisBiomeCustom; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.util.format.C; -import com.volmit.iris.util.io.IO; import it.unimi.dsi.fastutil.objects.Reference2IntMap; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; @@ -589,51 +586,10 @@ public class NMSBinding implements INMSBinding { } @Override - public boolean loadDatapack(File folder, boolean replace) { - var data = new File(folder, "iris/data"); - if (!data.exists() || !data.isDirectory()) return false; - FilenameFilter jsonFilter = (dir, name) -> new File(dir, name).isFile() && name.toLowerCase().endsWith(".json"); - - var files = data.listFiles((dir, name) -> new File(dir, name).isDirectory()); - if (files == null) return false; - for (File file : files) { - var biome = new File(file, "worldgen/biome"); - if (!biome.exists()) continue; - var biomeFiles = biome.listFiles(jsonFilter); - if (biomeFiles == null) continue; - for (File biomeFile : biomeFiles) { - String json = null; - int tries = 10; - while (json == null && tries-- > 0) { - try { - json = IO.readAll(biomeFile); - } catch (IOException e) { - Iris.error("Failed to read biome " + file.getName() + ":" + biomeFile.getName() + " tries left: " + tries); - if (tries == 0) { - e.printStackTrace(); - } - try { - Thread.sleep(100); - } catch (InterruptedException ignored) {} - } - } - if (json == null) continue; - - try { - var value = decode(net.minecraft.world.level.biome.Biome.CODEC, json).map(Holder::value).orElse(null); - register(Registries.BIOME, from(file.getName(), biomeFile), value, replace); - } catch (Throwable e) { - Iris.error("Failed to register biome " + file.getName() + ":" + biomeFile.getName()); - e.printStackTrace(); - } - } - } - return true; - } - - private ResourceLocation from(String namespace, File file) { - var name = file.getName(); - return new ResourceLocation(namespace, name.substring(0, name.lastIndexOf('.'))); + public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) { + var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null); + if (biomeBase == null) return false; + return register(Registries.BIOME, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace); } private Optional decode(Codec codec, String json) { diff --git a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/CustomBiomeSource.java b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/CustomBiomeSource.java index f3debbaad..3e26f6f79 100644 --- a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/CustomBiomeSource.java +++ b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/CustomBiomeSource.java @@ -2,6 +2,7 @@ package com.volmit.iris.core.nms.v1_19_R3; import com.mojang.serialization.Codec; import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMS; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisBiome; @@ -125,8 +126,16 @@ public class CustomBiomeSource extends BiomeSource { for (IrisBiome i : engine.getAllBiomes()) { if (i.isCustom()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) { - ResourceLocation resourceLocation = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); - Biome biome = customRegistry.get(resourceLocation); + ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); + Biome biome = customRegistry.get(location); + if (biome == null) { + INMS.get().registerBiome(location.getNamespace(), j, false); + biome = customRegistry.get(location); + if (biome == null) { + Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); + continue; + } + } Optional> optionalBiomeKey = customRegistry.getResourceKey(biome); if (optionalBiomeKey.isEmpty()) { Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); diff --git a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java index a1396ba1c..7499562de 100644 --- a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java +++ b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java @@ -5,12 +5,9 @@ import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -26,9 +23,9 @@ import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; import com.mojang.serialization.Lifecycle; +import com.volmit.iris.engine.object.IrisBiomeCustom; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.util.format.C; -import com.volmit.iris.util.io.IO; import it.unimi.dsi.fastutil.objects.Reference2IntMap; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; @@ -593,51 +590,10 @@ public class NMSBinding implements INMSBinding { } @Override - public boolean loadDatapack(File folder, boolean replace) { - var data = new File(folder, "iris/data"); - if (!data.exists() || !data.isDirectory()) return false; - FilenameFilter jsonFilter = (dir, name) -> new File(dir, name).isFile() && name.toLowerCase().endsWith(".json"); - - var files = data.listFiles((dir, name) -> new File(dir, name).isDirectory()); - if (files == null) return false; - for (File file : files) { - var biome = new File(file, "worldgen/biome"); - if (!biome.exists()) continue; - var biomeFiles = biome.listFiles(jsonFilter); - if (biomeFiles == null) continue; - for (File biomeFile : biomeFiles) { - String json = null; - int tries = 10; - while (json == null && tries-- > 0) { - try { - json = IO.readAll(biomeFile); - } catch (IOException e) { - Iris.error("Failed to read biome " + file.getName() + ":" + biomeFile.getName() + " tries left: " + tries); - if (tries == 0) { - e.printStackTrace(); - } - try { - Thread.sleep(100); - } catch (InterruptedException ignored) {} - } - } - if (json == null) continue; - - try { - var value = decode(net.minecraft.world.level.biome.Biome.CODEC, json).map(Holder::value).orElse(null); - register(Registries.BIOME, from(file.getName(), biomeFile), value, replace); - } catch (Throwable e) { - Iris.error("Failed to register biome " + file.getName() + ":" + biomeFile.getName()); - e.printStackTrace(); - } - } - } - return true; - } - - private ResourceLocation from(String namespace, File file) { - var name = file.getName(); - return new ResourceLocation(namespace, name.substring(0, name.lastIndexOf('.'))); + public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) { + var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null); + if (biomeBase == null) return false; + return register(Registries.BIOME, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace); } private Optional decode(Codec codec, String json) { diff --git a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/CustomBiomeSource.java b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/CustomBiomeSource.java index 41f4170c8..6ebea1093 100644 --- a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/CustomBiomeSource.java +++ b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/CustomBiomeSource.java @@ -2,6 +2,7 @@ package com.volmit.iris.core.nms.v1_20_R1; import com.mojang.serialization.Codec; import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMS; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisBiome; @@ -125,8 +126,16 @@ public class CustomBiomeSource extends BiomeSource { for (IrisBiome i : engine.getAllBiomes()) { if (i.isCustom()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) { - ResourceLocation resourceLocation = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); - Biome biome = customRegistry.get(resourceLocation); + ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); + Biome biome = customRegistry.get(location); + if (biome == null) { + INMS.get().registerBiome(location.getNamespace(), j, false); + biome = customRegistry.get(location); + if (biome == null) { + Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); + continue; + } + } Optional> optionalBiomeKey = customRegistry.getResourceKey(biome); if (optionalBiomeKey.isEmpty()) { Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); diff --git a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java index ab01736a8..52102bc32 100644 --- a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java +++ b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java @@ -12,12 +12,12 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.object.IrisBiomeCustom; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.format.C; import com.volmit.iris.util.hunk.Hunk; -import com.volmit.iris.util.io.IO; import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.Vector3d; @@ -47,7 +47,6 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.util.GsonHelper; import net.minecraft.world.RandomSequences; -import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.block.Block; @@ -73,9 +72,7 @@ import org.bukkit.craftbukkit.v1_20_R1.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.entity.EntityType; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; @@ -87,12 +84,9 @@ import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -580,51 +574,10 @@ public class NMSBinding implements INMSBinding { } @Override - public boolean loadDatapack(File folder, boolean replace) { - var data = new File(folder, "iris/data"); - if (!data.exists() || !data.isDirectory()) return false; - FilenameFilter jsonFilter = (dir, name) -> new File(dir, name).isFile() && name.toLowerCase().endsWith(".json"); - - var files = data.listFiles((dir, name) -> new File(dir, name).isDirectory()); - if (files == null) return false; - for (File file : files) { - var biome = new File(file, "worldgen/biome"); - if (!biome.exists()) continue; - var biomeFiles = biome.listFiles(jsonFilter); - if (biomeFiles == null) continue; - for (File biomeFile : biomeFiles) { - String json = null; - int tries = 10; - while (json == null && tries-- > 0) { - try { - json = IO.readAll(biomeFile); - } catch (IOException e) { - Iris.error("Failed to read biome " + file.getName() + ":" + biomeFile.getName() + " tries left: " + tries); - if (tries == 0) { - e.printStackTrace(); - } - try { - Thread.sleep(100); - } catch (InterruptedException ignored) {} - } - } - if (json == null) continue; - - try { - var value = decode(net.minecraft.world.level.biome.Biome.CODEC, json).map(Holder::value).orElse(null); - register(Registries.BIOME, from(file.getName(), biomeFile), value, replace); - } catch (Throwable e) { - Iris.error("Failed to register biome " + file.getName() + ":" + biomeFile.getName()); - e.printStackTrace(); - } - } - } - return true; - } - - private ResourceLocation from(String namespace, File file) { - var name = file.getName(); - return new ResourceLocation(namespace, name.substring(0, name.lastIndexOf('.'))); + public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) { + var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null); + if (biomeBase == null) return false; + return register(Registries.BIOME, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace); } private Optional decode(Codec codec, String json) { diff --git a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/CustomBiomeSource.java b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/CustomBiomeSource.java index fcf462f95..24ce23216 100644 --- a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/CustomBiomeSource.java +++ b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/CustomBiomeSource.java @@ -2,6 +2,7 @@ package com.volmit.iris.core.nms.v1_20_R2; import com.mojang.serialization.Codec; import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMS; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisBiome; @@ -124,8 +125,16 @@ public class CustomBiomeSource extends BiomeSource { for (IrisBiome i : engine.getAllBiomes()) { if (i.isCustom()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) { - ResourceLocation resourceLocation = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); - Biome biome = customRegistry.get(resourceLocation); + ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); + Biome biome = customRegistry.get(location); + if (biome == null) { + INMS.get().registerBiome(location.getNamespace(), j, false); + biome = customRegistry.get(location); + if (biome == null) { + Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); + continue; + } + } Optional> optionalBiomeKey = customRegistry.getResourceKey(biome); if (optionalBiomeKey.isEmpty()) { Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); diff --git a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java index e4af087ec..63e36f06b 100644 --- a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java +++ b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java @@ -5,12 +5,9 @@ import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -26,9 +23,9 @@ import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; import com.mojang.serialization.Lifecycle; +import com.volmit.iris.engine.object.IrisBiomeCustom; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.util.format.C; -import com.volmit.iris.util.io.IO; import it.unimi.dsi.fastutil.objects.Reference2IntMap; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; @@ -590,51 +587,10 @@ public class NMSBinding implements INMSBinding { } @Override - public boolean loadDatapack(File folder, boolean replace) { - var data = new File(folder, "iris/data"); - if (!data.exists() || !data.isDirectory()) return false; - FilenameFilter jsonFilter = (dir, name) -> new File(dir, name).isFile() && name.toLowerCase().endsWith(".json"); - - var files = data.listFiles((dir, name) -> new File(dir, name).isDirectory()); - if (files == null) return false; - for (File file : files) { - var biome = new File(file, "worldgen/biome"); - if (!biome.exists()) continue; - var biomeFiles = biome.listFiles(jsonFilter); - if (biomeFiles == null) continue; - for (File biomeFile : biomeFiles) { - String json = null; - int tries = 10; - while (json == null && tries-- > 0) { - try { - json = IO.readAll(biomeFile); - } catch (IOException e) { - Iris.error("Failed to read biome " + file.getName() + ":" + biomeFile.getName() + " tries left: " + tries); - if (tries == 0) { - e.printStackTrace(); - } - try { - Thread.sleep(100); - } catch (InterruptedException ignored) {} - } - } - if (json == null) continue; - - try { - var value = decode(net.minecraft.world.level.biome.Biome.CODEC, json).map(Holder::value).orElse(null); - register(Registries.BIOME, from(file.getName(), biomeFile), value, replace); - } catch (Throwable e) { - Iris.error("Failed to register biome " + file.getName() + ":" + biomeFile.getName()); - e.printStackTrace(); - } - } - } - return true; - } - - private ResourceLocation from(String namespace, File file) { - var name = file.getName(); - return new ResourceLocation(namespace, name.substring(0, name.lastIndexOf('.'))); + public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) { + var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null); + if (biomeBase == null) return false; + return register(Registries.BIOME, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace); } private Optional decode(Codec codec, String json) { diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/CustomBiomeSource.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/CustomBiomeSource.java index 3d3582239..323fa255b 100644 --- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/CustomBiomeSource.java +++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/CustomBiomeSource.java @@ -2,6 +2,7 @@ package com.volmit.iris.core.nms.v1_20_R3; import com.mojang.serialization.Codec; import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMS; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisBiome; @@ -124,8 +125,16 @@ public class CustomBiomeSource extends BiomeSource { for (IrisBiome i : engine.getAllBiomes()) { if (i.isCustom()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) { - ResourceLocation resourceLocation = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); - Biome biome = customRegistry.get(resourceLocation); + ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); + Biome biome = customRegistry.get(location); + if (biome == null) { + INMS.get().registerBiome(location.getNamespace(), j, false); + biome = customRegistry.get(location); + if (biome == null) { + Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); + continue; + } + } Optional> optionalBiomeKey = customRegistry.getResourceKey(biome); if (optionalBiomeKey.isEmpty()) { Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/Headless.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/Headless.java index 92520cdb4..36b552545 100644 --- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/Headless.java +++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/Headless.java @@ -48,7 +48,7 @@ public class Headless implements IHeadless, LevelHeightAccessor { private final Engine engine; private final RegionFileStorage storage; private final Queue chunkQueue = new ArrayDeque<>(); - private final ReentrantLock manualLock = new ReentrantLock(); + private final ReentrantLock saveLock = new ReentrantLock(); private final KMap> customBiomes = new KMap<>(); private final KMap> minecraftBiomes = new KMap<>(); private boolean closed = false; @@ -60,49 +60,50 @@ public class Headless implements IHeadless, LevelHeightAccessor { var queueLooper = new Looper() { @Override protected long loop() { - if (manualLock.isLocked()) { - manualLock.lock(); - manualLock.unlock(); - } - saveAll(); + save(); return closed ? -1 : 100; } }; queueLooper.setName("Region Save Looper"); queueLooper.start(); + + var dimKey = engine.getDimension().getLoadKey(); + for (var biome : engine.getAllBiomes()) { + if (!biome.isCustom()) continue; + for (var custom : biome.getCustomDerivitives()) { + binding.registerBiome(dimKey, custom, false); + } + } } @Override public boolean exists(int x, int z) { if (closed) return false; try { - return storage.getRegionFile(new ChunkPos(x << 5, z << 5), true) != null; + CompoundTag tag = storage.read(new ChunkPos(x, z)); + return tag != null && !"empty".equals(tag.getString("Status")); } catch (IOException e) { return false; } } @Override - public void saveAll() { - manualLock.lock(); - try { - save(); - } finally { - manualLock.unlock(); - } - } - - private void save() { + public void save() { if (closed) return; - while (!chunkQueue.isEmpty()) { - ChunkAccess chunk = chunkQueue.poll(); - if (chunk == null) break; - try { - storage.write(chunk.getPos(), binding.serializeChunk(chunk, this)); - } catch (Throwable e) { - Iris.error("Failed to save chunk " + chunk.getPos().x + ", " + chunk.getPos().z); - e.printStackTrace(); + saveLock.lock(); + try { + while (!chunkQueue.isEmpty()) { + ChunkAccess chunk = chunkQueue.poll(); + if (chunk == null) break; + try { + storage.write(chunk.getPos(), binding.serializeChunk(chunk, this)); + } catch (Throwable e) { + Iris.error("Failed to save chunk " + chunk.getPos().x + ", " + chunk.getPos().z); + e.printStackTrace(); + } } + } finally { + saveLock.unlock(); } } @@ -137,16 +138,9 @@ public class Headless implements IHeadless, LevelHeightAccessor { @Override public void generateChunk(int x, int z) { - if (closed) return; + if (closed || exists(x, z)) return; try { var pos = new ChunkPos(x, z); - try { - CompoundTag tag = storage.read(pos); - if (tag != null && !"empty".equals(tag.getString("Status"))) { - return; - } - } catch (Throwable ignored) {} - ProtoChunk chunk = binding.createProtoChunk(pos, this); var tc = new MCATerrainChunk(chunk); @@ -190,7 +184,7 @@ public class Headless implements IHeadless, LevelHeightAccessor { IrisContext.getOr(engine).setChunkContext(ctx); for (EngineStage i : engine.getMode().getStages()) { - i.generate(x, z, blocks, vbiomes, true, ctx); + i.generate(x, z, blocks, vbiomes, false, ctx); } } diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java index 9743b4830..bb056b10e 100644 --- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java +++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java @@ -5,8 +5,6 @@ import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -23,16 +21,9 @@ import com.mojang.serialization.JsonOps; import com.mojang.serialization.Lifecycle; import com.volmit.iris.core.nms.IHeadless; import com.volmit.iris.core.nms.v1_20_R3.mca.ChunkSerializer; -import com.volmit.iris.core.nms.v1_20_R3.mca.MCATerrainChunk; -import com.volmit.iris.core.nms.v1_20_R3.mca.RegionFileStorage; +import com.volmit.iris.engine.object.IrisBiomeCustom; import com.volmit.iris.engine.object.IrisDimension; -import com.volmit.iris.util.documentation.RegionCoordinates; import com.volmit.iris.util.format.C; -import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder; -import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder; -import com.volmit.iris.util.io.IO; -import com.volmit.iris.util.parallel.MultiBurst; -import com.volmit.iris.util.scheduling.PrecisionStopwatch; import it.unimi.dsi.fastutil.objects.Reference2IntMap; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; @@ -601,51 +592,10 @@ public class NMSBinding implements INMSBinding { } @Override - public boolean loadDatapack(File folder, boolean replace) { - var data = new File(folder, "iris/data"); - if (!data.exists() || !data.isDirectory()) return false; - FilenameFilter jsonFilter = (dir, name) -> new File(dir, name).isFile() && name.toLowerCase().endsWith(".json"); - - var files = data.listFiles((dir, name) -> new File(dir, name).isDirectory()); - if (files == null) return false; - for (File file : files) { - var biome = new File(file, "worldgen/biome"); - if (!biome.exists()) continue; - var biomeFiles = biome.listFiles(jsonFilter); - if (biomeFiles == null) continue; - for (File biomeFile : biomeFiles) { - String json = null; - int tries = 10; - while (json == null && tries-- > 0) { - try { - json = IO.readAll(biomeFile); - } catch (IOException e) { - Iris.error("Failed to read biome " + file.getName() + ":" + biomeFile.getName() + " tries left: " + tries); - if (tries == 0) { - e.printStackTrace(); - } - try { - Thread.sleep(100); - } catch (InterruptedException ignored) {} - } - } - if (json == null) continue; - - try { - var value = decode(net.minecraft.world.level.biome.Biome.CODEC, json).map(Holder::value).orElse(null); - register(Registries.BIOME, from(file.getName(), biomeFile), value, replace); - } catch (Throwable e) { - Iris.error("Failed to register biome " + file.getName() + ":" + biomeFile.getName()); - e.printStackTrace(); - } - } - } - return true; - } - - private ResourceLocation from(String namespace, File file) { - var name = file.getName(); - return new ResourceLocation(namespace, name.substring(0, name.lastIndexOf('.'))); + public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) { + var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null); + if (biomeBase == null) return false; + return register(Registries.BIOME, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace); } private Optional decode(Codec codec, String json) { diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/mca/MCATerrainChunk.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/mca/MCATerrainChunk.java index 589c01e93..e574c892a 100644 --- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/mca/MCATerrainChunk.java +++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/mca/MCATerrainChunk.java @@ -42,6 +42,9 @@ public record MCATerrainChunk(ChunkAccess chunk) implements TerrainChunk { @Override public void setBiome(int x, int y, int z, Biome bio) { + if (y < 0) return; + y += getMinHeight(); + if (y > getMaxHeight()) return; chunk.setBiome(x & 15, y, z & 15, CraftBiome.bukkitToMinecraftHolder(bio)); } @@ -61,9 +64,9 @@ public record MCATerrainChunk(ChunkAccess chunk) implements TerrainChunk { @Override public void setBlock(int x, int y, int z, BlockData blockData) { - if (y > getMaxHeight() || y < getMinHeight()) { - return; - } + if (y < 0) return; + y += getMinHeight(); + if (y > getMaxHeight()) return; if (blockData == null) { Iris.error("NULL BD"); @@ -76,14 +79,14 @@ public record MCATerrainChunk(ChunkAccess chunk) implements TerrainChunk { } private BlockState getBlockState(int x, int y, int z) { + if (y < 0) { + y = 0; + } + y += getMinHeight(); if (y > getMaxHeight()) { y = getMaxHeight(); } - if (y < getMinHeight()) { - y = getMinHeight(); - } - return chunk.getBlockState(new BlockPos(x & 15, y, z & 15)); } diff --git a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/CustomBiomeSource.java b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/CustomBiomeSource.java new file mode 100644 index 000000000..a27c9a306 --- /dev/null +++ b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/CustomBiomeSource.java @@ -0,0 +1,177 @@ +package com.volmit.iris.core.nms.v1_20_R4; + +import com.mojang.serialization.MapCodec; +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMS; +import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.object.IrisBiome; +import com.volmit.iris.engine.object.IrisBiomeCustom; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.math.RNG; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.Climate; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_20_R4.CraftServer; +import org.bukkit.craftbukkit.v1_20_R4.CraftWorld; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +public class CustomBiomeSource extends BiomeSource { + + private final long seed; + private final Engine engine; + private final Registry biomeCustomRegistry; + private final Registry biomeRegistry; + private final AtomicCache registryAccess = new AtomicCache<>(); + private final RNG rng; + private final KMap> customBiomes; + + public CustomBiomeSource(long seed, Engine engine, World world) { + this.engine = engine; + this.seed = seed; + this.biomeCustomRegistry = registry().registry(Registries.BIOME).orElse(null); + this.biomeRegistry = ((RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer())).registry(Registries.BIOME).orElse(null); + this.rng = new RNG(engine.getSeedManager().getBiome()); + this.customBiomes = fillCustomBiomes(biomeCustomRegistry, engine); + } + + private static List> getAllBiomes(Registry customRegistry, Registry registry, Engine engine) { + List> b = new ArrayList<>(); + + for (IrisBiome i : engine.getAllBiomes()) { + if (i.isCustom()) { + for (IrisBiomeCustom j : i.getCustomDerivitives()) { + b.add(customRegistry.getHolder(customRegistry.getResourceKey(customRegistry + .get(new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()))).get()).get()); + } + } else { + b.add(NMSBinding.biomeToBiomeBase(registry, i.getVanillaDerivative())); + } + } + + return b; + } + + private static Object getFor(Class type, Object source) { + Object o = fieldFor(type, source); + + if (o != null) { + return o; + } + + return invokeFor(type, source); + } + + private static Object fieldFor(Class returns, Object in) { + return fieldForClass(returns, in.getClass(), in); + } + + private static Object invokeFor(Class returns, Object in) { + for (Method i : in.getClass().getMethods()) { + if (i.getReturnType().equals(returns)) { + i.setAccessible(true); + try { + Iris.debug("[NMS] Found " + returns.getSimpleName() + " in " + in.getClass().getSimpleName() + "." + i.getName() + "()"); + return i.invoke(in); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + return null; + } + + @SuppressWarnings("unchecked") + private static T fieldForClass(Class returnType, Class sourceType, Object in) { + for (Field i : sourceType.getDeclaredFields()) { + if (i.getType().equals(returnType)) { + i.setAccessible(true); + try { + Iris.debug("[NMS] Found " + returnType.getSimpleName() + " in " + sourceType.getSimpleName() + "." + i.getName()); + return (T) i.get(in); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + return null; + } + + @Override + protected Stream> collectPossibleBiomes() { + return getAllBiomes( + ((RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer())) + .registry(Registries.BIOME).orElse(null), + ((CraftWorld) engine.getWorld().realWorld()).getHandle().registryAccess().registry(Registries.BIOME).orElse(null), + engine).stream(); + } + private KMap> fillCustomBiomes(Registry customRegistry, Engine engine) { + KMap> m = new KMap<>(); + + for (IrisBiome i : engine.getAllBiomes()) { + if (i.isCustom()) { + for (IrisBiomeCustom j : i.getCustomDerivitives()) { + ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); + Biome biome = customRegistry.get(location); + if (biome == null) { + INMS.get().registerBiome(location.getNamespace(), j, false); + biome = customRegistry.get(location); + if (biome == null) { + Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); + continue; + } + } + Optional> optionalBiomeKey = customRegistry.getResourceKey(biome); + if (optionalBiomeKey.isEmpty()) { + Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); + continue; + } + ResourceKey biomeKey = optionalBiomeKey.get(); + Optional> optionalReferenceHolder = customRegistry.getHolder(biomeKey); + if (optionalReferenceHolder.isEmpty()) { + Iris.error("Cannot find reference to biome " + biomeKey + " for engine " + engine.getName()); + continue; + } + m.put(j.getId(), optionalReferenceHolder.get()); + } + } + } + + return m; + } + + private RegistryAccess registry() { + return registryAccess.aquire(() -> (RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer())); + } + + @Override + protected MapCodec codec() { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public Holder getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) { + int m = (y - engine.getMinHeight()) << 2; + IrisBiome ib = engine.getComplex().getTrueBiomeStream().get(x << 2, z << 2); + if (ib.isCustom()) { + return customBiomes.get(ib.getCustomBiome(rng, x << 2, m, z << 2).getId()); + } else { + org.bukkit.block.Biome v = ib.getSkyBiome(rng, x << 2, m, z << 2); + return NMSBinding.biomeToBiomeBase(biomeRegistry, v); + } + } +} \ No newline at end of file diff --git a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java new file mode 100644 index 000000000..2c989e893 --- /dev/null +++ b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java @@ -0,0 +1,767 @@ +package com.volmit.iris.core.nms.v1_20_R4; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Vector; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; + +import com.google.common.base.Preconditions; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; +import com.volmit.iris.core.nms.datapack.DataVersion; +import com.volmit.iris.engine.object.IrisBiomeCustom; +import com.volmit.iris.engine.object.IrisDimension; +import com.volmit.iris.util.format.C; +import it.unimi.dsi.fastutil.objects.Reference2IntMap; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; +import net.bytebuddy.matcher.ElementMatchers; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.RegistrationInfo; +import net.minecraft.core.component.DataComponents; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.GsonHelper; +import net.minecraft.world.RandomSequences; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.PrimaryLevelData; +import org.bukkit.*; +import org.bukkit.block.Biome; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_20_R4.CraftChunk; +import org.bukkit.craftbukkit.v1_20_R4.CraftServer; +import org.bukkit.craftbukkit.v1_20_R4.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R4.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R4.entity.CraftDolphin; +import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R4.util.CraftNamespacedKey; +import org.bukkit.entity.Dolphin; +import org.bukkit.entity.Entity; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMSBinding; +import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.hunk.Hunk; +import com.volmit.iris.util.json.JSONObject; +import com.volmit.iris.util.mantle.Mantle; +import com.volmit.iris.util.math.Vector3d; +import com.volmit.iris.util.matter.MatterBiomeInject; +import com.volmit.iris.util.nbt.io.NBTUtil; +import com.volmit.iris.util.nbt.mca.NBTWorld; +import com.volmit.iris.util.nbt.mca.palette.*; +import com.volmit.iris.util.nbt.tag.CompoundTag; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.TagParser; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import sun.misc.Unsafe; + +public class NMSBinding implements INMSBinding { + private final KMap baseBiomeCache = new KMap<>(); + private final BlockData AIR = Material.AIR.createBlockData(); + private final AtomicCache> biomeMapCache = new AtomicCache<>(); + private final AtomicCache> registryCache = new AtomicCache<>(); + private final AtomicCache> globalCache = new AtomicCache<>(); + private final AtomicCache registryAccess = new AtomicCache<>(); + private final AtomicCache byIdRef = new AtomicCache<>(); + private Field biomeStorageCache = null; + + private static Object getFor(Class type, Object source) { + Object o = fieldFor(type, source); + + if (o != null) { + return o; + } + + return invokeFor(type, source); + } + + private static Object invokeFor(Class returns, Object in) { + for (Method i : in.getClass().getMethods()) { + if (i.getReturnType().equals(returns)) { + i.setAccessible(true); + try { + Iris.debug("[NMS] Found " + returns.getSimpleName() + " in " + in.getClass().getSimpleName() + "." + i.getName() + "()"); + return i.invoke(in); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + return null; + } + + private static Object fieldFor(Class returns, Object in) { + return fieldForClass(returns, in.getClass(), in); + } + + @SuppressWarnings("unchecked") + private static T fieldForClass(Class returnType, Class sourceType, Object in) { + for (Field i : sourceType.getDeclaredFields()) { + if (i.getType().equals(returnType)) { + i.setAccessible(true); + try { + Iris.debug("[NMS] Found " + returnType.getSimpleName() + " in " + sourceType.getSimpleName() + "." + i.getName()); + return (T) i.get(in); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + return null; + } + + private static Class getClassType(Class type, int ordinal) { + return type.getDeclaredClasses()[ordinal]; + } + + @Override + public boolean hasTile(Location l) { + return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; + } + + @Override + public CompoundTag serializeTile(Location location) { + BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); + + if (e == null) { + return null; + } + + net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(registry()); + return convert(tag); + } + + private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { + try { + ByteArrayOutputStream boas = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(boas); + tag.write(dos); + dos.close(); + return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); + } catch (Throwable ex) { + ex.printStackTrace(); + } + + return null; + } + + private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { + try { + ByteArrayOutputStream boas = new ByteArrayOutputStream(); + NBTUtil.write(tag, boas, false); + DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); + net.minecraft.nbt.CompoundTag c = NbtIo.read(din); + din.close(); + return c; + } catch (Throwable e) { + e.printStackTrace(); + } + + return null; + } + + @Override + public void deserializeTile(CompoundTag c, Location pos) { + ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); + } + + @Override + public CompoundTag serializeEntity(Entity location) { + return null;// TODO: + } + + @Override + public Entity deserializeEntity(CompoundTag s, Location newPosition) { + return null;// TODO: + } + + @Override + public boolean supportsCustomHeight() { + return true; + } + + private RegistryAccess registry() { + return registryAccess.aquire(() -> (RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer())); + } + + private Registry getCustomBiomeRegistry() { + return registry().registry(Registries.BIOME).orElse(null); + } + + private Registry getBlockRegistry() { + return registry().registry(Registries.BLOCK).orElse(null); + } + + @Override + public Object getBiomeBaseFromId(int id) { + return getCustomBiomeRegistry().getHolder(id); + } + + @Override + public int getMinHeight(World world) { + return world.getMinHeight(); + } + + @Override + public boolean supportsCustomBiomes() { + return true; + } + + @Override + public int getTrueBiomeBaseId(Object biomeBase) { + return getCustomBiomeRegistry().getId(((Holder) biomeBase).value()); + } + + @Override + public Object getTrueBiomeBase(Location location) { + return ((CraftWorld) location.getWorld()).getHandle().getBiome(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ())); + } + + @Override + public String getTrueBiomeBaseKey(Location location) { + return getKeyForBiomeBase(getTrueBiomeBase(location)); + } + + @Override + public Object getCustomBiomeBaseFor(String mckey) { + return getCustomBiomeRegistry().get(new ResourceLocation(mckey)); + } + + @Override + public Object getCustomBiomeBaseHolderFor(String mckey) { + return getCustomBiomeRegistry().getHolder(getTrueBiomeBaseId(getCustomBiomeRegistry().get(new ResourceLocation(mckey)))).get(); + } + + public int getBiomeBaseIdForKey(String key) { + return getCustomBiomeRegistry().getId(getCustomBiomeRegistry().get(new ResourceLocation(key))); + } + + @Override + public String getKeyForBiomeBase(Object biomeBase) { + return getCustomBiomeRegistry().getKey((net.minecraft.world.level.biome.Biome) biomeBase).getPath(); // something, not something:something + } + + @Override + public Object getBiomeBase(World world, Biome biome) { + return biomeToBiomeBase(((CraftWorld) world).getHandle() + .registryAccess().registry(Registries.BIOME).orElse(null), biome); + } + + @Override + public Object getBiomeBase(Object registry, Biome biome) { + Object v = baseBiomeCache.get(biome); + + if (v != null) { + return v; + } + //noinspection unchecked + v = biomeToBiomeBase((Registry) registry, biome); + if (v == null) { + // Ok so there is this new biome name called "CUSTOM" in Paper's new releases. + // But, this does NOT exist within CraftBukkit which makes it return an error. + // So, we will just return the ID that the plains biome returns instead. + //noinspection unchecked + return biomeToBiomeBase((Registry) registry, Biome.PLAINS); + } + baseBiomeCache.put(biome, v); + return v; + } + + @Override + public KList getBiomes() { + return new KList<>(Biome.values()).qadd(Biome.CHERRY_GROVE).qdel(Biome.CUSTOM); + } + + @Override + public boolean isBukkit() { + return true; + } + + @Override + public int getBiomeId(Biome biome) { + for (World i : Bukkit.getWorlds()) { + if (i.getEnvironment().equals(World.Environment.NORMAL)) { + Registry registry = ((CraftWorld) i).getHandle().registryAccess().registry(Registries.BIOME).orElse(null); + return registry.getId((net.minecraft.world.level.biome.Biome) getBiomeBase(registry, biome)); + } + } + + return biome.ordinal(); + } + + private MCAIdMap getBiomeMapping() { + return biomeMapCache.aquire(() -> new MCAIdMap<>() { + @NotNull + @Override + public Iterator iterator() { + return getCustomBiomeRegistry().iterator(); + } + + @Override + public int getId(net.minecraft.world.level.biome.Biome paramT) { + return getCustomBiomeRegistry().getId(paramT); + } + + @Override + public net.minecraft.world.level.biome.Biome byId(int paramInt) { + return (net.minecraft.world.level.biome.Biome) getBiomeBaseFromId(paramInt); + } + }); + } + + @NotNull + private MCABiomeContainer getBiomeContainerInterface(MCAIdMap biomeMapping, MCAChunkBiomeContainer base) { + return new MCABiomeContainer() { + @Override + public int[] getData() { + return base.writeBiomes(); + } + + @Override + public void setBiome(int x, int y, int z, int id) { + base.setBiome(x, y, z, biomeMapping.byId(id)); + } + + @Override + public int getBiome(int x, int y, int z) { + return biomeMapping.getId(base.getBiome(x, y, z)); + } + }; + } + + @Override + public MCABiomeContainer newBiomeContainer(int min, int max) { + MCAChunkBiomeContainer base = new MCAChunkBiomeContainer<>(getBiomeMapping(), min, max); + return getBiomeContainerInterface(getBiomeMapping(), base); + } + + @Override + public MCABiomeContainer newBiomeContainer(int min, int max, int[] data) { + MCAChunkBiomeContainer base = new MCAChunkBiomeContainer<>(getBiomeMapping(), min, max, data); + return getBiomeContainerInterface(getBiomeMapping(), base); + } + + @Override + public int countCustomBiomes() { + AtomicInteger a = new AtomicInteger(0); + + getCustomBiomeRegistry().keySet().forEach((i) -> { + if (i.getNamespace().equals("minecraft")) { + return; + } + + a.incrementAndGet(); + Iris.debug("Custom Biome: " + i); + }); + + return a.get(); + } + + public boolean supportsDataPacks() { + return true; + } + + public void setBiomes(int cx, int cz, World world, Hunk biomes) { + LevelChunk c = ((CraftWorld) world).getHandle().getChunk(cx, cz); + biomes.iterateSync((x, y, z, b) -> c.setBiome(x, y, z, (Holder) b)); + c.setUnsaved(true); + } + + @Override + public void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk) { + try { + ChunkAccess s = (ChunkAccess) getFieldForBiomeStorage(chunk).get(chunk); + Holder biome = (Holder) somethingVeryDirty; + s.setBiome(x, y, z, biome); + } catch (IllegalAccessException e) { + Iris.reportError(e); + e.printStackTrace(); + } + } + + private Field getFieldForBiomeStorage(Object storage) { + Field f = biomeStorageCache; + + if (f != null) { + return f; + } + try { + f = storage.getClass().getDeclaredField("biome"); + f.setAccessible(true); + return f; + } catch (Throwable e) { + Iris.reportError(e); + e.printStackTrace(); + Iris.error(storage.getClass().getCanonicalName()); + } + + biomeStorageCache = f; + return null; + } + + @Override + public MCAPaletteAccess createPalette() { + MCAIdMapper registry = registryCache.aquireNasty(() -> { + Field cf = net.minecraft.core.IdMapper.class.getDeclaredField("tToId"); + Field df = net.minecraft.core.IdMapper.class.getDeclaredField("idToT"); + Field bf = net.minecraft.core.IdMapper.class.getDeclaredField("nextId"); + cf.setAccessible(true); + df.setAccessible(true); + bf.setAccessible(true); + net.minecraft.core.IdMapper blockData = Block.BLOCK_STATE_REGISTRY; + int b = bf.getInt(blockData); + Object2IntMap c = (Object2IntMap) cf.get(blockData); + List d = (List) df.get(blockData); + return new MCAIdMapper(c, d, b); + }); + MCAPalette global = globalCache.aquireNasty(() -> new MCAGlobalPalette<>(registry, ((CraftBlockData) AIR).getState())); + MCAPalettedContainer container = new MCAPalettedContainer<>(global, registry, + i -> ((CraftBlockData) NBTWorld.getBlockData(i)).getState(), + i -> NBTWorld.getCompound(CraftBlockData.fromData(i)), + ((CraftBlockData) AIR).getState()); + return new MCAWrappedPalettedContainer<>(container, + i -> NBTWorld.getCompound(CraftBlockData.fromData(i)), + i -> ((CraftBlockData) NBTWorld.getBlockData(i)).getState()); + } + + @Override + public void injectBiomesFromMantle(Chunk e, Mantle mantle) { + ChunkAccess chunk = ((CraftChunk) e).getHandle(ChunkStatus.FULL); + AtomicInteger c = new AtomicInteger(); + AtomicInteger r = new AtomicInteger(); + mantle.iterateChunk(e.getX(), e.getZ(), MatterBiomeInject.class, (x, y, z, b) -> { + if (b != null) { + if (b.isCustom()) { + chunk.setBiome(x, y, z, getCustomBiomeRegistry().getHolder(b.getBiomeId()).get()); + c.getAndIncrement(); + } else { + chunk.setBiome(x, y, z, (Holder) getBiomeBase(e.getWorld(), b.getBiome())); + r.getAndIncrement(); + } + } + }); + } + + public ItemStack applyCustomNbt(ItemStack itemStack, KMap customNbt) throws IllegalArgumentException { + if (customNbt != null && !customNbt.isEmpty()) { + net.minecraft.world.item.ItemStack s = CraftItemStack.asNMSCopy(itemStack); + + try { + net.minecraft.nbt.CompoundTag tag = TagParser.parseTag((new JSONObject(customNbt)).toString()); + tag.merge(s.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).getUnsafe()); + s.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); + } catch (CommandSyntaxException var5) { + throw new IllegalArgumentException(var5); + } + + return CraftItemStack.asBukkitCopy(s); + } else { + return itemStack; + } + } + + public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) { + CraftDolphin cd = (CraftDolphin)dolphin; + cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ())); + cd.getHandle().setGotFish(true); + } + + public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { + ServerLevel serverLevel = ((CraftWorld)world).getHandle(); + Class clazz = serverLevel.getChunkSource().chunkMap.generator.getClass(); + Field biomeSource = getField(clazz, BiomeSource.class); + biomeSource.setAccessible(true); + Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + Unsafe unsafe = (Unsafe)unsafeField.get(null); + CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world); + unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource); + biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource); + } + + public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) { + Field[] fields = EntityType.class.getDeclaredFields(); + for (Field field : fields) { + if (Modifier.isStatic(field.getModifiers()) && field.getType().equals(EntityType.class)) { + try { + EntityType entityType = (EntityType) field.get(null); + if (entityType.getDescriptionId().equals("entity.minecraft." + entity.name().toLowerCase())) { + Vector v1 = new Vector<>(); + v1.add(entityType.getHeight()); + entityType.getDimensions(); + Vector3d box = new Vector3d( entityType.getWidth(), entityType.getHeight(), entityType.getWidth()); + //System.out.println("Entity Type: " + entityType.getDescriptionId() + ", " + "Height: " + height + ", Width: " + width); + return box; + } + } catch (IllegalAccessException e) { + Iris.error("Unable to get entity dimensions!"); + e.printStackTrace(); + } + } + } + return null; + } + + + @Override + public Entity spawnEntity(Location location, org.bukkit.entity.EntityType type, CreatureSpawnEvent.SpawnReason reason) { + return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); + } + + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { + try { + for (Field f : clazz.getDeclaredFields()) { + if (f.getType().equals(fieldType)) + return f; + } + throw new NoSuchFieldException(fieldType.getName()); + } catch (NoSuchFieldException var4) { + Class superClass = clazz.getSuperclass(); + if (superClass == null) { + throw var4; + } else { + return getField(superClass, fieldType); + } + } + } + + public static Holder biomeToBiomeBase(Registry registry, Biome biome) { + return registry.getHolderOrThrow(ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(biome.getKey()))); + } + + @Override + public DataVersion getDataVersion() { + return DataVersion.V1205; + } + + @Override + public boolean registerDimension(String name, IrisDimension dimension) { + var registry = registry(Registries.DIMENSION_TYPE); + var baseLocation = switch (dimension.getEnvironment()) { + case NORMAL -> new ResourceLocation("minecraft", "overworld"); + case NETHER -> new ResourceLocation("minecraft", "the_nether"); + case THE_END -> new ResourceLocation("minecraft", "the_end"); + case CUSTOM -> throw new IllegalArgumentException("Cannot register custom dimension"); + }; + var base = registry.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, baseLocation)).orElse(null); + if (base == null) return false; + var json = encode(DimensionType.CODEC, base).orElse(null); + if (json == null) return false; + var object = json.getAsJsonObject(); + var height = dimension.getDimensionHeight(); + object.addProperty("min_y", height.getMin()); + object.addProperty("height", height.getMax() - height.getMin()); + object.addProperty("logical_height", dimension.getLogicalHeight()); + var value = decode(DimensionType.CODEC, object.toString()).map(Holder::value).orElse(null); + if (value == null) return false; + return register(Registries.DIMENSION_TYPE, new ResourceLocation("iris", name), value, true); + } + + @Override + public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) { + var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null); + if (biomeBase == null) return false; + return register(Registries.BIOME, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace); + } + + private Optional decode(Codec codec, String json) { + return codec.decode(JsonOps.INSTANCE, GsonHelper.parse(json)).result().map(Pair::getFirst); + } + + private Optional encode(Codec codec, T value) { + return codec.encode(value, JsonOps.INSTANCE, new JsonObject()).result(); + } + + private boolean register(ResourceKey> registryKey, ResourceLocation location, T value, boolean replace) { + Preconditions.checkArgument(registryKey != null, "The registry cannot be null!"); + Preconditions.checkArgument(location != null, "The location cannot be null!"); + Preconditions.checkArgument(value != null, "The value cannot be null!"); + var registry = registry(registryKey); + var key = ResourceKey.create(registryKey, location); + try { + if (registry.containsKey(key)) { + if (!replace) return false; + return replace(registryKey, location, value); + } + Field field = getField(MappedRegistry.class, boolean.class); + field.setAccessible(true); + boolean frozen = field.getBoolean(registry); + field.setBoolean(registry, false); + Field valueField = getField(Holder.Reference.class, "T"); + valueField.setAccessible(true); + + try { + var holder = registry.register(key, value, RegistrationInfo.BUILT_IN); + if (frozen) valueField.set(holder, value); + return true; + } finally { + field.setBoolean(registry, frozen); + } + } catch (Throwable e) { + throw new IllegalStateException(e); + } + } + + @SuppressWarnings("unchecked") + private boolean replace(ResourceKey> registryKey, ResourceLocation location, T value) { + Preconditions.checkArgument(registryKey != null, "The registryKey cannot be null!"); + Preconditions.checkArgument(location != null, "The location cannot be null!"); + Preconditions.checkArgument(value != null, "The value cannot be null!"); + var registry = registry(registryKey); + var key = ResourceKey.create(registryKey, location); + try { + var holder = registry.getHolder(key).orElse(null); + if (holder == null) return false; + var oldValue = holder.value(); + Field valueField = getField(Holder.Reference.class, "T"); + valueField.setAccessible(true); + Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T")); + toIdField.setAccessible(true); + Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T"))); + byValueField.setAccessible(true); + var toId = (Reference2IntMap) toIdField.get(registry); + var byValue = (Map>) byValueField.get(registry); + + valueField.set(holder, value); + toId.put(value, toId.removeInt(oldValue)); + byValue.put(value, byValue.remove(oldValue)); + return true; + } catch (Throwable e) { + throw new IllegalStateException(e); + } + } + + private MappedRegistry registry(ResourceKey> registryKey) { + var rawRegistry = registry().registry(registryKey).orElse(null); + if (!(rawRegistry instanceof MappedRegistry registry)) + throw new IllegalStateException("The Registry is not a mapped Registry!"); + return registry; + } + + private static String buildType(Class clazz, String... parameterTypes) { + if (parameterTypes.length == 0) return clazz.getName(); + var builder = new StringBuilder(clazz.getName()) + .append("<"); + for (int i = 0; i < parameterTypes.length; i++) { + builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", "); + } + return builder.toString(); + } + + private static Field getField(Class clazz, String type) throws NoSuchFieldException { + try { + for (Field f : clazz.getDeclaredFields()) { + if (f.getGenericType().getTypeName().equals(type)) + return f; + } + throw new NoSuchFieldException(type); + } catch (NoSuchFieldException e) { + Class superClass = clazz.getSuperclass(); + if (superClass == null) throw e; + return getField(superClass, type); + } + } + + public void injectBukkit() { + try { + Iris.info("Injecting Bukkit"); + new ByteBuddy() + .redefine(WorldCreator.class) + .visit(Advice.to(WorldCreatorAdvice.class).on(ElementMatchers.isConstructor().and(ElementMatchers.takesArguments(String.class)))) + .make() + .load(WorldCreator.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); + new ByteBuddy() + .redefine(ServerLevel.class) + .visit(Advice.to(ServerLevelAdvice.class).on(ElementMatchers.isConstructor().and(ElementMatchers.takesArguments(MinecraftServer.class, Executor.class, LevelStorageSource.LevelStorageAccess.class, + PrimaryLevelData.class, ResourceKey.class, LevelStem.class, ChunkProgressListener.class, boolean.class, long.class, + List.class, boolean.class, RandomSequences.class, World.Environment.class, ChunkGenerator.class, BiomeProvider.class)))) + .make() + .load(ServerLevel.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); + Iris.info("Injected Bukkit Successfully!"); + } catch (Exception e) { + Iris.info(C.RED + "Failed to Inject Bukkit!"); + e.printStackTrace(); + Iris.reportError(e); + } + + } + + private static class ServerLevelAdvice { + @Advice.OnMethodEnter + static void enter(@Advice.Argument(0) MinecraftServer server, @Advice.Argument(2) LevelStorageSource.LevelStorageAccess access, @Advice.Argument(4) ResourceKey key, @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem) { + File iris = new File(access.levelDirectory.path().toFile(), "iris"); + if (!iris.exists() && !key.location().getPath().startsWith("iris/")) return; + ResourceKey typeKey = ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", key.location().getPath())); + RegistryAccess registryAccess = server.registryAccess(); + Registry registry = registryAccess.registry(Registries.DIMENSION_TYPE).orElse(null); + if (registry == null) throw new IllegalStateException("Unable to find registry for dimension type " + typeKey); + Holder holder = registry.getHolder(typeKey).orElse(null); + if (holder == null) throw new IllegalStateException("Unable to find dimension type " + typeKey); + levelStem = new LevelStem(holder, levelStem.generator()); + } + } + + private static class WorldCreatorAdvice { + @Advice.OnMethodEnter + static void enter(@Advice.Argument(0) String name) { + File isIrisWorld = new File(name, "iris"); + boolean isFromIris = false; + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + for (StackTraceElement stack : stackTrace) { + if (stack.getClassName().contains("Iris")) { + isFromIris = true; + break; + } + } + if (!isFromIris) { + Preconditions.checkArgument(!isIrisWorld.exists(), "Only Iris can load Iris Worlds!"); + } + } + } +} diff --git a/settings.gradle b/settings.gradle index e100bba88..d7ef7afe8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -26,6 +26,7 @@ rootProject.name = 'Iris' include 'app', 'com.volmit.gui' include(':core') include( + ':nms:v1_20_R4', ':nms:v1_20_R3', ':nms:v1_20_R2', ':nms:v1_20_R1',