From 76a6f1465adfe79acad417606d561715b117914c Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 26 Jul 2025 14:31:45 +0200 Subject: [PATCH 01/15] update slimjar --- core/src/main/java/com/volmit/iris/Iris.java | 1 - .../com/volmit/iris/core/IrisSettings.java | 2 -- .../com/volmit/iris/util/misc/SlimJar.java | 26 +++++++++---------- gradle/libs.versions.toml | 2 +- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index f299e4409..4bd6c7ffc 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -436,7 +436,6 @@ public class Iris extends VolmitPlugin implements Listener { public Iris() { instance = this; - SlimJar.debug(IrisSettings.get().getSentry().isDebug()); SlimJar.load(getDataFolder("cache", "libraries")); } diff --git a/core/src/main/java/com/volmit/iris/core/IrisSettings.java b/core/src/main/java/com/volmit/iris/core/IrisSettings.java index faaecc8f0..30216b29e 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/core/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -23,7 +23,6 @@ import com.volmit.iris.Iris; import com.volmit.iris.util.io.IO; import com.volmit.iris.util.json.JSONException; import com.volmit.iris.util.json.JSONObject; -import com.volmit.iris.util.misc.SlimJar; import com.volmit.iris.util.misc.getHardware; import com.volmit.iris.util.plugin.VolmitSender; import lombok.AllArgsConstructor; @@ -87,7 +86,6 @@ public class IrisSettings { Iris.error("Configuration Error in settings.json! " + ee.getClass().getSimpleName() + ": " + ee.getMessage()); } } - SlimJar.debug(settings.general.debug); return settings; } diff --git a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java index e4c882b74..f2cdb771a 100644 --- a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java +++ b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java @@ -21,19 +21,16 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiFunction; import java.util.function.Function; -import java.util.logging.Level; import java.util.logging.Logger; public class SlimJar { private static final String NAME = "Iris"; private static final Logger LOGGER = Logger.getLogger(NAME); - private static final ReentrantLock lock = new ReentrantLock(); - private static final AtomicBoolean loaded = new AtomicBoolean(); + private static final boolean DEBUG = Boolean.getBoolean("iris.debug-slimjar"); private static final boolean DISABLE_REMAPPER = Boolean.getBoolean("iris.disable-remapper"); - public static void debug(boolean debug) { - LOGGER.setLevel(debug ? Level.FINE : Level.INFO); - } + private static final ReentrantLock lock = new ReentrantLock(); + private static final AtomicBoolean loaded = new AtomicBoolean(); public static void load(@Nullable File localRepository) { if (loaded.get()) return; @@ -49,7 +46,8 @@ public class SlimJar { load(localRepository.toPath(), new ProcessLogger() { @Override public void info(@NotNull String message, @Nullable Object... args) { - LOGGER.fine(message.formatted(args)); + if (!DEBUG) return; + LOGGER.info(message.formatted(args)); } @Override @@ -59,7 +57,8 @@ public class SlimJar { @Override public void debug(@NotNull String message, @Nullable Object... args) { - LOGGER.fine(message.formatted(args)); + if (!DEBUG) return; + LOGGER.info(message.formatted(args)); } }); LOGGER.info("Libraries loaded successfully!"); @@ -82,15 +81,16 @@ public class SlimJar { private static void loadSpigot(Path downloadPath, ProcessLogger logger) throws Throwable { var current = SlimJar.class.getClassLoader(); - var libraryLoader = current.getClass().getDeclaredField("libraryLoader"); - libraryLoader.setAccessible(true); - if (!ClassLoader.class.isAssignableFrom(libraryLoader.getType())) throw new IllegalStateException("Failed to find library loader"); + var libraryLoaderField = current.getClass().getDeclaredField("libraryLoader"); + libraryLoaderField.setAccessible(true); + if (!ClassLoader.class.isAssignableFrom(libraryLoaderField.getType())) throw new IllegalStateException("Failed to find library loader"); + final var libraryLoader = (ClassLoader) libraryLoaderField.get(current); final var pair = findRemapper(); final var remapper = pair.getA(); final var factory = pair.getB(); - final var libraries = factory.apply(new URL[0], current.getParent()); + final var libraries = factory.apply(new URL[0], libraryLoader == null ? current.getParent() : libraryLoader); final var injecting = InjectableFactory.create(downloadPath, List.of(Repository.central()), libraries); ApplicationBuilder.injecting(NAME, new Injectable() { @@ -119,7 +119,7 @@ public class SlimJar { .logger(logger) .build(); - libraryLoader.set(current, libraries); + libraryLoaderField.set(current, libraries); } private static Pair, List>, BiFunction> findRemapper() { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cc74057db..4ea7eb557 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ [versions] # Plugins shadow = "9.0.0-rc1" # https://plugins.gradle.org/plugin/com.gradleup.shadow -slimjar = "2.0.8" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar +slimjar = "2.1.0" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar download = "5.6.0" # https://plugins.gradle.org/plugin/de.undercouch.download runPaper = "2.3.1" # https://plugins.gradle.org/plugin/xyz.jpenilla.run-paper sentryPlugin = "5.8.0" # https://github.com/getsentry/sentry-android-gradle-plugin From 472a98da169819ebc5cfc079b6b0649b9c58bd33 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 27 Jul 2025 18:43:33 +0200 Subject: [PATCH 02/15] update slimjar --- core/build.gradle.kts | 1 + core/src/main/java/com/volmit/iris/util/misc/SlimJar.java | 6 ++++-- gradle/libs.versions.toml | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 7f8361822..140281fbb 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -158,6 +158,7 @@ tasks { mergeServiceFiles() //minimize() relocate("io.github.slimjar", "$lib.slimjar") + exclude("modules/loader-agent.isolated-jar") } } diff --git a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java index f2cdb771a..ccdc58c5b 100644 --- a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java +++ b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java @@ -5,8 +5,8 @@ import com.volmit.iris.core.nms.container.Pair; import io.github.slimjar.app.builder.ApplicationBuilder; import io.github.slimjar.exceptions.InjectorException; import io.github.slimjar.injector.loader.Injectable; -import io.github.slimjar.injector.loader.InjectableFactory; import io.github.slimjar.injector.loader.IsolatedInjectableClassLoader; +import io.github.slimjar.injector.loader.factory.InjectableFactory; import io.github.slimjar.logging.ProcessLogger; import io.github.slimjar.resolver.data.Repository; import org.jetbrains.annotations.NotNull; @@ -31,6 +31,7 @@ public class SlimJar { private static final ReentrantLock lock = new ReentrantLock(); private static final AtomicBoolean loaded = new AtomicBoolean(); + private static final InjectableFactory FACTORY = InjectableFactory.selecting(InjectableFactory.ERROR, InjectableFactory.INJECTABLE, InjectableFactory.WRAPPED, InjectableFactory.UNSAFE); public static void load(@Nullable File localRepository) { if (loaded.get()) return; @@ -73,6 +74,7 @@ public class SlimJar { } catch (Throwable e) { Iris.warn("Failed to inject the library loader, falling back to application builder"); ApplicationBuilder.appending(NAME) + .injectableFactory(FACTORY) .downloadDirectoryPath(downloadPath) .logger(logger) .build(); @@ -91,7 +93,7 @@ public class SlimJar { final var factory = pair.getB(); final var libraries = factory.apply(new URL[0], libraryLoader == null ? current.getParent() : libraryLoader); - final var injecting = InjectableFactory.create(downloadPath, List.of(Repository.central()), libraries); + final var injecting = FACTORY.create(downloadPath, List.of(Repository.central()), libraries); ApplicationBuilder.injecting(NAME, new Injectable() { @Override diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4ea7eb557..8b6647568 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ [versions] # Plugins shadow = "9.0.0-rc1" # https://plugins.gradle.org/plugin/com.gradleup.shadow -slimjar = "2.1.0" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar +slimjar = "2.1.1" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar download = "5.6.0" # https://plugins.gradle.org/plugin/de.undercouch.download runPaper = "2.3.1" # https://plugins.gradle.org/plugin/xyz.jpenilla.run-paper sentryPlugin = "5.8.0" # https://github.com/getsentry/sentry-android-gradle-plugin From c4539441a0c087473f565a62fa809a39b503d6e4 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 27 Jul 2025 23:22:40 +0200 Subject: [PATCH 03/15] fix datapack generation ignoring worlds when updating from <3.7.0 --- .../java/com/volmit/iris/core/IrisWorlds.java | 43 ++++++++++++++++++- .../volmit/iris/core/ServerConfigurator.java | 5 +-- .../iris/core/safeguard/ServerBootSFG.java | 31 +++---------- 3 files changed, 49 insertions(+), 30 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java index 9c8302102..2e30bf117 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java +++ b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java @@ -4,10 +4,14 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import com.volmit.iris.Iris; +import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.io.IO; +import com.volmit.iris.util.misc.ServerProperties; import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.io.IOException; @@ -25,6 +29,7 @@ public class IrisWorlds { private IrisWorlds(KMap worlds) { this.worlds = worlds; + readBukkitWorlds().forEach(this::put); save(); } @@ -56,8 +61,19 @@ public class IrisWorlds { save(); } - public Stream getFolders() { - return worlds.keySet().stream().map(k -> new File(Bukkit.getWorldContainer(), k)); + public Stream getPacks() { + return getDimensions() + .map(IrisDimension::getLoader) + .filter(Objects::nonNull); + } + + public Stream getDimensions() { + return readBukkitWorlds() + .put(worlds) + .entrySet() + .stream() + .map(entry -> Iris.loadDimension(entry.getKey(), entry.getValue())) + .filter(Objects::nonNull); } public void clean() { @@ -76,4 +92,27 @@ public class IrisWorlds { Iris.reportError(e); } } + + private static KMap readBukkitWorlds() { + var bukkit = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML); + var worlds = bukkit.getConfigurationSection("worlds"); + if (worlds == null) return new KMap<>(); + + var result = new KMap(); + for (String world : worlds.getKeys(false)) { + var gen = worlds.getString(world + ".generator"); + if (gen == null) continue; + + String loadKey; + if (gen.equalsIgnoreCase("iris")) { + loadKey = IrisSettings.get().getGenerator().getDefaultWorldType(); + } else if (gen.startsWith("Iris:")) { + loadKey = gen.substring(5); + } else continue; + + result.put(world, loadKey); + } + + return result; + } } 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 d249bfbcd..51ab974c5 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -237,14 +237,13 @@ public class ServerConfigurator { } public static Stream allPacks() { - return Stream.concat(listFiles(Iris.instance.getDataFolder("packs")), - IrisWorlds.get().getFolders().map(w -> new File(w, "iris/pack"))) + return Stream.concat(listFiles(Iris.instance.getDataFolder("packs")) .filter(File::isDirectory) .filter( base -> { var content = new File(base, "dimensions").listFiles(); return content != null && content.length > 0; }) - .map(IrisData::get); + .map(IrisData::get), IrisWorlds.get().getPacks()); } @Nullable 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 8ec35899f..50de28b29 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 @@ -1,15 +1,13 @@ package com.volmit.iris.core.safeguard; import com.volmit.iris.Iris; -import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.IrisWorlds; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.v1X.NMSBinding1X; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.util.agent.Agent; import com.volmit.iris.util.collection.KSet; -import com.volmit.iris.util.misc.ServerProperties; import org.bukkit.Bukkit; -import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import javax.tools.JavaCompiler; @@ -21,6 +19,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.*; +import java.util.stream.Collectors; import static com.volmit.iris.Iris.getJavaVersion; import static com.volmit.iris.core.safeguard.IrisSafeguard.*; @@ -187,27 +186,9 @@ public class ServerBootSFG { } private static KSet getDimensionTypes() { - var bukkit = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML); - var worlds = bukkit.getConfigurationSection("worlds"); - if (worlds == null) return new KSet<>(); - - var types = new KSet(); - for (String world : worlds.getKeys(false)) { - var gen = worlds.getString(world + ".generator"); - if (gen == null) continue; - - String loadKey; - if (gen.equalsIgnoreCase("iris")) { - loadKey = IrisSettings.get().getGenerator().getDefaultWorldType(); - } else if (gen.startsWith("Iris:")) { - loadKey = gen.substring(5); - } else continue; - - IrisDimension dimension = Iris.loadDimension(world, loadKey); - if (dimension == null) continue; - types.add(dimension.getDimensionTypeKey()); - } - - return types; + return IrisWorlds.get() + .getDimensions() + .map(IrisDimension::getDimensionTypeKey) + .collect(Collectors.toCollection(KSet::new)); } } From 8471f15bc87aa74ef44265fd51881105b4821111 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 27 Jul 2025 23:23:04 +0200 Subject: [PATCH 04/15] make world creation more failsafe --- core/src/main/java/com/volmit/iris/Iris.java | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 4bd6c7ffc..194abbab4 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -501,12 +501,21 @@ public class Iris extends VolmitPlugin implements Listener { Iris.info("Loading World: %s | Generator: %s", s, generator); - Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "..."); - WorldCreator c = new WorldCreator(s) - .generator(getDefaultWorldGenerator(s, generator)) - .environment(IrisData.loadAnyDimension(generator).getEnvironment()); - INMS.get().createWorld(c); - Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"); + try { + var gen = getDefaultWorldGenerator(s, generator); + var dim = loadDimension(s, generator); + assert dim != null && gen != null; + + Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "..."); + WorldCreator c = new WorldCreator(s) + .generator(gen) + .environment(dim.getEnvironment()); + INMS.get().createWorld(c); + Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"); + } catch (Throwable e) { + Iris.error("Failed to load world " + s + "!"); + e.printStackTrace(); + } } } catch (Throwable e) { e.printStackTrace(); From 501c42630290b9a1daafeb7f42fe0d87ff0377c8 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 12:31:07 +0200 Subject: [PATCH 05/15] fix slimjar error for new projects --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8b6647568..84911a178 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ [versions] # Plugins shadow = "9.0.0-rc1" # https://plugins.gradle.org/plugin/com.gradleup.shadow -slimjar = "2.1.1" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar +slimjar = "2.1.2" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar download = "5.6.0" # https://plugins.gradle.org/plugin/de.undercouch.download runPaper = "2.3.1" # https://plugins.gradle.org/plugin/xyz.jpenilla.run-paper sentryPlugin = "5.8.0" # https://github.com/getsentry/sentry-android-gradle-plugin From 70130e976db202bd71fe94f77bf59854e905afc6 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 13:53:11 +0200 Subject: [PATCH 06/15] add getter method to IrisWorlds --- .../main/java/com/volmit/iris/core/IrisWorlds.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java index 2e30bf117..a46be559e 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java +++ b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java @@ -29,7 +29,7 @@ public class IrisWorlds { private IrisWorlds(KMap worlds) { this.worlds = worlds; - readBukkitWorlds().forEach(this::put); + readBukkitWorlds().forEach(this::put0); save(); } @@ -55,10 +55,18 @@ public class IrisWorlds { } public void put(String name, String type) { + put0(name, type); + save(); + } + + private void put0(String name, String type) { String old = worlds.put(name, type); if (!type.equals(old)) dirty = true; - save(); + } + + public KMap getWorlds() { + return readBukkitWorlds().put(worlds); } public Stream getPacks() { From 74128d58cfac96b91411ff2b88849fd2a1466024 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 15:06:34 +0200 Subject: [PATCH 07/15] disable pack trimming for now --- .../java/com/volmit/iris/core/commands/CommandIris.java | 6 ++++-- .../java/com/volmit/iris/core/commands/CommandStudio.java | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) 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 84f601642..77f794781 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 @@ -394,17 +394,19 @@ public class CommandIris implements DecreeExecutor { sender().sendMessage(C.GREEN + "Set debug to: " + to); } + //TODO fix pack trimming @Decree(description = "Download a project.", aliases = "dl") public void download( @Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project") String pack, @Param(name = "branch", description = "The branch to download from", defaultValue = "main") String branch, - @Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false") - boolean trim, + //@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false") + //boolean trim, @Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false") boolean overwrite ) { + boolean trim = false; sender().sendMessage(C.GREEN + "Downloading pack: " + pack + "/" + branch + (trim ? " trimmed" : "") + (overwrite ? " overwriting" : "")); if (pack.equals("overworld")) { String url = "https://github.com/IrisDimensions/overworld/releases/download/" + INMS.OVERWORLD_TAG + "/overworld.zip"; 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 1635dd3bb..d6261ee23 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 @@ -92,18 +92,19 @@ public class CommandStudio implements DecreeExecutor { return duration.toString().substring(2).replaceAll("(\\d[HMS])(?!$)", "$1 ").toLowerCase(); } + //TODO fix pack trimming @Decree(description = "Download a project.", aliases = "dl") public void download( @Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project") String pack, @Param(name = "branch", description = "The branch to download from", defaultValue = "master") String branch, - @Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false") - boolean trim, + //@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false") + //boolean trim, @Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false") boolean overwrite ) { - new CommandIris().download(pack, branch, trim, overwrite); + new CommandIris().download(pack, branch, overwrite); } @Decree(description = "Open a new studio world", aliases = "o", sync = true) From fba9c17e3f0381cb61f0cf8008335e3d7e7b4a9d Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 15:08:07 +0200 Subject: [PATCH 08/15] fix not using relocated bukkit.yml correctly and remove duplicate code --- core/src/main/java/com/volmit/iris/Iris.java | 42 ++------- .../java/com/volmit/iris/core/IrisWorlds.java | 2 +- .../iris/core/commands/CommandIris.java | 93 +------------------ .../volmit/iris/core/tools/IrisCreator.java | 3 +- .../iris/util/misc/ServerProperties.java | 31 +++++-- 5 files changed, 39 insertions(+), 132 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 194abbab4..f17fec0be 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -22,6 +22,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonParser; import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.IrisWorlds; import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.link.IrisPapiExpansion; import com.volmit.iris.core.link.MultiverseCoreLink; @@ -65,9 +66,6 @@ import org.bukkit.*; import org.bukkit.block.data.BlockData; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.event.*; import org.bukkit.generator.BiomeProvider; @@ -81,6 +79,7 @@ import java.io.*; import java.lang.annotation.Annotation; import java.net.URL; import java.util.*; +import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -466,42 +465,19 @@ public class Iris extends VolmitPlugin implements Listener { IrisSafeguard.splash(false); autoStartStudio(); - checkForBukkitWorlds(); + checkForBukkitWorlds(s -> true); IrisToolbelt.retainMantleDataForSlice(String.class.getCanonicalName()); IrisToolbelt.retainMantleDataForSlice(BlockData.class.getCanonicalName()); }); } - private void checkForBukkitWorlds() { - FileConfiguration fc = new YamlConfiguration(); + public void checkForBukkitWorlds(Predicate filter) { try { - fc.load(new File("bukkit.yml")); - ConfigurationSection section = fc.getConfigurationSection("worlds"); - if (section == null) { - return; - } - - for (String s : section.getKeys(false)) { - ConfigurationSection entry = section.getConfigurationSection(s); - if (!entry.contains("generator", true)) { - continue; - } - - String generator = entry.getString("generator"); - if (generator.startsWith("Iris:")) { - generator = generator.split("\\Q:\\E")[1]; - } else if (generator.equalsIgnoreCase("Iris")) { - generator = IrisSettings.get().getGenerator().getDefaultWorldType(); - } else { - continue; - } - - if (Bukkit.getWorld(s) != null) - continue; - - Iris.info("Loading World: %s | Generator: %s", s, generator); - + IrisWorlds.readBukkitWorlds().forEach((s, generator) -> { try { + if (Bukkit.getWorld(s) != null || !filter.test(s)) return; + + Iris.info("Loading World: %s | Generator: %s", s, generator); var gen = getDefaultWorldGenerator(s, generator); var dim = loadDimension(s, generator); assert dim != null && gen != null; @@ -516,7 +492,7 @@ public class Iris extends VolmitPlugin implements Listener { Iris.error("Failed to load world " + s + "!"); e.printStackTrace(); } - } + }); } catch (Throwable e) { e.printStackTrace(); reportError(e); diff --git a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java index a46be559e..69721ced2 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java +++ b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java @@ -101,7 +101,7 @@ public class IrisWorlds { } } - private static KMap readBukkitWorlds() { + public static KMap readBukkitWorlds() { var bukkit = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML); var worlds = bukkit.getConfigurationSection("worlds"); if (worlds == null) return new KMap<>(); 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 77f794781..89fa7cf5f 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,15 +20,12 @@ package com.volmit.iris.core.commands; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; -import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.pregenerator.ChunkUpdater; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisDimension; -import com.volmit.iris.engine.object.IrisWorld; -import com.volmit.iris.engine.platform.BukkitChunkGenerator; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeOrigin; @@ -44,21 +41,17 @@ import com.volmit.iris.util.scheduling.J; import lombok.SneakyThrows; import org.bukkit.Bukkit; import org.bukkit.World; -import org.bukkit.WorldCreator; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; -import org.bukkit.generator.ChunkGenerator; import org.bukkit.scheduler.BukkitRunnable; import java.io.*; -import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicReference; -import static com.volmit.iris.Iris.service; import static com.volmit.iris.core.service.EditSVC.deletingWorld; +import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML; import static org.bukkit.Bukkit.getServer; @Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command") @@ -504,7 +497,6 @@ public class CommandIris implements DecreeExecutor { return; } - File BUKKIT_YML = new File("bukkit.yml"); String pathtodim = world + File.separator +"iris"+File.separator +"pack"+File.separator +"dimensions"+File.separator; File directory = new File(Bukkit.getWorldContainer(), pathtodim); @@ -542,7 +534,7 @@ public class CommandIris implements DecreeExecutor { return; } } - checkForBukkitWorlds(world); + Iris.instance.checkForBukkitWorlds(world::equals); sender().sendMessage(C.GREEN + world + " loaded successfully."); } @Decree(description = "Evacuate an iris world", origin = DecreeOrigin.PLAYER, sync = true) @@ -563,85 +555,4 @@ public class CommandIris implements DecreeExecutor { File worldDirectory = new File(worldContainer, worldName); return worldDirectory.exists() && worldDirectory.isDirectory(); } - private void checkForBukkitWorlds(String world) { - FileConfiguration fc = new YamlConfiguration(); - try { - fc.load(new File("bukkit.yml")); - ConfigurationSection section = fc.getConfigurationSection("worlds"); - if (section == null) { - return; - } - - List worldsToLoad = Collections.singletonList(world); - - for (String s : section.getKeys(false)) { - if (!worldsToLoad.contains(s)) { - continue; - } - ConfigurationSection entry = section.getConfigurationSection(s); - if (!entry.contains("generator", true)) { - continue; - } - String generator = entry.getString("generator"); - if (generator.startsWith("Iris:")) { - generator = generator.split("\\Q:\\E")[1]; - } else if (generator.equalsIgnoreCase("Iris")) { - generator = IrisSettings.get().getGenerator().getDefaultWorldType(); - } else { - continue; - } - Iris.info("2 World: %s | Generator: %s", s, generator); - if (Bukkit.getWorlds().stream().anyMatch(w -> w.getName().equals(s))) { - continue; - } - Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "..."); - WorldCreator c = new WorldCreator(s) - .generator(getDefaultWorldGenerator(s, generator)) - .environment(IrisData.loadAnyDimension(generator).getEnvironment()); - INMS.get().createWorld(c); - Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"); - } - } catch (Throwable e) { - e.printStackTrace(); - } - } - public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { - Iris.debug("Default World Generator Called for " + worldName + " using ID: " + id); - IrisDimension dim; - if (id == null || id.isEmpty()) { - dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType()); - } else { - dim = IrisData.loadAnyDimension(id); - } - Iris.debug("Generator ID: " + id + " requested by bukkit/plugin"); - - if (dim == null) { - Iris.warn("Unable to find dimension type " + id + " Looking for online packs..."); - - service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, true); - dim = IrisData.loadAnyDimension(id); - - if (dim == null) { - throw new RuntimeException("Can't find dimension " + id + "!"); - } else { - Iris.info("Resolved missing dimension, proceeding with generation."); - } - } - Iris.debug("Assuming IrisDimension: " + dim.getName()); - IrisWorld w = IrisWorld.builder() - .name(worldName) - .seed(1337) - .environment(dim.getEnvironment()) - .worldFolder(new File(Bukkit.getWorldContainer(), worldName)) - .minHeight(dim.getMinHeight()) - .maxHeight(dim.getMaxHeight()) - .build(); - Iris.debug("Generator Config: " + w.toString()); - File ff = new File(w.worldFolder(), "iris/pack"); - if (!ff.exists() || ff.listFiles().length == 0) { - ff.mkdirs(); - service(StudioSVC.class).installIntoWorld(sender, dim.getLoadKey(), ff.getParentFile()); - } - return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey()); - } } 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 fac42b051..f10cbdfd2 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 @@ -46,13 +46,14 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; +import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML; + /** * Makes it a lot easier to setup an engine, world, studio or whatever */ @Data @Accessors(fluent = true, chain = true) public class IrisCreator { - private static final File BUKKIT_YML = new File("bukkit.yml"); /** * Specify an area to pregenerate during creation */ diff --git a/core/src/main/java/com/volmit/iris/util/misc/ServerProperties.java b/core/src/main/java/com/volmit/iris/util/misc/ServerProperties.java index ecfc4f518..fb9a31c73 100644 --- a/core/src/main/java/com/volmit/iris/util/misc/ServerProperties.java +++ b/core/src/main/java/com/volmit/iris/util/misc/ServerProperties.java @@ -1,5 +1,8 @@ package com.volmit.iris.util.misc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -22,12 +25,13 @@ public class ServerProperties { String bukkitYml = "bukkit.yml"; String levelName = null; - for (int i = 0; i < args.length - 1; i++) { - switch (args[i]) { - case "-c", "--config" -> propertiesPath = args[i + 1]; - case "-b", "--bukkit-settings" -> bukkitYml = args[i + 1]; - case "-w", "--level-name", "--world" -> levelName = args[i + 1]; - } + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + String next = i < args.length - 1 ? args[i + 1] : null; + + propertiesPath = parse(arg, next, propertiesPath, "-c", "--config"); + bukkitYml = parse(arg, next, bukkitYml, "-b", "--bukkit-settings"); + levelName = parse(arg, next, levelName, "-w", "--level-name", "--world"); } SERVER_PROPERTIES = new File(propertiesPath); @@ -41,4 +45,19 @@ public class ServerProperties { if (levelName != null) LEVEL_NAME = levelName; else LEVEL_NAME = DATA.getProperty("level-name", "world"); } + + private static String parse( + @NotNull String current, + @Nullable String next, + String fallback, + @NotNull String @NotNull ... keys + ) { + for (String k : keys) { + if (current.equals(k) && next != null) + return next; + if (current.startsWith(k + "=") && current.length() > k.length() + 1) + return current.substring(k.length() + 1); + } + return fallback; + } } From 0648cfd3fa2eaa6a24a6c8b12282c33c3b6b6fe6 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 15:16:21 +0200 Subject: [PATCH 09/15] add message for promotion of world to main world --- .../src/main/java/com/volmit/iris/core/commands/CommandIris.java | 1 + 1 file changed, 1 insertion(+) 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 89fa7cf5f..3f1c0b588 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 @@ -123,6 +123,7 @@ public class CommandIris implements DecreeExecutor { } worldCreation = false; sender().sendMessage(C.GREEN + "Successfully created your world!"); + if (main) sender().sendMessage(C.GREEN + "Your world will automatically be set as the main world when the server restarts."); } @SneakyThrows From a610d0a7a97d013188db665ff98da764433c5355 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 20:53:01 +0200 Subject: [PATCH 10/15] remove unnecessary classpath injections --- .../iris/core/tools/IrisWorldCreator.java | 3 -- .../volmit/iris/util/collection/KList.java | 13 ++++++ .../iris/util/function/NastyFunction.java | 3 +- .../com/volmit/iris/util/misc/SlimJar.java | 40 +++++-------------- 4 files changed, 24 insertions(+), 35 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisWorldCreator.java b/core/src/main/java/com/volmit/iris/core/tools/IrisWorldCreator.java index 97ec2eceb..cd6c17a91 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisWorldCreator.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisWorldCreator.java @@ -21,13 +21,10 @@ package com.volmit.iris.core.tools; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.platform.BukkitChunkGenerator; -import com.volmit.iris.util.reflect.WrappedField; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.WorldCreator; -import org.bukkit.WorldType; import org.bukkit.generator.ChunkGenerator; -import sun.misc.Unsafe; import java.io.File; diff --git a/core/src/main/java/com/volmit/iris/util/collection/KList.java b/core/src/main/java/com/volmit/iris/util/collection/KList.java index bf1cf916d..a22c562db 100644 --- a/core/src/main/java/com/volmit/iris/util/collection/KList.java +++ b/core/src/main/java/com/volmit/iris/util/collection/KList.java @@ -19,6 +19,7 @@ package com.volmit.iris.util.collection; import com.google.common.util.concurrent.AtomicDoubleArray; +import com.volmit.iris.util.function.NastyFunction; import com.volmit.iris.util.json.JSONArray; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; @@ -306,6 +307,18 @@ public class KList extends ArrayList implements List { return v; } + /** + * Convert this list into another list type. Such as GList to + * GList. list.convertNasty((i) -> "" + i); + */ + public KList convertNasty(NastyFunction converter) throws Throwable { + KList v = new KList(size()); + for (final var t : this) { + v.addNonNull(converter.run(t)); + } + return v; + } + public KList removeWhere(Predicate t) { for (T i : copy()) { if (t.test(i)) { diff --git a/core/src/main/java/com/volmit/iris/util/function/NastyFunction.java b/core/src/main/java/com/volmit/iris/util/function/NastyFunction.java index f490848a2..dd056c169 100644 --- a/core/src/main/java/com/volmit/iris/util/function/NastyFunction.java +++ b/core/src/main/java/com/volmit/iris/util/function/NastyFunction.java @@ -18,6 +18,7 @@ package com.volmit.iris.util.function; +@FunctionalInterface public interface NastyFunction { - R run(T t); + R run(T t) throws Throwable; } diff --git a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java index ccdc58c5b..488000bf9 100644 --- a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java +++ b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java @@ -2,13 +2,11 @@ package com.volmit.iris.util.misc; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.container.Pair; +import com.volmit.iris.util.collection.KList; import io.github.slimjar.app.builder.ApplicationBuilder; -import io.github.slimjar.exceptions.InjectorException; -import io.github.slimjar.injector.loader.Injectable; import io.github.slimjar.injector.loader.IsolatedInjectableClassLoader; import io.github.slimjar.injector.loader.factory.InjectableFactory; import io.github.slimjar.logging.ProcessLogger; -import io.github.slimjar.resolver.data.Repository; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,7 +29,6 @@ public class SlimJar { private static final ReentrantLock lock = new ReentrantLock(); private static final AtomicBoolean loaded = new AtomicBoolean(); - private static final InjectableFactory FACTORY = InjectableFactory.selecting(InjectableFactory.ERROR, InjectableFactory.INJECTABLE, InjectableFactory.WRAPPED, InjectableFactory.UNSAFE); public static void load(@Nullable File localRepository) { if (loaded.get()) return; @@ -74,7 +71,7 @@ public class SlimJar { } catch (Throwable e) { Iris.warn("Failed to inject the library loader, falling back to application builder"); ApplicationBuilder.appending(NAME) - .injectableFactory(FACTORY) + .injectableFactory(InjectableFactory.selecting(InjectableFactory.ERROR, InjectableFactory.INJECTABLE, InjectableFactory.WRAPPED, InjectableFactory.UNSAFE)) .downloadDirectoryPath(downloadPath) .logger(logger) .build(); @@ -91,37 +88,18 @@ public class SlimJar { final var pair = findRemapper(); final var remapper = pair.getA(); final var factory = pair.getB(); + final var classpath = new KList(); - final var libraries = factory.apply(new URL[0], libraryLoader == null ? current.getParent() : libraryLoader); - final var injecting = FACTORY.create(downloadPath, List.of(Repository.central()), libraries); - - ApplicationBuilder.injecting(NAME, new Injectable() { - @Override - public void inject(@NotNull URL url) throws InjectorException { - try { - final List mapped; - synchronized (remapper) { - mapped = remapper.apply(List.of(Path.of(url.toURI()))); - } - - for (final Path path : mapped) { - injecting.inject(path.toUri().toURL()); - } - } catch (Throwable e) { - throw new InjectorException("Failed to inject " + url, e); - } - } - - @Override - public boolean isThreadSafe() { - return injecting.isThreadSafe(); - } - }) + ApplicationBuilder.injecting(NAME, classpath::add) .downloadDirectoryPath(downloadPath) .logger(logger) .build(); - libraryLoaderField.set(current, libraries); + final var urls = remapper.andThen(KList::new) + .apply(classpath.convertNasty(url -> Path.of(url.toURI()))) + .convertNasty(path -> path.toUri().toURL()) + .toArray(URL[]::new); + libraryLoaderField.set(current, factory.apply(urls, libraryLoader == null ? current.getParent() : libraryLoader)); } private static Pair, List>, BiFunction> findRemapper() { From 8705ca6e47005831d419de605dab43ec275188d2 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 28 Jul 2025 21:44:27 +0200 Subject: [PATCH 11/15] save structure placed at block --- .../com/volmit/iris/engine/IrisEngine.java | 7 ++++ .../volmit/iris/engine/framework/Engine.java | 3 ++ .../iris/engine/jigsaw/PlannedStructure.java | 7 ++-- .../matter/slices/JigsawStructureMatter.java | 35 +++++++++++++++++++ .../container/JigsawStructureContainer.java | 13 +++++++ 5 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/util/matter/slices/JigsawStructureMatter.java create mode 100644 core/src/main/java/com/volmit/iris/util/matter/slices/container/JigsawStructureContainer.java 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 2f9bd5a88..e5db0d978 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -47,6 +47,7 @@ import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.matter.MatterStructurePOI; +import com.volmit.iris.util.matter.slices.container.JigsawStructureContainer; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; @@ -223,6 +224,12 @@ public class IrisEngine implements Engine { return getMantle().getJigsawComponent().guess(x, z); } + @Override + public IrisJigsawStructure getStructureAt(int x, int y, int z) { + var container = getMantle().getMantle().get(x, y, z, JigsawStructureContainer.class); + return container == null ? null : container.load(getData()); + } + private void warmupChunk(int x, int z) { for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java index 1e39c8667..40072c47b 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java @@ -231,6 +231,9 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat @ChunkCoordinates IrisJigsawStructure getStructureAt(int x, int z); + @BlockCoordinates + IrisJigsawStructure getStructureAt(int x, int y, int z); + @BlockCoordinates default IrisBiome getCaveBiome(int x, int z) { return getComplex().getCaveBiomeStream().get(x, z); diff --git a/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java b/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java index d6a49b58f..c045cf922 100644 --- a/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java +++ b/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java @@ -29,6 +29,7 @@ import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.matter.slices.container.JigsawPieceContainer; +import com.volmit.iris.util.matter.slices.container.JigsawStructureContainer; import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer; import com.volmit.iris.util.scheduling.J; import lombok.Data; @@ -149,11 +150,13 @@ public class PlannedStructure { } int id = rng.i(0, Integer.MAX_VALUE); - JigsawPieceContainer container = JigsawPieceContainer.toContainer(i.getPiece()); + JigsawPieceContainer piece = JigsawPieceContainer.toContainer(i.getPiece()); + JigsawStructureContainer structure = JigsawStructureContainer.toContainer(getStructure()); i.setRealPositions(xx, height, zz, placer); return v.place(xx, height, zz, placer, options, rng, (b, data) -> { e.set(b.getX(), b.getY(), b.getZ(), v.getLoadKey() + "@" + id); - e.set(b.getX(), b.getY(), b.getZ(), container); + e.set(b.getX(), b.getY(), b.getZ(), structure); + e.set(b.getX(), b.getY(), b.getZ(), piece); }, null, getData().getEngine() != null ? getData() : eng.getData()) != -1; } diff --git a/core/src/main/java/com/volmit/iris/util/matter/slices/JigsawStructureMatter.java b/core/src/main/java/com/volmit/iris/util/matter/slices/JigsawStructureMatter.java new file mode 100644 index 000000000..6e9ec2ce0 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/matter/slices/JigsawStructureMatter.java @@ -0,0 +1,35 @@ +package com.volmit.iris.util.matter.slices; + +import com.volmit.iris.util.data.palette.Palette; +import com.volmit.iris.util.matter.Sliced; +import com.volmit.iris.util.matter.slices.container.JigsawPieceContainer; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +@Sliced +public class JigsawStructureMatter extends RawMatter { + public JigsawStructureMatter() { + this(1,1,1); + } + + public JigsawStructureMatter(int width, int height, int depth) { + super(width, height, depth, JigsawPieceContainer.class); + } + + @Override + public Palette getGlobalPalette() { + return null; + } + + @Override + public void writeNode(JigsawPieceContainer b, DataOutputStream dos) throws IOException { + dos.writeUTF(b.getLoadKey()); + } + + @Override + public JigsawPieceContainer readNode(DataInputStream din) throws IOException { + return new JigsawPieceContainer(din.readUTF()); + } +} diff --git a/core/src/main/java/com/volmit/iris/util/matter/slices/container/JigsawStructureContainer.java b/core/src/main/java/com/volmit/iris/util/matter/slices/container/JigsawStructureContainer.java new file mode 100644 index 000000000..bd581ede3 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/matter/slices/container/JigsawStructureContainer.java @@ -0,0 +1,13 @@ +package com.volmit.iris.util.matter.slices.container; + +import com.volmit.iris.engine.object.IrisJigsawStructure; + +public class JigsawStructureContainer extends RegistrantContainer { + public JigsawStructureContainer(String loadKey) { + super(IrisJigsawStructure.class, loadKey); + } + + public static JigsawStructureContainer toContainer(IrisJigsawStructure structure) { + return new JigsawStructureContainer(structure.getLoadKey()); + } +} From 58b1bd115f6332d1b866bb4799c319c155c04f00 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 30 Jul 2025 19:18:57 +0200 Subject: [PATCH 12/15] update adventure api --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 84911a178..b1bbc6e5a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,8 +15,8 @@ grgit = "5.3.2" # https://github.com/ajoberstar/grgit lombok = "1.18.38" spigot = "1.20.1-R0.1-SNAPSHOT" # https://hub.spigotmc.org/nexus/repository/snapshots/org/spigotmc/spigot-api/maven-metadata.xml log4j = "2.19.0" # https://central.sonatype.com/artifact/org.apache.logging.log4j/log4j-api -adventure-api = "4.23.0" # https://github.com/KyoriPowered/adventure -adventure-platform = "4.4.0" # https://github.com/KyoriPowered/adventure-platform +adventure-api = "4.24.0" # https://github.com/KyoriPowered/adventure +adventure-platform = "4.4.1" # https://github.com/KyoriPowered/adventure-platform annotations = "26.0.2" # https://central.sonatype.com/artifact/org.jetbrains/annotations paralithic = "0.8.1" # https://github.com/PolyhedralDev/Paralithic/ From a5bca0a9bb623296e232159397228338c8de164b Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 1 Aug 2025 13:06:25 +0200 Subject: [PATCH 13/15] fix not reading enum values correctly --- .../java/com/volmit/iris/util/reflect/OldEnum.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/util/reflect/OldEnum.java b/core/src/main/java/com/volmit/iris/util/reflect/OldEnum.java index 24293ad2a..817721aa5 100644 --- a/core/src/main/java/com/volmit/iris/util/reflect/OldEnum.java +++ b/core/src/main/java/com/volmit/iris/util/reflect/OldEnum.java @@ -11,6 +11,7 @@ import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.Objects; +//TODO improve this public class OldEnum { private static final Class oldEnum; @@ -25,11 +26,16 @@ public class OldEnum { } public static T valueOf(Class c, String name) { - try { - return (T) c.getDeclaredField(name).get(null); - } catch (Throwable e) { - return null; + return valueOf(c, name, name.replace(".", "_")); + } + + public static T valueOf(Class c, String... names) { + for (final String name : names) { + try { + return (T) c.getDeclaredField(name).get(null); + } catch (Throwable ignored) {} } + return null; } public static String name(Object o) { From 5eb25f3977c0afa1daa683569342f03adae352cd Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 2 Aug 2025 00:00:51 +0200 Subject: [PATCH 14/15] add property to use registry keys for where applicable disabled by default for now --- .../com/volmit/iris/core/loader/IrisData.java | 11 +- .../iris/core/project/SchemaBuilder.java | 20 +-- .../util/data/registry/KeyedRegistry.java | 137 +++++++++++++++++ .../data/registry/RegistryTypeAdapter.java | 42 ++++++ .../iris/util/data/registry/RegistryUtil.java | 138 ++++++------------ .../volmit/iris/util/reflect/KeyedType.java | 37 +++++ .../com/volmit/iris/util/reflect/OldEnum.java | 21 +-- 7 files changed, 281 insertions(+), 125 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/util/data/registry/KeyedRegistry.java create mode 100644 core/src/main/java/com/volmit/iris/util/data/registry/RegistryTypeAdapter.java create mode 100644 core/src/main/java/com/volmit/iris/util/reflect/KeyedType.java diff --git a/core/src/main/java/com/volmit/iris/core/loader/IrisData.java b/core/src/main/java/com/volmit/iris/core/loader/IrisData.java index e6d410a5b..00e02ac00 100644 --- a/core/src/main/java/com/volmit/iris/core/loader/IrisData.java +++ b/core/src/main/java/com/volmit/iris/core/loader/IrisData.java @@ -36,7 +36,7 @@ import com.volmit.iris.util.format.C; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.MultiBurst; -import com.volmit.iris.util.reflect.OldEnum; +import com.volmit.iris.util.reflect.KeyedType; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; import lombok.Data; @@ -341,14 +341,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory { this.imageLoader = registerLoader(IrisImage.class); this.scriptLoader = registerLoader(IrisScript.class); this.matterObjectLoader = registerLoader(IrisMatterObject.class); - if (OldEnum.exists()) { - builder.registerTypeAdapterFactory(new TypeAdapterFactory() { - @Override - public TypeAdapter create(Gson gson, TypeToken type) { - return (TypeAdapter) OldEnum.create(type.getRawType()); - } - }); - } + builder.registerTypeAdapterFactory(KeyedType::createTypeAdapter); gson = builder.create(); } diff --git a/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java b/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java index 50ff64886..f5fe814c3 100644 --- a/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java +++ b/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java @@ -31,7 +31,7 @@ import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.data.B; import com.volmit.iris.util.json.JSONArray; import com.volmit.iris.util.json.JSONObject; -import com.volmit.iris.util.reflect.OldEnum; +import com.volmit.iris.util.reflect.KeyedType; import org.bukkit.enchantments.Enchantment; import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; @@ -336,10 +336,10 @@ public class SchemaBuilder { prop.put("$ref", "#/definitions/" + key); description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)"); + } else if (KeyedType.isKeyed(k.getType())) { + fancyType = addEnum(k.getType(), prop, description, KeyedType.values(k.getType()), Function.identity()); } else if (k.getType().isEnum()) { fancyType = addEnum(k.getType(), prop, description, k.getType().getEnumConstants(), o -> ((Enum) o).name()); - } else if (OldEnum.isOldEnum(k.getType())) { - fancyType = addEnum(k.getType(), prop, description, OldEnum.values(k.getType()), OldEnum::name); } } case "object" -> { @@ -504,10 +504,10 @@ public class SchemaBuilder { items.put("$ref", "#/definitions/" + key); prop.put("items", items); description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)"); + } else if (KeyedType.isKeyed(t.type())) { + fancyType = addEnumList(prop, description, t, KeyedType.values(t.type()), Function.identity()); } else if (t.type().isEnum()) { fancyType = addEnumList(prop, description, t, t.type().getEnumConstants(), o -> ((Enum) o).name()); - } else if (OldEnum.isOldEnum(t.type())) { - fancyType = addEnumList(prop, description, t, OldEnum.values(t.type()), OldEnum::name); } } } @@ -548,7 +548,7 @@ public class SchemaBuilder { if (value instanceof List) { d.add(" "); d.add("* Default Value is an empty list"); - } else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum()) && !OldEnum.isOldEnum(cl)) { + } else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum()) && !KeyedType.isKeyed(cl)) { d.add(" "); d.add("* Default Value is a default object (create this object to see default properties)"); } else { @@ -596,7 +596,7 @@ public class SchemaBuilder { } @NotNull - private String addEnumList(JSONObject prop, KList description, ArrayType t, Object[] values, Function function) { + private String addEnumList(JSONObject prop, KList description, ArrayType t, T[] values, Function function) { JSONObject items = new JSONObject(); var s = addEnum(t.type(), items, description, values, function); prop.put("items", items); @@ -605,10 +605,10 @@ public class SchemaBuilder { } @NotNull - private String addEnum(Class type, JSONObject prop, KList description, Object[] values, Function function) { + private String addEnum(Class type, JSONObject prop, KList description, T[] values, Function function) { JSONArray a = new JSONArray(); boolean advanced = type.isAnnotationPresent(Desc.class); - for (Object gg : values) { + for (T gg : values) { if (advanced) { try { JSONObject j = new JSONObject(); @@ -652,7 +652,7 @@ public class SchemaBuilder { return "boolean"; } - if (c.equals(String.class) || c.isEnum() || OldEnum.isOldEnum(c) || c.equals(Enchantment.class) || c.equals(PotionEffectType.class)) { + if (c.equals(String.class) || c.isEnum() || KeyedType.isKeyed(c)) { return "string"; } diff --git a/core/src/main/java/com/volmit/iris/util/data/registry/KeyedRegistry.java b/core/src/main/java/com/volmit/iris/util/data/registry/KeyedRegistry.java new file mode 100644 index 000000000..960ff8ca2 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/data/registry/KeyedRegistry.java @@ -0,0 +1,137 @@ +package com.volmit.iris.util.data.registry; + +import com.volmit.iris.util.collection.KMap; +import lombok.NonNull; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +public interface KeyedRegistry { + @NonNull Map map(); + + @Nullable T get(@NonNull NamespacedKey key); + @Nullable NamespacedKey keyOf(@NonNull T value); + + default boolean isEmpty() { + return map().isEmpty(); + } + + @NonNull + default Optional find(@NonNull String @NonNull ... keys) { + if (keys.length == 0) throw new IllegalArgumentException("Need at least one key"); + for (final String key : keys) { + final T t = get(NamespacedKey.minecraft(key)); + if (t != null) { + return Optional.of(t); + } + } + return Optional.empty(); + } + + @NonNull + default Optional find(@NonNull NamespacedKey @NonNull ... keys) { + if (keys.length == 0) throw new IllegalArgumentException("Need at least one key"); + for (final NamespacedKey key : keys) { + final T t = get(key); + if (t != null) { + return Optional.of(t); + } + } + return Optional.empty(); + } + + @Contract(value = "null -> null; !null -> new", pure = true) + static KeyedRegistry wrapped(Map map) { + if (map == null) return null; + return new MappedRegistry<>(map); + } + + @Contract(value = "null -> null; !null -> new", pure = true) + static KeyedRegistry wrapped(Registry registry) { + if (registry == null) return null; + return new BukkitRegistry<>(registry); + } + + @Contract(value = "_ -> new", pure = true) + static KeyedRegistry wrapped(@NonNull Collection<@NonNull KeyedRegistry> registries) { + return new CompoundRegistry<>(registries); + } + + + record MappedRegistry(Map map) implements KeyedRegistry { + @Override + public @Nullable T get(@NonNull NamespacedKey key) { + return map.get(key); + } + + @Override + public @Nullable NamespacedKey keyOf(@NonNull T value) { + return map.entrySet().stream() + .filter(e -> e.getValue().equals(value)) + .map(Map.Entry::getKey) + .findFirst() + .orElse(null); + } + } + + record BukkitRegistry(Registry registry) implements KeyedRegistry { + @Override + public @NonNull Map map() { + return registry.stream().collect(Collectors.toMap(Keyed::getKey, Function.identity())); + } + + @Override + public @Nullable T get(@NonNull NamespacedKey key) { + return registry.get(key); + } + + @Override + public @NonNull NamespacedKey keyOf(@NonNull T value) { + return value.getKey(); + } + } + + record CompoundRegistry(Collection> registries) implements KeyedRegistry { + @Override + public @NonNull Map map() { + final KMap m = new KMap<>(); + for (final KeyedRegistry registry : registries) { + m.put(registry.map()); + } + return m; + } + + @Override + public @Nullable T get(@NonNull NamespacedKey key) { + for (final KeyedRegistry registry : registries) { + final T t = registry.get(key); + if (t != null) { + return t; + } + } + return null; + } + + @Override + public @Nullable NamespacedKey keyOf(@NonNull T value) { + for (final KeyedRegistry registry : registries) { + final NamespacedKey key = registry.keyOf(value); + if (key != null) { + return key; + } + } + return null; + } + + @Override + public boolean isEmpty() { + return registries.isEmpty() || registries.stream().allMatch(KeyedRegistry::isEmpty); + } + } +} diff --git a/core/src/main/java/com/volmit/iris/util/data/registry/RegistryTypeAdapter.java b/core/src/main/java/com/volmit/iris/util/data/registry/RegistryTypeAdapter.java new file mode 100644 index 000000000..c328781b7 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/data/registry/RegistryTypeAdapter.java @@ -0,0 +1,42 @@ +package com.volmit.iris.util.data.registry; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import lombok.NonNull; +import org.bukkit.NamespacedKey; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; + +public class RegistryTypeAdapter extends TypeAdapter { + private final KeyedRegistry registry; + + private RegistryTypeAdapter(KeyedRegistry type) { + this.registry = type; + } + + @Nullable + public static RegistryTypeAdapter of(@NonNull Class type) { + final var registry = RegistryUtil.lookup(type); + return registry.isEmpty() ? null : new RegistryTypeAdapter<>(registry); + } + + @Override + public void write(JsonWriter out, T value) throws IOException { + if (value == null) { + out.nullValue(); + return; + } + + final var key = registry.keyOf(value); + if (key == null) out.nullValue(); + else out.value(key.toString()); + } + + @Override + public T read(JsonReader in) throws IOException { + final NamespacedKey key = NamespacedKey.fromString(in.nextString()); + return key == null ? null : registry.get(key); + } +} diff --git a/core/src/main/java/com/volmit/iris/util/data/registry/RegistryUtil.java b/core/src/main/java/com/volmit/iris/util/data/registry/RegistryUtil.java index b3377ebe8..6119cbdad 100644 --- a/core/src/main/java/com/volmit/iris/util/data/registry/RegistryUtil.java +++ b/core/src/main/java/com/volmit/iris/util/data/registry/RegistryUtil.java @@ -2,6 +2,8 @@ package com.volmit.iris.util.data.registry; import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; import lombok.NonNull; import org.bukkit.Bukkit; import org.bukkit.Keyed; @@ -13,116 +15,78 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; +import static com.volmit.iris.util.data.registry.KeyedRegistry.wrapped; @SuppressWarnings("unchecked") public class RegistryUtil { private static final AtomicCache registryLookup = new AtomicCache<>(); - private static final Map, Map> KEYED_REGISTRY = new HashMap<>(); - private static final Map, Map> ENUM_REGISTRY = new HashMap<>(); - private static final Map, Registry> REGISTRY = new HashMap<>(); + private static final KMap, KeyedRegistry> CACHE = new KMap<>(); @NonNull public static T find(@NonNull Class typeClass, @NonNull String... keys) { - return find(typeClass, defaultLookup(), keys); + return find(typeClass, Arrays.stream(keys).map(NamespacedKey::minecraft).toArray(NamespacedKey[]::new)); } @NonNull - public static T find(@NonNull Class typeClass, @Nullable Lookup lookup, @NonNull String... keys) { - return find(typeClass, lookup, Arrays.stream(keys).map(NamespacedKey::minecraft).toArray(NamespacedKey[]::new)); - } - public static T find(@NonNull Class typeClass, @NonNull NamespacedKey... keys) { - return find(typeClass, defaultLookup(), keys); + return lookup(typeClass).find(keys).orElseThrow(() -> new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys))); } @NonNull - public static T find(@NonNull Class typeClass, @Nullable Lookup lookup, @NonNull NamespacedKey... keys) { - if (keys.length == 0) throw new IllegalArgumentException("Need at least one key"); - Registry registry = null; - if (Keyed.class.isAssignableFrom(typeClass)) { - registry = getRegistry(typeClass.asSubclass(Keyed.class)); - } - if (registry == null) { - registry = REGISTRY.computeIfAbsent(typeClass, t -> Arrays.stream(Registry.class.getDeclaredFields()) - .filter(field -> Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers())) - .filter(field -> Registry.class.isAssignableFrom(field.getType())) - .filter(field -> ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0].equals(t)) - .map(field -> { - try { - return (Registry) field.get(null); - } catch (IllegalAccessException e) { - return null; - } - }) - .filter(Objects::nonNull) - .findFirst() - .orElse(null)); - } + public static KeyedRegistry lookup(@NonNull Class typeClass) { + return (KeyedRegistry) CACHE.computeIfAbsent(typeClass, $ -> { + final var registries = new KList>(); + if (Keyed.class.isAssignableFrom(typeClass)) { + var bukkit = wrapped(getRegistry(typeClass.asSubclass(Keyed.class))); + if (bukkit == null) { + bukkit = Arrays.stream(Registry.class.getDeclaredFields()) + .filter(field -> Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers())) + .filter(field -> Registry.class.isAssignableFrom(field.getType())) + .filter(field -> ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0].equals(typeClass)) + .map(field -> { + try { + return (Registry) field.get(null); + } catch (IllegalAccessException e) { + return null; + } + }) + .filter(Objects::nonNull) + .findFirst() + .map(KeyedRegistry::wrapped) + .orElse(null); + } - if (registry != null) { - for (NamespacedKey key : keys) { - Keyed value = registry.get(key); - if (value != null) - return (T) value; + registries.addNonNull((KeyedRegistry) (Object) bukkit); } - } + registries.add(getKeyedValues(typeClass)); + registries.add(getEnumValues(typeClass)); - if (lookup != null) - return lookup.find(typeClass, keys); - throw new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys)); + return wrapped(registries); + }); } - @NonNull - public static T findByField(@NonNull Class typeClass, @NonNull NamespacedKey... keys) { - var values = KEYED_REGISTRY.computeIfAbsent(typeClass, RegistryUtil::getKeyedValues); - for (NamespacedKey key : keys) { - var value = values.get(key); - if (value != null) - return (T) value; - } - throw new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys)); - } - - @NonNull - public static T findByEnum(@NonNull Class typeClass, @NonNull NamespacedKey... keys) { - var values = ENUM_REGISTRY.computeIfAbsent(typeClass, RegistryUtil::getEnumValues); - for (NamespacedKey key : keys) { - var value = values.get(key); - if (value != null) - return (T) value; - } - throw new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys)); - } - - @NonNull - public static Lookup defaultLookup() { - return Lookup.combine(RegistryUtil::findByField, RegistryUtil::findByEnum); - } - - private static Map getKeyedValues(@NonNull Class typeClass) { - return Arrays.stream(typeClass.getDeclaredFields()) + private static KeyedRegistry getKeyedValues(@NonNull Class typeClass) { + return wrapped(Arrays.stream(typeClass.getDeclaredFields()) .filter(field -> Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) .filter(field -> Keyed.class.isAssignableFrom(field.getType())) .map(field -> { try { - return (Keyed) field.get(null); + final var value = (Keyed) field.get(null); + return new Pair<>(value.getKey(), value); } catch (Throwable e) { return null; } }) .filter(Objects::nonNull) - .collect(Collectors.toMap(Keyed::getKey, Function.identity())); + .collect(Collectors.toMap(Pair::getA, Pair::getB))); } - private static Map getEnumValues(@NonNull Class typeClass) { - return Arrays.stream(typeClass.getDeclaredFields()) + private static KeyedRegistry getEnumValues(@NonNull Class typeClass) { + return wrapped(Arrays.stream(typeClass.getDeclaredFields()) .filter(field -> Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) .filter(field -> typeClass.isAssignableFrom(field.getType())) .map(field -> { @@ -133,28 +97,10 @@ public class RegistryUtil { } }) .filter(Objects::nonNull) - .collect(Collectors.toMap(Pair::getA, Pair::getB)); + .collect(Collectors.toMap(Pair::getA, Pair::getB))); } - @FunctionalInterface - public interface Lookup { - @NonNull - T find(@NonNull Class typeClass, @NonNull NamespacedKey... keys); - - static Lookup combine(@NonNull Lookup... lookups) { - if (lookups.length == 0) throw new IllegalArgumentException("Need at least one lookup"); - return (typeClass, keys) -> { - for (Lookup lookup : lookups) { - try { - return lookup.find(typeClass, keys); - } catch (IllegalArgumentException ignored) {} - } - throw new IllegalArgumentException("No element found for keys: " + Arrays.toString(keys)); - }; - } - } - @Nullable private static Registry getRegistry(@NotNull Class type) { RegistryLookup lookup = registryLookup.aquire(() -> { diff --git a/core/src/main/java/com/volmit/iris/util/reflect/KeyedType.java b/core/src/main/java/com/volmit/iris/util/reflect/KeyedType.java new file mode 100644 index 000000000..1316e7c15 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/reflect/KeyedType.java @@ -0,0 +1,37 @@ +package com.volmit.iris.util.reflect; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.volmit.iris.util.data.registry.RegistryTypeAdapter; +import com.volmit.iris.util.data.registry.RegistryUtil; +import org.bukkit.Keyed; + +public class KeyedType { + private static final boolean KEYED_ENABLED = Boolean.getBoolean("iris.keyed-types"); + private static final boolean KEYED_LENIENT = Boolean.getBoolean("iris.keyed-lenient"); + + public static String[] values(Class type) { + if (!isKeyed(type)) return new String[0]; + if (!KEYED_ENABLED) return OldEnum.values(type); + return RegistryUtil.lookup(type) + .map() + .keySet() + .stream() + .map(Object::toString) + .toArray(String[]::new); + } + + public static boolean isKeyed(Class type) { + if (KEYED_ENABLED) { + if (KEYED_LENIENT) return !RegistryUtil.lookup(type).isEmpty(); + else return Keyed.class.isAssignableFrom(type); + } else return OldEnum.isOldEnum(type); + } + + @SuppressWarnings("unchecked") + public static TypeAdapter createTypeAdapter(Gson gson, TypeToken type) { + if (!isKeyed(type.getRawType())) return null; + return (TypeAdapter) (KEYED_ENABLED ? RegistryTypeAdapter.of(type.getRawType()) : OldEnum.create(type.getRawType())); + } +} diff --git a/core/src/main/java/com/volmit/iris/util/reflect/OldEnum.java b/core/src/main/java/com/volmit/iris/util/reflect/OldEnum.java index 817721aa5..7a7500915 100644 --- a/core/src/main/java/com/volmit/iris/util/reflect/OldEnum.java +++ b/core/src/main/java/com/volmit/iris/util/reflect/OldEnum.java @@ -1,21 +1,22 @@ package com.volmit.iris.util.reflect; import com.google.gson.TypeAdapter; -import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import java.io.IOException; -import java.lang.reflect.Method; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.Objects; -//TODO improve this +@Deprecated(since = "3.7.1") public class OldEnum { private static final Class oldEnum; - private static final Method name; + private static final MethodHandle name; public static boolean exists() { return oldEnum != null; @@ -46,20 +47,20 @@ public class OldEnum { } } - public static Object[] values(Class clazz) { - if (!isOldEnum(clazz)) return new Object[0]; + public static String[] values(Class clazz) { + if (!isOldEnum(clazz)) return new String[0]; return Arrays.stream(clazz.getDeclaredFields()) .filter(f -> Modifier.isStatic(f.getModifiers())) .filter(f -> Modifier.isFinal(f.getModifiers())) .map(f -> { try { - return f.get(null); + return name(f.get(null)); } catch (Throwable ignored) { return null; } }) .filter(Objects::nonNull) - .toArray(); + .toArray(String[]::new); } public static TypeAdapter create(Class type) { @@ -82,10 +83,10 @@ public class OldEnum { static { Class clazz = null; - Method method = null; + MethodHandle method = null; try { clazz = Class.forName("org.bukkit.util.OldEnum"); - method = clazz.getDeclaredMethod("name"); + method = MethodHandles.lookup().findVirtual(clazz, "name", MethodType.methodType(String.class)); } catch (Throwable ignored) {} if (clazz == null || method == null) { From ebe8da0fd5c5c0cc7caac6f06850b8c5c1a24143 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 2 Aug 2025 21:22:44 +0200 Subject: [PATCH 15/15] update slimjar for built-in spigot helper --- core/build.gradle.kts | 4 +- core/src/main/java/com/volmit/iris/Iris.java | 2 +- .../com/volmit/iris/util/misc/SlimJar.java | 133 +++++------------- gradle/libs.versions.toml | 2 +- 4 files changed, 43 insertions(+), 98 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 140281fbb..4eb579b3f 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,4 +1,4 @@ -import io.github.slimjar.func.slimjar +import io.github.slimjar.func.slimjarHelper import io.github.slimjar.resolver.data.Mirror import org.ajoberstar.grgit.Grgit import java.net.URI @@ -67,7 +67,7 @@ dependencies { compileOnly(libs.multiverseCore) // Shaded - implementation(slimjar()) + implementation(slimjarHelper("spigot")) // Dynamically Loaded slim(libs.paralithic) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index f17fec0be..cc6dd888b 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -435,7 +435,7 @@ public class Iris extends VolmitPlugin implements Listener { public Iris() { instance = this; - SlimJar.load(getDataFolder("cache", "libraries")); + SlimJar.load(); } private void enable() { diff --git a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java index 488000bf9..4cee3df77 100644 --- a/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java +++ b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java @@ -1,124 +1,69 @@ package com.volmit.iris.util.misc; import com.volmit.iris.Iris; -import com.volmit.iris.core.nms.container.Pair; -import com.volmit.iris.util.collection.KList; import io.github.slimjar.app.builder.ApplicationBuilder; -import io.github.slimjar.injector.loader.IsolatedInjectableClassLoader; +import io.github.slimjar.app.builder.SpigotApplicationBuilder; import io.github.slimjar.injector.loader.factory.InjectableFactory; import io.github.slimjar.logging.ProcessLogger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.File; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Path; -import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.logging.Logger; + +import static com.volmit.iris.Iris.instance; public class SlimJar { - private static final String NAME = "Iris"; - private static final Logger LOGGER = Logger.getLogger(NAME); private static final boolean DEBUG = Boolean.getBoolean("iris.debug-slimjar"); private static final boolean DISABLE_REMAPPER = Boolean.getBoolean("iris.disable-remapper"); private static final ReentrantLock lock = new ReentrantLock(); private static final AtomicBoolean loaded = new AtomicBoolean(); - public static void load(@Nullable File localRepository) { + public static void load() { if (loaded.get()) return; lock.lock(); try { if (loaded.getAndSet(true)) return; - if (localRepository == null) { - localRepository = new File(".iris/libraries"); + final var downloadPath = instance.getDataFolder("cache", "libraries").toPath(); + final var logger = instance.getLogger(); + + logger.info("Loading libraries..."); + try { + new SpigotApplicationBuilder(instance) + .downloadDirectoryPath(downloadPath) + .debug(DEBUG) + .remap(!DISABLE_REMAPPER) + .build(); + } catch (Throwable e) { + Iris.warn("Failed to inject the library loader, falling back to application builder"); + ApplicationBuilder.appending(instance.getName()) + .injectableFactory(InjectableFactory.selecting(InjectableFactory.ERROR, InjectableFactory.INJECTABLE, InjectableFactory.WRAPPED, InjectableFactory.UNSAFE)) + .downloadDirectoryPath(downloadPath) + .logger(new ProcessLogger() { + @Override + public void info(@NotNull String message, @Nullable Object... args) { + if (!DEBUG) return; + instance.getLogger().info(message.formatted(args)); + } + + @Override + public void error(@NotNull String message, @Nullable Object... args) { + instance.getLogger().severe(message.formatted(args)); + } + + @Override + public void debug(@NotNull String message, @Nullable Object... args) { + if (!DEBUG) return; + instance.getLogger().info(message.formatted(args)); + } + }) + .build(); } - - LOGGER.info("Loading libraries..."); - load(localRepository.toPath(), new ProcessLogger() { - @Override - public void info(@NotNull String message, @Nullable Object... args) { - if (!DEBUG) return; - LOGGER.info(message.formatted(args)); - } - - @Override - public void error(@NotNull String message, @Nullable Object... args) { - LOGGER.severe(message.formatted(args)); - } - - @Override - public void debug(@NotNull String message, @Nullable Object... args) { - if (!DEBUG) return; - LOGGER.info(message.formatted(args)); - } - }); - LOGGER.info("Libraries loaded successfully!"); + logger.info("Libraries loaded successfully!"); } finally { lock.unlock(); } } - - private static void load(Path downloadPath, ProcessLogger logger) { - try { - loadSpigot(downloadPath, logger); - } catch (Throwable e) { - Iris.warn("Failed to inject the library loader, falling back to application builder"); - ApplicationBuilder.appending(NAME) - .injectableFactory(InjectableFactory.selecting(InjectableFactory.ERROR, InjectableFactory.INJECTABLE, InjectableFactory.WRAPPED, InjectableFactory.UNSAFE)) - .downloadDirectoryPath(downloadPath) - .logger(logger) - .build(); - } - } - - private static void loadSpigot(Path downloadPath, ProcessLogger logger) throws Throwable { - var current = SlimJar.class.getClassLoader(); - var libraryLoaderField = current.getClass().getDeclaredField("libraryLoader"); - libraryLoaderField.setAccessible(true); - if (!ClassLoader.class.isAssignableFrom(libraryLoaderField.getType())) throw new IllegalStateException("Failed to find library loader"); - final var libraryLoader = (ClassLoader) libraryLoaderField.get(current); - - final var pair = findRemapper(); - final var remapper = pair.getA(); - final var factory = pair.getB(); - final var classpath = new KList(); - - ApplicationBuilder.injecting(NAME, classpath::add) - .downloadDirectoryPath(downloadPath) - .logger(logger) - .build(); - - final var urls = remapper.andThen(KList::new) - .apply(classpath.convertNasty(url -> Path.of(url.toURI()))) - .convertNasty(path -> path.toUri().toURL()) - .toArray(URL[]::new); - libraryLoaderField.set(current, factory.apply(urls, libraryLoader == null ? current.getParent() : libraryLoader)); - } - - private static Pair, List>, BiFunction> findRemapper() { - Function, List> mapper = null; - BiFunction factory = null; - if (!DISABLE_REMAPPER) { - try { - var libraryLoader = Class.forName("org.bukkit.plugin.java.LibraryLoader"); - var mapperField = libraryLoader.getDeclaredField("REMAPPER"); - var factoryField = libraryLoader.getDeclaredField("LIBRARY_LOADER_FACTORY"); - mapperField.setAccessible(true); - factoryField.setAccessible(true); - mapper = (Function, List>) mapperField.get(null); - factory = (BiFunction) factoryField.get(null); - } catch (Throwable ignored) {} - } - - if (mapper == null) mapper = Function.identity(); - if (factory == null) factory = (urls, parent) -> new IsolatedInjectableClassLoader(urls, List.of(), parent); - return new Pair<>(mapper, factory); - } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b1bbc6e5a..0841ff347 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ [versions] # Plugins shadow = "9.0.0-rc1" # https://plugins.gradle.org/plugin/com.gradleup.shadow -slimjar = "2.1.2" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar +slimjar = "2.1.5" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar download = "5.6.0" # https://plugins.gradle.org/plugin/de.undercouch.download runPaper = "2.3.1" # https://plugins.gradle.org/plugin/xyz.jpenilla.run-paper sentryPlugin = "5.8.0" # https://github.com/getsentry/sentry-android-gradle-plugin