From 9c151abac781b046e741c1cb62f31388a3662493 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 10 Apr 2025 16:26:58 +0200 Subject: [PATCH 01/66] replace world load context injection with bytecode injections --- build.gradle | 10 + core/src/main/java/com/volmit/iris/Iris.java | 4 - .../com/volmit/iris/core/nms/INMSBinding.java | 27 +-- .../iris/core/nms/v1X/NMSBinding1X.java | 14 +- .../iris/core/safeguard/ServerBootSFG.java | 58 ++++- .../volmit/iris/core/safeguard/UtilsSFG.java | 5 + .../engine/object/IrisContextInjector.java | 66 ------ .../engine/platform/BukkitChunkGenerator.java | 1 - .../com/volmit/iris/util/agent/Agent.java | 41 ++++ .../com/volmit/iris/util/agent/Installer.java | 29 +++ core/src/main/resources/plugin.yml | 2 + .../iris/core/nms/v1_20_R1/NMSBinding.java | 201 +++++++++--------- .../iris/core/nms/v1_20_R2/NMSBinding.java | 198 ++++++++--------- .../iris/core/nms/v1_20_R3/NMSBinding.java | 198 ++++++++--------- .../iris/core/nms/v1_20_R4/NMSBinding.java | 195 +++++++++-------- .../iris/core/nms/v1_21_R1/NMSBinding.java | 199 ++++++++--------- .../iris/core/nms/v1_21_R2/NMSBinding.java | 190 +++++++++-------- .../iris/core/nms/v1_21_R3/NMSBinding.java | 190 +++++++++-------- 18 files changed, 861 insertions(+), 767 deletions(-) delete mode 100644 core/src/main/java/com/volmit/iris/engine/object/IrisContextInjector.java create mode 100644 core/src/main/java/com/volmit/iris/util/agent/Agent.java create mode 100644 core/src/main/java/com/volmit/iris/util/agent/Installer.java diff --git a/build.gradle b/build.gradle index ebe09d7d8..c7370bc97 100644 --- a/build.gradle +++ b/build.gradle @@ -97,6 +97,7 @@ NMS_BINDINGS.forEach { key, value -> systemProperty("disable.watchdog", "") systemProperty("net.kyori.ansi.colorLevel", COLOR) systemProperty("com.mojang.eula.agree", true) + jvmArgs("-javaagent:${tasks.shadowJar.archiveFile.get().asFile.absolutePath}") } } @@ -113,6 +114,12 @@ shadowJar { relocate 'net.kyori', 'com.volmit.iris.util.kyori' relocate 'org.bstats', 'com.volmit.util.metrics' archiveFileName.set("Iris-${project.version}.jar") + manifest.attributes( + 'Agent-Class': 'com.volmit.iris.util.agent.Installer', + 'Premain-Class': 'com.volmit.iris.util.agent.Installer', + 'Can-Redefine-Classes': true, + 'Can-Retransform-Classes': true + ) } dependencies { @@ -173,6 +180,9 @@ allprojects { compileOnly 'com.github.ben-manes.caffeine:caffeine:3.0.6' compileOnly 'org.apache.commons:commons-lang3:3.12.0' compileOnly 'com.github.oshi:oshi-core:6.6.5' + + compileOnly("net.bytebuddy:byte-buddy:1.17.5") + compileOnly("net.bytebuddy:byte-buddy-agent:1.17.5") } /** diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 07e01c6e4..e059b30e1 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -32,10 +32,8 @@ import com.volmit.iris.core.nms.v1X.NMSBinding1X; import com.volmit.iris.core.pregenerator.LazyPregenerator; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.tools.IrisToolbelt; -import com.volmit.iris.core.tools.IrisWorldCreator; import com.volmit.iris.engine.EnginePanic; import com.volmit.iris.engine.object.IrisCompat; -import com.volmit.iris.engine.object.IrisContextInjector; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisWorld; import com.volmit.iris.engine.platform.BukkitChunkGenerator; @@ -457,11 +455,9 @@ public class Iris extends VolmitPlugin implements Listener { services = new KMap<>(); setupAudience(); initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class) i.getClass(), (IrisService) i)); - INMS.get(); IO.delete(new File("iris")); compat = IrisCompat.configured(getDataFile("compat.json")); ServerConfigurator.configure(); - new IrisContextInjector(); IrisSafeguard.IrisSafeguardSystem(); getSender().setTag(getTag()); IrisSafeguard.earlySplash(); 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 1b881e6fe..8c57cb625 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,7 +18,6 @@ package com.volmit.iris.core.nms; -import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.engine.framework.Engine; @@ -89,13 +88,10 @@ public interface INMSBinding { MCABiomeContainer newBiomeContainer(int min, int max); default World createWorld(WorldCreator c) { - if (missingDimensionTypes(true, true, true)) + if (missingDimensionTypes(c.environment())) throw new IllegalStateException("Missing dimenstion types to create world"); - try (var ignored = injectLevelStems()) { - ignored.storeContext(); - return c.createWorld(); - } + return c.createWorld(); } int countCustomBiomes(); @@ -130,13 +126,20 @@ public interface INMSBinding { KList getStructureKeys(); - AutoClosing injectLevelStems(); - - default AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) { - return null; - } + KMap getMainWorlds(); boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end); - void removeCustomDimensions(World world); + default boolean missingDimensionTypes(World.Environment env) { + return switch (env) { + case NORMAL -> missingDimensionTypes(true, false, false); + case NETHER -> missingDimensionTypes(false, true, false); + case THE_END -> missingDimensionTypes(false, false, true); + default -> true; + }; + } + + default boolean injectBukkit() { + return true; + } } 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 a5ace2486..90e68c549 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 @@ -121,13 +121,8 @@ public class NMSBinding1X implements INMSBinding { } @Override - public AutoClosing injectLevelStems() { - return new AutoClosing(() -> {}); - } - - @Override - public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) { - return injectLevelStems(); + public KMap getMainWorlds() { + return new KMap<>(); } @Override @@ -135,11 +130,6 @@ public class NMSBinding1X implements INMSBinding { return false; } - @Override - public void removeCustomDimensions(World world) { - - } - @Override public CompoundTag serializeEntity(Entity location) { return null; 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 2c59c2ae9..9ee9a4d2e 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 @@ -3,8 +3,12 @@ package com.volmit.iris.core.safeguard; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.v1X.NMSBinding1X; -import com.volmit.iris.engine.object.IrisContextInjector; +import com.volmit.iris.util.agent.Agent; +import com.volmit.iris.util.misc.ServerProperties; import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import javax.tools.JavaCompiler; @@ -15,10 +19,8 @@ import java.nio.file.Files; 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; +import java.util.*; +import java.util.function.Predicate; import static com.volmit.iris.Iris.getJavaVersion; import static com.volmit.iris.core.safeguard.IrisSafeguard.*; @@ -31,6 +33,8 @@ public class ServerBootSFG { public static boolean hasPrivileges = true; public static boolean unsuportedversion = false; public static boolean missingDimensionTypes = false; + public static boolean missingAgent = false; + public static boolean failedInjection = false; protected static boolean safeguardPassed; public static boolean passedserversoftware = true; protected static int count; @@ -112,10 +116,21 @@ public class ServerBootSFG { severityMedium++; } - if (IrisContextInjector.isMissingDimensionTypes()) { - missingDimensionTypes = true; - joiner.add("Missing Dimension Types"); + if (!Agent.install()) { + missingAgent = true; + joiner.add("Missing Java Agent"); severityHigh++; + } else { + if (missingDimensionTypes()) { + missingDimensionTypes = true; + joiner.add("Missing Dimension Types"); + severityHigh++; + } + if (!INMS.get().injectBukkit()) { + failedInjection = true; + joiner.add("Failed Bukkit Injection"); + severityHigh++; + } } allIncompatibilities = joiner.toString(); @@ -173,4 +188,31 @@ public class ServerBootSFG { return !path.isEmpty() && (new File(path, "javac").exists() || new File(path, "javac.exe").exists()); } + private static boolean missingDimensionTypes() { + var irisWorlds = irisWorlds(); + if (irisWorlds.isEmpty()) return false; + + var worlds = INMS.get().getMainWorlds(); + worlds.keySet().removeIf(Predicate.not(irisWorlds::contains)); + + boolean overworld = worlds.containsValue(World.Environment.NORMAL) || worlds.containsValue(World.Environment.CUSTOM); + boolean nether = worlds.containsValue(World.Environment.NETHER); + boolean end = worlds.containsValue(World.Environment.THE_END); + + if (overworld || nether || end) + return INMS.get().missingDimensionTypes(overworld, nether, end); + return false; + } + + private static List irisWorlds() { + var config = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML); + ConfigurationSection section = config.getConfigurationSection("worlds"); + if (section == null) return List.of(); + + return section.getKeys(false) + .stream() + .filter(k -> section.getString(k + ".generator", "").startsWith("Iris")) + .toList(); + } + } 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 c45cfc7bb..e3deb6f2b 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 @@ -44,6 +44,11 @@ public class UtilsSFG { Iris.safeguard(C.RED + "- Required Iris dimension types were not loaded."); Iris.safeguard(C.RED + "- If this still happens after a restart please contact support."); } + if (ServerBootSFG.missingAgent) { + Iris.safeguard(C.RED + "Java Agent"); + Iris.safeguard(C.RED + "- Please enable dynamic agent loading by adding -XX:+EnableDynamicAgentLoading to your jvm arguments."); + Iris.safeguard(C.RED + "- or add the jvm argument -javaagent:plugins/" + Iris.instance.getJarFile().getName()); + } if (!ServerBootSFG.passedserversoftware) { Iris.safeguard(C.YELLOW + "Unsupported Server Software"); Iris.safeguard(C.YELLOW + "- Please consider using Paper or Purpur instead."); diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisContextInjector.java b/core/src/main/java/com/volmit/iris/engine/object/IrisContextInjector.java deleted file mode 100644 index 415dd7ec8..000000000 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisContextInjector.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.volmit.iris.engine.object; - -import com.volmit.iris.core.nms.INMS; -import com.volmit.iris.core.nms.container.AutoClosing; -import com.volmit.iris.util.collection.KList; -import com.volmit.iris.util.misc.ServerProperties; -import lombok.Getter; -import org.bukkit.Bukkit; -import org.bukkit.NamespacedKey; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.world.WorldInitEvent; - -import java.util.List; - -import static com.volmit.iris.Iris.instance; - -public class IrisContextInjector implements Listener { - @Getter - private static boolean missingDimensionTypes = false; - private AutoClosing autoClosing = null; - - public IrisContextInjector() { - if (!Bukkit.getWorlds().isEmpty()) return; - - String levelName = ServerProperties.LEVEL_NAME; - List irisWorlds = irisWorlds(); - boolean overworld = irisWorlds.contains(levelName); - boolean nether = irisWorlds.contains(levelName + "_nether"); - boolean end = irisWorlds.contains(levelName + "_end"); - - if (INMS.get().missingDimensionTypes(overworld, nether, end)) { - missingDimensionTypes = true; - return; - } - - if (overworld || nether || end) { - autoClosing = INMS.get().injectUncached(overworld, nether, end); - } - - instance.registerListener(this); - } - - @EventHandler(priority = EventPriority.LOWEST) - public void on(WorldInitEvent event) { - if (autoClosing != null) { - autoClosing.close(); - autoClosing = null; - } - instance.unregisterListener(this); - } - - private List irisWorlds() { - var config = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML); - ConfigurationSection section = config.getConfigurationSection("worlds"); - if (section == null) return List.of(); - - return section.getKeys(false) - .stream() - .filter(k -> section.getString(k + ".generator", "").startsWith("Iris")) - .toList(); - } -} diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index 90117a5a4..4285dd799 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -130,7 +130,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun if (initialized || !world.name().equals(event.getWorld().getName())) return; AutoClosing.closeContext(); - INMS.get().removeCustomDimensions(event.getWorld()); world.setRawWorldSeed(event.getWorld().getSeed()); Engine engine = getEngine(event.getWorld()); if (engine == null) { diff --git a/core/src/main/java/com/volmit/iris/util/agent/Agent.java b/core/src/main/java/com/volmit/iris/util/agent/Agent.java new file mode 100644 index 000000000..009923b30 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/agent/Agent.java @@ -0,0 +1,41 @@ +package com.volmit.iris.util.agent; + +import com.volmit.iris.Iris; +import net.bytebuddy.agent.ByteBuddyAgent; +import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; + +import java.lang.instrument.Instrumentation; + +public class Agent { + private static final String NAME = "com.volmit.iris.util.agent.Installer"; + + public static ClassReloadingStrategy installed() { + return ClassReloadingStrategy.of(getInstrumentation()); + } + + public static Instrumentation getInstrumentation() { + Instrumentation instrumentation = doGetInstrumentation(); + if (instrumentation == null) throw new IllegalStateException("The agent is not initialized or unavailable"); + return instrumentation; + } + + public static boolean install() { + if (doGetInstrumentation() != null) + return true; + try { + Iris.info("Installing Java Agent..."); + ByteBuddyAgent.attach(Iris.instance.getJarFile(), ByteBuddyAgent.ProcessProvider.ForCurrentVm.INSTANCE); + } catch (Throwable e) { + e.printStackTrace(); + } + return doGetInstrumentation() != null; + } + + private static Instrumentation doGetInstrumentation() { + try { + return (Instrumentation) Class.forName(NAME, true, ClassLoader.getSystemClassLoader()).getMethod("getInstrumentation").invoke(null); + } catch (Exception ex) { + return null; + } + } +} diff --git a/core/src/main/java/com/volmit/iris/util/agent/Installer.java b/core/src/main/java/com/volmit/iris/util/agent/Installer.java new file mode 100644 index 000000000..3c68fd579 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/agent/Installer.java @@ -0,0 +1,29 @@ +package com.volmit.iris.util.agent; + +import java.lang.instrument.Instrumentation; + +public class Installer { + private static volatile Instrumentation instrumentation; + + public static Instrumentation getInstrumentation() { + Instrumentation instrumentation = Installer.instrumentation; + if (instrumentation == null) { + throw new IllegalStateException("The agent is not loaded or this method is not called via the system class loader"); + } + return instrumentation; + } + + public static void premain(String arguments, Instrumentation instrumentation) { + doMain(instrumentation); + } + + public static void agentmain(String arguments, Instrumentation instrumentation) { + doMain(instrumentation); + } + + private static synchronized void doMain(Instrumentation instrumentation) { + if (Installer.instrumentation != null) + return; + Installer.instrumentation = instrumentation; + } +} \ No newline at end of file diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml index 7ff73ff7e..aa75fc983 100644 --- a/core/src/main/resources/plugin.yml +++ b/core/src/main/resources/plugin.yml @@ -20,6 +20,8 @@ libraries: - bsf:bsf:2.4.0 - org.lz4:lz4-java:1.8.0 - com.github.oshi:oshi-core:6.6.5 + - net.bytebuddy:byte-buddy:1.17.5 + - net.bytebuddy:byte-buddy-agent:1.17.5 commands: iris: aliases: [ ir, irs ] 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 8f974008b..f096e5a78 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 @@ -2,27 +2,30 @@ package com.volmit.iris.core.nms.v1_20_R1; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Lifecycle; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMSBinding; -import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.util.agent.Agent; 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.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.misc.ServerProperties; 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 com.volmit.iris.util.scheduling.J; import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.SneakyThrows; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatchers; import net.minecraft.core.*; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; @@ -31,13 +34,12 @@ import net.minecraft.nbt.Tag; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.WorldLoader; import net.minecraft.server.commands.data.BlockDataAccessor; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.tags.TagKey; -import net.minecraft.world.entity.EntityDimensions; +import net.minecraft.world.RandomSequences; import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -52,6 +54,8 @@ import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +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; @@ -63,31 +67,23 @@ import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; -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; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import sun.misc.Unsafe; import java.awt.Color; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; public class NMSBinding implements INMSBinding { @@ -95,11 +91,11 @@ 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 dataLoadContext = new AtomicCache<>(); + private final AtomicBoolean injected = new AtomicBoolean(); private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final ReentrantLock dataContextLock = new ReentrantLock(true); + private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -645,44 +641,28 @@ public class NMSBinding implements INMSBinding { } @Override - @SneakyThrows - public AutoClosing injectLevelStems() { - if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!"); + @SuppressWarnings("all") + public KMap getMainWorlds() { + String levelName = ServerProperties.LEVEL_NAME; + KMap worlds = new KMap<>(); + for (var key : registry().registryOrThrow(Registries.LEVEL_STEM).registryKeySet()) { + World.Environment env = World.Environment.NORMAL; + if (key == LevelStem.NETHER) { + if (!Bukkit.getAllowNether()) + continue; + env = World.Environment.NETHER; + } else if (key == LevelStem.END) { + if (!Bukkit.getAllowEnd()) + continue; + env = World.Environment.THE_END; + } else if (key != LevelStem.OVERWORLD) { + env = World.Environment.CUSTOM; + } - var server = ((CraftServer) Bukkit.getServer()); - var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class); - var nmsServer = server.getServer(); - var old = nmsServer.worldLoader; - - field.setAccessible(true); - field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext( - old.resources(), - old.dataConfiguration(), - old.datapackWorldgen(), - createRegistryAccess(old.datapackDimensions(), false, true, true, true) - ))); - - return new AutoClosing(() -> { - field.set(nmsServer, old); - dataContextLock.unlock(); - }); - } - - @Override - @SneakyThrows - public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) { - var reg = registry(); - var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class); - field.setAccessible(true); - - var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end); - var injected = access.registryOrThrow(Registries.LEVEL_STEM); - var old = (Map>, Registry>) field.get(reg); - var fake = new HashMap<>(old); - fake.put(Registries.LEVEL_STEM, injected); - field.set(reg, fake); - - return new AutoClosing(() -> field.set(reg, old)); + String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); + worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); + } + return worlds; } @Override @@ -695,53 +675,74 @@ public class NMSBinding implements INMSBinding { } @Override - public void removeCustomDimensions(World world) { - ((CraftWorld) world).getHandle().K.customDimensions = null; - } - - private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) { - var access = registry(); - var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE); - - var settings = new FlatLevelGeneratorSettings( - Optional.empty(), - access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID), - List.of() - ); - settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); - settings.updateLayers(); - - var source = new FlatLevelSource(settings); - var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental()); - if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD); - if (nether) register(fake, dimensions, source, LevelStem.NETHER); - if (end) register(fake, dimensions, source, LevelStem.END); - copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null)); - - if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM)); - - return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze(); - } - - private void register(MappedRegistry target, Registry dimensions, FlatLevelSource source, ResourceKey key) { - var loc = createIrisKey(key); - target.register(key, new LevelStem( - dimensions.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, loc)).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())), - source - ), Lifecycle.stable()); - } - - private void copy(MappedRegistry target, Registry source) { - if (source == null) return; - source.registryKeySet().forEach(key -> { - var value = source.get(key); - var info = source.lifecycle(value); - if (value != null && info != null && !target.containsKey(key)) - target.register(key, value, info); - }); + public boolean injectBukkit() { + if (injected.getAndSet(true)) + return true; + try { + Iris.info("Injecting Bukkit"); + 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(), Agent.installed()); + return true; + } catch (Throwable e) { + Iris.error(C.RED + "Failed to inject Bukkit"); + e.printStackTrace(); + } + return false; } private ResourceLocation createIrisKey(ResourceKey key) { return new ResourceLocation("iris", key.location().getPath()); } + + public LevelStem levelStem(RegistryAccess access, World.Environment env) { + if (env == World.Environment.CUSTOM) + env = World.Environment.NORMAL; + return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); + } + + private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { + return access.registryOrThrow(Registries.DIMENSION_TYPE).getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", switch (env) { + case NORMAL, CUSTOM -> "overworld"; + case NETHER -> "the_nether"; + case THE_END -> "the_end"; + }))); + } + + private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { + var settings = new FlatLevelGeneratorSettings(Optional.empty(), access.registryOrThrow(Registries.BIOME).getHolderOrThrow(Biomes.THE_VOID), List.of()); + settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); + settings.updateLayers(); + return new FlatLevelSource(settings); + } + + private static class ServerLevelAdvice { + @SneakyThrows + @Advice.OnMethodEnter + static void enter( + @Advice.Argument(0) MinecraftServer server, + @Advice.Argument(3) PrimaryLevelData levelData, + @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem, + @Advice.Argument(12) World.Environment env, + @Advice.Argument(value = 13) ChunkGenerator gen + ) { + if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) + return; + + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) + .invoke(bindings, server.registryAccess(), env); + levelData.customDimensions = null; + } + } } 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 c68a8a19e..dbba77c83 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 @@ -1,32 +1,33 @@ package com.volmit.iris.core.nms.v1_20_R2; import java.awt.Color; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Lifecycle; -import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; +import com.volmit.iris.util.agent.Agent; +import com.volmit.iris.util.format.C; +import com.volmit.iris.util.misc.ServerProperties; import com.volmit.iris.util.scheduling.J; import lombok.SneakyThrows; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatchers; import net.minecraft.core.*; import net.minecraft.core.Registry; import net.minecraft.nbt.*; import net.minecraft.nbt.Tag; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.WorldLoader; import net.minecraft.server.commands.data.BlockDataAccessor; +import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.tags.TagKey; +import net.minecraft.world.RandomSequences; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Blocks; @@ -36,6 +37,8 @@ import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +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; @@ -45,12 +48,11 @@ import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_20_R2.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R2.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.Contract; @@ -68,7 +70,6 @@ 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; @@ -79,24 +80,22 @@ 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.ChunkStatus; 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 dataLoadContext = new AtomicCache<>(); + private final AtomicBoolean injected = new AtomicBoolean(); private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final ReentrantLock dataContextLock = new ReentrantLock(true); + private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -646,44 +645,28 @@ public class NMSBinding implements INMSBinding { } @Override - @SneakyThrows - public AutoClosing injectLevelStems() { - if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!"); + @SuppressWarnings("all") + public KMap getMainWorlds() { + String levelName = ServerProperties.LEVEL_NAME; + KMap worlds = new KMap<>(); + for (var key : registry().registryOrThrow(Registries.LEVEL_STEM).registryKeySet()) { + World.Environment env = World.Environment.NORMAL; + if (key == LevelStem.NETHER) { + if (!Bukkit.getAllowNether()) + continue; + env = World.Environment.NETHER; + } else if (key == LevelStem.END) { + if (!Bukkit.getAllowEnd()) + continue; + env = World.Environment.THE_END; + } else if (key != LevelStem.OVERWORLD) { + env = World.Environment.CUSTOM; + } - var server = ((CraftServer) Bukkit.getServer()); - var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class); - var nmsServer = server.getServer(); - var old = nmsServer.worldLoader; - - field.setAccessible(true); - field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext( - old.resources(), - old.dataConfiguration(), - old.datapackWorldgen(), - createRegistryAccess(old.datapackDimensions(), false, true, true, true) - ))); - - return new AutoClosing(() -> { - field.set(nmsServer, old); - dataContextLock.unlock(); - }); - } - - @Override - @SneakyThrows - public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) { - var reg = registry(); - var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class); - field.setAccessible(true); - - var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end); - var injected = access.registryOrThrow(Registries.LEVEL_STEM); - var old = (Map>, Registry>) field.get(reg); - var fake = new HashMap<>(old); - fake.put(Registries.LEVEL_STEM, injected); - field.set(reg, fake); - - return new AutoClosing(() -> field.set(reg, old)); + String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); + worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); + } + return worlds; } @Override @@ -696,53 +679,74 @@ public class NMSBinding implements INMSBinding { } @Override - public void removeCustomDimensions(World world) { - ((CraftWorld) world).getHandle().K.customDimensions = null; - } - - private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) { - var access = registry(); - var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE); - - var settings = new FlatLevelGeneratorSettings( - Optional.empty(), - access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID), - List.of() - ); - settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); - settings.updateLayers(); - - var source = new FlatLevelSource(settings); - var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental()); - if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD); - if (nether) register(fake, dimensions, source, LevelStem.NETHER); - if (end) register(fake, dimensions, source, LevelStem.END); - copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null)); - - if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM)); - - return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze(); - } - - private void register(MappedRegistry target, Registry dimensions, FlatLevelSource source, ResourceKey key) { - var loc = createIrisKey(key); - target.register(key, new LevelStem( - dimensions.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, loc)).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())), - source - ), Lifecycle.stable()); - } - - private void copy(MappedRegistry target, Registry source) { - if (source == null) return; - source.registryKeySet().forEach(key -> { - var value = source.get(key); - var info = source.lifecycle(value); - if (value != null && info != null && !target.containsKey(key)) - target.register(key, value, info); - }); + public boolean injectBukkit() { + if (injected.getAndSet(true)) + return true; + try { + Iris.info("Injecting Bukkit"); + 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(), Agent.installed()); + return true; + } catch (Throwable e) { + Iris.error(C.RED + "Failed to inject Bukkit"); + e.printStackTrace(); + } + return false; } private ResourceLocation createIrisKey(ResourceKey key) { return new ResourceLocation("iris", key.location().getPath()); } + + public LevelStem levelStem(RegistryAccess access, World.Environment env) { + if (env == World.Environment.CUSTOM) + env = World.Environment.NORMAL; + return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); + } + + private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { + return access.registryOrThrow(Registries.DIMENSION_TYPE).getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", switch (env) { + case NORMAL, CUSTOM -> "overworld"; + case NETHER -> "the_nether"; + case THE_END -> "the_end"; + }))); + } + + private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { + var settings = new FlatLevelGeneratorSettings(Optional.empty(), access.registryOrThrow(Registries.BIOME).getHolderOrThrow(Biomes.THE_VOID), List.of()); + settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); + settings.updateLayers(); + return new FlatLevelSource(settings); + } + + private static class ServerLevelAdvice { + @SneakyThrows + @Advice.OnMethodEnter + static void enter( + @Advice.Argument(0) MinecraftServer server, + @Advice.Argument(3) PrimaryLevelData levelData, + @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem, + @Advice.Argument(12) World.Environment env, + @Advice.Argument(value = 13) ChunkGenerator gen + ) { + if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) + return; + + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) + .invoke(bindings, server.registryAccess(), env); + levelData.customDimensions = null; + } + } } 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 2d0e08931..18d4c724c 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 @@ -1,32 +1,33 @@ package com.volmit.iris.core.nms.v1_20_R3; import java.awt.Color; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Lifecycle; -import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; +import com.volmit.iris.util.agent.Agent; +import com.volmit.iris.util.format.C; +import com.volmit.iris.util.misc.ServerProperties; import com.volmit.iris.util.scheduling.J; import lombok.SneakyThrows; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatchers; import net.minecraft.core.*; import net.minecraft.core.Registry; import net.minecraft.nbt.*; import net.minecraft.nbt.Tag; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.WorldLoader; import net.minecraft.server.commands.data.BlockDataAccessor; +import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.tags.TagKey; +import net.minecraft.world.RandomSequences; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Blocks; @@ -36,6 +37,8 @@ import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +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; @@ -45,12 +48,11 @@ import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R3.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.Contract; @@ -68,7 +70,6 @@ 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; @@ -79,24 +80,22 @@ 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.ChunkStatus; 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 dataLoadContext = new AtomicCache<>(); + private final AtomicBoolean injected = new AtomicBoolean(); private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final ReentrantLock dataContextLock = new ReentrantLock(true); + private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -647,44 +646,28 @@ public class NMSBinding implements INMSBinding { } @Override - @SneakyThrows - public AutoClosing injectLevelStems() { - if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!"); + @SuppressWarnings("all") + public KMap getMainWorlds() { + String levelName = ServerProperties.LEVEL_NAME; + KMap worlds = new KMap<>(); + for (var key : registry().registryOrThrow(Registries.LEVEL_STEM).registryKeySet()) { + World.Environment env = World.Environment.NORMAL; + if (key == LevelStem.NETHER) { + if (!Bukkit.getAllowNether()) + continue; + env = World.Environment.NETHER; + } else if (key == LevelStem.END) { + if (!Bukkit.getAllowEnd()) + continue; + env = World.Environment.THE_END; + } else if (key != LevelStem.OVERWORLD) { + env = World.Environment.CUSTOM; + } - var server = ((CraftServer) Bukkit.getServer()); - var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class); - var nmsServer = server.getServer(); - var old = nmsServer.worldLoader; - - field.setAccessible(true); - field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext( - old.resources(), - old.dataConfiguration(), - old.datapackWorldgen(), - createRegistryAccess(old.datapackDimensions(), false, true, true, true) - ))); - - return new AutoClosing(() -> { - field.set(nmsServer, old); - dataContextLock.unlock(); - }); - } - - @Override - @SneakyThrows - public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) { - var reg = registry(); - var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class); - field.setAccessible(true); - - var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end); - var injected = access.registryOrThrow(Registries.LEVEL_STEM); - var old = (Map>, Registry>) field.get(reg); - var fake = new HashMap<>(old); - fake.put(Registries.LEVEL_STEM, injected); - field.set(reg, fake); - - return new AutoClosing(() -> field.set(reg, old)); + String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); + worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); + } + return worlds; } @Override @@ -697,53 +680,74 @@ public class NMSBinding implements INMSBinding { } @Override - public void removeCustomDimensions(World world) { - ((CraftWorld) world).getHandle().K.customDimensions = null; - } - - private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) { - var access = registry(); - var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE); - - var settings = new FlatLevelGeneratorSettings( - Optional.empty(), - access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID), - List.of() - ); - settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); - settings.updateLayers(); - - var source = new FlatLevelSource(settings); - var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental()); - if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD); - if (nether) register(fake, dimensions, source, LevelStem.NETHER); - if (end) register(fake, dimensions, source, LevelStem.END); - copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null)); - - if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM)); - - return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze(); - } - - private void register(MappedRegistry target, Registry dimensions, FlatLevelSource source, ResourceKey key) { - var loc = createIrisKey(key); - target.register(key, new LevelStem( - dimensions.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, loc)).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())), - source - ), Lifecycle.stable()); - } - - private void copy(MappedRegistry target, Registry source) { - if (source == null) return; - source.registryKeySet().forEach(key -> { - var value = source.get(key); - var info = source.lifecycle(value); - if (value != null && info != null && !target.containsKey(key)) - target.register(key, value, info); - }); + public boolean injectBukkit() { + if (injected.getAndSet(true)) + return true; + try { + Iris.info("Injecting Bukkit"); + 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(), Agent.installed()); + return true; + } catch (Throwable e) { + Iris.error(C.RED + "Failed to inject Bukkit"); + e.printStackTrace(); + } + return false; } private ResourceLocation createIrisKey(ResourceKey key) { return new ResourceLocation("iris", key.location().getPath()); } + + public LevelStem levelStem(RegistryAccess access, World.Environment env) { + if (env == World.Environment.CUSTOM) + env = World.Environment.NORMAL; + return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); + } + + private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { + return access.registryOrThrow(Registries.DIMENSION_TYPE).getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", switch (env) { + case NORMAL, CUSTOM -> "overworld"; + case NETHER -> "the_nether"; + case THE_END -> "the_end"; + }))); + } + + private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { + var settings = new FlatLevelGeneratorSettings(Optional.empty(), access.registryOrThrow(Registries.BIOME).getHolderOrThrow(Biomes.THE_VOID), List.of()); + settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); + settings.updateLayers(); + return new FlatLevelSource(settings); + } + + private static class ServerLevelAdvice { + @SneakyThrows + @Advice.OnMethodEnter + static void enter( + @Advice.Argument(0) MinecraftServer server, + @Advice.Argument(3) PrimaryLevelData levelData, + @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem, + @Advice.Argument(12) World.Environment env, + @Advice.Argument(value = 13) ChunkGenerator gen + ) { + if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) + return; + + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) + .invoke(bindings, server.registryAccess(), env); + levelData.customDimensions = null; + } + } } 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 index ec076e7df..1e6b0e465 100644 --- 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 @@ -5,18 +5,22 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Lifecycle; -import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; +import com.volmit.iris.util.agent.Agent; +import com.volmit.iris.util.format.C; +import com.volmit.iris.util.misc.ServerProperties; import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.scheduling.J; import lombok.SneakyThrows; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatchers; import net.minecraft.core.*; import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponents; @@ -31,23 +35,24 @@ import net.minecraft.nbt.ShortTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.WorldLoader; import net.minecraft.server.commands.data.BlockDataAccessor; -import net.minecraft.server.commands.data.DataCommands; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.tags.TagKey; +import net.minecraft.world.RandomSequences; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.entity.BlockEntityType; 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.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +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; @@ -56,15 +61,12 @@ import org.bukkit.craftbukkit.v1_20_R4.CraftServer; import org.bukkit.craftbukkit.v1_20_R4.CraftWorld; import org.bukkit.craftbukkit.v1_20_R4.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R4.block.CraftBlockStates; -import org.bukkit.craftbukkit.v1_20_R4.block.CraftBlockType; 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.generator.CustomChunkGenerator; 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.Contract; @@ -100,11 +102,11 @@ 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 dataLoadContext = new AtomicCache<>(); + private final AtomicBoolean injected = new AtomicBoolean(); private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final ReentrantLock dataContextLock = new ReentrantLock(true); + private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -672,44 +674,28 @@ public class NMSBinding implements INMSBinding { } @Override - @SneakyThrows - public AutoClosing injectLevelStems() { - if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!"); + @SuppressWarnings("all") + public KMap getMainWorlds() { + String levelName = ServerProperties.LEVEL_NAME; + KMap worlds = new KMap<>(); + for (var key : registry().registryOrThrow(Registries.LEVEL_STEM).registryKeySet()) { + World.Environment env = World.Environment.NORMAL; + if (key == LevelStem.NETHER) { + if (!Bukkit.getAllowNether()) + continue; + env = World.Environment.NETHER; + } else if (key == LevelStem.END) { + if (!Bukkit.getAllowEnd()) + continue; + env = World.Environment.THE_END; + } else if (key != LevelStem.OVERWORLD) { + env = World.Environment.CUSTOM; + } - var server = ((CraftServer) Bukkit.getServer()); - var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class); - var nmsServer = server.getServer(); - var old = nmsServer.worldLoader; - - field.setAccessible(true); - field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext( - old.resources(), - old.dataConfiguration(), - old.datapackWorldgen(), - createRegistryAccess(old.datapackDimensions(), false, true, true, true) - ))); - - return new AutoClosing(() -> { - field.set(nmsServer, old); - dataContextLock.unlock(); - }); - } - - @Override - @SneakyThrows - public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) { - var reg = registry(); - var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class); - field.setAccessible(true); - - var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end); - var injected = access.registryOrThrow(Registries.LEVEL_STEM); - var old = (Map>, Registry>) field.get(reg); - var fake = new HashMap<>(old); - fake.put(Registries.LEVEL_STEM, injected); - field.set(reg, fake); - - return new AutoClosing(() -> field.set(reg, old)); + String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); + worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); + } + return worlds; } @Override @@ -722,53 +708,74 @@ public class NMSBinding implements INMSBinding { } @Override - public void removeCustomDimensions(World world) { - ((CraftWorld) world).getHandle().K.customDimensions = null; - } - - private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) { - var access = registry(); - var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE); - - var settings = new FlatLevelGeneratorSettings( - Optional.empty(), - access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID), - List.of() - ); - settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); - settings.updateLayers(); - - var source = new FlatLevelSource(settings); - var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental()); - if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD); - if (nether) register(fake, dimensions, source, LevelStem.NETHER); - if (end) register(fake, dimensions, source, LevelStem.END); - copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null)); - - if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM)); - - return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze(); - } - - private void register(MappedRegistry target, Registry dimensions, FlatLevelSource source, ResourceKey key) { - var loc = createIrisKey(key); - target.register(key, new LevelStem( - dimensions.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, loc)).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())), - source - ), RegistrationInfo.BUILT_IN); - } - - private void copy(MappedRegistry target, Registry source) { - if (source == null) return; - source.registryKeySet().forEach(key -> { - var value = source.get(key); - var info = source.registrationInfo(key).orElse(null); - if (value != null && info != null && !target.containsKey(key)) - target.register(key, value, info); - }); + public boolean injectBukkit() { + if (injected.getAndSet(true)) + return true; + try { + Iris.info("Injecting Bukkit"); + 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(), Agent.installed()); + return true; + } catch (Throwable e) { + Iris.error(C.RED + "Failed to inject Bukkit"); + e.printStackTrace(); + } + return false; } private ResourceLocation createIrisKey(ResourceKey key) { return new ResourceLocation("iris", key.location().getPath()); } + + public LevelStem levelStem(RegistryAccess access, World.Environment env) { + if (env == World.Environment.CUSTOM) + env = World.Environment.NORMAL; + return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); + } + + private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { + return access.registryOrThrow(Registries.DIMENSION_TYPE).getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", switch (env) { + case NORMAL, CUSTOM -> "overworld"; + case NETHER -> "the_nether"; + case THE_END -> "the_end"; + }))); + } + + private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { + var settings = new FlatLevelGeneratorSettings(Optional.empty(), access.registryOrThrow(Registries.BIOME).getHolderOrThrow(Biomes.THE_VOID), List.of()); + settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); + settings.updateLayers(); + return new FlatLevelSource(settings); + } + + private static class ServerLevelAdvice { + @SneakyThrows + @Advice.OnMethodEnter + static void enter( + @Advice.Argument(0) MinecraftServer server, + @Advice.Argument(3) PrimaryLevelData levelData, + @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem, + @Advice.Argument(12) World.Environment env, + @Advice.Argument(value = 13) ChunkGenerator gen + ) { + if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) + return; + + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) + .invoke(bindings, server.registryAccess(), env); + levelData.customDimensions = null; + } + } } diff --git a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java index 7613bf71f..2fb20264f 100644 --- a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java +++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java @@ -1,35 +1,35 @@ package com.volmit.iris.core.nms.v1_21_R1; import java.awt.Color; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Lifecycle; -import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; +import com.volmit.iris.util.agent.Agent; +import com.volmit.iris.util.format.C; +import com.volmit.iris.util.misc.ServerProperties; import com.volmit.iris.util.scheduling.J; import lombok.SneakyThrows; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatchers; import net.minecraft.core.*; import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.*; import net.minecraft.nbt.Tag; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.WorldLoader; import net.minecraft.server.commands.data.BlockDataAccessor; -import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.tags.TagKey; +import net.minecraft.world.RandomSequences; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.biome.Biomes; @@ -42,6 +42,8 @@ import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +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; @@ -51,12 +53,11 @@ import org.bukkit.craftbukkit.v1_21_R1.CraftWorld; import org.bukkit.craftbukkit.v1_21_R1.block.CraftBlockState; import org.bukkit.craftbukkit.v1_21_R1.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_21_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_21_R1.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_21_R1.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.Contract; @@ -74,7 +75,6 @@ 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; @@ -85,23 +85,21 @@ 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 dataLoadContext = new AtomicCache<>(); + private final AtomicBoolean injected = new AtomicBoolean(); private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final ReentrantLock dataContextLock = new ReentrantLock(true); + private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -676,44 +674,28 @@ public class NMSBinding implements INMSBinding { } @Override - @SneakyThrows - public AutoClosing injectLevelStems() { - if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!"); + @SuppressWarnings("all") + public KMap getMainWorlds() { + String levelName = ServerProperties.LEVEL_NAME; + KMap worlds = new KMap<>(); + for (var key : registry().registryOrThrow(Registries.LEVEL_STEM).registryKeySet()) { + World.Environment env = World.Environment.NORMAL; + if (key == LevelStem.NETHER) { + if (!Bukkit.getAllowNether()) + continue; + env = World.Environment.NETHER; + } else if (key == LevelStem.END) { + if (!Bukkit.getAllowEnd()) + continue; + env = World.Environment.THE_END; + } else if (key != LevelStem.OVERWORLD) { + env = World.Environment.CUSTOM; + } - var server = ((CraftServer) Bukkit.getServer()); - var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class); - var nmsServer = server.getServer(); - var old = nmsServer.worldLoader; - - field.setAccessible(true); - field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext( - old.resources(), - old.dataConfiguration(), - old.datapackWorldgen(), - createRegistryAccess(old.datapackDimensions(), false, true, true, true) - ))); - - return new AutoClosing(() -> { - field.set(nmsServer, old); - dataContextLock.unlock(); - }); - } - - @Override - @SneakyThrows - public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) { - var reg = registry(); - var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class); - field.setAccessible(true); - - var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end); - var injected = access.registryOrThrow(Registries.LEVEL_STEM); - var old = (Map>, Registry>) field.get(reg); - var fake = new HashMap<>(old); - fake.put(Registries.LEVEL_STEM, injected); - field.set(reg, fake); - - return new AutoClosing(() -> field.set(reg, old)); + String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); + worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); + } + return worlds; } @Override @@ -726,53 +708,74 @@ public class NMSBinding implements INMSBinding { } @Override - public void removeCustomDimensions(World world) { - ((CraftWorld) world).getHandle().K.customDimensions = null; - } - - private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) { - var access = registry(); - var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE); - - var settings = new FlatLevelGeneratorSettings( - Optional.empty(), - access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID), - List.of() - ); - settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); - settings.updateLayers(); - - var source = new FlatLevelSource(settings); - var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental()); - if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD); - if (nether) register(fake, dimensions, source, LevelStem.NETHER); - if (end) register(fake, dimensions, source, LevelStem.END); - copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null)); - - if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM)); - - return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze(); - } - - private void register(MappedRegistry target, Registry dimensions, FlatLevelSource source, ResourceKey key) { - var loc = createIrisKey(key); - target.register(key, new LevelStem( - dimensions.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, loc)).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())), - source - ), RegistrationInfo.BUILT_IN); - } - - private void copy(MappedRegistry target, Registry source) { - if (source == null) return; - source.registryKeySet().forEach(key -> { - var value = source.get(key); - var info = source.registrationInfo(key).orElse(null); - if (value != null && info != null && !target.containsKey(key)) - target.register(key, value, info); - }); + public boolean injectBukkit() { + if (injected.getAndSet(true)) + return true; + try { + Iris.info("Injecting Bukkit"); + 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(), Agent.installed()); + return true; + } catch (Throwable e) { + Iris.error(C.RED + "Failed to inject Bukkit"); + e.printStackTrace(); + } + return false; } private ResourceLocation createIrisKey(ResourceKey key) { return ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath()); } + + public LevelStem levelStem(RegistryAccess access, World.Environment env) { + if (env == World.Environment.CUSTOM) + env = World.Environment.NORMAL; + return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); + } + + private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { + return access.registryOrThrow(Registries.DIMENSION_TYPE).getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, ResourceLocation.fromNamespaceAndPath("iris", switch (env) { + case NORMAL, CUSTOM -> "overworld"; + case NETHER -> "the_nether"; + case THE_END -> "the_end"; + }))); + } + + private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { + var settings = new FlatLevelGeneratorSettings(Optional.empty(), access.registryOrThrow(Registries.BIOME).getHolderOrThrow(Biomes.THE_VOID), List.of()); + settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); + settings.updateLayers(); + return new FlatLevelSource(settings); + } + + private static class ServerLevelAdvice { + @SneakyThrows + @Advice.OnMethodEnter + static void enter( + @Advice.Argument(0) MinecraftServer server, + @Advice.Argument(3) PrimaryLevelData levelData, + @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem, + @Advice.Argument(12) World.Environment env, + @Advice.Argument(value = 13) ChunkGenerator gen + ) { + if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) + return; + + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) + .invoke(bindings, server.registryAccess(), env); + levelData.customDimensions = null; + } + } } diff --git a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java index 41b75953b..2a4c1315c 100644 --- a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java +++ b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java @@ -5,26 +5,30 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; -import com.mojang.serialization.Lifecycle; -import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; -import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.core.nms.datapack.DataVersion; +import com.volmit.iris.util.agent.Agent; +import com.volmit.iris.util.format.C; +import com.volmit.iris.util.misc.ServerProperties; import com.volmit.iris.util.scheduling.J; import lombok.SneakyThrows; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatchers; import net.minecraft.core.*; import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.*; import net.minecraft.nbt.Tag; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.WorldLoader; import net.minecraft.server.commands.data.BlockDataAccessor; +import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.tags.TagKey; +import net.minecraft.world.RandomSequences; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.biome.Biomes; @@ -37,6 +41,8 @@ import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +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; @@ -50,6 +56,7 @@ import org.bukkit.craftbukkit.v1_21_R2.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_21_R2.util.CraftNamespacedKey; 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.Contract; @@ -87,11 +94,11 @@ 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 dataLoadContext = new AtomicCache<>(); + private final AtomicBoolean injected = new AtomicBoolean(); private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final ReentrantLock dataContextLock = new ReentrantLock(true); + private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -666,44 +673,28 @@ public class NMSBinding implements INMSBinding { } @Override - @SneakyThrows - public AutoClosing injectLevelStems() { - if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!"); + @SuppressWarnings("all") + public KMap getMainWorlds() { + String levelName = ServerProperties.LEVEL_NAME; + KMap worlds = new KMap<>(); + for (var key : registry().lookupOrThrow(Registries.LEVEL_STEM).registryKeySet()) { + World.Environment env = World.Environment.NORMAL; + if (key == LevelStem.NETHER) { + if (!Bukkit.getAllowNether()) + continue; + env = World.Environment.NETHER; + } else if (key == LevelStem.END) { + if (!Bukkit.getAllowEnd()) + continue; + env = World.Environment.THE_END; + } else if (key != LevelStem.OVERWORLD) { + env = World.Environment.CUSTOM; + } - var server = ((CraftServer) Bukkit.getServer()); - var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class); - var nmsServer = server.getServer(); - var old = nmsServer.worldLoader; - - field.setAccessible(true); - field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext( - old.resources(), - old.dataConfiguration(), - old.datapackWorldgen(), - createRegistryAccess(old.datapackDimensions(), false, true, true, true) - ))); - - return new AutoClosing(() -> { - field.set(nmsServer, old); - dataContextLock.unlock(); - }); - } - - @Override - @SneakyThrows - public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) { - var reg = registry(); - var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class); - field.setAccessible(true); - - var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end); - var injected = access.lookupOrThrow(Registries.LEVEL_STEM); - var old = (Map>, Registry>) field.get(reg); - var fake = new HashMap<>(old); - fake.put(Registries.LEVEL_STEM, injected); - field.set(reg, fake); - - return new AutoClosing(() -> field.set(reg, old)); + String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); + worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); + } + return worlds; } @Override @@ -716,53 +707,74 @@ public class NMSBinding implements INMSBinding { } @Override - public void removeCustomDimensions(World world) { - ((CraftWorld) world).getHandle().L.customDimensions = null; - } - - private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) { - var access = registry(); - var dimensions = access.lookupOrThrow(Registries.DIMENSION_TYPE); - - var settings = new FlatLevelGeneratorSettings( - Optional.empty(), - access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID), - List.of() - ); - settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); - settings.updateLayers(); - - var source = new FlatLevelSource(settings); - var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental()); - if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD); - if (nether) register(fake, dimensions, source, LevelStem.NETHER); - if (end) register(fake, dimensions, source, LevelStem.END); - copy(fake, datapack.lookup(Registries.LEVEL_STEM).orElse(null)); - - if (copy) copy(fake, access.lookupOrThrow(Registries.LEVEL_STEM)); - - return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze(); - } - - private void register(MappedRegistry target, Registry dimensions, FlatLevelSource source, ResourceKey key) { - var loc = createIrisKey(key); - target.register(key, new LevelStem( - dimensions.get(loc).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())), - source - ), RegistrationInfo.BUILT_IN); - } - - private void copy(MappedRegistry target, Registry source) { - if (source == null) return; - source.listElementIds().forEach(key -> { - var value = source.getValue(key); - var info = source.registrationInfo(key).orElse(null); - if (value != null && info != null && !target.containsKey(key)) - target.register(key, value, info); - }); + public boolean injectBukkit() { + if (injected.getAndSet(true)) + return true; + try { + Iris.info("Injecting Bukkit"); + 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(), Agent.installed()); + return true; + } catch (Throwable e) { + Iris.error(C.RED + "Failed to inject Bukkit"); + e.printStackTrace(); + } + return false; } private ResourceLocation createIrisKey(ResourceKey key) { return ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath()); } + + public LevelStem levelStem(RegistryAccess access, World.Environment env) { + if (env == World.Environment.CUSTOM) + env = World.Environment.NORMAL; + return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); + } + + private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { + return access.lookupOrThrow(Registries.DIMENSION_TYPE).getOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, ResourceLocation.fromNamespaceAndPath("iris", switch (env) { + case NORMAL, CUSTOM -> "overworld"; + case NETHER -> "the_nether"; + case THE_END -> "the_end"; + }))); + } + + private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { + var settings = new FlatLevelGeneratorSettings(Optional.empty(), access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID), List.of()); + settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); + settings.updateLayers(); + return new FlatLevelSource(settings); + } + + private static class ServerLevelAdvice { + @SneakyThrows + @Advice.OnMethodEnter + static void enter( + @Advice.Argument(0) MinecraftServer server, + @Advice.Argument(3) PrimaryLevelData levelData, + @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem, + @Advice.Argument(12) World.Environment env, + @Advice.Argument(value = 13) ChunkGenerator gen + ) { + if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) + return; + + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) + .invoke(bindings, server.registryAccess(), env); + levelData.customDimensions = null; + } + } } diff --git a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java index c6ba0e6dd..adb05e88d 100644 --- a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java +++ b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java @@ -1,28 +1,31 @@ package com.volmit.iris.core.nms.v1_21_R3; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.serialization.Lifecycle; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMSBinding; -import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; -import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.util.agent.Agent; 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.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.misc.ServerProperties; 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 com.volmit.iris.util.scheduling.J; import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.SneakyThrows; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatchers; import net.minecraft.core.Registry; import net.minecraft.core.*; import net.minecraft.core.component.DataComponents; @@ -32,10 +35,11 @@ import net.minecraft.nbt.*; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.WorldLoader; import net.minecraft.server.commands.data.BlockDataAccessor; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.tags.TagKey; +import net.minecraft.world.RandomSequences; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.LevelReader; @@ -54,6 +58,8 @@ import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +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; @@ -67,6 +73,7 @@ import org.bukkit.craftbukkit.v1_21_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_21_R3.util.CraftNamespacedKey; 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.Contract; @@ -78,19 +85,19 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.List; import java.util.*; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; 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 dataLoadContext = new AtomicCache<>(); + private final AtomicBoolean injected = new AtomicBoolean(); private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final ReentrantLock dataContextLock = new ReentrantLock(true); + private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -665,44 +672,28 @@ public class NMSBinding implements INMSBinding { } @Override - @SneakyThrows - public AutoClosing injectLevelStems() { - if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!"); + @SuppressWarnings("all") + public KMap getMainWorlds() { + String levelName = ServerProperties.LEVEL_NAME; + KMap worlds = new KMap<>(); + for (var key : registry().lookupOrThrow(Registries.LEVEL_STEM).registryKeySet()) { + World.Environment env = World.Environment.NORMAL; + if (key == LevelStem.NETHER) { + if (!Bukkit.getAllowNether()) + continue; + env = World.Environment.NETHER; + } else if (key == LevelStem.END) { + if (!Bukkit.getAllowEnd()) + continue; + env = World.Environment.THE_END; + } else if (key != LevelStem.OVERWORLD) { + env = World.Environment.CUSTOM; + } - var server = ((CraftServer) Bukkit.getServer()); - var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class); - var nmsServer = server.getServer(); - var old = nmsServer.worldLoader; - - field.setAccessible(true); - field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext( - old.resources(), - old.dataConfiguration(), - old.datapackWorldgen(), - createRegistryAccess(old.datapackDimensions(), false, true, true, true) - ))); - - return new AutoClosing(() -> { - field.set(nmsServer, old); - dataContextLock.unlock(); - }); - } - - @Override - @SneakyThrows - public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) { - var reg = registry(); - var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class); - field.setAccessible(true); - - var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end); - var injected = access.lookupOrThrow(Registries.LEVEL_STEM); - var old = (Map>, Registry>) field.get(reg); - var fake = new HashMap<>(old); - fake.put(Registries.LEVEL_STEM, injected); - field.set(reg, fake); - - return new AutoClosing(() -> field.set(reg, old)); + String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); + worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); + } + return worlds; } @Override @@ -715,53 +706,74 @@ public class NMSBinding implements INMSBinding { } @Override - public void removeCustomDimensions(World world) { - ((CraftWorld) world).getHandle().L.customDimensions = null; - } - - private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) { - var access = registry(); - var dimensions = access.lookupOrThrow(Registries.DIMENSION_TYPE); - - var settings = new FlatLevelGeneratorSettings( - Optional.empty(), - access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID), - List.of() - ); - settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); - settings.updateLayers(); - - var source = new FlatLevelSource(settings); - var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental()); - if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD); - if (nether) register(fake, dimensions, source, LevelStem.NETHER); - if (end) register(fake, dimensions, source, LevelStem.END); - copy(fake, datapack.lookup(Registries.LEVEL_STEM).orElse(null)); - - if (copy) copy(fake, access.lookupOrThrow(Registries.LEVEL_STEM)); - - return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze(); - } - - private void register(MappedRegistry target, Registry dimensions, FlatLevelSource source, ResourceKey key) { - var loc = createIrisKey(key); - target.register(key, new LevelStem( - dimensions.get(loc).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())), - source - ), RegistrationInfo.BUILT_IN); - } - - private void copy(MappedRegistry target, Registry source) { - if (source == null) return; - source.listElementIds().forEach(key -> { - var value = source.getValue(key); - var info = source.registrationInfo(key).orElse(null); - if (value != null && info != null && !target.containsKey(key)) - target.register(key, value, info); - }); + public boolean injectBukkit() { + if (injected.getAndSet(true)) + return true; + try { + Iris.info("Injecting Bukkit"); + 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(), Agent.installed()); + return true; + } catch (Throwable e) { + Iris.error(C.RED + "Failed to inject Bukkit"); + e.printStackTrace(); + } + return false; } private ResourceLocation createIrisKey(ResourceKey key) { return ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath()); } + + public LevelStem levelStem(RegistryAccess access, World.Environment env) { + if (env == World.Environment.CUSTOM) + env = World.Environment.NORMAL; + return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); + } + + private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { + return access.lookupOrThrow(Registries.DIMENSION_TYPE).getOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, ResourceLocation.fromNamespaceAndPath("iris", switch (env) { + case NORMAL, CUSTOM -> "overworld"; + case NETHER -> "the_nether"; + case THE_END -> "the_end"; + }))); + } + + private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { + var settings = new FlatLevelGeneratorSettings(Optional.empty(), access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID), List.of()); + settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); + settings.updateLayers(); + return new FlatLevelSource(settings); + } + + private static class ServerLevelAdvice { + @SneakyThrows + @Advice.OnMethodEnter + static void enter( + @Advice.Argument(0) MinecraftServer server, + @Advice.Argument(3) PrimaryLevelData levelData, + @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem, + @Advice.Argument(12) World.Environment env, + @Advice.Argument(value = 13) ChunkGenerator gen + ) { + if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) + return; + + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) + .invoke(bindings, server.registryAccess(), env); + levelData.customDimensions = null; + } + } } From 3415e7c7af00449d68b09c5d0716cbe2c96ed096 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 16 Apr 2025 21:52:30 +0200 Subject: [PATCH 02/66] implement complete world height isolation --- .../volmit/iris/core/ServerConfigurator.java | 109 ++++++++++-------- .../iris/core/nms/datapack/IDataFixer.java | 11 +- .../nms/datapack/v1192/DataFixerV1192.java | 4 +- .../iris/engine/object/IrisDimension.java | 79 +++++++++---- .../engine/platform/BukkitChunkGenerator.java | 57 +++++---- .../platform/PlatformChunkGenerator.java | 10 +- .../iris/core/nms/v1_20_R1/NMSBinding.java | 45 ++++---- .../iris/core/nms/v1_20_R2/NMSBinding.java | 45 ++++---- .../iris/core/nms/v1_20_R3/NMSBinding.java | 45 ++++---- .../iris/core/nms/v1_20_R4/NMSBinding.java | 45 ++++---- .../iris/core/nms/v1_21_R1/NMSBinding.java | 47 ++++---- .../iris/core/nms/v1_21_R2/NMSBinding.java | 45 ++++---- .../iris/core/nms/v1_21_R3/NMSBinding.java | 46 ++++---- 13 files changed, 322 insertions(+), 266 deletions(-) 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 ffeae3115..b4d281c09 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -26,7 +26,6 @@ import com.volmit.iris.core.nms.datapack.IDataFixer; 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.KMap; import com.volmit.iris.util.collection.KSet; @@ -34,8 +33,8 @@ import com.volmit.iris.util.format.C; import com.volmit.iris.util.misc.ServerProperties; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; -import lombok.Data; import lombok.NonNull; +import lombok.SneakyThrows; import org.bukkit.Bukkit; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.FileConfiguration; @@ -45,12 +44,12 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; -import java.util.Arrays; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicIntegerArray; import java.util.stream.Stream; -import static com.volmit.iris.core.nms.datapack.IDataFixer.Dimension.*; - public class ServerConfigurator { public static void configure() { IrisSettings.IrisSettingsAutoconfiguration s = IrisSettings.get().getAutoConfiguration(); @@ -112,14 +111,16 @@ public class ServerConfigurator { KList folders = getDatapacksFolder(); KMap> biomes = new KMap<>(); - allPacks().flatMap(height::merge) - .parallel() - .forEach(dim -> { - Iris.verbose(" Checking Dimension " + dim.getLoadFile().getPath()); - dim.installBiomes(fixer, dim::getLoader, folders, biomes.computeIfAbsent(dim.getLoadKey(), k -> new KSet<>())); - }); + try (Stream stream = allPacks()) { + stream.flatMap(height::merge) + .parallel() + .forEach(dim -> { + Iris.verbose(" Checking Dimension " + dim.getLoadFile().getPath()); + dim.installBiomes(fixer, dim::getLoader, folders, biomes.computeIfAbsent(dim.getLoadKey(), k -> new KSet<>())); + dim.installDimensionType(fixer, folders); + }); + } IrisDimension.writeShared(folders, height); - Iris.info("Data Packs Setup!"); if (fullInstall) @@ -127,19 +128,21 @@ public class ServerConfigurator { } private static void verifyDataPacksPost(boolean allowRestarting) { - boolean bad = allPacks() - .map(data -> { - Iris.verbose("Checking Pack: " + data.getDataFolder().getPath()); - var loader = data.getDimensionLoader(); - return loader.loadAll(loader.getPossibleKeys()) - .stream() - .map(ServerConfigurator::verifyDataPackInstalled) - .toList() - .contains(false); - }) - .toList() - .contains(true); - if (!bad) return; + try (Stream stream = allPacks()) { + boolean bad = stream + .map(data -> { + Iris.verbose("Checking Pack: " + data.getDataFolder().getPath()); + var loader = data.getDimensionLoader(); + return loader.loadAll(loader.getPossibleKeys()) + .stream() + .map(ServerConfigurator::verifyDataPackInstalled) + .toList() + .contains(false); + }) + .toList() + .contains(true); + if (!bad) return; + } if (allowRestarting) { @@ -239,20 +242,24 @@ public class ServerConfigurator { return path.substring(worldContainer.length(), path.length() - l); } + @SneakyThrows private static Stream listFiles(File parent) { - var files = parent.listFiles(); - return files == null ? Stream.empty() : Arrays.stream(files); + if (!parent.isDirectory()) return Stream.empty(); + return Files.walk(parent.toPath()).map(Path::toFile); } - @Data public static class DimensionHeight { private final IDataFixer fixer; - private IrisRange overworld = new IrisRange(); - private IrisRange nether = new IrisRange(); - private IrisRange end = new IrisRange(); - private int logicalOverworld = 0; - private int logicalNether = 0; - private int logicalEnd = 0; + private final AtomicIntegerArray[] dimensions = new AtomicIntegerArray[3]; + + public DimensionHeight(IDataFixer fixer) { + this.fixer = fixer; + for (int i = 0; i < 3; i++) { + dimensions[i] = new AtomicIntegerArray(new int[]{ + Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE + }); + } + } public Stream merge(IrisData data) { Iris.verbose("Checking Pack: " + data.getDataFolder().getPath()); @@ -263,25 +270,29 @@ public class ServerConfigurator { } public void merge(IrisDimension dimension) { - overworld.merge(dimension.getDimensionHeight()); - nether.merge(dimension.getDimensionHeight()); - end.merge(dimension.getDimensionHeight()); - - logicalOverworld = Math.max(logicalOverworld, dimension.getLogicalHeight()); - logicalNether = Math.max(logicalNether, dimension.getLogicalHeightNether()); - logicalEnd = Math.max(logicalEnd, dimension.getLogicalHeightEnd()); + AtomicIntegerArray array = dimensions[dimension.getBaseDimension().ordinal()]; + array.updateAndGet(0, min -> Math.min(min, dimension.getMinHeight())); + array.updateAndGet(1, max -> Math.max(max, dimension.getMaxHeight())); + array.updateAndGet(2, logical -> Math.max(logical, dimension.getLogicalHeight())); } - public String overworldType() { - return fixer.createDimension(OVERRWORLD, overworld, logicalOverworld).toString(4); + public String[] jsonStrings() { + var dims = IDataFixer.Dimension.values(); + var arr = new String[3]; + for (int i = 0; i < 3; i++) { + arr[i] = jsonString(dims[i]); + } + return arr; } - public String netherType() { - return fixer.createDimension(NETHER, nether, logicalNether).toString(4); - } - - public String endType() { - return fixer.createDimension(THE_END, end, logicalEnd).toString(4); + public String jsonString(IDataFixer.Dimension dimension) { + var data = dimensions[dimension.ordinal()]; + int minY = data.get(0); + int maxY = data.get(1); + int logicalHeight = data.get(2); + if (minY == Integer.MAX_VALUE || maxY == Integer.MIN_VALUE || Integer.MIN_VALUE == logicalHeight) + return null; + return fixer.createDimension(dimension, minY, maxY, logicalHeight).toString(4); } } } 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 index 4d972128e..889acddff 100644 --- 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 @@ -1,7 +1,6 @@ package com.volmit.iris.core.nms.datapack; import com.volmit.iris.engine.object.IrisBiomeCustom; -import com.volmit.iris.engine.object.IrisRange; import com.volmit.iris.util.json.JSONObject; public interface IDataFixer { @@ -12,17 +11,17 @@ public interface IDataFixer { JSONObject rawDimension(Dimension dimension); - default JSONObject createDimension(Dimension dimension, IrisRange height, int logicalHeight) { + default JSONObject createDimension(Dimension dimension, int minY, int maxY, int logicalHeight) { JSONObject obj = rawDimension(dimension); - obj.put("min_y", height.getMin()); - obj.put("height", height.getMax() - height.getMin()); + obj.put("min_y", minY); + obj.put("height", maxY - minY); obj.put("logical_height", logicalHeight); return obj; } enum Dimension { - OVERRWORLD, + OVERWORLD, NETHER, - THE_END + END } } 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 index a0a854868..f2697cf38 100644 --- 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 @@ -7,7 +7,7 @@ import java.util.Map; public class DataFixerV1192 implements IDataFixer { private static final Map DIMENSIONS = Map.of( - Dimension.OVERRWORLD, """ + Dimension.OVERWORLD, """ { "ambient_light": 0.0, "bed_works": true, @@ -48,7 +48,7 @@ public class DataFixerV1192 implements IDataFixer { "respawn_anchor_works": true, "ultrawarm": true }""", - Dimension.THE_END, """ + Dimension.END, """ { "ambient_light": 0.0, "bed_works": false, 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 f2c5b724c..ba6b07717 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 @@ -25,11 +25,13 @@ import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.datapack.IDataFixer; +import com.volmit.iris.core.nms.datapack.IDataFixer.Dimension; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.data.DataProvider; +import com.volmit.iris.util.data.Varint; import com.volmit.iris.util.io.IO; import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.math.Position2; @@ -45,6 +47,8 @@ import org.bukkit.Material; import org.bukkit.World.Environment; import org.bukkit.block.data.BlockData; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.File; import java.io.IOException; @@ -74,10 +78,6 @@ public class IrisDimension extends IrisRegistrant { @MaxNumber(2032) @Desc("Maximum height at which players can be teleported to through gameplay.") private int logicalHeight = 256; - @Desc("Maximum height at which players can be teleported to through gameplay.") - private int logicalHeightEnd = 256; - @Desc("Maximum height at which players can be teleported to through gameplay.") - private int logicalHeightNether = 256; @RegistryListResource(IrisJigsawStructure.class) @Desc("If defined, Iris will place the given jigsaw structure where minecraft should place the overworld stronghold.") private String stronghold; @@ -166,10 +166,6 @@ public class IrisDimension extends IrisRegistrant { private int fluidHeight = 63; @Desc("Define the min and max Y bounds of this dimension. Please keep in mind that Iris internally generates from 0 to (max - min). \n\nFor example at -64 to 320, Iris is internally generating to 0 to 384, then on outputting chunks, it shifts it down by the min height (64 blocks). The default is -64 to 320. \n\nThe fluid height is placed at (fluid height + min height). So a fluid height of 63 would actually show up in the world at 1.") private IrisRange dimensionHeight = new IrisRange(-64, 320); - @Desc("Define the min and max Y bounds of this dimension. Please keep in mind that Iris internally generates from 0 to (max - min). \n\nFor example at -64 to 320, Iris is internally generating to 0 to 384, then on outputting chunks, it shifts it down by the min height (64 blocks). The default is -64 to 320. \n\nThe fluid height is placed at (fluid height + min height). So a fluid height of 63 would actually show up in the world at 1.") - private IrisRange dimensionHeightEnd = new IrisRange(-64, 320); - @Desc("Define the min and max Y bounds of this dimension. Please keep in mind that Iris internally generates from 0 to (max - min). \n\nFor example at -64 to 320, Iris is internally generating to 0 to 384, then on outputting chunks, it shifts it down by the min height (64 blocks). The default is -64 to 320. \n\nThe fluid height is placed at (fluid height + min height). So a fluid height of 63 would actually show up in the world at 1.") - private IrisRange dimensionHeightNether = new IrisRange(-64, 320); @RegistryListResource(IrisBiome.class) @Desc("Keep this either undefined or empty. Setting any biome name into this will force iris to only generate the specified biome. Great for testing.") private String focus = ""; @@ -410,6 +406,40 @@ public class IrisDimension extends IrisRegistrant { }); } + public Dimension getBaseDimension() { + return switch (getEnvironment()) { + case NETHER -> Dimension.NETHER; + case THE_END -> Dimension.END; + default -> Dimension.OVERWORLD; + }; + } + + public String getDimensionTypeKey() { + return getDimensionTypeKey(getBaseDimension(), getMinHeight(), getMaxHeight(), getLogicalHeight()); + } + + public void installDimensionType(IDataFixer fixer, KList folders) { + String key = getDimensionTypeKey(); + String json = fixer.createDimension( + getBaseDimension(), + getMinHeight(), + getMaxHeight(), + getLogicalHeight() + ).toString(4); + + Iris.verbose(" Installing Data Pack Dimension Type: \"iris:" + key + '"'); + for (File datapacks : folders) { + File output = new File(datapacks, "iris/data/iris/dimension_type/" + key + ".json"); + output.getParentFile().mkdirs(); + try { + IO.writeAll(output, json); + } catch (IOException e) { + Iris.reportError(e); + e.printStackTrace(); + } + } + } + @Override public String getFolderName() { return "dimensions"; @@ -426,11 +456,12 @@ public class IrisDimension extends IrisRegistrant { } public static void writeShared(KList folders, DimensionHeight height) { - Iris.verbose(" Installing Data Pack Dimension Types: \"iris:overworld\", \"iris:the_nether\", \"iris:the_end\""); + Iris.verbose(" Installing Data Pack Vanilla Dimension Types"); + String[] jsonStrings = height.jsonStrings(); for (File datapacks : folders) { - write(datapacks, "overworld", height.overworldType()); - write(datapacks, "the_nether", height.netherType()); - write(datapacks, "the_end", height.endType()); + write(datapacks, "overworld", jsonStrings[0]); + write(datapacks, "the_nether", jsonStrings[1]); + write(datapacks, "the_end", jsonStrings[2]); } String raw = """ @@ -454,18 +485,24 @@ public class IrisDimension extends IrisRegistrant { } } - private static void write(File datapacks, String type, String json) { - File dimType = new File(datapacks, "iris/data/iris/dimension_type/" + type + ".json"); - File dimTypeVanilla = new File(datapacks, "iris/data/minecraft/dimension_type/" + type + ".json"); - - dimType.getParentFile().mkdirs(); - try { - IO.writeAll(dimType, json); + public static String getDimensionTypeKey(Dimension dimension, int minY, int maxY, int logicalHeight) { + var stream = new ByteArrayOutputStream(13); + try (var dos = new DataOutputStream(stream)) { + dos.writeByte(dimension.ordinal()); + Varint.writeUnsignedVarInt(logicalHeight, dos); + Varint.writeUnsignedVarInt(maxY - minY, dos); + Varint.writeSignedVarInt(minY, dos); } catch (IOException e) { - Iris.reportError(e); - e.printStackTrace(); + throw new RuntimeException("This is impossible", e); } + return IO.encode(stream.toByteArray()).replace("=", ".").toLowerCase(); + } + + private static void write(File datapacks, String type, String json) { + if (json == null) return; + File dimTypeVanilla = new File(datapacks, "iris/data/minecraft/dimension_type/" + type + ".json"); + if (IrisSettings.get().getGeneral().adjustVanillaHeight || dimTypeVanilla.exists()) { dimTypeVanilla.getParentFile().mkdirs(); try { diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index 4285dd799..db5076e35 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -24,6 +24,7 @@ import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.engine.IrisEngine; +import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.data.chunk.TerrainChunk; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.EngineTarget; @@ -86,6 +87,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun private final boolean studio; private final AtomicInteger a = new AtomicInteger(0); private final CompletableFuture spawnChunks = new CompletableFuture<>(); + private final AtomicCache targetCache = new AtomicCache<>(); private Engine engine; private Looper hotloader; private StudioMode lastMode; @@ -158,37 +160,48 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun } private void setupEngine() { - IrisData data = IrisData.get(dataLocation); - IrisDimension dimension = data.getDimensionLoader().load(dimensionKey); + lastMode = StudioMode.NORMAL; + engine = new IrisEngine(getTarget(), studio); + populators.clear(); + targetCache.reset(); + } - if (dimension == null) { - Iris.error("Oh No! There's no pack in " + data.getDataFolder().getPath() + " or... there's no dimension for the key " + dimensionKey); - IrisDimension test = IrisData.loadAnyDimension(dimensionKey); + @NotNull + @Override + public EngineTarget getTarget() { + if (engine != null) return engine.getTarget(); - if (test != null) { - Iris.warn("Looks like " + dimensionKey + " exists in " + test.getLoadFile().getPath() + " "); - Iris.service(StudioSVC.class).installIntoWorld(Iris.getSender(), dimensionKey, dataLocation.getParentFile().getParentFile()); - Iris.warn("Attempted to install into " + data.getDataFolder().getPath()); - data.dump(); - data.clearLists(); - test = data.getDimensionLoader().load(dimensionKey); + return targetCache.aquire(() -> { + IrisData data = IrisData.get(dataLocation); + IrisDimension dimension = data.getDimensionLoader().load(dimensionKey); + + if (dimension == null) { + Iris.error("Oh No! There's no pack in " + data.getDataFolder().getPath() + " or... there's no dimension for the key " + dimensionKey); + IrisDimension test = IrisData.loadAnyDimension(dimensionKey); if (test != null) { - Iris.success("Woo! Patched the Engine!"); - dimension = test; + Iris.warn("Looks like " + dimensionKey + " exists in " + test.getLoadFile().getPath() + " "); + Iris.service(StudioSVC.class).installIntoWorld(Iris.getSender(), dimensionKey, dataLocation.getParentFile().getParentFile()); + Iris.warn("Attempted to install into " + data.getDataFolder().getPath()); + data.dump(); + data.clearLists(); + test = data.getDimensionLoader().load(dimensionKey); + + if (test != null) { + Iris.success("Woo! Patched the Engine!"); + dimension = test; + } else { + Iris.error("Failed to patch dimension!"); + throw new RuntimeException("Missing Dimension: " + dimensionKey); + } } else { - Iris.error("Failed to patch dimension!"); + Iris.error("Nope, you don't have an installation containing " + dimensionKey + " try downloading it?"); throw new RuntimeException("Missing Dimension: " + dimensionKey); } - } else { - Iris.error("Nope, you don't have an installation containing " + dimensionKey + " try downloading it?"); - throw new RuntimeException("Missing Dimension: " + dimensionKey); } - } - lastMode = StudioMode.NORMAL; - engine = new IrisEngine(new EngineTarget(world, dimension, data), studio); - populators.clear(); + return new EngineTarget(world, dimension, data); + }); } @Override diff --git a/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java index e79c3dd6f..687788527 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java @@ -24,21 +24,23 @@ import com.volmit.iris.engine.framework.EngineTarget; import com.volmit.iris.engine.framework.Hotloadable; import com.volmit.iris.util.data.DataProvider; import org.bukkit.World; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; public interface PlatformChunkGenerator extends Hotloadable, DataProvider { + @Nullable Engine getEngine(); @Override default IrisData getData() { - return getEngine().getData(); + return getTarget().getData(); } - default EngineTarget getTarget() { - return getEngine().getTarget(); - } + @NotNull + EngineTarget getTarget(); void injectChunkReplacement(World world, int x, int z, Consumer jobs); 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 f096e5a78..e723b55b7 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 @@ -7,6 +7,7 @@ import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.agent.Agent; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; @@ -22,7 +23,6 @@ import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.scheduling.J; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import lombok.SneakyThrows; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; @@ -49,7 +49,6 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; @@ -78,6 +77,7 @@ import org.jetbrains.annotations.NotNull; import java.awt.Color; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; @@ -700,18 +700,13 @@ public class NMSBinding implements INMSBinding { return new ResourceLocation("iris", key.location().getPath()); } - public LevelStem levelStem(RegistryAccess access, World.Environment env) { - if (env == World.Environment.CUSTOM) - env = World.Environment.NORMAL; - return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); - } + public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { + if (!(raw instanceof PlatformChunkGenerator gen)) + throw new IllegalStateException("Generator is not platform chunk generator!"); - private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { - return access.registryOrThrow(Registries.DIMENSION_TYPE).getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", switch (env) { - case NORMAL, CUSTOM -> "overworld"; - case NETHER -> "the_nether"; - case THE_END -> "the_end"; - }))); + var dimensionKey = new ResourceLocation("iris", gen.getTarget().getDimension().getDimensionTypeKey()); + var dimensionType = access.lookupOrThrow(Registries.DIMENSION_TYPE).getOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, dimensionKey)); + return new LevelStem(dimensionType, chunkGenerator(access)); } private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { @@ -722,7 +717,6 @@ public class NMSBinding implements INMSBinding { } private static class ServerLevelAdvice { - @SneakyThrows @Advice.OnMethodEnter static void enter( @Advice.Argument(0) MinecraftServer server, @@ -734,15 +728,20 @@ public class NMSBinding implements INMSBinding { if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) return; - Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") - .getClass() - .getClassLoader()) - .getDeclaredMethod("get") - .invoke(null); - levelStem = (LevelStem) bindings.getClass() - .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) - .invoke(bindings, server.registryAccess(), env); - levelData.customDimensions = null; + try { + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, ChunkGenerator.class) + .invoke(bindings, server.registryAccess(), gen); + + levelData.customDimensions = null; + } catch (Throwable e) { + throw new RuntimeException("Iris failed to replace the levelStem", e instanceof InvocationTargetException ex ? ex.getCause() : e); + } } } } 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 dbba77c83..eed8f0bd6 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 @@ -2,6 +2,7 @@ package com.volmit.iris.core.nms.v1_20_R2; import java.awt.Color; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; @@ -11,11 +12,11 @@ import java.util.concurrent.atomic.AtomicInteger; import com.mojang.datafixers.util.Pair; import com.volmit.iris.core.nms.container.BiomeColor; +import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.agent.Agent; import com.volmit.iris.util.format.C; import com.volmit.iris.util.misc.ServerProperties; import com.volmit.iris.util.scheduling.J; -import lombok.SneakyThrows; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; @@ -32,7 +33,6 @@ import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; @@ -704,18 +704,13 @@ public class NMSBinding implements INMSBinding { return new ResourceLocation("iris", key.location().getPath()); } - public LevelStem levelStem(RegistryAccess access, World.Environment env) { - if (env == World.Environment.CUSTOM) - env = World.Environment.NORMAL; - return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); - } + public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { + if (!(raw instanceof PlatformChunkGenerator gen)) + throw new IllegalStateException("Generator is not platform chunk generator!"); - private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { - return access.registryOrThrow(Registries.DIMENSION_TYPE).getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", switch (env) { - case NORMAL, CUSTOM -> "overworld"; - case NETHER -> "the_nether"; - case THE_END -> "the_end"; - }))); + var dimensionKey = new ResourceLocation("iris", gen.getTarget().getDimension().getDimensionTypeKey()); + var dimensionType = access.lookupOrThrow(Registries.DIMENSION_TYPE).getOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, dimensionKey)); + return new LevelStem(dimensionType, chunkGenerator(access)); } private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { @@ -726,7 +721,6 @@ public class NMSBinding implements INMSBinding { } private static class ServerLevelAdvice { - @SneakyThrows @Advice.OnMethodEnter static void enter( @Advice.Argument(0) MinecraftServer server, @@ -738,15 +732,20 @@ public class NMSBinding implements INMSBinding { if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) return; - Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") - .getClass() - .getClassLoader()) - .getDeclaredMethod("get") - .invoke(null); - levelStem = (LevelStem) bindings.getClass() - .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) - .invoke(bindings, server.registryAccess(), env); - levelData.customDimensions = null; + try { + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, ChunkGenerator.class) + .invoke(bindings, server.registryAccess(), gen); + + levelData.customDimensions = null; + } catch (Throwable e) { + throw new RuntimeException("Iris failed to replace the levelStem", e instanceof InvocationTargetException ex ? ex.getCause() : e); + } } } } 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 18d4c724c..58e2f8df9 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 @@ -2,6 +2,7 @@ package com.volmit.iris.core.nms.v1_20_R3; import java.awt.Color; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; @@ -11,11 +12,11 @@ import java.util.concurrent.atomic.AtomicInteger; import com.mojang.datafixers.util.Pair; import com.volmit.iris.core.nms.container.BiomeColor; +import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.agent.Agent; import com.volmit.iris.util.format.C; import com.volmit.iris.util.misc.ServerProperties; import com.volmit.iris.util.scheduling.J; -import lombok.SneakyThrows; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; @@ -32,7 +33,6 @@ import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; @@ -705,18 +705,13 @@ public class NMSBinding implements INMSBinding { return new ResourceLocation("iris", key.location().getPath()); } - public LevelStem levelStem(RegistryAccess access, World.Environment env) { - if (env == World.Environment.CUSTOM) - env = World.Environment.NORMAL; - return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); - } + public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { + if (!(raw instanceof PlatformChunkGenerator gen)) + throw new IllegalStateException("Generator is not platform chunk generator!"); - private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { - return access.registryOrThrow(Registries.DIMENSION_TYPE).getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", switch (env) { - case NORMAL, CUSTOM -> "overworld"; - case NETHER -> "the_nether"; - case THE_END -> "the_end"; - }))); + var dimensionKey = new ResourceLocation("iris", gen.getTarget().getDimension().getDimensionTypeKey()); + var dimensionType = access.lookupOrThrow(Registries.DIMENSION_TYPE).getOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, dimensionKey)); + return new LevelStem(dimensionType, chunkGenerator(access)); } private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { @@ -727,7 +722,6 @@ public class NMSBinding implements INMSBinding { } private static class ServerLevelAdvice { - @SneakyThrows @Advice.OnMethodEnter static void enter( @Advice.Argument(0) MinecraftServer server, @@ -739,15 +733,20 @@ public class NMSBinding implements INMSBinding { if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) return; - Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") - .getClass() - .getClassLoader()) - .getDeclaredMethod("get") - .invoke(null); - levelStem = (LevelStem) bindings.getClass() - .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) - .invoke(bindings, server.registryAccess(), env); - levelData.customDimensions = null; + try { + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, ChunkGenerator.class) + .invoke(bindings, server.registryAccess(), gen); + + levelData.customDimensions = null; + } catch (Throwable e) { + throw new RuntimeException("Iris failed to replace the levelStem", e instanceof InvocationTargetException ex ? ex.getCause() : e); + } } } } 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 index 1e6b0e465..066995605 100644 --- 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 @@ -2,6 +2,7 @@ package com.volmit.iris.core.nms.v1_20_R4; import java.awt.Color; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; @@ -12,12 +13,12 @@ import java.util.concurrent.atomic.AtomicInteger; import com.mojang.datafixers.util.Pair; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; +import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.agent.Agent; import com.volmit.iris.util.format.C; import com.volmit.iris.util.misc.ServerProperties; import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.scheduling.J; -import lombok.SneakyThrows; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; @@ -46,7 +47,6 @@ import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; 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.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; @@ -733,18 +733,13 @@ public class NMSBinding implements INMSBinding { return new ResourceLocation("iris", key.location().getPath()); } - public LevelStem levelStem(RegistryAccess access, World.Environment env) { - if (env == World.Environment.CUSTOM) - env = World.Environment.NORMAL; - return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); - } + public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { + if (!(raw instanceof PlatformChunkGenerator gen)) + throw new IllegalStateException("Generator is not platform chunk generator!"); - private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { - return access.registryOrThrow(Registries.DIMENSION_TYPE).getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", switch (env) { - case NORMAL, CUSTOM -> "overworld"; - case NETHER -> "the_nether"; - case THE_END -> "the_end"; - }))); + var dimensionKey = new ResourceLocation("iris", gen.getTarget().getDimension().getDimensionTypeKey()); + var dimensionType = access.lookupOrThrow(Registries.DIMENSION_TYPE).getOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, dimensionKey)); + return new LevelStem(dimensionType, chunkGenerator(access)); } private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { @@ -755,7 +750,6 @@ public class NMSBinding implements INMSBinding { } private static class ServerLevelAdvice { - @SneakyThrows @Advice.OnMethodEnter static void enter( @Advice.Argument(0) MinecraftServer server, @@ -767,15 +761,20 @@ public class NMSBinding implements INMSBinding { if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) return; - Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") - .getClass() - .getClassLoader()) - .getDeclaredMethod("get") - .invoke(null); - levelStem = (LevelStem) bindings.getClass() - .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) - .invoke(bindings, server.registryAccess(), env); - levelData.customDimensions = null; + try { + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, ChunkGenerator.class) + .invoke(bindings, server.registryAccess(), gen); + + levelData.customDimensions = null; + } catch (Throwable e) { + throw new RuntimeException("Iris failed to replace the levelStem", e instanceof InvocationTargetException ex ? ex.getCause() : e); + } } } } diff --git a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java index 2fb20264f..50a4c4d7a 100644 --- a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java +++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java @@ -2,6 +2,7 @@ package com.volmit.iris.core.nms.v1_21_R1; import java.awt.Color; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; @@ -12,11 +13,11 @@ import java.util.concurrent.atomic.AtomicInteger; import com.mojang.datafixers.util.Pair; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; +import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.agent.Agent; import com.volmit.iris.util.format.C; import com.volmit.iris.util.misc.ServerProperties; import com.volmit.iris.util.scheduling.J; -import lombok.SneakyThrows; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; @@ -37,7 +38,6 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.WorldGenContext; -import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; @@ -733,18 +733,15 @@ public class NMSBinding implements INMSBinding { return ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath()); } - public LevelStem levelStem(RegistryAccess access, World.Environment env) { - if (env == World.Environment.CUSTOM) - env = World.Environment.NORMAL; - return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); - } - private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { - return access.registryOrThrow(Registries.DIMENSION_TYPE).getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, ResourceLocation.fromNamespaceAndPath("iris", switch (env) { - case NORMAL, CUSTOM -> "overworld"; - case NETHER -> "the_nether"; - case THE_END -> "the_end"; - }))); + + public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { + if (!(raw instanceof PlatformChunkGenerator gen)) + throw new IllegalStateException("Generator is not platform chunk generator!"); + + var dimensionKey = ResourceLocation.fromNamespaceAndPath("iris", gen.getTarget().getDimension().getDimensionTypeKey()); + var dimensionType = access.lookupOrThrow(Registries.DIMENSION_TYPE).getOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, dimensionKey)); + return new LevelStem(dimensionType, chunkGenerator(access)); } private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { @@ -755,7 +752,6 @@ public class NMSBinding implements INMSBinding { } private static class ServerLevelAdvice { - @SneakyThrows @Advice.OnMethodEnter static void enter( @Advice.Argument(0) MinecraftServer server, @@ -767,15 +763,20 @@ public class NMSBinding implements INMSBinding { if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) return; - Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") - .getClass() - .getClassLoader()) - .getDeclaredMethod("get") - .invoke(null); - levelStem = (LevelStem) bindings.getClass() - .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) - .invoke(bindings, server.registryAccess(), env); - levelData.customDimensions = null; + try { + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, ChunkGenerator.class) + .invoke(bindings, server.registryAccess(), gen); + + levelData.customDimensions = null; + } catch (Throwable e) { + throw new RuntimeException("Iris failed to replace the levelStem", e instanceof InvocationTargetException ex ? ex.getCause() : e); + } } } } diff --git a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java index 2a4c1315c..b8504cbe8 100644 --- a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java +++ b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java @@ -2,6 +2,7 @@ package com.volmit.iris.core.nms.v1_21_R2; import java.awt.Color; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; @@ -11,11 +12,11 @@ import java.util.concurrent.atomic.AtomicInteger; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; +import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.agent.Agent; import com.volmit.iris.util.format.C; import com.volmit.iris.util.misc.ServerProperties; import com.volmit.iris.util.scheduling.J; -import lombok.SneakyThrows; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; @@ -36,7 +37,6 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.WorldGenContext; -import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; @@ -732,18 +732,13 @@ public class NMSBinding implements INMSBinding { return ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath()); } - public LevelStem levelStem(RegistryAccess access, World.Environment env) { - if (env == World.Environment.CUSTOM) - env = World.Environment.NORMAL; - return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); - } + public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { + if (!(raw instanceof PlatformChunkGenerator gen)) + throw new IllegalStateException("Generator is not platform chunk generator!"); - private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { - return access.lookupOrThrow(Registries.DIMENSION_TYPE).getOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, ResourceLocation.fromNamespaceAndPath("iris", switch (env) { - case NORMAL, CUSTOM -> "overworld"; - case NETHER -> "the_nether"; - case THE_END -> "the_end"; - }))); + var dimensionKey = ResourceLocation.fromNamespaceAndPath("iris", gen.getTarget().getDimension().getDimensionTypeKey()); + var dimensionType = access.lookupOrThrow(Registries.DIMENSION_TYPE).getOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, dimensionKey)); + return new LevelStem(dimensionType, chunkGenerator(access)); } private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { @@ -754,7 +749,6 @@ public class NMSBinding implements INMSBinding { } private static class ServerLevelAdvice { - @SneakyThrows @Advice.OnMethodEnter static void enter( @Advice.Argument(0) MinecraftServer server, @@ -766,15 +760,20 @@ public class NMSBinding implements INMSBinding { if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) return; - Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") - .getClass() - .getClassLoader()) - .getDeclaredMethod("get") - .invoke(null); - levelStem = (LevelStem) bindings.getClass() - .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) - .invoke(bindings, server.registryAccess(), env); - levelData.customDimensions = null; + try { + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, ChunkGenerator.class) + .invoke(bindings, server.registryAccess(), gen); + + levelData.customDimensions = null; + } catch (Throwable e) { + throw new RuntimeException("Iris failed to replace the levelStem", e instanceof InvocationTargetException ex ? ex.getCause() : e); + } } } } diff --git a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java index adb05e88d..7f5524b3c 100644 --- a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java +++ b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java @@ -7,6 +7,7 @@ import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.agent.Agent; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; @@ -16,13 +17,11 @@ 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.misc.ServerProperties; 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 com.volmit.iris.util.scheduling.J; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import lombok.SneakyThrows; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; @@ -53,7 +52,6 @@ import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.WorldGenContext; -import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; @@ -81,6 +79,7 @@ import org.jetbrains.annotations.NotNull; import java.awt.Color; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.List; @@ -731,18 +730,13 @@ public class NMSBinding implements INMSBinding { return ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath()); } - public LevelStem levelStem(RegistryAccess access, World.Environment env) { - if (env == World.Environment.CUSTOM) - env = World.Environment.NORMAL; - return stems.computeIfAbsent(env, key -> new LevelStem(dimensionType(access, key), chunkGenerator(access))); - } + public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { + if (!(raw instanceof PlatformChunkGenerator gen)) + throw new IllegalStateException("Generator is not platform chunk generator!"); - private Holder.Reference dimensionType(RegistryAccess access, World.Environment env) { - return access.lookupOrThrow(Registries.DIMENSION_TYPE).getOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, ResourceLocation.fromNamespaceAndPath("iris", switch (env) { - case NORMAL, CUSTOM -> "overworld"; - case NETHER -> "the_nether"; - case THE_END -> "the_end"; - }))); + var dimensionKey = ResourceLocation.fromNamespaceAndPath("iris", gen.getTarget().getDimension().getDimensionTypeKey()); + var dimensionType = access.lookupOrThrow(Registries.DIMENSION_TYPE).getOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, dimensionKey)); + return new LevelStem(dimensionType, chunkGenerator(access)); } private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { @@ -753,7 +747,6 @@ public class NMSBinding implements INMSBinding { } private static class ServerLevelAdvice { - @SneakyThrows @Advice.OnMethodEnter static void enter( @Advice.Argument(0) MinecraftServer server, @@ -765,15 +758,20 @@ public class NMSBinding implements INMSBinding { if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) return; - Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") - .getClass() - .getClassLoader()) - .getDeclaredMethod("get") - .invoke(null); - levelStem = (LevelStem) bindings.getClass() - .getDeclaredMethod("levelStem", RegistryAccess.class, World.Environment.class) - .invoke(bindings, server.registryAccess(), env); - levelData.customDimensions = null; + try { + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, ChunkGenerator.class) + .invoke(bindings, server.registryAccess(), gen); + + levelData.customDimensions = null; + } catch (Throwable e) { + throw new RuntimeException("Iris failed to replace the levelStem", e instanceof InvocationTargetException ex ? ex.getCause() : e); + } } } } From 6577f4a5de02c72b72d18ac56d7a68257ce62545 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 16 Apr 2025 22:02:42 +0200 Subject: [PATCH 03/66] rough safeguard for missing dimension type --- .../com/volmit/iris/core/nms/INMSBinding.java | 16 +-- .../iris/core/nms/v1X/NMSBinding1X.java | 10 +- .../iris/core/safeguard/ServerBootSFG.java | 31 +--- .../iris/core/nms/v1_20_R1/NMSBinding.java | 53 ++----- .../iris/core/nms/v1_20_R2/NMSBinding.java | 132 +++++++----------- .../iris/core/nms/v1_20_R3/NMSBinding.java | 126 +++++++---------- .../iris/core/nms/v1_20_R4/NMSBinding.java | 124 ++++++---------- .../iris/core/nms/v1_21_R1/NMSBinding.java | 126 +++++++---------- .../iris/core/nms/v1_21_R2/NMSBinding.java | 120 +++++++--------- .../iris/core/nms/v1_21_R3/NMSBinding.java | 48 ++----- 10 files changed, 282 insertions(+), 504 deletions(-) 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 8c57cb625..5cc90a53b 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 @@ -35,6 +35,7 @@ import org.bukkit.entity.EntityType; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; import java.awt.Color; @@ -88,7 +89,7 @@ public interface INMSBinding { MCABiomeContainer newBiomeContainer(int min, int max); default World createWorld(WorldCreator c) { - if (missingDimensionTypes(c.environment())) + if (missingDimensionTypes(c.generator())) throw new IllegalStateException("Missing dimenstion types to create world"); return c.createWorld(); @@ -126,18 +127,7 @@ public interface INMSBinding { KList getStructureKeys(); - KMap getMainWorlds(); - - boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end); - - default boolean missingDimensionTypes(World.Environment env) { - return switch (env) { - case NORMAL -> missingDimensionTypes(true, false, false); - case NETHER -> missingDimensionTypes(false, true, false); - case THE_END -> missingDimensionTypes(false, false, true); - default -> true; - }; - } + boolean missingDimensionTypes(@Nullable ChunkGenerator generator); default boolean injectBukkit() { return true; 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 90e68c549..4b2ef8158 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 @@ -20,9 +20,7 @@ package com.volmit.iris.core.nms.v1X; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMSBinding; -import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; -import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; @@ -39,6 +37,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.structure.Structure; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; import java.awt.Color; import java.util.stream.StreamSupport; @@ -121,12 +120,7 @@ public class NMSBinding1X implements INMSBinding { } @Override - public KMap getMainWorlds() { - return new KMap<>(); - } - - @Override - public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) { + public boolean missingDimensionTypes(@Nullable ChunkGenerator generator) { return false; } 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 9ee9a4d2e..37a300a6a 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 @@ -4,11 +4,7 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.v1X.NMSBinding1X; import com.volmit.iris.util.agent.Agent; -import com.volmit.iris.util.misc.ServerProperties; import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import javax.tools.JavaCompiler; @@ -20,7 +16,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.*; -import java.util.function.Predicate; import static com.volmit.iris.Iris.getJavaVersion; import static com.volmit.iris.core.safeguard.IrisSafeguard.*; @@ -189,30 +184,6 @@ public class ServerBootSFG { } private static boolean missingDimensionTypes() { - var irisWorlds = irisWorlds(); - if (irisWorlds.isEmpty()) return false; - - var worlds = INMS.get().getMainWorlds(); - worlds.keySet().removeIf(Predicate.not(irisWorlds::contains)); - - boolean overworld = worlds.containsValue(World.Environment.NORMAL) || worlds.containsValue(World.Environment.CUSTOM); - boolean nether = worlds.containsValue(World.Environment.NETHER); - boolean end = worlds.containsValue(World.Environment.THE_END); - - if (overworld || nether || end) - return INMS.get().missingDimensionTypes(overworld, nether, end); - return false; + return INMS.get().missingDimensionTypes(null); } - - private static List irisWorlds() { - var config = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML); - ConfigurationSection section = config.getConfigurationSection("worlds"); - if (section == null) return List.of(); - - return section.getKeys(false) - .stream() - .filter(k -> section.getString(k + ".generator", "").startsWith("Iris")) - .toList(); - } - } 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 e723b55b7..54ec3cb4d 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 @@ -17,7 +17,6 @@ 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.misc.ServerProperties; import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; @@ -26,8 +25,10 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; -import net.minecraft.core.*; +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.*; import net.minecraft.nbt.Tag; @@ -58,7 +59,6 @@ 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_R1.CraftChunk; import org.bukkit.craftbukkit.v1_20_R1.CraftServer; import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; @@ -75,12 +75,14 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import java.awt.*; import java.awt.Color; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; +import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -641,37 +643,16 @@ public class NMSBinding implements INMSBinding { } @Override - @SuppressWarnings("all") - public KMap getMainWorlds() { - String levelName = ServerProperties.LEVEL_NAME; - KMap worlds = new KMap<>(); - for (var key : registry().registryOrThrow(Registries.LEVEL_STEM).registryKeySet()) { - World.Environment env = World.Environment.NORMAL; - if (key == LevelStem.NETHER) { - if (!Bukkit.getAllowNether()) - continue; - env = World.Environment.NETHER; - } else if (key == LevelStem.END) { - if (!Bukkit.getAllowEnd()) - continue; - env = World.Environment.THE_END; - } else if (key != LevelStem.OVERWORLD) { - env = World.Environment.CUSTOM; - } - - String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); - worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); - } - return worlds; - } - - @Override - public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) { - var registry = registry().registryOrThrow(Registries.DIMENSION_TYPE); - if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD)); - if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER)); - if (end) end = !registry.containsKey(createIrisKey(LevelStem.END)); - return overworld || nether || end; + public boolean missingDimensionTypes(ChunkGenerator generator) { + if (generator == null) + return registry().registryOrThrow(Registries.DIMENSION_TYPE) + .keySet() + .stream() + .noneMatch(loc -> loc.getNamespace().equals("iris")); + if (!(generator instanceof PlatformChunkGenerator pcg)) + return false; + var dimensionKey = new ResourceLocation("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); + return !registry().registryOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); } @Override @@ -696,10 +677,6 @@ public class NMSBinding implements INMSBinding { return false; } - private ResourceLocation createIrisKey(ResourceKey key) { - return new ResourceLocation("iris", key.location().getPath()); - } - public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { if (!(raw instanceof PlatformChunkGenerator gen)) throw new IllegalStateException("Generator is not platform chunk generator!"); 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 eed8f0bd6..f21238b97 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 @@ -1,38 +1,56 @@ package com.volmit.iris.core.nms.v1_20_R2; -import java.awt.Color; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.*; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - +import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.datafixers.util.Pair; +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.core.nms.container.BiomeColor; +import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.agent.Agent; +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.misc.ServerProperties; +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.mca.NBTWorld; +import com.volmit.iris.util.nbt.mca.palette.*; +import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.scheduling.J; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; -import net.minecraft.core.*; +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.*; import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.commands.data.BlockDataAccessor; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.tags.TagKey; import net.minecraft.world.RandomSequences; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; +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.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; @@ -58,34 +76,17 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Contract; 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.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.registries.Registries; -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.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.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; +import java.awt.*; +import java.awt.Color; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; public class NMSBinding implements INMSBinding { private final KMap baseBiomeCache = new KMap<>(); @@ -623,6 +624,19 @@ public class NMSBinding implements INMSBinding { return keys; } + @Override + public boolean missingDimensionTypes(ChunkGenerator generator) { + if (generator == null) + return registry().registryOrThrow(Registries.DIMENSION_TYPE) + .keySet() + .stream() + .noneMatch(loc -> loc.getNamespace().equals("iris")); + if (!(generator instanceof PlatformChunkGenerator pcg)) + return false; + var dimensionKey = new ResourceLocation("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); + return !registry().registryOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); + } + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { try { for (Field f : clazz.getDeclaredFields()) { @@ -644,40 +658,6 @@ public class NMSBinding implements INMSBinding { return registry.getHolderOrThrow(ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(biome.getKey()))); } - @Override - @SuppressWarnings("all") - public KMap getMainWorlds() { - String levelName = ServerProperties.LEVEL_NAME; - KMap worlds = new KMap<>(); - for (var key : registry().registryOrThrow(Registries.LEVEL_STEM).registryKeySet()) { - World.Environment env = World.Environment.NORMAL; - if (key == LevelStem.NETHER) { - if (!Bukkit.getAllowNether()) - continue; - env = World.Environment.NETHER; - } else if (key == LevelStem.END) { - if (!Bukkit.getAllowEnd()) - continue; - env = World.Environment.THE_END; - } else if (key != LevelStem.OVERWORLD) { - env = World.Environment.CUSTOM; - } - - String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); - worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); - } - return worlds; - } - - @Override - public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) { - var registry = registry().registryOrThrow(Registries.DIMENSION_TYPE); - if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD)); - if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER)); - if (end) end = !registry.containsKey(createIrisKey(LevelStem.END)); - return overworld || nether || end; - } - @Override public boolean injectBukkit() { if (injected.getAndSet(true)) @@ -700,10 +680,6 @@ public class NMSBinding implements INMSBinding { return false; } - private ResourceLocation createIrisKey(ResourceKey key) { - return new ResourceLocation("iris", key.location().getPath()); - } - public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { if (!(raw instanceof PlatformChunkGenerator gen)) throw new IllegalStateException("Generator is not platform chunk generator!"); 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 58e2f8df9..f9b960626 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 @@ -1,38 +1,56 @@ package com.volmit.iris.core.nms.v1_20_R3; -import java.awt.Color; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.*; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - +import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.datafixers.util.Pair; +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.core.nms.container.BiomeColor; +import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.agent.Agent; +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.misc.ServerProperties; +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.mca.NBTWorld; +import com.volmit.iris.util.nbt.mca.palette.*; +import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.scheduling.J; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; -import net.minecraft.core.*; +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.*; import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.commands.data.BlockDataAccessor; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.tags.TagKey; import net.minecraft.world.RandomSequences; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; +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.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; @@ -58,34 +76,17 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Contract; 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.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.registries.Registries; -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.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.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; +import java.awt.*; +import java.awt.Color; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; public class NMSBinding implements INMSBinding { private final KMap baseBiomeCache = new KMap<>(); @@ -646,37 +647,16 @@ public class NMSBinding implements INMSBinding { } @Override - @SuppressWarnings("all") - public KMap getMainWorlds() { - String levelName = ServerProperties.LEVEL_NAME; - KMap worlds = new KMap<>(); - for (var key : registry().registryOrThrow(Registries.LEVEL_STEM).registryKeySet()) { - World.Environment env = World.Environment.NORMAL; - if (key == LevelStem.NETHER) { - if (!Bukkit.getAllowNether()) - continue; - env = World.Environment.NETHER; - } else if (key == LevelStem.END) { - if (!Bukkit.getAllowEnd()) - continue; - env = World.Environment.THE_END; - } else if (key != LevelStem.OVERWORLD) { - env = World.Environment.CUSTOM; - } - - String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); - worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); - } - return worlds; - } - - @Override - public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) { - var registry = registry().registryOrThrow(Registries.DIMENSION_TYPE); - if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD)); - if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER)); - if (end) end = !registry.containsKey(createIrisKey(LevelStem.END)); - return overworld || nether || end; + public boolean missingDimensionTypes(ChunkGenerator generator) { + if (generator == null) + return registry().registryOrThrow(Registries.DIMENSION_TYPE) + .keySet() + .stream() + .noneMatch(loc -> loc.getNamespace().equals("iris")); + if (!(generator instanceof PlatformChunkGenerator pcg)) + return false; + var dimensionKey = new ResourceLocation("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); + return !registry().registryOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); } @Override @@ -701,10 +681,6 @@ public class NMSBinding implements INMSBinding { return false; } - private ResourceLocation createIrisKey(ResourceKey key) { - return new ResourceLocation("iris", key.location().getPath()); - } - public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { if (!(raw instanceof PlatformChunkGenerator gen)) throw new IllegalStateException("Generator is not platform chunk generator!"); 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 index 066995605..7fe71001d 100644 --- 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 @@ -1,51 +1,56 @@ package com.volmit.iris.core.nms.v1_20_R4; -import java.awt.Color; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.*; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - +import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.datafixers.util.Pair; +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; +import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.agent.Agent; +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.misc.ServerProperties; +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.mca.NBTWorld; +import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.scheduling.J; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; import net.minecraft.core.*; import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.Registries; import net.minecraft.nbt.*; -import net.minecraft.nbt.ByteTag; -import net.minecraft.nbt.DoubleTag; -import net.minecraft.nbt.EndTag; -import net.minecraft.nbt.FloatTag; -import net.minecraft.nbt.IntTag; -import net.minecraft.nbt.LongTag; -import net.minecraft.nbt.ShortTag; -import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.commands.data.BlockDataAccessor; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.tags.TagKey; import net.minecraft.world.RandomSequences; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; +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 net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; @@ -72,31 +77,17 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Contract; 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.mca.NBTWorld; -import com.volmit.iris.util.nbt.mca.palette.*; - -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import net.minecraft.core.registries.Registries; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.EntityType; -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 java.awt.*; +import java.awt.Color; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; public class NMSBinding implements INMSBinding { private final KMap baseBiomeCache = new KMap<>(); @@ -674,37 +665,16 @@ public class NMSBinding implements INMSBinding { } @Override - @SuppressWarnings("all") - public KMap getMainWorlds() { - String levelName = ServerProperties.LEVEL_NAME; - KMap worlds = new KMap<>(); - for (var key : registry().registryOrThrow(Registries.LEVEL_STEM).registryKeySet()) { - World.Environment env = World.Environment.NORMAL; - if (key == LevelStem.NETHER) { - if (!Bukkit.getAllowNether()) - continue; - env = World.Environment.NETHER; - } else if (key == LevelStem.END) { - if (!Bukkit.getAllowEnd()) - continue; - env = World.Environment.THE_END; - } else if (key != LevelStem.OVERWORLD) { - env = World.Environment.CUSTOM; - } - - String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); - worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); - } - return worlds; - } - - @Override - public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) { - var registry = registry().registryOrThrow(Registries.DIMENSION_TYPE); - if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD)); - if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER)); - if (end) end = !registry.containsKey(createIrisKey(LevelStem.END)); - return overworld || nether || end; + public boolean missingDimensionTypes(ChunkGenerator generator) { + if (generator == null) + return registry().registryOrThrow(Registries.DIMENSION_TYPE) + .keySet() + .stream() + .noneMatch(loc -> loc.getNamespace().equals("iris")); + if (!(generator instanceof PlatformChunkGenerator pcg)) + return false; + var dimensionKey = new ResourceLocation("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); + return !registry().registryOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); } @Override @@ -729,10 +699,6 @@ public class NMSBinding implements INMSBinding { return false; } - private ResourceLocation createIrisKey(ResourceKey key) { - return new ResourceLocation("iris", key.location().getPath()); - } - public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { if (!(raw instanceof PlatformChunkGenerator gen)) throw new IllegalStateException("Generator is not platform chunk generator!"); diff --git a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java index 50a4c4d7a..18b7daac9 100644 --- a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java +++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java @@ -1,41 +1,58 @@ package com.volmit.iris.core.nms.v1_21_R1; -import java.awt.Color; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.*; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - +import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.datafixers.util.Pair; +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; +import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.agent.Agent; +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.misc.ServerProperties; +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.mca.NBTWorld; +import com.volmit.iris.util.nbt.mca.palette.*; +import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.scheduling.J; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; -import net.minecraft.core.*; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.Registries; import net.minecraft.nbt.*; import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.commands.data.BlockDataAccessor; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.tags.TagKey; import net.minecraft.world.RandomSequences; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; +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 net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.WorldGenContext; import net.minecraft.world.level.dimension.LevelStem; @@ -63,33 +80,17 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Contract; 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.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.registries.Registries; -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.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 java.awt.*; +import java.awt.Color; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; public class NMSBinding implements INMSBinding { private final KMap baseBiomeCache = new KMap<>(); @@ -674,37 +675,16 @@ public class NMSBinding implements INMSBinding { } @Override - @SuppressWarnings("all") - public KMap getMainWorlds() { - String levelName = ServerProperties.LEVEL_NAME; - KMap worlds = new KMap<>(); - for (var key : registry().registryOrThrow(Registries.LEVEL_STEM).registryKeySet()) { - World.Environment env = World.Environment.NORMAL; - if (key == LevelStem.NETHER) { - if (!Bukkit.getAllowNether()) - continue; - env = World.Environment.NETHER; - } else if (key == LevelStem.END) { - if (!Bukkit.getAllowEnd()) - continue; - env = World.Environment.THE_END; - } else if (key != LevelStem.OVERWORLD) { - env = World.Environment.CUSTOM; - } - - String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); - worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); - } - return worlds; - } - - @Override - public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) { - var registry = registry().registryOrThrow(Registries.DIMENSION_TYPE); - if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD)); - if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER)); - if (end) end = !registry.containsKey(createIrisKey(LevelStem.END)); - return overworld || nether || end; + public boolean missingDimensionTypes(ChunkGenerator generator) { + if (generator == null) + return registry().registryOrThrow(Registries.DIMENSION_TYPE) + .keySet() + .stream() + .noneMatch(loc -> loc.getNamespace().equals("iris")); + if (!(generator instanceof PlatformChunkGenerator pcg)) + return false; + var dimensionKey = ResourceLocation.fromNamespaceAndPath("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); + return !registry().registryOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); } @Override @@ -729,12 +709,6 @@ public class NMSBinding implements INMSBinding { return false; } - private ResourceLocation createIrisKey(ResourceKey key) { - return ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath()); - } - - - public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { if (!(raw instanceof PlatformChunkGenerator gen)) throw new IllegalStateException("Generator is not platform chunk generator!"); diff --git a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java index b8504cbe8..7b0fb012b 100644 --- a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java +++ b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java @@ -1,40 +1,55 @@ package com.volmit.iris.core.nms.v1_21_R2; -import java.awt.Color; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.*; -import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; +import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.agent.Agent; +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.misc.ServerProperties; +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.mca.NBTWorld; +import com.volmit.iris.util.nbt.mca.palette.*; +import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.scheduling.J; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; import net.minecraft.core.*; import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.Registries; import net.minecraft.nbt.*; import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.commands.data.BlockDataAccessor; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.tags.TagKey; import net.minecraft.world.RandomSequences; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; +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 net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.WorldGenContext; import net.minecraft.world.level.dimension.LevelStem; @@ -62,33 +77,17 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Contract; 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.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.registries.Registries; -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.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 java.awt.*; +import java.awt.Color; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; public class NMSBinding implements INMSBinding { private final KMap baseBiomeCache = new KMap<>(); @@ -673,37 +672,16 @@ public class NMSBinding implements INMSBinding { } @Override - @SuppressWarnings("all") - public KMap getMainWorlds() { - String levelName = ServerProperties.LEVEL_NAME; - KMap worlds = new KMap<>(); - for (var key : registry().lookupOrThrow(Registries.LEVEL_STEM).registryKeySet()) { - World.Environment env = World.Environment.NORMAL; - if (key == LevelStem.NETHER) { - if (!Bukkit.getAllowNether()) - continue; - env = World.Environment.NETHER; - } else if (key == LevelStem.END) { - if (!Bukkit.getAllowEnd()) - continue; - env = World.Environment.THE_END; - } else if (key != LevelStem.OVERWORLD) { - env = World.Environment.CUSTOM; - } - - String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); - worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); - } - return worlds; - } - - @Override - public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) { - var registry = registry().lookupOrThrow(Registries.DIMENSION_TYPE); - if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD)); - if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER)); - if (end) end = !registry.containsKey(createIrisKey(LevelStem.END)); - return overworld || nether || end; + public boolean missingDimensionTypes(ChunkGenerator generator) { + if (generator == null) + return registry().lookupOrThrow(Registries.DIMENSION_TYPE) + .keySet() + .stream() + .noneMatch(loc -> loc.getNamespace().equals("iris")); + if (!(generator instanceof PlatformChunkGenerator pcg)) + return false; + var dimensionKey = ResourceLocation.fromNamespaceAndPath("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); + return !registry().lookupOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); } @Override @@ -728,10 +706,6 @@ public class NMSBinding implements INMSBinding { return false; } - private ResourceLocation createIrisKey(ResourceKey key) { - return ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath()); - } - public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { if (!(raw instanceof PlatformChunkGenerator gen)) throw new IllegalStateException("Generator is not platform chunk generator!"); diff --git a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java index 7f5524b3c..72f21e757 100644 --- a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java +++ b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java @@ -25,12 +25,12 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; -import net.minecraft.core.Registry; import net.minecraft.core.*; +import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.Tag; import net.minecraft.nbt.*; +import net.minecraft.nbt.Tag; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; @@ -77,13 +77,14 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import java.awt.*; import java.awt.Color; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.List; import java.util.*; +import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -671,37 +672,16 @@ public class NMSBinding implements INMSBinding { } @Override - @SuppressWarnings("all") - public KMap getMainWorlds() { - String levelName = ServerProperties.LEVEL_NAME; - KMap worlds = new KMap<>(); - for (var key : registry().lookupOrThrow(Registries.LEVEL_STEM).registryKeySet()) { - World.Environment env = World.Environment.NORMAL; - if (key == LevelStem.NETHER) { - if (!Bukkit.getAllowNether()) - continue; - env = World.Environment.NETHER; - } else if (key == LevelStem.END) { - if (!Bukkit.getAllowEnd()) - continue; - env = World.Environment.THE_END; - } else if (key != LevelStem.OVERWORLD) { - env = World.Environment.CUSTOM; - } - - String worldType = env == World.Environment.CUSTOM ? key.location().getNamespace() + "_" + key.location().getPath() : env.toString().toLowerCase(Locale.ROOT); - worlds.put(key == LevelStem.OVERWORLD ? levelName : levelName + "_" + worldType, env); - } - return worlds; - } - - @Override - public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) { - var registry = registry().lookupOrThrow(Registries.DIMENSION_TYPE); - if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD)); - if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER)); - if (end) end = !registry.containsKey(createIrisKey(LevelStem.END)); - return overworld || nether || end; + public boolean missingDimensionTypes(ChunkGenerator generator) { + if (generator == null) + return registry().lookupOrThrow(Registries.DIMENSION_TYPE) + .keySet() + .stream() + .noneMatch(loc -> loc.getNamespace().equals("iris")); + if (!(generator instanceof PlatformChunkGenerator pcg)) + return false; + var dimensionKey = ResourceLocation.fromNamespaceAndPath("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); + return !registry().lookupOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); } @Override From 86c64f99e9364958dd9db73775757688a8b93f30 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 16 Apr 2025 23:01:57 +0200 Subject: [PATCH 04/66] filter out non iris pack directories in allPacks stream --- .../main/java/com/volmit/iris/core/ServerConfigurator.java | 4 ++++ 1 file changed, 4 insertions(+) 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 b4d281c09..6db180dbc 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -228,6 +228,10 @@ public class ServerConfigurator { return Stream.concat(listFiles(new File("plugins/Iris/packs")), listFiles(Bukkit.getWorldContainer()).map(w -> new File(w, "iris/pack"))) .filter(File::isDirectory) + .filter( base -> { + var content = new File(base, "dimensions").listFiles(); + return content != null && content.length > 0; + }) .map(IrisData::get); } From 2008975a8a79eb06c3d733901f71632f2b2094d0 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 17 Apr 2025 17:30:29 +0200 Subject: [PATCH 05/66] expose most of the dimension type options --- .../volmit/iris/core/ServerConfigurator.java | 6 +- .../iris/core/nms/datapack/IDataFixer.java | 14 +- .../nms/datapack/v1192/DataFixerV1192.java | 101 +++--- .../nms/datapack/v1206/DataFixerV1206.java | 7 +- .../iris/engine/object/IrisDimension.java | 41 +-- .../iris/engine/object/IrisDimensionType.java | 91 +++++ .../object/IrisDimensionTypeOptions.java | 320 ++++++++++++++++++ 7 files changed, 499 insertions(+), 81 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/engine/object/IrisDimensionType.java create mode 100644 core/src/main/java/com/volmit/iris/engine/object/IrisDimensionTypeOptions.java 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 6db180dbc..f9aaee49c 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -23,9 +23,7 @@ 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.datapack.IDataFixer; -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.*; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KSet; @@ -296,7 +294,7 @@ public class ServerConfigurator { int logicalHeight = data.get(2); if (minY == Integer.MAX_VALUE || maxY == Integer.MIN_VALUE || Integer.MIN_VALUE == logicalHeight) return null; - return fixer.createDimension(dimension, minY, maxY, logicalHeight).toString(4); + return fixer.createDimension(dimension, minY, maxY - minY, logicalHeight, null).toString(4); } } } 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 index 889acddff..0e8a706a3 100644 --- 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 @@ -1,21 +1,25 @@ package com.volmit.iris.core.nms.datapack; import com.volmit.iris.engine.object.IrisBiomeCustom; +import com.volmit.iris.engine.object.IrisDimensionTypeOptions; import com.volmit.iris.util.json.JSONObject; +import org.jetbrains.annotations.Nullable; public interface IDataFixer { - default JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) { return json; } - JSONObject rawDimension(Dimension dimension); + JSONObject resolve(Dimension dimension, @Nullable IrisDimensionTypeOptions options); - default JSONObject createDimension(Dimension dimension, int minY, int maxY, int logicalHeight) { - JSONObject obj = rawDimension(dimension); + void fixDimension(Dimension dimension, JSONObject json); + + default JSONObject createDimension(Dimension base, int minY, int height, int logicalHeight, @Nullable IrisDimensionTypeOptions options) { + JSONObject obj = resolve(base, options); obj.put("min_y", minY); - obj.put("height", maxY - minY); + obj.put("height", height); obj.put("logical_height", logicalHeight); + fixDimension(base, obj); return obj; } 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 index f2697cf38..a9bb59e0e 100644 --- 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 @@ -1,81 +1,104 @@ package com.volmit.iris.core.nms.datapack.v1192; import com.volmit.iris.core.nms.datapack.IDataFixer; +import com.volmit.iris.engine.object.IrisDimensionTypeOptions; import com.volmit.iris.util.json.JSONObject; +import org.jetbrains.annotations.Nullable; + import java.util.Map; +import static com.volmit.iris.engine.object.IrisDimensionTypeOptions.TriState.*; + public class DataFixerV1192 implements IDataFixer { + private static final Map OPTIONS = Map.of( + Dimension.OVERWORLD, new IrisDimensionTypeOptions( + FALSE, + TRUE, + FALSE, + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, + 1d, + 0f, + null, + 192, + 0), + Dimension.NETHER, new IrisDimensionTypeOptions( + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + FALSE, + FALSE, + TRUE, + 8d, + 0.1f, + 18000L, + null, + 15), + Dimension.END, new IrisDimensionTypeOptions( + FALSE, + FALSE, + FALSE, + FALSE, + FALSE, + TRUE, + FALSE, + FALSE, + 1d, + 0f, + 6000L, + null, + 0) + ); private static final Map DIMENSIONS = Map.of( Dimension.OVERWORLD, """ { - "ambient_light": 0.0, - "bed_works": true, - "coordinate_scale": 1.0, "effects": "minecraft:overworld", - "has_ceiling": false, - "has_raids": true, - "has_skylight": true, "infiniburn": "#minecraft:infiniburn_overworld", - "monster_spawn_block_light_limit": 0, "monster_spawn_light_level": { "type": "minecraft:uniform", "value": { "max_inclusive": 7, "min_inclusive": 0 } - }, - "natural": true, - "piglin_safe": false, - "respawn_anchor_works": false, - "ultrawarm": false + } }""", Dimension.NETHER, """ { - "ambient_light": 0.1, - "bed_works": false, - "coordinate_scale": 8.0, "effects": "minecraft:the_nether", - "fixed_time": 18000, - "has_ceiling": true, - "has_raids": false, - "has_skylight": false, "infiniburn": "#minecraft:infiniburn_nether", - "monster_spawn_block_light_limit": 15, "monster_spawn_light_level": 7, - "natural": false, - "piglin_safe": true, - "respawn_anchor_works": true, - "ultrawarm": true }""", Dimension.END, """ { - "ambient_light": 0.0, - "bed_works": false, - "coordinate_scale": 1.0, "effects": "minecraft:the_end", - "fixed_time": 6000, - "has_ceiling": false, - "has_raids": true, - "has_skylight": false, "infiniburn": "#minecraft:infiniburn_end", - "monster_spawn_block_light_limit": 0, "monster_spawn_light_level": { "type": "minecraft:uniform", "value": { "max_inclusive": 7, "min_inclusive": 0 } - }, - "natural": false, - "piglin_safe": false, - "respawn_anchor_works": false, - "ultrawarm": false + } }""" ); @Override - public JSONObject rawDimension(Dimension dimension) { - return new JSONObject(DIMENSIONS.get(dimension)); + public JSONObject resolve(Dimension dimension, @Nullable IrisDimensionTypeOptions options) { + return options == null ? OPTIONS.get(dimension).toJson() : options.resolve(OPTIONS.get(dimension)).toJson(); + } + + @Override + public void fixDimension(Dimension dimension, JSONObject json) { + var missing = new JSONObject(DIMENSIONS.get(dimension)); + for (String key : missing.keySet()) { + if (json.has(key)) continue; + json.put(key, missing.get(key)); + } } } 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 index 638f043b1..eb8b59c28 100644 --- 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 @@ -45,13 +45,12 @@ public class DataFixerV1206 extends DataFixerV1192 { } @Override - public JSONObject rawDimension(Dimension dimension) { - JSONObject json = super.rawDimension(dimension); + public void fixDimension(Dimension dimension, JSONObject json) { + super.fixDimension(dimension, json); if (!(json.get("monster_spawn_light_level") instanceof JSONObject lightLevel)) - return json; + return; 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/engine/object/IrisDimension.java b/core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java index ba6b07717..7c1cb852c 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 @@ -31,7 +31,6 @@ import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.data.DataProvider; -import com.volmit.iris.util.data.Varint; import com.volmit.iris.util.io.IO; import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.math.Position2; @@ -47,10 +46,7 @@ import org.bukkit.Material; import org.bukkit.World.Environment; import org.bukkit.block.data.BlockData; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.IOException; +import java.io.*; @Accessors(chain = true) @AllArgsConstructor @@ -166,6 +162,8 @@ public class IrisDimension extends IrisRegistrant { private int fluidHeight = 63; @Desc("Define the min and max Y bounds of this dimension. Please keep in mind that Iris internally generates from 0 to (max - min). \n\nFor example at -64 to 320, Iris is internally generating to 0 to 384, then on outputting chunks, it shifts it down by the min height (64 blocks). The default is -64 to 320. \n\nThe fluid height is placed at (fluid height + min height). So a fluid height of 63 would actually show up in the world at 1.") private IrisRange dimensionHeight = new IrisRange(-64, 320); + @Desc("Define options for this dimension") + private IrisDimensionTypeOptions dimensionOptions = new IrisDimensionTypeOptions(); @RegistryListResource(IrisBiome.class) @Desc("Keep this either undefined or empty. Setting any biome name into this will force iris to only generate the specified biome. Great for testing.") private String focus = ""; @@ -415,21 +413,20 @@ public class IrisDimension extends IrisRegistrant { } public String getDimensionTypeKey() { - return getDimensionTypeKey(getBaseDimension(), getMinHeight(), getMaxHeight(), getLogicalHeight()); + return getDimensionType().key(); + } + + public IrisDimensionType getDimensionType() { + return new IrisDimensionType(getBaseDimension(), getDimensionOptions(), getLogicalHeight(), getMaxHeight() - getMinHeight(), getMinHeight()); } public void installDimensionType(IDataFixer fixer, KList folders) { - String key = getDimensionTypeKey(); - String json = fixer.createDimension( - getBaseDimension(), - getMinHeight(), - getMaxHeight(), - getLogicalHeight() - ).toString(4); + IrisDimensionType type = getDimensionType(); + String json = type.toJson(fixer); - Iris.verbose(" Installing Data Pack Dimension Type: \"iris:" + key + '"'); + Iris.verbose(" Installing Data Pack Dimension Type: \"iris:" + type.key() + '"'); for (File datapacks : folders) { - File output = new File(datapacks, "iris/data/iris/dimension_type/" + key + ".json"); + File output = new File(datapacks, "iris/data/iris/dimension_type/" + type.key() + ".json"); output.getParentFile().mkdirs(); try { IO.writeAll(output, json); @@ -485,20 +482,6 @@ public class IrisDimension extends IrisRegistrant { } } - public static String getDimensionTypeKey(Dimension dimension, int minY, int maxY, int logicalHeight) { - var stream = new ByteArrayOutputStream(13); - try (var dos = new DataOutputStream(stream)) { - dos.writeByte(dimension.ordinal()); - Varint.writeUnsignedVarInt(logicalHeight, dos); - Varint.writeUnsignedVarInt(maxY - minY, dos); - Varint.writeSignedVarInt(minY, dos); - } catch (IOException e) { - throw new RuntimeException("This is impossible", e); - } - - return IO.encode(stream.toByteArray()).replace("=", ".").toLowerCase(); - } - private static void write(File datapacks, String type, String json) { if (json == null) return; File dimTypeVanilla = new File(datapacks, "iris/data/minecraft/dimension_type/" + type + ".json"); diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisDimensionType.java b/core/src/main/java/com/volmit/iris/engine/object/IrisDimensionType.java new file mode 100644 index 000000000..756e4c538 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisDimensionType.java @@ -0,0 +1,91 @@ +package com.volmit.iris.engine.object; + +import com.volmit.iris.core.nms.datapack.IDataFixer; +import com.volmit.iris.util.data.Varint; +import com.volmit.iris.util.io.IO; +import lombok.*; +import lombok.experimental.Accessors; + +import java.io.*; + +@Getter +@ToString +@Accessors(fluent = true, chain = true) +@EqualsAndHashCode +public final class IrisDimensionType { + @NonNull + private final String key; + @NonNull + private final IDataFixer.Dimension base; + @NonNull + private final IrisDimensionTypeOptions options; + private final int logicalHeight; + private final int height; + private final int minY; + + public IrisDimensionType( + @NonNull IDataFixer.Dimension base, + @NonNull IrisDimensionTypeOptions options, + int logicalHeight, + int height, + int minY + ) { + if (logicalHeight > height) throw new IllegalArgumentException("Logical height cannot be greater than height"); + if (logicalHeight < 0) throw new IllegalArgumentException("Logical height cannot be less than zero"); + if (height < 16 || height > 4064 ) throw new IllegalArgumentException("Height must be between 16 and 4064"); + if ((height & 15) != 0) throw new IllegalArgumentException("Height must be a multiple of 16"); + if (minY < -2032 || minY > 2031) throw new IllegalArgumentException("Min Y must be between -2032 and 2031"); + if ((minY & 15) != 0) throw new IllegalArgumentException("Min Y must be a multiple of 16"); + + this.base = base; + this.options = options; + this.logicalHeight = logicalHeight; + this.height = height; + this.minY = minY; + this.key = createKey(); + } + + public static IrisDimensionType fromKey(String key) { + var stream = new ByteArrayInputStream(IO.decode(key.replace(".", "=").toUpperCase())); + try (var din = new DataInputStream(stream)) { + return new IrisDimensionType( + IDataFixer.Dimension.values()[din.readUnsignedByte()], + new IrisDimensionTypeOptions().read(din), + Varint.readUnsignedVarInt(din), + Varint.readUnsignedVarInt(din), + Varint.readSignedVarInt(din) + ); + } catch (IOException e) { + throw new RuntimeException("This is impossible", e); + } + } + + public String toJson(IDataFixer fixer) { + return fixer.createDimension( + base, + minY, + height, + logicalHeight, + options.copy() + ).toString(4); + } + + private String createKey() { + var stream = new ByteArrayOutputStream(41); + try (var dos = new DataOutputStream(stream)) { + dos.writeByte(base.ordinal()); + options.write(dos); + Varint.writeUnsignedVarInt(logicalHeight, dos); + Varint.writeUnsignedVarInt(height, dos); + Varint.writeSignedVarInt(minY, dos); + } catch (IOException e) { + throw new RuntimeException("This is impossible", e); + } + + return IO.encode(stream.toByteArray()).replace("=", ".").toLowerCase(); + } + + public IrisDimensionTypeOptions options() { + return options.copy(); + } +} diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisDimensionTypeOptions.java b/core/src/main/java/com/volmit/iris/engine/object/IrisDimensionTypeOptions.java new file mode 100644 index 000000000..139d6296d --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisDimensionTypeOptions.java @@ -0,0 +1,320 @@ +package com.volmit.iris.engine.object; + +import com.volmit.iris.engine.object.annotations.Desc; +import com.volmit.iris.engine.object.annotations.MaxNumber; +import com.volmit.iris.engine.object.annotations.MinNumber; +import com.volmit.iris.util.data.Varint; +import com.volmit.iris.util.json.JSONObject; +import lombok.*; +import lombok.experimental.Accessors; +import org.jetbrains.annotations.Nullable; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.Arrays; + +import static com.volmit.iris.engine.object.IrisDimensionTypeOptions.TriState.*; + +@Data +@NoArgsConstructor +@Accessors(fluent = true, chain = true) +@Desc("Optional options for the dimension type") +public class IrisDimensionTypeOptions { + @MinNumber(0.00001) + @MaxNumber(30000000) + @Desc("The multiplier applied to coordinates when leaving the dimension. Value between 0.00001 and 30000000.0 (both inclusive).") + private double coordinateScale = -1; + @MinNumber(0) + @MaxNumber(1) + @Desc("How much light the dimension has. When set to 0, it completely follows the light level; when set to 1, there is no ambient lighting.") + private float ambientLight = -1; + @Nullable + @MinNumber(0) + @MaxNumber(Long.MAX_VALUE) + @Desc("If this is set to an int, the time of the day is the specified value. To ensure a normal time cycle, set it to null.") + private Long fixedTime = -1L; + @Nullable + @MinNumber(-2032) + @MaxNumber(2031) + @Desc("Optional value between -2032 and 2031. If set, determines the lower edge of the clouds. If set to null, clouds are disabled in the dimension.") + private Integer cloudHeight = -1; + @MinNumber(0) + @MaxNumber(15) + @Desc("Value between 0 and 15 (both inclusive). Maximum block light required when the monster spawns.") + private int monsterSpawnBlockLightLimit = -1; + + @NonNull + @Desc("Whether the dimensions behaves like the nether (water evaporates and sponges dry) or not. Also lets stalactites drip lava and causes lava to spread faster and thinner.") + private TriState ultrawarm = DEFAULT; + @NonNull + @Desc("When false, compasses spin randomly, and using a bed to set the respawn point or sleep, is disabled. When true, nether portals can spawn zombified piglins, and creaking hearts can spawn creakings.") + private TriState natural = DEFAULT; + @NonNull + @Desc("When false, Piglins and hoglins shake and transform to zombified entities.") + private TriState piglinSafe = DEFAULT; + @NonNull + @Desc("When false, the respawn anchor blows up when trying to set spawn point.") + private TriState respawnAnchorWorks = DEFAULT; + @NonNull + @Desc("When false, the bed blows up when trying to sleep.") + private TriState bedWorks = DEFAULT; + @NonNull + @Desc("Whether players with the Bad Omen effect can cause a raid.") + private TriState raids = DEFAULT; + @NonNull + @Desc("Whether the dimension has skylight or not.") + private TriState skylight = DEFAULT; + @NonNull + @Desc("Whether the dimension has a bedrock ceiling. Note that this is only a logical ceiling. It is unrelated with whether the dimension really has a block ceiling.") + private TriState ceiling = DEFAULT; + + public IrisDimensionTypeOptions( + @NonNull TriState ultrawarm, + @NonNull TriState natural, + @NonNull TriState piglinSafe, + @NonNull TriState respawnAnchorWorks, + @NonNull TriState bedWorks, + @NonNull TriState raids, + @NonNull TriState skylight, + @NonNull TriState ceiling, + double coordinateScale, + float ambientLight, + @Nullable Long fixedTime, + @Nullable Integer cloudHeight, + int monsterSpawnBlockLightLimit + ) { + if (coordinateScale != -1 && (coordinateScale < 0.00001 || coordinateScale > 30000000)) + throw new IllegalArgumentException("Coordinate scale must be between 0.00001 and 30000000"); + if (ambientLight != -1 && (ambientLight < 0 || ambientLight > 1)) + throw new IllegalArgumentException("Ambient light must be between 0 and 1"); + if (cloudHeight != null && cloudHeight != -1 && (cloudHeight < -2032 || cloudHeight > 2031)) + throw new IllegalArgumentException("Cloud height must be between -2032 and 2031"); + if (monsterSpawnBlockLightLimit != -1 && (monsterSpawnBlockLightLimit < 0 || monsterSpawnBlockLightLimit > 15)) + throw new IllegalArgumentException("Monster spawn block light limit must be between 0 and 15"); + + this.ultrawarm = ultrawarm; + this.natural = natural; + this.piglinSafe = piglinSafe; + this.respawnAnchorWorks = respawnAnchorWorks; + this.bedWorks = bedWorks; + this.raids = raids; + this.skylight = skylight; + this.ceiling = ceiling; + this.coordinateScale = coordinateScale; + this.ambientLight = ambientLight; + this.fixedTime = fixedTime; + this.cloudHeight = cloudHeight; + this.monsterSpawnBlockLightLimit = monsterSpawnBlockLightLimit; + } + + public IrisDimensionTypeOptions coordinateScale(double coordinateScale) { + if (coordinateScale != -1 && (coordinateScale < 0.00001 || coordinateScale > 30000000)) + throw new IllegalArgumentException("Coordinate scale must be between 0.00001 and 30000000"); + this.coordinateScale = coordinateScale; + return this; + } + + public IrisDimensionTypeOptions ambientLight(float ambientLight) { + if (ambientLight != -1 && (ambientLight < 0 || ambientLight > 1)) + throw new IllegalArgumentException("Ambient light must be between 0 and 1"); + this.ambientLight = ambientLight; + return this; + } + + public IrisDimensionTypeOptions cloudHeight(@Nullable Integer cloudHeight) { + if (cloudHeight != null && cloudHeight != -1 && (cloudHeight < -2032 || cloudHeight > 2031)) + throw new IllegalArgumentException("Cloud height must be between -2032 and 2031"); + this.cloudHeight = cloudHeight; + return this; + } + + public IrisDimensionTypeOptions monsterSpawnBlockLightLimit(int monsterSpawnBlockLightLimit) { + if (monsterSpawnBlockLightLimit != -1 && (monsterSpawnBlockLightLimit < 0 || monsterSpawnBlockLightLimit > 15)) + throw new IllegalArgumentException("Monster spawn block light limit must be between 0 and 15"); + this.monsterSpawnBlockLightLimit = monsterSpawnBlockLightLimit; + return this; + } + + public void write(DataOutput dos) throws IOException { + int bits = 0; + int index = 0; + + for (TriState state : new TriState[]{ + ultrawarm, + natural, + skylight, + ceiling, + piglinSafe, + bedWorks, + respawnAnchorWorks, + raids + }) { + if (state == DEFAULT) { + index++; + continue; + } + + bits |= (short) (1 << index++); + if (state == TRUE) + bits |= (short) (1 << index++); + } + + if (coordinateScale != -1) + bits |= (1 << index++); + if (ambientLight != -1) + bits |= (1 << index++); + if (monsterSpawnBlockLightLimit != -1) + bits |= (1 << index++); + if (fixedTime != null) { + bits |= (1 << index++); + if (fixedTime != -1L) + bits |= (1 << index++); + } + if (cloudHeight != null) { + bits |= (1 << index++); + if (cloudHeight != -1) + bits |= (1 << index); + } + + Varint.writeSignedVarInt(bits, dos); + + if (coordinateScale != -1) + Varint.writeUnsignedVarLong(Double.doubleToLongBits(coordinateScale), dos); + if (ambientLight != -1) + Varint.writeUnsignedVarInt(Float.floatToIntBits(ambientLight), dos); + if (monsterSpawnBlockLightLimit != -1) + Varint.writeSignedVarInt(monsterSpawnBlockLightLimit, dos); + if (fixedTime != null && fixedTime != -1L) + Varint.writeSignedVarLong(fixedTime, dos); + if (cloudHeight != null && cloudHeight != -1) + Varint.writeSignedVarInt(cloudHeight, dos); + } + + public IrisDimensionTypeOptions read(DataInput dis) throws IOException { + TriState[] states = new TriState[8]; + Arrays.fill(states, DEFAULT); + + int bits = Varint.readSignedVarInt(dis); + int index = 0; + + for (int i = 0; i < 8; i++) { + if ((bits & (1 << index++)) == 0) + continue; + states[i] = (bits & (1 << index++)) == 0 ? FALSE : TRUE; + } + ultrawarm = states[0]; + natural = states[1]; + skylight = states[2]; + ceiling = states[3]; + piglinSafe = states[4]; + bedWorks = states[5]; + respawnAnchorWorks = states[6]; + raids = states[7]; + + coordinateScale = (bits & (1 << index++)) != 0 ? Double.longBitsToDouble(Varint.readUnsignedVarLong(dis)) : -1; + ambientLight = (bits & (1 << index++)) != 0 ? Float.intBitsToFloat(Varint.readUnsignedVarInt(dis)) : -1; + monsterSpawnBlockLightLimit = (bits & (1 << index++)) != 0 ? Varint.readSignedVarInt(dis) : -1; + fixedTime = (bits & (1 << index++)) != 0 ? (bits & (1 << index)) != 0 ? Varint.readSignedVarLong(dis) : -1L : null; + cloudHeight = (bits & (1 << index++)) != 0 ? (bits & (1 << index)) != 0 ? Varint.readSignedVarInt(dis) : -1 : null; + + return this; + } + + public IrisDimensionTypeOptions resolve(IrisDimensionTypeOptions other) { + if (ultrawarm == DEFAULT) + ultrawarm = other.ultrawarm; + if (natural == DEFAULT) + natural = other.natural; + if (piglinSafe == DEFAULT) + piglinSafe = other.piglinSafe; + if (respawnAnchorWorks == DEFAULT) + respawnAnchorWorks = other.respawnAnchorWorks; + if (bedWorks == DEFAULT) + bedWorks = other.bedWorks; + if (raids == DEFAULT) + raids = other.raids; + if (skylight == DEFAULT) + skylight = other.skylight; + if (ceiling == DEFAULT) + ceiling = other.ceiling; + if (coordinateScale == -1) + coordinateScale = other.coordinateScale; + if (ambientLight == -1) + ambientLight = other.ambientLight; + if (fixedTime != null && fixedTime == -1L) + fixedTime = other.fixedTime; + if (cloudHeight != null && cloudHeight == -1) + cloudHeight = other.cloudHeight; + if (monsterSpawnBlockLightLimit == -1) + monsterSpawnBlockLightLimit = other.monsterSpawnBlockLightLimit; + return this; + } + + public JSONObject toJson() { + if (!isComplete()) throw new IllegalStateException("Cannot serialize incomplete options"); + JSONObject json = new JSONObject(); + json.put("ultrawarm", ultrawarm.bool()); + json.put("natural", natural.bool()); + json.put("piglin_safe", piglinSafe.bool()); + json.put("respawn_anchor_works", respawnAnchorWorks.bool()); + json.put("bed_works", bedWorks.bool()); + json.put("has_raids", raids.bool()); + json.put("has_skylight", skylight.bool()); + json.put("has_ceiling", ceiling.bool()); + json.put("coordinate_scale", coordinateScale); + json.put("ambient_light", ambientLight); + json.put("monster_spawn_block_light_limit", monsterSpawnBlockLightLimit); + if (fixedTime != null) json.put("fixed_time", fixedTime); + if (cloudHeight != null) json.put("cloud_height", cloudHeight); + return json; + } + + public IrisDimensionTypeOptions copy() { + return new IrisDimensionTypeOptions( + ultrawarm, + natural, + piglinSafe, + respawnAnchorWorks, + bedWorks, + raids, + skylight, + ceiling, + coordinateScale, + ambientLight, + fixedTime, + cloudHeight, + monsterSpawnBlockLightLimit + ); + } + + public boolean isComplete() { + return ultrawarm != DEFAULT + && natural != DEFAULT + && piglinSafe != DEFAULT + && respawnAnchorWorks != DEFAULT + && bedWorks != DEFAULT + && raids != DEFAULT + && skylight != DEFAULT + && ceiling != DEFAULT + && coordinateScale != -1 + && ambientLight != -1 + && monsterSpawnBlockLightLimit != -1 + && (fixedTime == null || fixedTime != -1L) + && (cloudHeight == null || cloudHeight != -1); + } + + @Desc("Allows reusing the behavior of the base dimension") + public enum TriState { + @Desc("Follow the behavior of the base dimension") + DEFAULT, + @Desc("True") + TRUE, + @Desc("False") + FALSE; + + public boolean bool() { + return this == TRUE; + } + } +} From 6724b0f4c5f71adba810497571920251416d4e31 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 25 Apr 2025 21:18:33 +0200 Subject: [PATCH 06/66] minor cleanup and improved safeguard for missing dimension types --- core/src/main/java/com/volmit/iris/Iris.java | 39 +++++++++++-------- .../com/volmit/iris/core/nms/INMSBinding.java | 9 +++-- .../iris/core/nms/v1X/NMSBinding1X.java | 7 +++- .../iris/core/safeguard/ServerBootSFG.java | 32 ++++++++++++++- .../iris/core/nms/v1_20_R1/NMSBinding.java | 16 +++----- .../iris/core/nms/v1_20_R2/NMSBinding.java | 16 +++----- .../iris/core/nms/v1_20_R3/NMSBinding.java | 16 +++----- .../iris/core/nms/v1_20_R4/NMSBinding.java | 16 +++----- .../iris/core/nms/v1_21_R1/NMSBinding.java | 16 +++----- .../iris/core/nms/v1_21_R2/NMSBinding.java | 16 +++----- .../iris/core/nms/v1_21_R3/NMSBinding.java | 22 +++-------- 11 files changed, 100 insertions(+), 105 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 9e2769ebb..40cc4a659 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -63,6 +63,7 @@ import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.Queue; import com.volmit.iris.util.scheduling.ShurikenQueue; import io.papermc.lib.PaperLib; +import lombok.NonNull; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.text.serializer.ComponentSerializer; import org.bstats.bukkit.Metrics; @@ -748,25 +749,11 @@ public class Iris extends VolmitPlugin implements Listener { } } - IrisDimension dim; - if (id == null || id.isEmpty()) { - dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType()); - } else { - dim = IrisData.loadAnyDimension(id); - } + if (id == null || id.isEmpty()) id = IrisSettings.get().getGenerator().getDefaultWorldType(); Iris.debug("Generator ID: " + id + " requested by bukkit/plugin"); - + IrisDimension dim = loadDimension(worldName, id); 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."); - } + throw new RuntimeException("Can't find dimension " + id + "!"); } Iris.debug("Assuming IrisDimension: " + dim.getName()); @@ -791,6 +778,24 @@ public class Iris extends VolmitPlugin implements Listener { return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey()); } + @Nullable + public static IrisDimension loadDimension(@NonNull String worldName, @NonNull String id) { + var data = IrisData.get(new File(Bukkit.getWorldContainer(), String.join(File.separator, worldName, "iris", "pack"))); + var dimension = data.getDimensionLoader().load(id); + if (dimension == null) dimension = IrisData.loadAnyDimension(id); + if (dimension == null) { + Iris.warn("Unable to find dimension type " + id + " Looking for online packs..."); + Iris.service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, true); + dimension = IrisData.loadAnyDimension(id); + + if (dimension != null) { + Iris.info("Resolved missing dimension, proceeding."); + } + } + + return dimension; + } + public void splash() { if (!IrisSettings.get().getGeneral().isSplashLogoStartup()) { return; 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 5cc90a53b..29fa4e37d 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 @@ -21,6 +21,7 @@ package com.volmit.iris.core.nms; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.mantle.Mantle; @@ -89,9 +90,9 @@ public interface INMSBinding { MCABiomeContainer newBiomeContainer(int min, int max); default World createWorld(WorldCreator c) { - if (missingDimensionTypes(c.generator())) - throw new IllegalStateException("Missing dimenstion types to create world"); - + if (c.generator() instanceof PlatformChunkGenerator gen + && missingDimensionTypes(gen.getTarget().getDimension().getDimensionTypeKey())) + throw new IllegalStateException("Missing dimension types to create world"); return c.createWorld(); } @@ -127,7 +128,7 @@ public interface INMSBinding { KList getStructureKeys(); - boolean missingDimensionTypes(@Nullable ChunkGenerator generator); + boolean missingDimensionTypes(String... keys); default boolean injectBukkit() { return true; 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 4b2ef8158..63a983939 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 @@ -120,7 +120,12 @@ public class NMSBinding1X implements INMSBinding { } @Override - public boolean missingDimensionTypes(@Nullable ChunkGenerator generator) { + public KList getLevelStems() { + return new KList<>(); + } + + @Override + public boolean missingDimensionTypes(String... keys) { return false; } 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 37a300a6a..f7c222db5 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,10 +1,15 @@ package com.volmit.iris.core.safeguard; import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; 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; @@ -184,6 +189,31 @@ public class ServerBootSFG { } private static boolean missingDimensionTypes() { - return INMS.get().missingDimensionTypes(null); + return INMS.get().missingDimensionTypes(getDimensionTypes().toArray(String[]::new)); + } + + 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; } } 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 54ec3cb4d..8bb4d8182 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 @@ -97,7 +97,6 @@ public class NMSBinding implements INMSBinding { private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -643,16 +642,11 @@ public class NMSBinding implements INMSBinding { } @Override - public boolean missingDimensionTypes(ChunkGenerator generator) { - if (generator == null) - return registry().registryOrThrow(Registries.DIMENSION_TYPE) - .keySet() - .stream() - .noneMatch(loc -> loc.getNamespace().equals("iris")); - if (!(generator instanceof PlatformChunkGenerator pcg)) - return false; - var dimensionKey = new ResourceLocation("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); - return !registry().registryOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); + public boolean missingDimensionTypes(String... keys) { + var type = registry().registryOrThrow(Registries.DIMENSION_TYPE); + return !Arrays.stream(keys) + .map(key -> new ResourceLocation("iris", key)) + .allMatch(type::containsKey); } @Override 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 f21238b97..00224f458 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 @@ -96,7 +96,6 @@ public class NMSBinding implements INMSBinding { private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -625,16 +624,11 @@ public class NMSBinding implements INMSBinding { } @Override - public boolean missingDimensionTypes(ChunkGenerator generator) { - if (generator == null) - return registry().registryOrThrow(Registries.DIMENSION_TYPE) - .keySet() - .stream() - .noneMatch(loc -> loc.getNamespace().equals("iris")); - if (!(generator instanceof PlatformChunkGenerator pcg)) - return false; - var dimensionKey = new ResourceLocation("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); - return !registry().registryOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); + public boolean missingDimensionTypes(String... keys) { + var type = registry().registryOrThrow(Registries.DIMENSION_TYPE); + return !Arrays.stream(keys) + .map(key -> new ResourceLocation("iris", key)) + .allMatch(type::containsKey); } private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { 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 f9b960626..fb47198fc 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 @@ -96,7 +96,6 @@ public class NMSBinding implements INMSBinding { private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -647,16 +646,11 @@ public class NMSBinding implements INMSBinding { } @Override - public boolean missingDimensionTypes(ChunkGenerator generator) { - if (generator == null) - return registry().registryOrThrow(Registries.DIMENSION_TYPE) - .keySet() - .stream() - .noneMatch(loc -> loc.getNamespace().equals("iris")); - if (!(generator instanceof PlatformChunkGenerator pcg)) - return false; - var dimensionKey = new ResourceLocation("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); - return !registry().registryOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); + public boolean missingDimensionTypes(String... keys) { + var type = registry().registryOrThrow(Registries.DIMENSION_TYPE); + return !Arrays.stream(keys) + .map(key -> new ResourceLocation("iris", key)) + .allMatch(type::containsKey); } @Override 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 index 7fe71001d..14e02eabc 100644 --- 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 @@ -97,7 +97,6 @@ public class NMSBinding implements INMSBinding { private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -665,16 +664,11 @@ public class NMSBinding implements INMSBinding { } @Override - public boolean missingDimensionTypes(ChunkGenerator generator) { - if (generator == null) - return registry().registryOrThrow(Registries.DIMENSION_TYPE) - .keySet() - .stream() - .noneMatch(loc -> loc.getNamespace().equals("iris")); - if (!(generator instanceof PlatformChunkGenerator pcg)) - return false; - var dimensionKey = new ResourceLocation("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); - return !registry().registryOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); + public boolean missingDimensionTypes(String... keys) { + var type = registry().registryOrThrow(Registries.DIMENSION_TYPE); + return !Arrays.stream(keys) + .map(key -> new ResourceLocation("iris", key)) + .allMatch(type::containsKey); } @Override diff --git a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java index 18b7daac9..035f2cbb6 100644 --- a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java +++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java @@ -100,7 +100,6 @@ public class NMSBinding implements INMSBinding { private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -675,16 +674,11 @@ public class NMSBinding implements INMSBinding { } @Override - public boolean missingDimensionTypes(ChunkGenerator generator) { - if (generator == null) - return registry().registryOrThrow(Registries.DIMENSION_TYPE) - .keySet() - .stream() - .noneMatch(loc -> loc.getNamespace().equals("iris")); - if (!(generator instanceof PlatformChunkGenerator pcg)) - return false; - var dimensionKey = ResourceLocation.fromNamespaceAndPath("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); - return !registry().registryOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); + public boolean missingDimensionTypes(String... keys) { + var type = registry().registryOrThrow(Registries.DIMENSION_TYPE); + return !Arrays.stream(keys) + .map(key -> ResourceLocation.fromNamespaceAndPath("iris", key)) + .allMatch(type::containsKey); } @Override diff --git a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java index 7b0fb012b..93019eb7b 100644 --- a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java +++ b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java @@ -97,7 +97,6 @@ public class NMSBinding implements INMSBinding { private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -672,16 +671,11 @@ public class NMSBinding implements INMSBinding { } @Override - public boolean missingDimensionTypes(ChunkGenerator generator) { - if (generator == null) - return registry().lookupOrThrow(Registries.DIMENSION_TYPE) - .keySet() - .stream() - .noneMatch(loc -> loc.getNamespace().equals("iris")); - if (!(generator instanceof PlatformChunkGenerator pcg)) - return false; - var dimensionKey = ResourceLocation.fromNamespaceAndPath("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); - return !registry().lookupOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); + public boolean missingDimensionTypes(String... keys) { + var type = registry().lookupOrThrow(Registries.DIMENSION_TYPE); + return !Arrays.stream(keys) + .map(key -> ResourceLocation.fromNamespaceAndPath("iris", key)) + .allMatch(type::containsKey); } @Override diff --git a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java index 72f21e757..cf02a9ddb 100644 --- a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java +++ b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java @@ -11,6 +11,7 @@ import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.agent.Agent; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.format.C; import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.json.JSONObject; @@ -77,7 +78,6 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import java.awt.*; import java.awt.Color; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -97,7 +97,6 @@ public class NMSBinding implements INMSBinding { private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final KMap stems = new KMap<>(); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -672,16 +671,11 @@ public class NMSBinding implements INMSBinding { } @Override - public boolean missingDimensionTypes(ChunkGenerator generator) { - if (generator == null) - return registry().lookupOrThrow(Registries.DIMENSION_TYPE) - .keySet() - .stream() - .noneMatch(loc -> loc.getNamespace().equals("iris")); - if (!(generator instanceof PlatformChunkGenerator pcg)) - return false; - var dimensionKey = ResourceLocation.fromNamespaceAndPath("iris", pcg.getTarget().getDimension().getDimensionTypeKey()); - return !registry().lookupOrThrow(Registries.DIMENSION_TYPE).containsKey(dimensionKey); + public boolean missingDimensionTypes(String... keys) { + var type = registry().lookupOrThrow(Registries.DIMENSION_TYPE); + return !Arrays.stream(keys) + .map(key -> ResourceLocation.fromNamespaceAndPath("iris", key)) + .allMatch(type::containsKey); } @Override @@ -706,10 +700,6 @@ public class NMSBinding implements INMSBinding { return false; } - private ResourceLocation createIrisKey(ResourceKey key) { - return ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath()); - } - public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { if (!(raw instanceof PlatformChunkGenerator gen)) throw new IllegalStateException("Generator is not platform chunk generator!"); From f68600464bed47f07aaa97aa587dd4b757682ea9 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 25 May 2025 18:12:48 +0200 Subject: [PATCH 07/66] remove redundant method from NMSBinding1X --- .../java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java | 6 ------ 1 file changed, 6 deletions(-) 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 63a983939..642a00e38 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 @@ -37,7 +37,6 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.structure.Structure; import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.Nullable; import java.awt.Color; import java.util.stream.StreamSupport; @@ -119,11 +118,6 @@ public class NMSBinding1X implements INMSBinding { return new KList<>(list); } - @Override - public KList getLevelStems() { - return new KList<>(); - } - @Override public boolean missingDimensionTypes(String... keys) { return false; From abb1d9cd627569f16dcffb8ab1eaeec5c8665118 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 5 Jun 2025 20:26:16 +0200 Subject: [PATCH 08/66] add bytebuddy binding for 1.21.5 --- .../iris/core/nms/v1_21_R4/NMSBinding.java | 175 ++++++++---------- 1 file changed, 80 insertions(+), 95 deletions(-) diff --git a/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java b/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java index 3b11e017b..6766d2ab8 100644 --- a/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java +++ b/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java @@ -1,16 +1,17 @@ package com.volmit.iris.core.nms.v1_21_R4; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.serialization.Lifecycle; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMSBinding; -import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.platform.PlatformChunkGenerator; +import com.volmit.iris.util.agent.Agent; 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.json.JSONObject; import com.volmit.iris.util.mantle.Mantle; @@ -21,20 +22,24 @@ import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.scheduling.J; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import lombok.SneakyThrows; -import net.minecraft.core.Registry; +import it.unimi.dsi.fastutil.shorts.ShortList; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatchers; import net.minecraft.core.*; +import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.Tag; import net.minecraft.nbt.*; +import net.minecraft.nbt.Tag; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.WorldLoader; import net.minecraft.server.commands.data.BlockDataAccessor; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.tags.TagKey; +import net.minecraft.world.RandomSequences; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.LevelReader; @@ -46,13 +51,16 @@ 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 net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.WorldGenContext; -import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.chunk.storage.SerializableChunkData; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +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; @@ -66,6 +74,7 @@ import org.bukkit.craftbukkit.v1_21_R4.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_21_R4.util.CraftNamespacedKey; 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.Contract; @@ -73,22 +82,23 @@ import org.jetbrains.annotations.NotNull; import java.awt.Color; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.List; import java.util.*; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.ReentrantLock; 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 dataLoadContext = new AtomicCache<>(); + private final AtomicBoolean injected = new AtomicBoolean(); private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); private final AtomicCache registryAccess = new AtomicCache<>(); - private final ReentrantLock dataContextLock = new ReentrantLock(true); private final AtomicCache byIdRef = new AtomicCache<>(); private Field biomeStorageCache = null; @@ -663,103 +673,78 @@ public class NMSBinding implements INMSBinding { } @Override - @SneakyThrows - public AutoClosing injectLevelStems() { - if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!"); - - var server = ((CraftServer) Bukkit.getServer()); - var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class); - var nmsServer = server.getServer(); - var old = nmsServer.worldLoader; - - field.setAccessible(true); - field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext( - old.resources(), - old.dataConfiguration(), - old.datapackWorldgen(), - createRegistryAccess(old.datapackDimensions(), false, true, true, true) - ))); - - return new AutoClosing(() -> { - field.set(nmsServer, old); - dataContextLock.unlock(); - }); + public boolean missingDimensionTypes(String... keys) { + var type = registry().lookupOrThrow(Registries.DIMENSION_TYPE); + return !Arrays.stream(keys) + .map(key -> ResourceLocation.fromNamespaceAndPath("iris", key)) + .allMatch(type::containsKey); } @Override - @SneakyThrows - public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) { - var reg = registry(); - var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class); - field.setAccessible(true); + public boolean injectBukkit() { + if (injected.getAndSet(true)) + return true; + try { + Iris.info("Injecting Bukkit"); + var buddy = new ByteBuddy(); + buddy.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(), Agent.installed()); - var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end); - var injected = access.lookupOrThrow(Registries.LEVEL_STEM); - var old = (Map>, Registry>) field.get(reg); - var fake = new HashMap<>(old); - fake.put(Registries.LEVEL_STEM, injected); - field.set(reg, fake); - - return new AutoClosing(() -> field.set(reg, old)); + return true; + } catch (Throwable e) { + Iris.error(C.RED + "Failed to inject Bukkit"); + e.printStackTrace(); + } + return false; } - @Override - public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) { - var registry = registry().lookupOrThrow(Registries.DIMENSION_TYPE); - if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD)); - if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER)); - if (end) end = !registry.containsKey(createIrisKey(LevelStem.END)); - return overworld || nether || end; + public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { + if (!(raw instanceof PlatformChunkGenerator gen)) + throw new IllegalStateException("Generator is not platform chunk generator!"); + + var dimensionKey = ResourceLocation.fromNamespaceAndPath("iris", gen.getTarget().getDimension().getDimensionTypeKey()); + var dimensionType = access.lookupOrThrow(Registries.DIMENSION_TYPE).getOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, dimensionKey)); + return new LevelStem(dimensionType, chunkGenerator(access)); } - @Override - public void removeCustomDimensions(World world) { - ((CraftWorld) world).getHandle().L.customDimensions = null; - } - - private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) { - var access = registry(); - var dimensions = access.lookupOrThrow(Registries.DIMENSION_TYPE); - - var settings = new FlatLevelGeneratorSettings( - Optional.empty(), - access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID), - List.of() - ); + private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { + var settings = new FlatLevelGeneratorSettings(Optional.empty(), access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID), List.of()); settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); settings.updateLayers(); - - var source = new FlatLevelSource(settings); - var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental()); - if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD); - if (nether) register(fake, dimensions, source, LevelStem.NETHER); - if (end) register(fake, dimensions, source, LevelStem.END); - copy(fake, datapack.lookup(Registries.LEVEL_STEM).orElse(null)); - - if (copy) copy(fake, access.lookupOrThrow(Registries.LEVEL_STEM)); - - return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze(); + return new FlatLevelSource(settings); } - private void register(MappedRegistry target, Registry dimensions, FlatLevelSource source, ResourceKey key) { - var loc = createIrisKey(key); - target.register(key, new LevelStem( - dimensions.get(loc).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())), - source - ), RegistrationInfo.BUILT_IN); - } + private static class ServerLevelAdvice { + @Advice.OnMethodEnter + static void enter( + @Advice.Argument(0) MinecraftServer server, + @Advice.Argument(3) PrimaryLevelData levelData, + @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem, + @Advice.Argument(12) World.Environment env, + @Advice.Argument(value = 13) ChunkGenerator gen + ) { + if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) + return; - private void copy(MappedRegistry target, Registry source) { - if (source == null) return; - source.listElementIds().forEach(key -> { - var value = source.getValue(key); - var info = source.registrationInfo(key).orElse(null); - if (value != null && info != null && !target.containsKey(key)) - target.register(key, value, info); - }); - } + try { + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, ChunkGenerator.class) + .invoke(bindings, server.registryAccess(), gen); - private ResourceLocation createIrisKey(ResourceKey key) { - return ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath()); + levelData.customDimensions = null; + } catch (Throwable e) { + throw new RuntimeException("Iris failed to replace the levelStem", e instanceof InvocationTargetException ex ? ex.getCause() : e); + } + } } } From cc27e8737650988e4957442ffdd38862fca066b2 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 5 Jun 2025 20:34:25 +0200 Subject: [PATCH 09/66] fix world height decreases deleting the whole chunk --- .../iris/core/nms/v1_20_R1/NMSBinding.java | 19 ++++++++++++++++-- .../iris/core/nms/v1_20_R2/NMSBinding.java | 19 ++++++++++++++++-- .../iris/core/nms/v1_20_R3/NMSBinding.java | 19 ++++++++++++++++-- .../iris/core/nms/v1_20_R4/NMSBinding.java | 19 ++++++++++++++++-- .../iris/core/nms/v1_21_R1/NMSBinding.java | 20 +++++++++++++++++-- .../iris/core/nms/v1_21_R2/NMSBinding.java | 20 +++++++++++++++++-- .../iris/core/nms/v1_21_R3/NMSBinding.java | 20 +++++++++++++++++-- .../iris/core/nms/v1_21_R4/NMSBinding.java | 13 ++++++++++++ 8 files changed, 135 insertions(+), 14 deletions(-) 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 8bb4d8182..9b28f5456 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 @@ -50,6 +50,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; @@ -655,14 +656,21 @@ public class NMSBinding implements INMSBinding { return true; try { Iris.info("Injecting Bukkit"); - new ByteBuddy() - .redefine(ServerLevel.class) + var buddy = new ByteBuddy(); + buddy.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(), Agent.installed()); + for (Class clazz : List.of(ChunkAccess.class, ProtoChunk.class)) { + buddy.redefine(clazz) + .visit(Advice.to(ChunkAccessAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(short.class, int.class)))) + .make() + .load(clazz.getClassLoader(), Agent.installed()); + } + return true; } catch (Throwable e) { Iris.error(C.RED + "Failed to inject Bukkit"); @@ -687,6 +695,13 @@ public class NMSBinding implements INMSBinding { return new FlatLevelSource(settings); } + private static class ChunkAccessAdvice { + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + static boolean enter(@Advice.This ChunkAccess access, @Advice.Argument(1) int index) { + return index >= access.getPostProcessing().length; + } + } + private static class ServerLevelAdvice { @Advice.OnMethodEnter static void enter( 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 00224f458..99187723f 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 @@ -51,6 +51,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; @@ -658,14 +659,21 @@ public class NMSBinding implements INMSBinding { return true; try { Iris.info("Injecting Bukkit"); - new ByteBuddy() - .redefine(ServerLevel.class) + var buddy = new ByteBuddy(); + buddy.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(), Agent.installed()); + for (Class clazz : List.of(ChunkAccess.class, ProtoChunk.class)) { + buddy.redefine(clazz) + .visit(Advice.to(ChunkAccessAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(short.class, int.class)))) + .make() + .load(clazz.getClassLoader(), Agent.installed()); + } + return true; } catch (Throwable e) { Iris.error(C.RED + "Failed to inject Bukkit"); @@ -690,6 +698,13 @@ public class NMSBinding implements INMSBinding { return new FlatLevelSource(settings); } + private static class ChunkAccessAdvice { + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + static boolean enter(@Advice.This ChunkAccess access, @Advice.Argument(1) int index) { + return index >= access.getPostProcessing().length; + } + } + private static class ServerLevelAdvice { @Advice.OnMethodEnter static void enter( 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 fb47198fc..c1680fb93 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 @@ -51,6 +51,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; @@ -659,14 +660,21 @@ public class NMSBinding implements INMSBinding { return true; try { Iris.info("Injecting Bukkit"); - new ByteBuddy() - .redefine(ServerLevel.class) + var buddy = new ByteBuddy(); + buddy.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(), Agent.installed()); + for (Class clazz : List.of(ChunkAccess.class, ProtoChunk.class)) { + buddy.redefine(clazz) + .visit(Advice.to(ChunkAccessAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(short.class, int.class)))) + .make() + .load(clazz.getClassLoader(), Agent.installed()); + } + return true; } catch (Throwable e) { Iris.error(C.RED + "Failed to inject Bukkit"); @@ -691,6 +699,13 @@ public class NMSBinding implements INMSBinding { return new FlatLevelSource(settings); } + private static class ChunkAccessAdvice { + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + static boolean enter(@Advice.This ChunkAccess access, @Advice.Argument(1) int index) { + return index >= access.getPostProcessing().length; + } + } + private static class ServerLevelAdvice { @Advice.OnMethodEnter static void enter( 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 index 14e02eabc..1ce8b16b4 100644 --- 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 @@ -51,6 +51,7 @@ 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 net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.FlatLevelSource; @@ -677,14 +678,21 @@ public class NMSBinding implements INMSBinding { return true; try { Iris.info("Injecting Bukkit"); - new ByteBuddy() - .redefine(ServerLevel.class) + var buddy = new ByteBuddy(); + buddy.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(), Agent.installed()); + for (Class clazz : List.of(ChunkAccess.class, ProtoChunk.class)) { + buddy.redefine(clazz) + .visit(Advice.to(ChunkAccessAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(short.class, int.class)))) + .make() + .load(clazz.getClassLoader(), Agent.installed()); + } + return true; } catch (Throwable e) { Iris.error(C.RED + "Failed to inject Bukkit"); @@ -709,6 +717,13 @@ public class NMSBinding implements INMSBinding { return new FlatLevelSource(settings); } + private static class ChunkAccessAdvice { + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + static boolean enter(@Advice.This ChunkAccess access, @Advice.Argument(1) int index) { + return index >= access.getPostProcessing().length; + } + } + private static class ServerLevelAdvice { @Advice.OnMethodEnter static void enter( diff --git a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java index 035f2cbb6..485b44e0c 100644 --- a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java +++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java @@ -23,6 +23,7 @@ import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.scheduling.J; import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.shorts.ShortList; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; @@ -53,6 +54,7 @@ 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 net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.WorldGenContext; import net.minecraft.world.level.dimension.LevelStem; @@ -687,14 +689,21 @@ public class NMSBinding implements INMSBinding { return true; try { Iris.info("Injecting Bukkit"); - new ByteBuddy() - .redefine(ServerLevel.class) + var buddy = new ByteBuddy(); + buddy.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(), Agent.installed()); + for (Class clazz : List.of(ChunkAccess.class, ProtoChunk.class)) { + buddy.redefine(clazz) + .visit(Advice.to(ChunkAccessAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(short.class, int.class)))) + .make() + .load(clazz.getClassLoader(), Agent.installed()); + } + return true; } catch (Throwable e) { Iris.error(C.RED + "Failed to inject Bukkit"); @@ -719,6 +728,13 @@ public class NMSBinding implements INMSBinding { return new FlatLevelSource(settings); } + private static class ChunkAccessAdvice { + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + static boolean enter(@Advice.This ChunkAccess access, @Advice.Argument(1) int index) { + return index >= access.getPostProcessing().length; + } + } + private static class ServerLevelAdvice { @Advice.OnMethodEnter static void enter( diff --git a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java index 93019eb7b..dff3db099 100644 --- a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java +++ b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java @@ -22,6 +22,7 @@ import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.scheduling.J; import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.shorts.ShortList; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; @@ -50,6 +51,7 @@ 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 net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.WorldGenContext; import net.minecraft.world.level.dimension.LevelStem; @@ -684,14 +686,21 @@ public class NMSBinding implements INMSBinding { return true; try { Iris.info("Injecting Bukkit"); - new ByteBuddy() - .redefine(ServerLevel.class) + var buddy = new ByteBuddy(); + buddy.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(), Agent.installed()); + for (Class clazz : List.of(ChunkAccess.class, ProtoChunk.class)) { + buddy.redefine(clazz) + .visit(Advice.to(ChunkAccessAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(ShortList.class, int.class)))) + .make() + .load(clazz.getClassLoader(), Agent.installed()); + } + return true; } catch (Throwable e) { Iris.error(C.RED + "Failed to inject Bukkit"); @@ -716,6 +725,13 @@ public class NMSBinding implements INMSBinding { return new FlatLevelSource(settings); } + private static class ChunkAccessAdvice { + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + static boolean enter(@Advice.This ChunkAccess access, @Advice.Argument(1) int index) { + return index >= access.getPostProcessing().length; + } + } + private static class ServerLevelAdvice { @Advice.OnMethodEnter static void enter( diff --git a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java index cf02a9ddb..ca046a955 100644 --- a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java +++ b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java @@ -23,6 +23,7 @@ import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.scheduling.J; import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.shorts.ShortList; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; @@ -51,6 +52,7 @@ 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 net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.WorldGenContext; import net.minecraft.world.level.dimension.LevelStem; @@ -684,14 +686,21 @@ public class NMSBinding implements INMSBinding { return true; try { Iris.info("Injecting Bukkit"); - new ByteBuddy() - .redefine(ServerLevel.class) + var buddy = new ByteBuddy(); + buddy.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(), Agent.installed()); + for (Class clazz : List.of(ChunkAccess.class, ProtoChunk.class)) { + buddy.redefine(clazz) + .visit(Advice.to(ChunkAccessAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(ShortList.class, int.class)))) + .make() + .load(clazz.getClassLoader(), Agent.installed()); + } + return true; } catch (Throwable e) { Iris.error(C.RED + "Failed to inject Bukkit"); @@ -716,6 +725,13 @@ public class NMSBinding implements INMSBinding { return new FlatLevelSource(settings); } + private static class ChunkAccessAdvice { + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + static boolean enter(@Advice.This ChunkAccess access, @Advice.Argument(1) int index) { + return index >= access.getPostProcessing().length; + } + } + private static class ServerLevelAdvice { @Advice.OnMethodEnter static void enter( diff --git a/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java b/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java index 6766d2ab8..a376cb83d 100644 --- a/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java +++ b/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java @@ -694,6 +694,12 @@ public class NMSBinding implements INMSBinding { boolean.class, RandomSequences.class, World.Environment.class, ChunkGenerator.class, BiomeProvider.class)))) .make() .load(ServerLevel.class.getClassLoader(), Agent.installed()); + for (Class clazz : List.of(ChunkAccess.class, ProtoChunk.class)) { + buddy.redefine(clazz) + .visit(Advice.to(ChunkAccessAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(ShortList.class, int.class)))) + .make() + .load(clazz.getClassLoader(), Agent.installed()); + } return true; } catch (Throwable e) { @@ -719,6 +725,13 @@ public class NMSBinding implements INMSBinding { return new FlatLevelSource(settings); } + private static class ChunkAccessAdvice { + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + static boolean enter(@Advice.This ChunkAccess access, @Advice.Argument(1) int index) { + return index >= access.getPostProcessing().length; + } + } + private static class ServerLevelAdvice { @Advice.OnMethodEnter static void enter( From b62ac875d590b6caa481efe9a7695f4120d04c05 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 10 Jun 2025 16:48:00 +0200 Subject: [PATCH 10/66] cleanup gradle --- build.gradle.kts | 10 +++++++ core/build.gradle.kts | 48 +++++++++++++----------------- core/src/main/resources/plugin.yml | 18 +---------- 3 files changed, 32 insertions(+), 44 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index bb061f2bc..272e924e7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -89,6 +89,7 @@ nmsBindings.forEach { key, value -> dependencies { compileOnly(project(":core")) compileOnly("org.jetbrains:annotations:26.0.2") + compileOnly("net.bytebuddy:byte-buddy:1.17.5") } } @@ -103,6 +104,7 @@ nmsBindings.forEach { key, value -> systemProperty("disable.watchdog", "") systemProperty("net.kyori.ansi.colorLevel", color) systemProperty("com.mojang.eula.agree", true) + jvmArgs("-javaagent:${tasks.jar.flatMap { it.archiveFile }.get().asFile.absolutePath}") } } @@ -114,6 +116,13 @@ tasks { } from(project(":core").tasks.shadowJar.flatMap { it.archiveFile }.map { zipTree(it) }) archiveFileName.set("Iris-${project.version}.jar") + + manifest.attributes( + "Agent-Class" to "com.volmit.iris.util.agent.Installer", + "Premain-Class" to "com.volmit.iris.util.agent.Installer", + "Can-Redefine-Classes" to true, + "Can-Retransform-Classes" to true + ) } register("iris") { @@ -191,6 +200,7 @@ allprojects { maven("https://repo.mineinabyss.com/releases") maven("https://hub.jeff-media.com/nexus/repository/jeff-media-public/") maven("https://repo.nexomc.com/releases/") + maven("https://nexus.phoenixdevt.fr/repository/maven-public/") } dependencies { diff --git a/core/build.gradle.kts b/core/build.gradle.kts index cebfbc6c5..836bd2f7b 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -26,10 +26,8 @@ plugins { val apiVersion = "1.19" val main = "com.volmit.iris.Iris" -repositories { - maven("https://nexus.phoenixdevt.fr/repository/maven-public/") - maven("https://repo.auxilor.io/repository/maven-public/") -} +val dynamic: Configuration by configurations.creating +configurations.compileOnly { extendsFrom(dynamic) } /** * Dependencies. @@ -48,10 +46,6 @@ dependencies { compileOnly("org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT") compileOnly("org.apache.logging.log4j:log4j-api:2.19.0") compileOnly("org.apache.logging.log4j:log4j-core:2.19.0") - compileOnly("commons-io:commons-io:2.13.0") - compileOnly("commons-lang:commons-lang:2.6") - compileOnly("com.github.oshi:oshi-core:5.8.5") - compileOnly("org.lz4:lz4-java:1.8.0") // Third Party Integrations compileOnly("com.nexomc:nexo:1.6.0") @@ -60,9 +54,10 @@ dependencies { 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") + compileOnly("io.lumine:Mythic-Dist:5.2.1") + compileOnly("io.lumine:MythicCrucible-Dist:2.0.0") //implementation files("libs/CustomItems.jar") - // Shaded implementation("com.dfsek:paralithic:0.8.1") implementation("io.papermc:paperlib:1.0.5") @@ -71,24 +66,22 @@ dependencies { implementation("net.kyori:adventure-api:4.17.0") implementation("org.bstats:bstats-bukkit:3.1.0") - //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") - compileOnly("io.lumine:MythicCrucible-Dist:2.0.0") - // Dynamically Loaded - compileOnly("io.timeandspace:smoothie-map:2.0.2") - compileOnly("it.unimi.dsi:fastutil:8.5.8") - compileOnly("com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2") - compileOnly("org.zeroturnaround:zt-zip:1.14") - compileOnly("com.google.code.gson:gson:2.10.1") - compileOnly("org.ow2.asm:asm:9.2") - compileOnly("com.google.guava:guava:33.0.0-jre") - compileOnly("bsf:bsf:2.4.0") - compileOnly("rhino:js:1.7R2") - compileOnly("com.github.ben-manes.caffeine:caffeine:3.0.6") - compileOnly("org.apache.commons:commons-lang3:3.12.0") - compileOnly("com.github.oshi:oshi-core:6.6.5") + dynamic("commons-io:commons-io:2.13.0") + dynamic("commons-lang:commons-lang:2.6") + dynamic("com.github.oshi:oshi-core:6.6.5") + dynamic("org.lz4:lz4-java:1.8.0") + dynamic("it.unimi.dsi:fastutil:8.5.8") + dynamic("com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2") + dynamic("org.zeroturnaround:zt-zip:1.14") + dynamic("com.google.code.gson:gson:2.10.1") + dynamic("org.ow2.asm:asm:9.8") + dynamic("bsf:bsf:2.4.0") + dynamic("rhino:js:1.7R2") + dynamic("com.github.ben-manes.caffeine:caffeine:3.0.6") + dynamic("org.apache.commons:commons-lang3:3.12.0") + dynamic("net.bytebuddy:byte-buddy:1.17.5") + dynamic("net.bytebuddy:byte-buddy-agent:1.17.5") } java { @@ -120,7 +113,8 @@ tasks { "name" to rootProject.name, "version" to rootProject.version, "apiVersion" to apiVersion, - "main" to main + "main" to main, + "libraries" to dynamic.allDependencies.map { "\n - $it" }.sorted().joinToString("") ) filesMatching("**/plugin.yml") { expand(inputs.properties) diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml index d742560ac..89fbfb449 100644 --- a/core/src/main/resources/plugin.yml +++ b/core/src/main/resources/plugin.yml @@ -5,23 +5,7 @@ load: STARTUP authors: [ cyberpwn, NextdoorPsycho, Vatuu ] website: volmit.com description: More than a Dimension! -libraries: - - com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2 - - com.github.ben-manes.caffeine:caffeine:3.0.5 - - org.apache.commons:commons-lang3:3.12.0 - - commons-io:commons-io:2.13.0 - - io.timeandspace:smoothie-map:2.0.2 - - com.google.guava:guava:31.0.1-jre - - com.google.code.gson:gson:2.10.1 - - org.zeroturnaround:zt-zip:1.14 - - it.unimi.dsi:fastutil:8.5.6 - - org.ow2.asm:asm:9.2 - - rhino:js:1.7R2 - - bsf:bsf:2.4.0 - - org.lz4:lz4-java:1.8.0 - - com.github.oshi:oshi-core:6.6.5 - - net.bytebuddy:byte-buddy:1.17.5 - - net.bytebuddy:byte-buddy-agent:1.17.5 +libraries: ${libraries} commands: iris: aliases: [ ir, irs ] From 80548f753c71afea4a9bf531cb9bbbda36cfd7f1 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 21 Jun 2025 11:48:58 +0200 Subject: [PATCH 11/66] isolate java agent to prevent class loader issues --- build.gradle.kts | 14 ++------------ core/agent/build.gradle.kts | 12 ++++++++++++ .../java/com/volmit/iris/util/agent/Installer.java | 0 .../com/volmit/iris/core/safeguard/UtilsSFG.java | 3 ++- .../java/com/volmit/iris/util/agent/Agent.java | 7 ++++++- settings.gradle.kts | 2 +- 6 files changed, 23 insertions(+), 15 deletions(-) create mode 100644 core/agent/build.gradle.kts rename core/{ => agent}/src/main/java/com/volmit/iris/util/agent/Installer.java (100%) diff --git a/build.gradle.kts b/build.gradle.kts index 6c13f9c12..89b226ee0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -106,7 +106,7 @@ nmsBindings.forEach { key, value -> systemProperty("net.kyori.ansi.colorLevel", color) systemProperty("com.mojang.eula.agree", true) systemProperty("iris.errorReporting", errorReporting) - jvmArgs("-javaagent:${tasks.jar.flatMap { it.archiveFile }.get().asFile.absolutePath}") + jvmArgs("-javaagent:${project(":core:agent").tasks.jar.flatMap { it.archiveFile }.get().asFile.absolutePath}") } } @@ -117,14 +117,8 @@ tasks { from(project(":nms:$key").tasks.named("remap").map { zipTree(it.outputs.files.singleFile) }) } from(project(":core").tasks.shadowJar.flatMap { it.archiveFile }.map { zipTree(it) }) + from(project(":core:agent").tasks.jar.flatMap { it.archiveFile }) archiveFileName.set("Iris-${project.version}.jar") - - manifest.attributes( - "Agent-Class" to "com.volmit.iris.util.agent.Installer", - "Premain-Class" to "com.volmit.iris.util.agent.Installer", - "Can-Redefine-Classes" to true, - "Can-Retransform-Classes" to true - ) } register("iris") { @@ -177,10 +171,6 @@ fun exec(vararg command: Any) { p.waitFor() } -dependencies { - implementation(project(":core")) -} - configurations.configureEach { resolutionStrategy.cacheChangingModulesFor(60, "minutes") resolutionStrategy.cacheDynamicVersionsFor(60, "minutes") diff --git a/core/agent/build.gradle.kts b/core/agent/build.gradle.kts new file mode 100644 index 000000000..a0d8024df --- /dev/null +++ b/core/agent/build.gradle.kts @@ -0,0 +1,12 @@ +plugins { + java +} + +tasks.jar { + manifest.attributes( + "Agent-Class" to "com.volmit.iris.util.agent.Installer", + "Premain-Class" to "com.volmit.iris.util.agent.Installer", + "Can-Redefine-Classes" to true, + "Can-Retransform-Classes" to true + ) +} \ No newline at end of file diff --git a/core/src/main/java/com/volmit/iris/util/agent/Installer.java b/core/agent/src/main/java/com/volmit/iris/util/agent/Installer.java similarity index 100% rename from core/src/main/java/com/volmit/iris/util/agent/Installer.java rename to core/agent/src/main/java/com/volmit/iris/util/agent/Installer.java 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 e3deb6f2b..b59a24585 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 @@ -1,6 +1,7 @@ package com.volmit.iris.core.safeguard; import com.volmit.iris.Iris; +import com.volmit.iris.util.agent.Agent; import com.volmit.iris.util.format.C; public class UtilsSFG { @@ -47,7 +48,7 @@ public class UtilsSFG { if (ServerBootSFG.missingAgent) { Iris.safeguard(C.RED + "Java Agent"); Iris.safeguard(C.RED + "- Please enable dynamic agent loading by adding -XX:+EnableDynamicAgentLoading to your jvm arguments."); - Iris.safeguard(C.RED + "- or add the jvm argument -javaagent:plugins/" + Iris.instance.getJarFile().getName()); + Iris.safeguard(C.RED + "- or add the jvm argument -javaagent:" + Agent.AGENT_JAR.getPath()); } if (!ServerBootSFG.passedserversoftware) { Iris.safeguard(C.YELLOW + "Unsupported Server Software"); diff --git a/core/src/main/java/com/volmit/iris/util/agent/Agent.java b/core/src/main/java/com/volmit/iris/util/agent/Agent.java index 009923b30..5f823fc30 100644 --- a/core/src/main/java/com/volmit/iris/util/agent/Agent.java +++ b/core/src/main/java/com/volmit/iris/util/agent/Agent.java @@ -4,10 +4,14 @@ import com.volmit.iris.Iris; import net.bytebuddy.agent.ByteBuddyAgent; import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; +import java.io.File; import java.lang.instrument.Instrumentation; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; public class Agent { private static final String NAME = "com.volmit.iris.util.agent.Installer"; + public static final File AGENT_JAR = new File(Iris.instance.getDataFolder(), "agent.jar"); public static ClassReloadingStrategy installed() { return ClassReloadingStrategy.of(getInstrumentation()); @@ -23,8 +27,9 @@ public class Agent { if (doGetInstrumentation() != null) return true; try { + Files.copy(Iris.instance.getResource("agent.jar"), AGENT_JAR.toPath(), StandardCopyOption.REPLACE_EXISTING); Iris.info("Installing Java Agent..."); - ByteBuddyAgent.attach(Iris.instance.getJarFile(), ByteBuddyAgent.ProcessProvider.ForCurrentVm.INSTANCE); + ByteBuddyAgent.attach(AGENT_JAR, ByteBuddyAgent.ProcessProvider.ForCurrentVm.INSTANCE); } catch (Throwable e) { e.printStackTrace(); } diff --git a/settings.gradle.kts b/settings.gradle.kts index c45462895..862732b5a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,7 +28,7 @@ plugins { rootProject.name = "Iris" -include(":core") +include(":core", ":core:agent") include( ":nms:v1_21_R4", ":nms:v1_21_R3", From 0a0f77ff585f1c1b5cdda9fefeff3c0e1380a86b Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 23 Jun 2025 12:20:43 +0200 Subject: [PATCH 12/66] fix splash being shown twice --- core/src/main/java/com/volmit/iris/Iris.java | 5 ++--- .../volmit/iris/core/safeguard/IrisSafeguard.java | 13 +++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index e472df55a..b38379d26 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -470,7 +470,7 @@ public class Iris extends VolmitPlugin implements Listener { ServerConfigurator.configure(); IrisSafeguard.IrisSafeguardSystem(); getSender().setTag(getTag()); - IrisSafeguard.earlySplash(); + IrisSafeguard.splash(true); linkMultiverseCore = new MultiverseCoreLink(); linkMythicMobs = new MythicMobsLink(); configWatcher = new FileWatcher(getDataFile("settings.json")); @@ -485,8 +485,7 @@ public class Iris extends VolmitPlugin implements Listener { J.sr(this::tickQueue, 0); J.s(this::setupPapi); J.a(ServerConfigurator::configure, 20); - splash(); - UtilsSFG.splash(); + IrisSafeguard.splash(false); autoStartStudio(); checkForBukkitWorlds(); diff --git a/core/src/main/java/com/volmit/iris/core/safeguard/IrisSafeguard.java b/core/src/main/java/com/volmit/iris/core/safeguard/IrisSafeguard.java index 2c9eb9be1..241bdd01f 100644 --- a/core/src/main/java/com/volmit/iris/core/safeguard/IrisSafeguard.java +++ b/core/src/main/java/com/volmit/iris/core/safeguard/IrisSafeguard.java @@ -3,7 +3,10 @@ package com.volmit.iris.core.safeguard; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; +import java.util.concurrent.atomic.AtomicBoolean; + public class IrisSafeguard { + private static final AtomicBoolean sfg = new AtomicBoolean(false); public static boolean unstablemode = false; public static boolean warningmode = false; public static boolean stablemode = false; @@ -13,12 +16,14 @@ public class IrisSafeguard { ServerBootSFG.BootCheck(); } - public static void earlySplash() { - if (ServerBootSFG.safeguardPassed || IrisSettings.get().getGeneral().DoomsdayAnnihilationSelfDestructMode) + public static void splash(boolean early) { + if (early && (ServerBootSFG.safeguardPassed || IrisSettings.get().getGeneral().DoomsdayAnnihilationSelfDestructMode)) return; - Iris.instance.splash(); - UtilsSFG.splash(); + if (!sfg.getAndSet(true)) { + Iris.instance.splash(); + UtilsSFG.splash(); + } } public static String mode() { From 67398174bb889874c08b16bea7527ce6e68cf40a Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 23 Jun 2025 12:25:07 +0200 Subject: [PATCH 13/66] cache iris worlds in a map for datapack generation --- .../java/com/volmit/iris/core/IrisWorlds.java | 79 +++++++++++++++++++ .../volmit/iris/core/ServerConfigurator.java | 4 +- .../engine/platform/BukkitChunkGenerator.java | 53 ++++++------- .../main/java/com/volmit/iris/util/io/IO.java | 2 +- 4 files changed, 108 insertions(+), 30 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/core/IrisWorlds.java diff --git a/core/src/main/java/com/volmit/iris/core/IrisWorlds.java b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java new file mode 100644 index 000000000..9c8302102 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/IrisWorlds.java @@ -0,0 +1,79 @@ +package com.volmit.iris.core; + +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.engine.data.cache.AtomicCache; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.io.IO; +import org.bukkit.Bukkit; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.lang.reflect.Type; +import java.util.Objects; +import java.util.stream.Stream; + +public class IrisWorlds { + private static final AtomicCache cache = new AtomicCache<>(); + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static final Type TYPE = TypeToken.getParameterized(KMap.class, String.class, String.class).getType(); + private final KMap worlds; + private volatile boolean dirty = false; + + private IrisWorlds(KMap worlds) { + this.worlds = worlds; + save(); + } + + public static IrisWorlds get() { + return cache.aquire(() -> { + File file = Iris.instance.getDataFile("worlds.json"); + if (!file.exists()) { + return new IrisWorlds(new KMap<>()); + } + + try { + String json = IO.readAll(file); + KMap worlds = GSON.fromJson(json, TYPE); + return new IrisWorlds(Objects.requireNonNullElseGet(worlds, KMap::new)); + } catch (Throwable e) { + Iris.error("Failed to load worlds.json!"); + e.printStackTrace(); + Iris.reportError(e); + } + + return new IrisWorlds(new KMap<>()); + }); + } + + public void put(String name, String type) { + String old = worlds.put(name, type); + if (!type.equals(old)) + dirty = true; + save(); + } + + public Stream getFolders() { + return worlds.keySet().stream().map(k -> new File(Bukkit.getWorldContainer(), k)); + } + + public void clean() { + dirty = worlds.entrySet().removeIf(entry -> !new File(Bukkit.getWorldContainer(), entry.getKey() + "/iris/pack/dimensions/" + entry.getValue() + ".json").exists()); + } + + public synchronized void save() { + clean(); + if (!dirty) return; + try { + IO.write(Iris.instance.getDataFile("worlds.json"), OutputStreamWriter::new, writer -> GSON.toJson(worlds, TYPE, writer)); + dirty = false; + } catch (IOException e) { + Iris.error("Failed to save worlds.json!"); + e.printStackTrace(); + Iris.reportError(e); + } + } +} 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 f039f3b6d..79261d63d 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -226,8 +226,8 @@ public class ServerConfigurator { } public static Stream allPacks() { - return Stream.concat(listFiles(new File("plugins/Iris/packs")), - listFiles(Bukkit.getWorldContainer()).map(w -> new File(w, "iris/pack"))) + return Stream.concat(listFiles(Iris.instance.getDataFolder("packs")), + IrisWorlds.get().getFolders().map(w -> new File(w, "iris/pack"))) .filter(File::isDirectory) .filter( base -> { var content = new File(base, "dimensions").listFiles(); diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index e1c598fed..2e6035534 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -19,9 +19,9 @@ package com.volmit.iris.engine.platform; import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisWorlds; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.INMS; -import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.engine.IrisEngine; import com.volmit.iris.engine.data.cache.AtomicCache; @@ -62,7 +62,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; -import java.lang.reflect.Field; import java.util.List; import java.util.Random; import java.util.concurrent.CompletableFuture; @@ -115,35 +114,35 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun @EventHandler(priority = EventPriority.LOWEST) public void onWorldInit(WorldInitEvent event) { - try { - if (initialized || !world.name().equals(event.getWorld().getName())) - return; - AutoClosing.closeContext(); - world.setRawWorldSeed(event.getWorld().getSeed()); - Engine engine = getEngine(event.getWorld()); - if (engine == null) { - Iris.warn("Failed to get Engine!"); - J.s(() -> { - Engine engine1 = getEngine(event.getWorld()); - if (engine1 != null) { - try { - INMS.get().inject(event.getWorld().getSeed(), engine1, event.getWorld()); - Iris.info("Injected Iris Biome Source into " + event.getWorld().getName()); - initialized = true; - } catch (Throwable e) { - e.printStackTrace(); - } - } - }, 10); - } else { - INMS.get().inject(event.getWorld().getSeed(), engine, event.getWorld()); - Iris.info("Injected Iris Biome Source into " + event.getWorld().getName()); - spawnChunks.complete(INMS.get().getSpawnChunkCount(event.getWorld())); - initialized = true; + if (initialized || !world.name().equals(event.getWorld().getName())) + return; + world.setRawWorldSeed(event.getWorld().getSeed()); + if (initialize(event.getWorld())) return; + + Iris.warn("Failed to get Engine for " + event.getWorld().getName() + " re-trying..."); + J.s(() -> { + if (!initialize(event.getWorld())) { + Iris.error("Failed to get Engine for " + event.getWorld().getName() + "!"); } + }, 10); + } + + private boolean initialize(World world) { + Engine engine = getEngine(world); + if (engine == null) return false; + try { + INMS.get().inject(world.getSeed(), engine, world); + Iris.info("Injected Iris Biome Source into " + world.getName()); } catch (Throwable e) { + Iris.reportError(e); + Iris.error("Failed to inject biome source into " + world.getName()); e.printStackTrace(); } + spawnChunks.complete(INMS.get().getSpawnChunkCount(world)); + Iris.instance.unregisterListener(this); + initialized = true; + IrisWorlds.get().put(world.getName(), dimensionKey); + return true; } @Nullable diff --git a/core/src/main/java/com/volmit/iris/util/io/IO.java b/core/src/main/java/com/volmit/iris/util/io/IO.java index 281f08096..61deb3670 100644 --- a/core/src/main/java/com/volmit/iris/util/io/IO.java +++ b/core/src/main/java/com/volmit/iris/util/io/IO.java @@ -1643,7 +1643,7 @@ public class IO { return (ch2 == -1); } - public static void write(File file, IOFunction builder, IOConsumer action) throws IOException { + public static void write(File file, IOFunction builder, IOConsumer action) throws IOException { File dir = new File(file.getParentFile(), ".tmp"); dir.mkdirs(); dir.deleteOnExit(); From e38dae0a328ead0a157737b84289edd81fff8610 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 23 Jun 2025 15:51:29 +0200 Subject: [PATCH 14/66] fix required properties for json schemas --- .../java/com/volmit/iris/core/project/SchemaBuilder.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 398d1630b..61d626247 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 @@ -140,6 +140,8 @@ public class SchemaBuilder { JSONObject property = buildProperty(k, c); + if (property.getBoolean("!required")) + required.put(k.getName()); property.remove("!required"); properties.put(k.getName(), property); } @@ -512,8 +514,9 @@ public class SchemaBuilder { d.add(fancyType); d.add(getDescription(k.getType())); - if (k.getType().isAnnotationPresent(Snippet.class)) { - String sm = k.getType().getDeclaredAnnotation(Snippet.class).value(); + Snippet snippet = k.getType().getDeclaredAnnotation(Snippet.class); + if (snippet != null) { + String sm = snippet.value(); d.add(" "); d.add("You can instead specify \"snippet/" + sm + "/some-name.json\" to use a snippet file instead of specifying it here."); } From 36779311148c987fc83a34126f934e1f89807b93 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 23 Jun 2025 15:51:53 +0200 Subject: [PATCH 15/66] improve snippet finder --- .../com/volmit/iris/core/loader/IrisData.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) 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 a272be0d7..52144fef5 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 @@ -44,6 +44,8 @@ import lombok.Data; import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Objects; import java.util.function.Function; @@ -427,8 +429,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory { File f = new File(getDataFolder(), r + ".json"); if (f.exists()) { - try { - JsonReader snippetReader = new JsonReader(new FileReader(f)); + try (JsonReader snippetReader = new JsonReader(new FileReader(f))){ return adapter.read(snippetReader); } catch (Throwable e) { Iris.error("Couldn't read snippet " + r + " in " + reader.getPath() + " (" + e.getMessage() + ")"); @@ -462,11 +463,20 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory { KList l = new KList<>(); File snippetFolder = new File(getDataFolder(), "snippet/" + f); + if (!snippetFolder.exists()) return l; - if (snippetFolder.exists() && snippetFolder.isDirectory()) { - for (File i : snippetFolder.listFiles()) { - l.add("snippet/" + f + "/" + i.getName().split("\\Q.\\E")[0]); - } + String absPath = snippetFolder.getAbsolutePath(); + try (var stream = Files.walk(snippetFolder.toPath())) { + stream.filter(Files::isRegularFile) + .map(Path::toAbsolutePath) + .map(Path::toString) + .filter(s -> s.endsWith(".json")) + .map(s -> s.substring(absPath.length() + 1)) + .map(s -> s.replace("\\", "/")) + .map(s -> s.split("\\Q.\\E")[0]) + .forEach(s -> l.add("snippet/" + f + "/" + s)); + } catch (Throwable e) { + e.printStackTrace(); } return l; From a802edc375810030dd297cb9bdb6e4ee098d7061 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 23 Jun 2025 17:16:45 +0200 Subject: [PATCH 16/66] add some options for customizing caves --- .../iris/engine/mantle/MantleWriter.java | 70 ++++++++++++++++--- .../volmit/iris/engine/object/IrisCave.java | 11 ++- .../iris/engine/object/IrisCaveShape.java | 52 ++++++++++++++ .../volmit/iris/util/mantle/MantleChunk.java | 10 ++- 4 files changed, 131 insertions(+), 12 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java b/core/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java index b71051472..ee2c9bf2d 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/MantleWriter.java @@ -35,6 +35,7 @@ import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.MantleChunk; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.matter.Matter; +import com.volmit.iris.util.noise.CNG; import lombok.Data; import org.bukkit.block.data.BlockData; import org.bukkit.util.Vector; @@ -71,6 +72,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable { private static Set getBallooned(Set vset, double radius) { Set returnset = new HashSet<>(); int ceilrad = (int) Math.ceil(radius); + double r2 = Math.pow(radius, 2); for (IrisPosition v : vset) { int tipx = v.getX(); @@ -80,7 +82,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable { for (int loopx = tipx - ceilrad; loopx <= tipx + ceilrad; loopx++) { for (int loopy = tipy - ceilrad; loopy <= tipy + ceilrad; loopy++) { for (int loopz = tipz - ceilrad; loopz <= tipz + ceilrad; loopz++) { - if (hypot(loopx - tipx, loopy - tipy, loopz - tipz) <= radius) { + if (hypot(loopx - tipx, loopy - tipy, loopz - tipz) <= r2) { returnset.add(new IrisPosition(loopx, loopy, loopz)); } } @@ -113,7 +115,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable { for (double d : pars) { sum += Math.pow(d, 2); } - return Math.sqrt(sum); + return sum; } private static double lengthSq(double x, double y, double z) { @@ -453,6 +455,62 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable { * @param the type of data to apply to the mantle */ public void setLineConsumer(List vectors, double radius, boolean filled, Function3 data) { + Set vset = cleanup(vectors); + vset = getBallooned(vset, radius); + + if (!filled) { + vset = getHollowed(vset); + } + + setConsumer(vset, data); + } + + /** + * Set lines for points + * + * @param vectors the points + * @param radius the radius + * @param filled hollow or filled? + * @param data the data to set + * @param the type of data to apply to the mantle + */ + public void setNoiseMasked(List vectors, double radius, double threshold, CNG shape, Set masks, boolean filled, Function3 data) { + Set vset = cleanup(vectors); + vset = masks == null ? getBallooned(vset, radius) : getMasked(vset, masks, radius); + vset.removeIf(p -> shape.noise(p.getX(), p.getY(), p.getZ()) < threshold); + + if (!filled) { + vset = getHollowed(vset); + } + + setConsumer(vset, data); + } + + private static Set getMasked(Set vectors, Set masks, double radius) { + Set vset = new KSet<>(); + int ceil = (int) Math.ceil(radius); + double r2 = Math.pow(radius, 2); + + for (IrisPosition v : vectors) { + int tipX = v.getX(); + int tipY = v.getY(); + int tipZ = v.getZ(); + + for (int x = -ceil; x <= ceil; x++) { + for (int y = -ceil; y <= ceil; y++) { + for (int z = -ceil; z <= ceil; z++) { + if (hypot(x, y, z) > r2 || !masks.contains(new IrisPosition(x, y, z))) + continue; + vset.add(new IrisPosition(tipX + x, tipY + y, tipZ + z)); + } + } + } + } + + return vset; + } + + private static Set cleanup(List vectors) { Set vset = new KSet<>(); for (int i = 0; vectors.size() != 0 && i < vectors.size() - 1; i++) { @@ -504,13 +562,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable { } } - vset = getBallooned(vset, radius); - - if (!filled) { - vset = getHollowed(vset); - } - - setConsumer(vset, data); + return vset; } /** diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java index 22a45ccc4..db953f1a0 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java @@ -25,9 +25,11 @@ import com.volmit.iris.engine.mantle.MantleWriter; import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.RegistryListResource; import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.matter.MatterCavern; +import com.volmit.iris.util.noise.CNG; import com.volmit.iris.util.plugin.VolmitSender; import lombok.AllArgsConstructor; import lombok.Data; @@ -55,6 +57,9 @@ public class IrisCave extends IrisRegistrant { @Desc("Limit the worm from ever getting higher or lower than this range") private IrisRange verticalRange = new IrisRange(3, 255); + @Desc("Shape of the caves") + private IrisCaveShape shape = new IrisCaveShape(); + @Override public String getFolderName() { return "caves"; @@ -96,8 +101,10 @@ public class IrisCave extends IrisRegistrant { MatterCavern c = new MatterCavern(true, customBiome, (byte) 0); MatterCavern w = new MatterCavern(true, customBiome, (byte) 1); - writer.setLineConsumer(points, - girth, true, + CNG cng = shape.getNoise(rng, engine); + KSet mask = shape.getMasked(rng, engine); + writer.setNoiseMasked(points, + girth, cng.noise(x, y, z), cng, mask, true, (xf, yf, zf) -> yf <= h ? w : c); } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java new file mode 100644 index 000000000..f5001befb --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java @@ -0,0 +1,52 @@ +package com.volmit.iris.engine.object; + +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.object.annotations.Desc; +import com.volmit.iris.engine.object.annotations.RegistryListResource; +import com.volmit.iris.engine.object.annotations.Snippet; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.noise.CNG; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +@Snippet("cave-shape") +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +@Desc("Cave Shape") +@Data +public class IrisCaveShape { + private transient final KMap> cache = new KMap<>(); + + @Desc("Noise used for the shape of the cave") + private IrisGeneratorStyle noise = new IrisGeneratorStyle(); + @RegistryListResource(IrisObject.class) + @Desc("Object used as mask for the shape of the cave") + private String object = null; + @Desc("Rotation to apply to objects before using them as mask") + private IrisObjectRotation objectRotation = new IrisObjectRotation(); + + public CNG getNoise(RNG rng, Engine engine) { + return noise.create(rng, engine.getData()); + } + + public KSet getMasked(RNG rng, Engine engine) { + if (object == null) return null; + return cache.computeIfAbsent(new IrisPosition( + rng.i(0, 360), + rng.i(0, 360), + rng.i(0, 360)), + pos -> { + var rotated = new KSet(); + engine.getData().getObjectLoader().load(object).getBlocks().forEach((vector, data) -> { + if (data.getMaterial().isAir()) return; + rotated.add(new IrisPosition(objectRotation.rotate(vector, pos.getX(), pos.getY(), pos.getZ()))); + }); + return rotated; + }); + } +} diff --git a/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java b/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java index ae4fd1701..1c50d8c98 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java @@ -27,6 +27,7 @@ import com.volmit.iris.util.matter.IrisMatter; import com.volmit.iris.util.matter.Matter; import com.volmit.iris.util.matter.MatterSlice; import lombok.Getter; +import lombok.SneakyThrows; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; @@ -111,9 +112,11 @@ public class MantleChunk { } } - public void close() throws InterruptedException { + @SneakyThrows + public void close() { closed.set(true); ref.acquire(Integer.MAX_VALUE); + ref.release(Integer.MAX_VALUE); } public boolean inUse() { @@ -123,6 +126,10 @@ public class MantleChunk { public MantleChunk use() { if (closed.get()) throw new IllegalStateException("Chunk is closed!"); ref.acquireUninterruptibly(); + if (closed.get()) { + ref.release(); + throw new IllegalStateException("Chunk is closed!"); + } return this; } @@ -213,6 +220,7 @@ public class MantleChunk { * @throws IOException shit happens */ public void write(DataOutputStream dos) throws IOException { + close(); dos.writeByte(x); dos.writeByte(z); dos.writeByte(sections.length()); From cca0bed482c9d4eff8710a050b311ff1e16da089 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 24 Jun 2025 16:53:26 +0200 Subject: [PATCH 17/66] fix cave max size calculation --- core/src/main/java/com/volmit/iris/engine/object/IrisCave.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java index db953f1a0..bcfd2a05c 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java @@ -114,6 +114,6 @@ public class IrisCave extends IrisRegistrant { } public int getMaxSize(IrisData data, int depth) { - return getWorm().getMaxDistance() + fork.getMaxRange(data, depth); + return (int) (Math.ceil(getWorm().getGirth().getMax() * 2) + getWorm().getMaxDistance() + fork.getMaxRange(data, depth)); } } From cf8243a0008db153b8f92dd270c058f2be969437 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 24 Jun 2025 19:37:37 +0200 Subject: [PATCH 18/66] make caves more deterministic --- .../com/volmit/iris/engine/object/IrisCarving.java | 14 +++++++------- .../com/volmit/iris/engine/object/IrisCave.java | 14 +++++++------- .../volmit/iris/engine/object/IrisCavePlacer.java | 8 ++++---- .../com/volmit/iris/engine/object/IrisRavine.java | 12 ++++++------ .../iris/engine/object/IrisRavinePlacer.java | 6 +++--- .../com/volmit/iris/engine/object/IrisWorm.java | 6 +++--- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCarving.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCarving.java index 1da8b1a31..8287db8c4 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCarving.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCarving.java @@ -62,31 +62,31 @@ public class IrisCarving { @BlockCoordinates public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int depth) { - doCarving(writer, rng, engine, x, y, z, depth, -1); + doCarving(writer, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, depth, -1); } @BlockCoordinates - public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { + public void doCarving(MantleWriter writer, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) { int nextRecursion = recursion + 1; if (caves.isNotEmpty()) { for (IrisCavePlacer i : caves) { if (recursion > i.getMaxRecursion()) continue; - i.generateCave(writer, rng, engine, x, y, z, nextRecursion, waterHint); + i.generateCave(writer, rng, base, engine, x, y, z, nextRecursion, waterHint); } } if (ravines.isNotEmpty()) { for (IrisRavinePlacer i : ravines) { if (recursion > i.getMaxRecursion()) continue; - i.generateRavine(writer, rng, engine, x, y, z, nextRecursion, waterHint); + i.generateRavine(writer, rng, base, engine, x, y, z, nextRecursion, waterHint); } } if (spheres.isNotEmpty()) { for (IrisSphere i : spheres) { if (rng.nextInt(i.getRarity()) == 0) { - i.generate(rng, engine, writer, x, y, z); + i.generate(base, engine, writer, x, y, z); } } } @@ -94,7 +94,7 @@ public class IrisCarving { if (elipsoids.isNotEmpty()) { for (IrisElipsoid i : elipsoids) { if (rng.nextInt(i.getRarity()) == 0) { - i.generate(rng, engine, writer, x, y, z); + i.generate(base, engine, writer, x, y, z); } } } @@ -102,7 +102,7 @@ public class IrisCarving { if (pyramids.isNotEmpty()) { for (IrisPyramid i : pyramids) { if (rng.nextInt(i.getRarity()) == 0) { - i.generate(rng, engine, writer, x, y, z); + i.generate(base, engine, writer, x, y, z); } } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java index bcfd2a05c..b780d257d 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java @@ -71,12 +71,12 @@ public class IrisCave extends IrisRegistrant { } public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) { - generate(writer, rng, engine, x, y, z, 0, -1, true); + generate(writer, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1, true); } - public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint, boolean breakSurface) { - double girth = getWorm().getGirth().get(rng, x, z, engine.getData()); - KList points = getWorm().generate(rng, engine.getData(), writer, verticalRange, x, y, z, breakSurface, girth + 9); + public void generate(MantleWriter writer, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint, boolean breakSurface) { + double girth = getWorm().getGirth().get(base.nextParallelRNG(465156), x, z, engine.getData()); + KList points = getWorm().generate(base.nextParallelRNG(784684), engine.getData(), writer, verticalRange, x, y, z, breakSurface, girth + 9); int highestWater = Math.max(waterHint, -1); if (highestWater == -1) { @@ -92,16 +92,16 @@ public class IrisCave extends IrisRegistrant { } - int h = Math.min(Math.max(highestWater, waterHint), engine.getDimension().getFluidHeight()); + int h = Math.min(highestWater, engine.getDimension().getFluidHeight()); for (IrisPosition i : points) { - fork.doCarving(writer, rng, engine, i.getX(), i.getY(), i.getZ(), recursion, h); + fork.doCarving(writer, rng, base, engine, i.getX(), i.getY(), i.getZ(), recursion, h); } MatterCavern c = new MatterCavern(true, customBiome, (byte) 0); MatterCavern w = new MatterCavern(true, customBiome, (byte) 1); - CNG cng = shape.getNoise(rng, engine); + CNG cng = shape.getNoise(base.nextParallelRNG(8131545), engine); KSet mask = shape.getMasked(rng, engine); writer.setNoiseMasked(points, girth, cng.noise(x, y, z), cng, mask, true, diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCavePlacer.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCavePlacer.java index c56a53d69..ccdcaafb9 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCavePlacer.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCavePlacer.java @@ -64,10 +64,10 @@ public class IrisCavePlacer implements IRare { } public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z) { - generateCave(mantle, rng, engine, x, y, z, 0, -1); + generateCave(mantle, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1); } - public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { + public void generateCave(MantleWriter mantle, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) { if (fail.get()) { return; } @@ -86,13 +86,13 @@ public class IrisCavePlacer implements IRare { } if (y == -1) { - int h = (int) caveStartHeight.get(rng, x, z, data); + int h = (int) caveStartHeight.get(base, x, z, data); int ma = breakSurface ? h : (int) (engine.getComplex().getHeightStream().get(x, z) - 9); y = Math.min(h, ma); } try { - cave.generate(mantle, rng, engine, x + rng.nextInt(15), y, z + rng.nextInt(15), recursion, waterHint, breakSurface); + cave.generate(mantle, rng, base, engine, x + rng.nextInt(15), y, z + rng.nextInt(15), recursion, waterHint, breakSurface); } catch (Throwable e) { e.printStackTrace(); fail.set(true); diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisRavine.java b/core/src/main/java/com/volmit/iris/engine/object/IrisRavine.java index 3edd37c29..b7c453bd6 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisRavine.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisRavine.java @@ -93,13 +93,13 @@ public class IrisRavine extends IrisRegistrant { } public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) { - generate(writer, rng, engine, x, y, z, 0, -1); + generate(writer, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1); } - public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { - KList pos = getWorm().generate(rng, engine.getData(), writer, null, x, y, z, true, 0); - CNG dg = depthStyle.getGenerator().createNoCache(rng, engine.getData()); - CNG bw = baseWidthStyle.getGenerator().createNoCache(rng, engine.getData()); + public void generate(MantleWriter writer, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) { + KList pos = getWorm().generate(base.nextParallelRNG(879615), engine.getData(), writer, null, x, y, z, true, 0); + CNG dg = depthStyle.getGenerator().create(base.nextParallelRNG(7894156), engine.getData()); + CNG bw = baseWidthStyle.getGenerator().create(base.nextParallelRNG(15315456), engine.getData()); int highestWater = Math.max(waterHint, -1); boolean water = false; @@ -134,7 +134,7 @@ public class IrisRavine extends IrisRegistrant { int width = (int) Math.round(bw.fitDouble(baseWidthStyle.getMin(), baseWidthStyle.getMax(), p.getX(), p.getZ())); int surface = (int) Math.round(rsurface - depth * 0.45); - fork.doCarving(writer, rng, engine, p.getX(), rng.i(surface - depth, surface), p.getZ(), recursion, Math.max(highestWater, waterHint)); + fork.doCarving(writer, rng, base, engine, p.getX(), rng.i(surface - depth, surface), p.getZ(), recursion, highestWater); for (int i = surface + depth; i >= surface; i--) { if (i % ribThickness == 0) { diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisRavinePlacer.java b/core/src/main/java/com/volmit/iris/engine/object/IrisRavinePlacer.java index fa65c5c79..ed9c01841 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisRavinePlacer.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisRavinePlacer.java @@ -60,10 +60,10 @@ public class IrisRavinePlacer implements IRare { } public void generateRavine(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z) { - generateRavine(mantle, rng, engine, x, y, z, 0, -1); + generateRavine(mantle, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1); } - public void generateRavine(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { + public void generateRavine(MantleWriter mantle, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) { if (fail.get()) { return; } @@ -84,7 +84,7 @@ public class IrisRavinePlacer implements IRare { try { int xx = x + rng.nextInt(15); int zz = z + rng.nextInt(15); - ravine.generate(mantle, rng, engine, xx, y, zz, recursion, waterHint); + ravine.generate(mantle, rng, base, engine, xx, y, zz, recursion, waterHint); } catch (Throwable e) { e.printStackTrace(); fail.set(true); diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisWorm.java b/core/src/main/java/com/volmit/iris/engine/object/IrisWorm.java index b50f9d3be..e83fead07 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisWorm.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisWorm.java @@ -71,9 +71,9 @@ public class IrisWorm { IrisPosition start = new IrisPosition(x, y, z); KList pos = new KList<>(); KSet check = allowLoops ? null : new KSet<>(); - CNG gx = xStyle.getGenerator().createNoCache(new RNG(rng.lmax()), data); - CNG gy = yStyle.getGenerator().createNoCache(new RNG(rng.lmax()), data); - CNG gz = zStyle.getGenerator().createNoCache(new RNG(rng.lmax()), data); + CNG gx = xStyle.getGenerator().create(rng.nextParallelRNG(14567), data); + CNG gy = yStyle.getGenerator().create(rng.nextParallelRNG(64789), data); + CNG gz = zStyle.getGenerator().create(rng.nextParallelRNG(34790), data); while (itr-- > 0) { IrisPosition current = new IrisPosition(Math.round(cx), Math.round(cy), Math.round(cz)); From 5d28563b7c09388c15a330f81c6dea38daadb00e Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 24 Jun 2025 19:43:46 +0200 Subject: [PATCH 19/66] implement generate surface for ores --- .../engine/actuator/IrisTerrainNormalActuator.java | 14 +++++++++++--- .../com/volmit/iris/engine/object/IrisBiome.java | 4 +++- .../volmit/iris/engine/object/IrisDimension.java | 4 +++- .../com/volmit/iris/engine/object/IrisRegion.java | 4 +++- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/actuator/IrisTerrainNormalActuator.java b/core/src/main/java/com/volmit/iris/engine/actuator/IrisTerrainNormalActuator.java index 7d602021e..646ca0773 100644 --- a/core/src/main/java/com/volmit/iris/engine/actuator/IrisTerrainNormalActuator.java +++ b/core/src/main/java/com/volmit/iris/engine/actuator/IrisTerrainNormalActuator.java @@ -106,6 +106,14 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator } } + BlockData ore = biome.generateOres(realX, i, realZ, rng, getData(), true); + ore = ore == null ? region.generateOres(realX, i, realZ, rng, getData(), true) : ore; + ore = ore == null ? getDimension().generateOres(realX, i, realZ, rng, getData(), true) : ore; + if (ore != null) { + h.set(xf, i, zf, ore); + continue; + } + if (i > he && i <= hf) { fdepth = hf - i; @@ -138,9 +146,9 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator continue; } - BlockData ore = biome.generateOres(realX, i, realZ, rng, getData()); - ore = ore == null ? region.generateOres(realX, i, realZ, rng, getData()) : ore; - ore = ore == null ? getDimension().generateOres(realX, i, realZ, rng, getData()) : ore; + ore = biome.generateOres(realX, i, realZ, rng, getData(), false); + ore = ore == null ? region.generateOres(realX, i, realZ, rng, getData(), false) : ore; + ore = ore == null ? getDimension().generateOres(realX, i, realZ, rng, getData(), false) : ore; if (ore != null) { h.set(xf, i, zf, ore); diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisBiome.java b/core/src/main/java/com/volmit/iris/engine/object/IrisBiome.java index 0b4eb11c3..ac1390d83 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisBiome.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisBiome.java @@ -171,12 +171,14 @@ public class IrisBiome extends IrisRegistrant implements IRare { @ArrayType(type = IrisOreGenerator.class, min = 1) private KList ores = new KList<>(); - public BlockData generateOres(int x, int y, int z, RNG rng, IrisData data) { + public BlockData generateOres(int x, int y, int z, RNG rng, IrisData data, boolean surface) { if (ores.isEmpty()) { return null; } BlockData b = null; for (IrisOreGenerator i : ores) { + if (i.isGenerateSurface() != surface) + continue; b = i.generate(x, y, z, rng, data); if (b != null) { 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 f2c5b724c..0459e1d06 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 @@ -253,12 +253,14 @@ public class IrisDimension extends IrisRegistrant { return (int) getDimensionHeight().getMin(); } - public BlockData generateOres(int x, int y, int z, RNG rng, IrisData data) { + public BlockData generateOres(int x, int y, int z, RNG rng, IrisData data, boolean surface) { if (ores.isEmpty()) { return null; } BlockData b = null; for (IrisOreGenerator i : ores) { + if (i.isGenerateSurface() != surface) + continue; b = i.generate(x, y, z, rng, data); if (b != null) { diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisRegion.java b/core/src/main/java/com/volmit/iris/engine/object/IrisRegion.java index 158f04f3e..a2712786a 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisRegion.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisRegion.java @@ -151,12 +151,14 @@ public class IrisRegion extends IrisRegistrant implements IRare { @ArrayType(type = IrisOreGenerator.class, min = 1) private KList ores = new KList<>(); - public BlockData generateOres(int x, int y, int z, RNG rng, IrisData data) { + public BlockData generateOres(int x, int y, int z, RNG rng, IrisData data, boolean surface) { if (ores.isEmpty()) { return null; } BlockData b = null; for (IrisOreGenerator i : ores) { + if (i.isGenerateSurface() != surface) + continue; b = i.generate(x, y, z, rng, data); if (b != null) { From 0ae1334a57fba81752794a0bef28b2d6992e7902 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 27 Jun 2025 12:20:25 +0200 Subject: [PATCH 20/66] fix snippet tab completion --- .../iris/core/project/SchemaBuilder.java | 70 +++++++++---------- 1 file changed, 33 insertions(+), 37 deletions(-) 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 61d626247..2e133f944 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 @@ -153,19 +153,7 @@ public class SchemaBuilder { o.put("properties", properties); - if (c.isAnnotationPresent(Snippet.class)) { - JSONObject anyOf = new JSONObject(); - JSONArray arr = new JSONArray(); - JSONObject str = new JSONObject(); - str.put("type", "string"); - arr.put(o); - arr.put(str); - anyOf.put("anyOf", arr); - - return anyOf; - } - - return o; + return buildSnippet(o, c); } private JSONObject buildProperty(Field k, Class cl) { @@ -515,6 +503,13 @@ public class SchemaBuilder { d.add(getDescription(k.getType())); Snippet snippet = k.getType().getDeclaredAnnotation(Snippet.class); + if (snippet == null) { + ArrayType array = k.getType().getDeclaredAnnotation(ArrayType.class); + if (array != null) { + snippet = array.type().getDeclaredAnnotation(Snippet.class); + } + } + if (snippet != null) { String sm = snippet.value(); d.add(" "); @@ -544,35 +539,36 @@ public class SchemaBuilder { description.forEach((g) -> d.add(g.trim())); prop.put("type", type); prop.put("description", d.toString("\n")); + return buildSnippet(prop, k.getType()); + } - if (k.getType().isAnnotationPresent(Snippet.class)) { - JSONObject anyOf = new JSONObject(); - JSONArray arr = new JSONArray(); - JSONObject str = new JSONObject(); - str.put("type", "string"); - String key = "enum-snippet-" + k.getType().getDeclaredAnnotation(Snippet.class).value(); - str.put("$ref", "#/definitions/" + key); + private JSONObject buildSnippet(JSONObject prop, Class type) { + Snippet snippet = type.getDeclaredAnnotation(Snippet.class); + if (snippet == null) return prop; - if (!definitions.containsKey(key)) { - JSONObject j = new JSONObject(); - JSONArray snl = new JSONArray(); - data.getPossibleSnippets(k.getType().getDeclaredAnnotation(Snippet.class).value()).forEach(snl::put); - j.put("enum", snl); - definitions.put(key, j); - } + JSONObject anyOf = new JSONObject(); + JSONArray arr = new JSONArray(); + JSONObject str = new JSONObject(); + str.put("type", "string"); + String key = "enum-snippet-" + snippet.value(); + str.put("$ref", "#/definitions/" + key); - arr.put(prop); - arr.put(str); - prop.put("description", d.toString("\n")); - str.put("description", d.toString("\n")); - anyOf.put("anyOf", arr); - anyOf.put("description", d.toString("\n")); - anyOf.put("!required", k.isAnnotationPresent(Required.class)); - - return anyOf; + if (!definitions.containsKey(key)) { + JSONObject j = new JSONObject(); + JSONArray snl = new JSONArray(); + data.getPossibleSnippets(snippet.value()).forEach(snl::put); + j.put("enum", snl); + definitions.put(key, j); } - return prop; + arr.put(prop); + arr.put(str); + str.put("description", prop.getString("description")); + anyOf.put("anyOf", arr); + anyOf.put("description", prop.getString("description")); + anyOf.put("!required", type.isAnnotationPresent(Required.class)); + + return anyOf; } @NotNull From 6f0b2b6bba3a12c5de46b721f12cb8f1c594def4 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 27 Jun 2025 12:21:59 +0200 Subject: [PATCH 21/66] initialize generators for isolated focus biomes / regions --- .../com/volmit/iris/engine/IrisComplex.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/IrisComplex.java b/core/src/main/java/com/volmit/iris/engine/IrisComplex.java index e92e6da84..652b728ca 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisComplex.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisComplex.java @@ -108,10 +108,17 @@ public class IrisComplex implements DataProvider { } //@builder - engine.getDimension().getRegions().forEach((i) -> data.getRegionLoader().load(i) - .getAllBiomes(this).forEach((b) -> b - .getGenerators() - .forEach((c) -> registerGenerator(c.getCachedGenerator(this))))); + if (focusRegion != null) { + focusRegion.getAllBiomes(this).forEach(this::registerGenerators); + } else if (focusBiome != null) { + registerGenerators(focusBiome); + } else { + engine.getDimension() + .getRegions() + .forEach(i -> data.getRegionLoader().load(i) + .getAllBiomes(this) + .forEach(this::registerGenerators)); + } overlayStream = ProceduralStream.ofDouble((x, z) -> 0.0D).waste("Overlay Stream"); engine.getDimension().getOverlayNoise().forEach(i -> overlayStream = overlayStream.add((x, z) -> i.get(rng, getData(), x, z))); rockStream = engine.getDimension().getRockPalette().getLayerGenerator(rng.nextParallelRNG(45), data).stream() @@ -360,6 +367,10 @@ public class IrisComplex implements DataProvider { return Math.max(Math.min(getInterpolatedHeight(engine, x, z, seed) + fluidHeight + overlayStream.get(x, z), engine.getHeight()), 0); } + private void registerGenerators(IrisBiome biome) { + biome.getGenerators().forEach(c -> registerGenerator(c.getCachedGenerator(this))); + } + private void registerGenerator(IrisGenerator cachedGenerator) { generators.computeIfAbsent(cachedGenerator.getInterpolator(), (k) -> new KSet<>()).add(cachedGenerator); } From 8c025a9ba27eddccc2b64302a89772d7ba7b31e5 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 3 Jul 2025 23:45:27 +0200 Subject: [PATCH 22/66] clear snippet lists on hotload --- core/src/main/java/com/volmit/iris/core/loader/IrisData.java | 1 + 1 file changed, 1 insertion(+) 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 52144fef5..e6d410a5b 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 @@ -363,6 +363,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory { for (ResourceLoader i : loaders.values()) { i.clearList(); } + possibleSnippets.clear(); } public String toLoadKey(File f) { From 39f65d02bfff812d37af61207ae0d56a5f01ee9d Mon Sep 17 00:00:00 2001 From: Julian Krings <47589149+CrazyDev05@users.noreply.github.com> Date: Thu, 3 Jul 2025 23:58:31 +0200 Subject: [PATCH 23/66] 1.21.6/7 Support (#1210) --- build.gradle.kts | 1 + .../volmit/iris/core/ServerConfigurator.java | 4 + .../java/com/volmit/iris/core/nms/INMS.java | 4 +- .../iris/core/nms/datapack/DataVersion.java | 1 + .../iris/core/nms/v1X/NMSBinding1X.java | 6 + .../decree/handlers/DataVersionHandler.java | 2 +- .../core/nms/v1_21_R5/CustomBiomeSource.java | 169 ++++ .../core/nms/v1_21_R5/IrisChunkGenerator.java | 311 +++++++ .../iris/core/nms/v1_21_R5/NMSBinding.java | 762 ++++++++++++++++++ settings.gradle.kts | 1 + 10 files changed, 1259 insertions(+), 2 deletions(-) create mode 100644 nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/CustomBiomeSource.java create mode 100644 nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/IrisChunkGenerator.java create mode 100644 nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/NMSBinding.java diff --git a/build.gradle.kts b/build.gradle.kts index 98ee16ae3..2fc7ed8b5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -63,6 +63,7 @@ val color = "truecolor" val errorReporting = false val nmsBindings = mapOf( + "v1_21_R5" to "1.21.7-R0.1-SNAPSHOT", "v1_21_R4" to "1.21.5-R0.1-SNAPSHOT", "v1_21_R3" to "1.21.4-R0.1-SNAPSHOT", "v1_21_R2" to "1.21.3-R0.1-SNAPSHOT", 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 79261d63d..ed833b323 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -107,6 +107,10 @@ public class ServerConfigurator { } public static void installDataPacks(IDataFixer fixer, boolean fullInstall) { + if (fixer == null) { + Iris.error("Unable to install datapacks, fixer is null!"); + return; + } Iris.info("Checking Data Packs..."); DimensionHeight height = new DimensionHeight(fixer); KList folders = getDatapacksFolder(); 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 99ef8514f..848b08879 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 @@ -35,7 +35,9 @@ public class INMS { "1.21.2", "v1_21_R2", "1.21.3", "v1_21_R2", "1.21.4", "v1_21_R3", - "1.21.5", "v1_21_R4" + "1.21.5", "v1_21_R4", + "1.21.6", "v1_21_R5", + "1.21.7", "v1_21_R5" ); private static final List PACKS = List.of( new Version(21, 4, "31020"), 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 index f73850b0c..1314d8ecf 100644 --- 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 @@ -13,6 +13,7 @@ import java.util.function.Supplier; //https://minecraft.wiki/w/Pack_format @Getter public enum DataVersion { + UNSUPPORTED("0.0.0", 0, () -> null), V1192("1.19.2", 10, DataFixerV1192::new), V1205("1.20.6", 41, DataFixerV1206::new), V1213("1.21.3", 57, DataFixerV1213::new); 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 642a00e38..e180ab8d2 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 @@ -21,6 +21,7 @@ package com.volmit.iris.core.nms.v1X; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.core.nms.container.BiomeColor; +import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; @@ -207,6 +208,11 @@ public class NMSBinding1X implements INMSBinding { return true; } + @Override + public DataVersion getDataVersion() { + return DataVersion.UNSUPPORTED; + } + @Override public int getBiomeId(Biome biome) { return biome.ordinal(); 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 index 489590496..53dff488e 100644 --- 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 @@ -8,7 +8,7 @@ import com.volmit.iris.util.decree.exceptions.DecreeParsingException; public class DataVersionHandler implements DecreeParameterHandler { @Override public KList getPossibilities() { - return new KList<>(DataVersion.values()); + return new KList<>(DataVersion.values()).qdel(DataVersion.UNSUPPORTED); } @Override diff --git a/nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/CustomBiomeSource.java b/nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/CustomBiomeSource.java new file mode 100644 index 000000000..c8fa95353 --- /dev/null +++ b/nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/CustomBiomeSource.java @@ -0,0 +1,169 @@ +package com.volmit.iris.core.nms.v1_21_R5; + +import com.mojang.serialization.MapCodec; +import com.volmit.iris.Iris; +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_21_R5.CraftServer; +import org.bukkit.craftbukkit.v1_21_R5.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().lookup(Registries.BIOME).orElse(null); + this.biomeRegistry = ((RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer())).lookup(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.get(customRegistry.getResourceKey(customRegistry + .getValue(ResourceLocation.fromNamespaceAndPath(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())) + .lookup(Registries.BIOME).orElse(null), + ((CraftWorld) engine.getWorld().realWorld()).getHandle().registryAccess().lookup(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 resourceLocation = ResourceLocation.fromNamespaceAndPath(engine.getDimension().getLoadKey(), j.getId()); + Biome biome = customRegistry.getValue(resourceLocation); + 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.get(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_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/IrisChunkGenerator.java b/nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/IrisChunkGenerator.java new file mode 100644 index 000000000..c156c09df --- /dev/null +++ b/nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/IrisChunkGenerator.java @@ -0,0 +1,311 @@ +package com.volmit.iris.core.nms.v1_21_R5; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.MapCodec; +import com.volmit.iris.Iris; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.framework.ResultLocator; +import com.volmit.iris.engine.framework.WrongEngineBroException; +import com.volmit.iris.engine.object.IrisJigsawStructure; +import com.volmit.iris.engine.object.IrisJigsawStructurePlacement; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.mantle.MantleFlag; +import com.volmit.iris.util.math.Position2; +import com.volmit.iris.util.reflect.WrappedField; +import net.minecraft.core.*; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.tags.StructureTags; +import net.minecraft.tags.TagKey; +import net.minecraft.util.random.WeightedList; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.*; +import net.minecraft.world.level.biome.*; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.levelgen.RandomState; +import net.minecraft.world.level.levelgen.blending.Blender; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureSet; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R5.generator.CustomChunkGenerator; +import org.spigotmc.SpigotWorldConfig; + +import javax.annotation.Nullable; +import java.lang.reflect.Field; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +public class IrisChunkGenerator extends CustomChunkGenerator { + private static final WrappedField BIOME_SOURCE; + private final ChunkGenerator delegate; + private final Engine engine; + private final KMap, KSet> structures = new KMap<>(); + + public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) { + super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null); + this.delegate = delegate; + this.engine = engine; + var dimension = engine.getDimension(); + + KSet placements = new KSet<>(); + addAll(dimension.getJigsawStructures(), placements); + for (var region : dimension.getAllRegions(engine)) { + addAll(region.getJigsawStructures(), placements); + for (var biome : region.getAllBiomes(engine)) + addAll(biome.getJigsawStructures(), placements); + } + var stronghold = dimension.getStronghold(); + if (stronghold != null) + placements.add(engine.getData().getJigsawStructureLoader().load(stronghold)); + placements.removeIf(Objects::isNull); + + var registry = ((CraftWorld) world).getHandle().registryAccess().lookup(Registries.STRUCTURE).orElseThrow(); + for (var s : placements) { + try { + String raw = s.getStructureKey(); + if (raw == null) continue; + boolean tag = raw.startsWith("#"); + if (tag) raw = raw.substring(1); + + var location = ResourceLocation.parse(raw); + if (!tag) { + structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey()); + continue; + } + + var key = TagKey.create(Registries.STRUCTURE, location); + var set = registry.get(key).orElse(null); + if (set == null) { + Iris.error("Could not find structure tag: " + raw); + continue; + } + for (var holder : set) { + var resourceKey = holder.unwrapKey().orElse(null); + if (resourceKey == null) continue; + structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey()); + } + } catch (Throwable e) { + Iris.error("Failed to load structure: " + s.getLoadKey()); + e.printStackTrace(); + } + } + } + + private void addAll(KList placements, KSet structures) { + if (placements == null) return; + placements.stream() + .map(IrisJigsawStructurePlacement::getStructure) + .map(engine.getData().getJigsawStructureLoader()::load) + .filter(Objects::nonNull) + .forEach(structures::add); + } + + @Override + public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) { + if (holders.size() == 0) return null; + if (holders.unwrapKey().orElse(null) == StructureTags.EYE_OF_ENDER_LOCATED) { + var next = engine.getNearestStronghold(new Position2(pos.getX(), pos.getZ())); + return next == null ? null : new Pair<>(new BlockPos(next.getX(), 0, next.getZ()), holders.get(0)); + } + if (engine.getDimension().isDisableExplorerMaps()) + return null; + + KMap> structures = new KMap<>(); + for (var holder : holders) { + if (holder == null) continue; + var key = holder.unwrapKey().orElse(null); + var set = this.structures.get(key); + if (set == null) continue; + for (var structure : set) { + structures.put(structure, holder); + } + } + if (structures.isEmpty()) + return null; + + var locator = ResultLocator.locateStructure(structures.keySet()) + .then((e, p , s) -> structures.get(s.getLoadKey())); + if (findUnexplored) + locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s); + + try { + var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get(); + if (result == null) return null; + var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ()); + return Pair.of(blockPos, result.obj()); + } catch (WrongEngineBroException | ExecutionException | InterruptedException e) { + return null; + } + } + + @Override + protected MapCodec codec() { + return MapCodec.unit(null); + } + + @Override + public ChunkGenerator getDelegate() { + if (delegate instanceof CustomChunkGenerator chunkGenerator) + return chunkGenerator.getDelegate(); + return delegate; + } + + @Override + public int getMinY() { + return delegate.getMinY(); + } + + @Override + public int getSeaLevel() { + return delegate.getSeaLevel(); + } + + @Override + public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager, ResourceKey resourcekey) { + delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager, resourcekey); + } + + @Override + public ChunkGeneratorStructureState createState(HolderLookup holderlookup, RandomState randomstate, long i, SpigotWorldConfig conf) { + return delegate.createState(holderlookup, randomstate, i, conf); + } + + @Override + public void createReferences(WorldGenLevel generatoraccessseed, StructureManager structuremanager, ChunkAccess ichunkaccess) { + delegate.createReferences(generatoraccessseed, structuremanager, ichunkaccess); + } + + @Override + public CompletableFuture createBiomes(RandomState randomstate, Blender blender, StructureManager structuremanager, ChunkAccess ichunkaccess) { + return delegate.createBiomes(randomstate, blender, structuremanager, ichunkaccess); + } + + @Override + public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) { + delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess); + } + + @Override + public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess) { + delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess); + } + + @Override + public CompletableFuture fillFromNoise(Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess ichunkaccess) { + return delegate.fillFromNoise(blender, randomstate, structuremanager, ichunkaccess); + } + + @Override + public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate); + } + + @Override + public WeightedList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) { + return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition); + } + + @Override + public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) { + delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager); + } + + @Override + public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) { + delegate.addDebugScreenInfo(list, randomstate, blockposition); + } + + @Override + public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) { + delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, vanilla); + } + + @Override + public int getFirstFreeHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getFirstFreeHeight(i, j, heightmap_type, levelheightaccessor, randomstate); + } + + @Override + public int getFirstOccupiedHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getFirstOccupiedHeight(i, j, heightmap_type, levelheightaccessor, randomstate); + } + + @Override + public void addVanillaDecorations(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) { + delegate.addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager); + } + + @Override + public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) { + delegate.spawnOriginalMobs(regionlimitedworldaccess); + } + + @Override + public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) { + return delegate.getSpawnHeight(levelheightaccessor); + } + + @Override + public int getGenDepth() { + return delegate.getGenDepth(); + } + + @Override + public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) { + return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate); + } + + @Override + public Optional>> getTypeNameForDataFixer() { + return delegate.getTypeNameForDataFixer(); + } + + @Override + public void validate() { + delegate.validate(); + } + + @Override + @SuppressWarnings("deprecation") + public BiomeGenerationSettings getBiomeGenerationSettings(Holder holder) { + return delegate.getBiomeGenerationSettings(holder); + } + + static { + Field biomeSource = null; + for (Field field : ChunkGenerator.class.getDeclaredFields()) { + if (!field.getType().equals(BiomeSource.class)) + continue; + biomeSource = field; + break; + } + if (biomeSource == null) + throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!"); + BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName()); + } + + private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) { + try { + BIOME_SOURCE.set(generator, source); + if (generator instanceof CustomChunkGenerator custom) + BIOME_SOURCE.set(custom.getDelegate(), source); + + return generator; + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} diff --git a/nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/NMSBinding.java b/nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/NMSBinding.java new file mode 100644 index 000000000..425dd25a7 --- /dev/null +++ b/nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/NMSBinding.java @@ -0,0 +1,762 @@ +package com.volmit.iris.core.nms.v1_21_R5; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMSBinding; +import com.volmit.iris.core.nms.container.BiomeColor; +import com.volmit.iris.core.nms.datapack.DataVersion; +import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.platform.PlatformChunkGenerator; +import com.volmit.iris.util.agent.Agent; +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.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.mca.NBTWorld; +import com.volmit.iris.util.nbt.mca.palette.*; +import com.volmit.iris.util.nbt.tag.CompoundTag; +import com.volmit.iris.util.scheduling.J; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.shorts.ShortList; +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatchers; +import net.minecraft.core.*; +import net.minecraft.core.Registry; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.*; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.commands.data.BlockDataAccessor; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.tags.TagKey; +import net.minecraft.world.RandomSequences; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.EntityBlock; +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 net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.WorldGenContext; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; +import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +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_21_R5.CraftChunk; +import org.bukkit.craftbukkit.v1_21_R5.CraftServer; +import org.bukkit.craftbukkit.v1_21_R5.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_21_R5.block.CraftBlockStates; +import org.bukkit.craftbukkit.v1_21_R5.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R5.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R5.util.CraftNamespacedKey; +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.Contract; +import org.jetbrains.annotations.NotNull; + +import java.awt.Color; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +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 AtomicBoolean injected = new AtomicBoolean(); + 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(Material material) { + return !CraftBlockState.class.equals(CraftBlockStates.getBlockStateType(material)); + } + + @Override + public boolean hasTile(Location l) { + return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; + } + + @Override + @SuppressWarnings("unchecked") + public KMap serializeTile(Location location) { + BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), false); + + if (e == null) { + return null; + } + + net.minecraft.nbt.CompoundTag tag = e.saveWithoutMetadata(registry()); + return (KMap) convertFromTag(tag, 0, 64); + } + + @Contract(value = "null, _, _ -> null", pure = true) + private Object convertFromTag(Tag tag, int depth, int maxDepth) { + if (tag == null || depth > maxDepth) return null; + return switch (tag) { + case CollectionTag collection -> { + KList list = new KList<>(); + + for (Object i : collection) { + if (i instanceof Tag t) + list.add(convertFromTag(t, depth + 1, maxDepth)); + else list.add(i); + } + yield list; + } + case net.minecraft.nbt.CompoundTag compound -> { + KMap map = new KMap<>(); + + for (String key : compound.keySet()) { + var child = compound.get(key); + if (child == null) continue; + var value = convertFromTag(child, depth + 1, maxDepth); + if (value == null) continue; + map.put(key, value); + } + yield map; + } + case NumericTag numeric -> numeric.box(); + default -> tag.asString().orElse(null); + }; + } + + @Override + public void deserializeTile(KMap map, Location pos) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); + var level = ((CraftWorld) pos.getWorld()).getHandle(); + var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); + J.s(() -> merge(level, blockPos, tag)); + } + + private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { + var blockEntity = level.getBlockEntity(blockPos); + if (blockEntity == null) { + Iris.warn("[NMS] BlockEntity not found at " + blockPos); + var state = level.getBlockState(blockPos); + if (!state.hasBlockEntity()) + return; + + blockEntity = ((EntityBlock) state.getBlock()) + .newBlockEntity(blockPos, state); + } + var accessor = new BlockDataAccessor(blockEntity, blockPos); + accessor.setData(accessor.getData().merge(tag)); + } + + private Tag convertToTag(Object object, int depth, int maxDepth) { + if (object == null || depth > maxDepth) return EndTag.INSTANCE; + return switch (object) { + case Map map -> { + var tag = new net.minecraft.nbt.CompoundTag(); + for (var i : map.entrySet()) { + tag.put(i.getKey().toString(), convertToTag(i.getValue(), depth + 1, maxDepth)); + } + yield tag; + } + case List list -> { + var tag = new ListTag(); + for (var i : list) { + tag.add(convertToTag(i, depth + 1, maxDepth)); + } + yield tag; + } + case Byte number -> ByteTag.valueOf(number); + case Short number -> ShortTag.valueOf(number); + case Integer number -> IntTag.valueOf(number); + case Long number -> LongTag.valueOf(number); + case Float number -> FloatTag.valueOf(number); + case Double number -> DoubleTag.valueOf(number); + case String string -> StringTag.valueOf(string); + default -> EndTag.INSTANCE; + }; + } + + @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().lookup(Registries.BIOME).orElse(null); + } + + private Registry getBlockRegistry() { + return registry().lookup(Registries.BLOCK).orElse(null); + } + + @Override + public Object getBiomeBaseFromId(int id) { + return getCustomBiomeRegistry().get(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().getValue(ResourceLocation.parse(mckey)); + } + + @Override + public Object getCustomBiomeBaseHolderFor(String mckey) { + return getCustomBiomeRegistry().get(getTrueBiomeBaseId(getCustomBiomeRegistry().get(ResourceLocation.parse(mckey)))).orElse(null); + } + + public int getBiomeBaseIdForKey(String key) { + return getCustomBiomeRegistry().getId(getCustomBiomeRegistry().get(ResourceLocation.parse(key)).map(Holder::value).orElse(null)); + } + + @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().lookup(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().lookup(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.markUnsaved(); + } + + @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 = IdMapper.class.getDeclaredField("tToId"); + Field df = IdMapper.class.getDeclaredField("idToT"); + Field bf = IdMapper.class.getDeclaredField("nextId"); + cf.setAccessible(true); + df.setAccessible(true); + bf.setAccessible(true); + 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().get(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.parseCompoundFully((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 inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { + var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap; + var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class); + worldGenContextField.setAccessible(true); + var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap); + var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null); + if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris")) + Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString()); + + var newContext = new WorldGenContext( + worldGenContext.level(), new IrisChunkGenerator(worldGenContext.generator(), seed, engine, world), + worldGenContext.structureManager(), worldGenContext.lightEngine(), worldGenContext.mainThreadExecutor(), worldGenContext.unsavedListener()); + + worldGenContextField.set(chunkMap, newContext); + } + + 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); + } + + @Override + public Color getBiomeColor(Location location, BiomeColor type) { + LevelReader reader = ((CraftWorld) location.getWorld()).getHandle(); + var holder = reader.getBiome(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ())); + var biome = holder.value(); + if (biome == null) throw new IllegalArgumentException("Invalid biome: " + holder.unwrapKey().orElse(null)); + + int rgba = switch (type) { + case FOG -> biome.getFogColor(); + case WATER -> biome.getWaterColor(); + case WATER_FOG -> biome.getWaterFogColor(); + case SKY -> biome.getSkyColor(); + case FOLIAGE -> biome.getFoliageColor(); + case GRASS -> biome.getGrassColor(location.getBlockX(), location.getBlockZ()); + }; + if (rgba == 0) { + if (BiomeColor.FOLIAGE == type && biome.getSpecialEffects().getFoliageColorOverride().isEmpty()) + return null; + if (BiomeColor.GRASS == type && biome.getSpecialEffects().getGrassColorOverride().isEmpty()) + return null; + } + return new Color(rgba, true); + } + + 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.getOrThrow(ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(biome.getKey()))); + } + + @Override + public DataVersion getDataVersion() { + return DataVersion.V1213; + } + + @Override + public int getSpawnChunkCount(World world) { + var radius = Optional.ofNullable(world.getGameRuleValue(GameRule.SPAWN_CHUNK_RADIUS)) + .orElseGet(() -> world.getGameRuleDefault(GameRule.SPAWN_CHUNK_RADIUS)); + if (radius == null) throw new IllegalStateException("GameRule.SPAWN_CHUNK_RADIUS is null!"); + return (int) Math.pow(2 * radius + 1, 2); + } + + @Override + public KList getStructureKeys() { + KList keys = new KList<>(); + + var registry = registry().lookup(Registries.STRUCTURE).orElse(null); + if (registry == null) return keys; + registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add); + registry.getTags() + .map(HolderSet.Named::key) + .map(TagKey::location) + .map(ResourceLocation::toString) + .map(s -> "#" + s) + .forEach(keys::add); + + return keys; + } + + @Override + public boolean missingDimensionTypes(String... keys) { + var type = registry().lookupOrThrow(Registries.DIMENSION_TYPE); + return !Arrays.stream(keys) + .map(key -> ResourceLocation.fromNamespaceAndPath("iris", key)) + .allMatch(type::containsKey); + } + + @Override + public boolean injectBukkit() { + if (injected.getAndSet(true)) + return true; + try { + Iris.info("Injecting Bukkit"); + var buddy = new ByteBuddy(); + buddy.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(), Agent.installed()); + for (Class clazz : List.of(ChunkAccess.class, ProtoChunk.class)) { + buddy.redefine(clazz) + .visit(Advice.to(ChunkAccessAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(ShortList.class, int.class)))) + .make() + .load(clazz.getClassLoader(), Agent.installed()); + } + + return true; + } catch (Throwable e) { + Iris.error(C.RED + "Failed to inject Bukkit"); + e.printStackTrace(); + } + return false; + } + + public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) { + if (!(raw instanceof PlatformChunkGenerator gen)) + throw new IllegalStateException("Generator is not platform chunk generator!"); + + var dimensionKey = ResourceLocation.fromNamespaceAndPath("iris", gen.getTarget().getDimension().getDimensionTypeKey()); + var dimensionType = access.lookupOrThrow(Registries.DIMENSION_TYPE).getOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, dimensionKey)); + return new LevelStem(dimensionType, chunkGenerator(access)); + } + + private net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator(RegistryAccess access) { + var settings = new FlatLevelGeneratorSettings(Optional.empty(), access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID), List.of()); + settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR)); + settings.updateLayers(); + return new FlatLevelSource(settings); + } + + private static class ChunkAccessAdvice { + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + static boolean enter(@Advice.This ChunkAccess access, @Advice.Argument(1) int index) { + return index >= access.getPostProcessing().length; + } + } + + private static class ServerLevelAdvice { + @Advice.OnMethodEnter + static void enter( + @Advice.Argument(0) MinecraftServer server, + @Advice.Argument(3) PrimaryLevelData levelData, + @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem, + @Advice.Argument(12) World.Environment env, + @Advice.Argument(value = 13) ChunkGenerator gen + ) { + if (gen == null || !gen.getClass().getPackageName().startsWith("com.volmit.iris")) + return; + + try { + Object bindings = Class.forName("com.volmit.iris.core.nms.INMS", true, Bukkit.getPluginManager().getPlugin("Iris") + .getClass() + .getClassLoader()) + .getDeclaredMethod("get") + .invoke(null); + levelStem = (LevelStem) bindings.getClass() + .getDeclaredMethod("levelStem", RegistryAccess.class, ChunkGenerator.class) + .invoke(bindings, server.registryAccess(), gen); + + levelData.customDimensions = null; + } catch (Throwable e) { + throw new RuntimeException("Iris failed to replace the levelStem", e instanceof InvocationTargetException ex ? ex.getCause() : e); + } + } + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 862732b5a..3ffcee083 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,6 +30,7 @@ rootProject.name = "Iris" include(":core", ":core:agent") include( + ":nms:v1_21_R5", ":nms:v1_21_R4", ":nms:v1_21_R3", ":nms:v1_21_R2", From 4e8079e431823459bf07f8396481e9217d15dcad Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 4 Jul 2025 00:01:16 +0200 Subject: [PATCH 24/66] use ticket queue for pregen by default --- core/src/main/java/com/volmit/iris/core/IrisSettings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c409c1f9d..30216b29e 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/core/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -150,7 +150,7 @@ public class IrisSettings { public boolean useCacheByDefault = true; public boolean useHighPriority = false; public boolean useVirtualThreads = false; - public boolean useTicketQueue = false; + public boolean useTicketQueue = true; public int maxConcurrency = 256; } From 44af23ba2ef6dbf5b1e2989aa9c06ea6f284d78e Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 4 Jul 2025 00:06:55 +0200 Subject: [PATCH 25/66] add check for new dimension types --- .../main/java/com/volmit/iris/core/ServerConfigurator.java | 5 +++++ 1 file changed, 5 insertions(+) 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 ed833b323..ca8b242d2 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -221,6 +221,11 @@ public class ServerConfigurator { } } + if (INMS.get().missingDimensionTypes(dimension.getDimensionTypeKey())) { + Iris.warn("The Dimension Type for " + dimension.getLoadFile() + " is not registered on the server."); + warn = true; + } + if (warn) { Iris.error("The Pack " + key + " is INCAPABLE of generating custom biomes"); Iris.error("If not done automatically, restart your server before generating with this pack!"); From 77b425362457c7d06101585306a46aa922da31df Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 4 Jul 2025 12:34:20 +0200 Subject: [PATCH 26/66] fix sentry safeguard info --- core/src/main/java/com/volmit/iris/Iris.java | 2 +- .../iris/core/safeguard/IrisSafeguard.java | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 9f39f70ad..a47b6c617 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -976,7 +976,7 @@ public class Iris extends VolmitPlugin implements Listener { event.setTag("iris.nms", INMS.get().getClass().getCanonicalName()); var context = IrisContext.get(); if (context != null) event.getContexts().set("engine", context.asContext()); - event.getContexts().set("safeguard", ServerBootSFG.allIncompatibilities); + event.getContexts().set("safeguard", IrisSafeguard.asContext()); return event; }); }); diff --git a/core/src/main/java/com/volmit/iris/core/safeguard/IrisSafeguard.java b/core/src/main/java/com/volmit/iris/core/safeguard/IrisSafeguard.java index 241bdd01f..7a4ca9b5c 100644 --- a/core/src/main/java/com/volmit/iris/core/safeguard/IrisSafeguard.java +++ b/core/src/main/java/com/volmit/iris/core/safeguard/IrisSafeguard.java @@ -2,6 +2,8 @@ package com.volmit.iris.core.safeguard; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; import java.util.concurrent.atomic.AtomicBoolean; @@ -35,5 +37,23 @@ public class IrisSafeguard { return "stable"; } } + + public static KMap asContext() { + KMap m = new KMap<>(); + m.put("diskSpace", !ServerBootSFG.hasEnoughDiskSpace); + m.put("javaVersion", !ServerBootSFG.isCorrectJDK); + m.put("jre", ServerBootSFG.isJRE); + m.put("missingAgent", ServerBootSFG.missingAgent); + m.put("missingDimensionTypes", ServerBootSFG.missingDimensionTypes); + m.put("failedInjection", ServerBootSFG.failedInjection); + m.put("unsupportedVersion", ServerBootSFG.unsuportedversion); + m.put("serverSoftware", !ServerBootSFG.passedserversoftware); + KList incompatiblePlugins = new KList<>(); + ServerBootSFG.incompatibilities.forEach((plugin, present) -> { + if (present) incompatiblePlugins.add(plugin); + }); + m.put("plugins", incompatiblePlugins); + return m; + } } From 54402faea8a25e99bb9dc2cbad139894d387d00a Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 4 Jul 2025 13:18:28 +0200 Subject: [PATCH 27/66] fix automatic deepslate variant replacement --- core/src/main/java/com/volmit/iris/util/data/B.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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 02e0e89cc..1c7a521cb 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 @@ -105,7 +105,15 @@ public class B { DEEPSLATE_TILES, DEEPSLATE_TILE_STAIRS, DEEPSLATE_TILE_WALL, - CRACKED_DEEPSLATE_TILES + CRACKED_DEEPSLATE_TILES, + DEEPSLATE_COAL_ORE, + DEEPSLATE_IRON_ORE, + DEEPSLATE_COPPER_ORE, + DEEPSLATE_DIAMOND_ORE, + DEEPSLATE_EMERALD_ORE, + DEEPSLATE_GOLD_ORE, + DEEPSLATE_LAPIS_ORE, + DEEPSLATE_REDSTONE_ORE, }).forEach((i) -> b.add(i.ordinal())); return IntSets.unmodifiable(b); From 86d986dfbcc4e319cd0c85e7cee28ef2ae02d059 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 6 Jul 2025 19:40:14 +0200 Subject: [PATCH 28/66] fix deposits spawning in columns --- .../iris/engine/modifier/IrisDepositModifier.java | 12 ++++++++---- .../iris/engine/object/IrisDepositGenerator.java | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/modifier/IrisDepositModifier.java b/core/src/main/java/com/volmit/iris/engine/modifier/IrisDepositModifier.java index 037f77d8d..d998088b2 100644 --- a/core/src/main/java/com/volmit/iris/engine/modifier/IrisDepositModifier.java +++ b/core/src/main/java/com/volmit/iris/engine/modifier/IrisDepositModifier.java @@ -52,16 +52,20 @@ public class IrisDepositModifier extends EngineAssignedModifier { BurstExecutor burst = burst().burst(multicore); long seed = x * 341873128712L + z * 132897987541L; + long mask = 0; for (IrisDepositGenerator k : getDimension().getDeposits()) { - burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(seed), x, z, false, context)); + long finalSeed = seed * ++mask; + burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context)); } for (IrisDepositGenerator k : region.getDeposits()) { - burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(seed), x, z, false, context)); + long finalSeed = seed * ++mask; + burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context)); } for (IrisDepositGenerator k : biome.getDeposits()) { - burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(seed), x, z, false, context)); + long finalSeed = seed * ++mask; + burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context)); } burst.complete(); } @@ -78,7 +82,7 @@ public class IrisDepositModifier extends EngineAssignedModifier { if (k.getPerClumpSpawnChance() < rng.d()) continue; - IrisObject clump = k.getClump(rng, getData()); + IrisObject clump = k.getClump(getEngine(), rng, getData()); int dim = clump.getW(); int min = dim / 2; diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisDepositGenerator.java b/core/src/main/java/com/volmit/iris/engine/object/IrisDepositGenerator.java index 271b54ded..19623ca39 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisDepositGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisDepositGenerator.java @@ -20,6 +20,7 @@ package com.volmit.iris.engine.object; import com.volmit.iris.core.loader.IrisData; 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.collection.KSet; @@ -87,10 +88,10 @@ public class IrisDepositGenerator { @Desc("Ore varience is how many different objects clumps iris will create") private int varience = 3; - public IrisObject getClump(RNG rng, IrisData rdata) { + public IrisObject getClump(Engine engine, RNG rng, IrisData rdata) { KList objects = this.objects.aquire(() -> { - RNG rngv = rng.nextParallelRNG(3957778); + RNG rngv = new RNG(engine.getSeedManager().getDeposit() + hashCode()); KList objectsf = new KList<>(); for (int i = 0; i < varience; i++) { From c9ed4519a8d94a1722836e0edb915a110fbe8d25 Mon Sep 17 00:00:00 2001 From: Julian Krings <47589149+CrazyDev05@users.noreply.github.com> Date: Sun, 6 Jul 2025 20:00:06 +0200 Subject: [PATCH 29/66] remove multiverse core incompatibility warning (#1212) --- build.gradle.kts | 1 + core/build.gradle.kts | 1 + core/src/main/java/com/volmit/iris/Iris.java | 13 -- .../iris/core/link/MultiverseCoreLink.java | 144 +++++------------- .../iris/core/safeguard/ServerBootSFG.java | 2 - .../volmit/iris/core/tools/IrisCreator.java | 4 +- 6 files changed, 44 insertions(+), 121 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 2fc7ed8b5..5681a8cf4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -194,6 +194,7 @@ allprojects { maven("https://hub.jeff-media.com/nexus/repository/jeff-media-public/") maven("https://repo.nexomc.com/releases/") maven("https://nexus.phoenixdevt.fr/repository/maven-public/") + maven("https://repo.onarandombox.com/content/groups/public/") } dependencies { diff --git a/core/build.gradle.kts b/core/build.gradle.kts index e2facc0dc..17158627f 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -59,6 +59,7 @@ dependencies { compileOnly("me.kryniowesegryderiusz:kgenerators-core:7.3") { isTransitive = false } + compileOnly("org.mvplugins.multiverse.core:multiverse-core:5.1.0") //implementation files("libs/CustomItems.jar") // Shaded diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index a47b6c617..7904a6f20 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -38,7 +38,6 @@ import com.volmit.iris.engine.object.IrisCompat; 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.engine.platform.DummyChunkGenerator; import com.volmit.iris.core.safeguard.IrisSafeguard; import com.volmit.iris.core.safeguard.UtilsSFG; import com.volmit.iris.engine.platform.PlatformChunkGenerator; @@ -756,18 +755,6 @@ public class Iris extends VolmitPlugin implements Listener { @Override public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { Iris.debug("Default World Generator Called for " + worldName + " using ID: " + id); - if (worldName.equals("test")) { - try { - throw new RuntimeException(); - } catch (Throwable e) { - Iris.info(e.getStackTrace()[1].getClassName()); - if (e.getStackTrace()[1].getClassName().contains("com.onarandombox.MultiverseCore")) { - Iris.debug("MVC Test detected, Quick! Send them the dummy!"); - return new DummyChunkGenerator(); - } - } - } - if (id == null || id.isEmpty()) id = IrisSettings.get().getGenerator().getDefaultWorldType(); Iris.debug("Generator ID: " + id + " requested by bukkit/plugin"); IrisDimension dim = loadDimension(worldName, id); diff --git a/core/src/main/java/com/volmit/iris/core/link/MultiverseCoreLink.java b/core/src/main/java/com/volmit/iris/core/link/MultiverseCoreLink.java index c483ce756..920abeb5c 100644 --- a/core/src/main/java/com/volmit/iris/core/link/MultiverseCoreLink.java +++ b/core/src/main/java/com/volmit/iris/core/link/MultiverseCoreLink.java @@ -18,126 +18,60 @@ package com.volmit.iris.core.link; -import com.volmit.iris.Iris; -import com.volmit.iris.engine.object.IrisDimension; -import com.volmit.iris.util.collection.KMap; +import lombok.SneakyThrows; import org.bukkit.Bukkit; import org.bukkit.World; -import org.bukkit.WorldType; -import org.bukkit.plugin.Plugin; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Map; +import org.mvplugins.multiverse.core.MultiverseCoreApi; +import org.mvplugins.multiverse.core.world.MultiverseWorld; +import org.mvplugins.multiverse.core.world.WorldManager; +import org.mvplugins.multiverse.core.world.options.ImportWorldOptions; public class MultiverseCoreLink { - private final KMap worldNameTypes = new KMap<>(); + private final boolean active; public MultiverseCoreLink() { - - } - - public boolean addWorld(String worldName, IrisDimension dim, String seed) { - if (!isSupported()) { - return false; - } - - try { - Plugin p = getMultiverse(); - Object mvWorldManager = p.getClass().getDeclaredMethod("getMVWorldManager").invoke(p); - Method m = mvWorldManager.getClass().getDeclaredMethod("addWorld", - - String.class, World.Environment.class, String.class, WorldType.class, Boolean.class, String.class, boolean.class); - boolean b = (boolean) m.invoke(mvWorldManager, worldName, dim.getEnvironment(), seed, WorldType.NORMAL, false, "Iris", false); - saveConfig(); - return b; - } catch (Throwable e) { - Iris.reportError(e); - e.printStackTrace(); - } - - return false; - } - - @SuppressWarnings("unchecked") - public Map getList() { - try { - Plugin p = getMultiverse(); - Object mvWorldManager = p.getClass().getDeclaredMethod("getMVWorldManager").invoke(p); - Field f = mvWorldManager.getClass().getDeclaredField("worldsFromTheConfig"); - f.setAccessible(true); - return (Map) f.get(mvWorldManager); - } catch (Throwable e) { - Iris.reportError(e); - e.printStackTrace(); - } - - return null; + active = Bukkit.getPluginManager().getPlugin("Multiverse-Core") != null; } public void removeFromConfig(World world) { - if (!isSupported()) { - return; - } - - getList().remove(world.getName()); - saveConfig(); + removeFromConfig(world.getName()); } public void removeFromConfig(String world) { - if (!isSupported()) { - return; + if (!active) return; + var manager = worldManager(); + manager.removeWorld(world).onSuccess(manager::saveWorldsConfig); + } + + @SneakyThrows + public void updateWorld(World bukkitWorld, String pack) { + if (!active) return; + var generator = "Iris:" + pack; + var manager = worldManager(); + var world = manager.getWorld(bukkitWorld).getOrElse(() -> { + var options = ImportWorldOptions.worldName(bukkitWorld.getName()) + .generator(generator) + .environment(bukkitWorld.getEnvironment()) + .useSpawnAdjust(false); + return manager.importWorld(options).get(); + }); + + world.setAutoLoad(false); + if (!generator.equals(world.getGenerator())) { + var field = MultiverseWorld.class.getDeclaredField("worldConfig"); + field.setAccessible(true); + + var config = field.get(world); + config.getClass() + .getDeclaredMethod("setGenerator", String.class) + .invoke(config, generator); } - getList().remove(world); - saveConfig(); + manager.saveWorldsConfig(); } - public void saveConfig() { - try { - Plugin p = getMultiverse(); - Object mvWorldManager = p.getClass().getDeclaredMethod("getMVWorldManager").invoke(p); - mvWorldManager.getClass().getDeclaredMethod("saveWorldsConfig").invoke(mvWorldManager); - } catch (Throwable e) { - Iris.reportError(e); - e.printStackTrace(); - } - } - - public void assignWorldType(String worldName, String type) { - worldNameTypes.put(worldName, type); - } - - public String getWorldNameType(String worldName, String defaultType) { - try { - String t = worldNameTypes.get(worldName); - return t == null ? defaultType : t; - } catch (Throwable e) { - Iris.reportError(e); - return defaultType; - } - } - - public boolean isSupported() { - return getMultiverse() != null; - } - - public Plugin getMultiverse() { - - return Bukkit.getPluginManager().getPlugin("Multiverse-Core"); - } - - public String envName(World.Environment environment) { - if (environment == null) { - return "normal"; - } - - return switch (environment) { - case NORMAL -> "normal"; - case NETHER -> "nether"; - case THE_END -> "end"; - default -> environment.toString().toLowerCase(); - }; - + private WorldManager worldManager() { + var api = MultiverseCoreApi.get(); + return api.getWorldManager(); } } 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 f3fbbd9dc..8ec35899f 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 @@ -49,9 +49,7 @@ public class ServerBootSFG { Plugin[] plugins = pluginManager.getPlugins(); incompatibilities.clear(); - incompatibilities.put("Multiverse-Core", false); incompatibilities.put("dynmap", false); - incompatibilities.put("TerraformGenerator", false); incompatibilities.put("Stratos", false); String pluginName; 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 ddcd5ff85..fac42b051 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 @@ -199,8 +199,10 @@ public class IrisCreator { world.get().setTime(6000); } }); - } else + } else { addToBukkitYml(); + J.s(() -> Iris.linkMultiverseCore.updateWorld(world.get(), dimension)); + } if (pregen != null) { CompletableFuture ff = new CompletableFuture<>(); From cb93e782429952b7cbcd3fbac13a15beac40d036 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 7 Jul 2025 13:18:31 +0200 Subject: [PATCH 30/66] fix safeguard error --- .../com/volmit/iris/core/safeguard/UtilsSFG.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) 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 b59a24585..064f48db0 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 @@ -10,7 +10,9 @@ public class UtilsSFG { } public static void printIncompatibleWarnings() { - // String SupportedIrisVersion = getDescription().getVersion(); //todo Automatic version + String[] parts = Iris.instance.getDescription().getVersion().split("-"); + String minVersion = parts[1]; + String maxVersion = parts[2]; if (ServerBootSFG.safeguardPassed) { Iris.safeguard(C.BLUE + "0 Conflicts found"); @@ -22,23 +24,18 @@ public class UtilsSFG { Iris.safeguard(C.YELLOW + "" + ServerBootSFG.count + " Conflicts found"); } - if (ServerBootSFG.incompatibilities.get("Multiverse-Core")) { - Iris.safeguard(C.RED + "Multiverse"); - Iris.safeguard(C.RED + "- The plugin Multiverse is not compatible with the server."); - Iris.safeguard(C.RED + "- If you want to have a world manager, consider using PhantomWorlds or MyWorlds instead."); - } if (ServerBootSFG.incompatibilities.get("dynmap")) { Iris.safeguard(C.RED + "Dynmap"); Iris.safeguard(C.RED + "- The plugin Dynmap is not compatible with the server."); Iris.safeguard(C.RED + "- If you want to have a map plugin like Dynmap, consider Bluemap."); } - if (ServerBootSFG.incompatibilities.get("TerraformGenerator") || ServerBootSFG.incompatibilities.get("Stratos")) { - Iris.safeguard(C.YELLOW + "Terraform Generator / Stratos"); + if (ServerBootSFG.incompatibilities.get("Stratos")) { + Iris.safeguard(C.YELLOW + "Stratos"); Iris.safeguard(C.YELLOW + "- Iris is not compatible with other worldgen plugins."); } if (ServerBootSFG.unsuportedversion) { Iris.safeguard(C.RED + "Server Version"); - Iris.safeguard(C.RED + "- Iris only supports 1.20.1 > 1.21.4"); + Iris.safeguard(C.RED + "- Iris only supports " + minVersion + " > " + maxVersion); } if (ServerBootSFG.missingDimensionTypes) { Iris.safeguard(C.RED + "Dimension Types"); From 20c7891c2fbc73031f60cf8d58d6fad009f75e2a Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 7 Jul 2025 22:54:35 +0200 Subject: [PATCH 31/66] add api generation task --- build.gradle.kts | 1 + buildSrc/build.gradle.kts | 11 +++ buildSrc/src/main/kotlin/ApiGenerator.kt | 101 +++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 buildSrc/build.gradle.kts create mode 100644 buildSrc/src/main/kotlin/ApiGenerator.kt diff --git a/build.gradle.kts b/build.gradle.kts index 5681a8cf4..733f6134e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -35,6 +35,7 @@ plugins { id("xyz.jpenilla.run-paper") version "2.3.1" id("io.sentry.jvm.gradle") version "5.7.0" } +apply() version = "3.6.11-1.20.1-1.21.5" diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 000000000..c94238170 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + kotlin("jvm") version "2.0.20" +} + +repositories { + mavenCentral() +} + +dependencies { + implementation("org.ow2.asm:asm:9.8") +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/ApiGenerator.kt b/buildSrc/src/main/kotlin/ApiGenerator.kt new file mode 100644 index 000000000..f1bd334d5 --- /dev/null +++ b/buildSrc/src/main/kotlin/ApiGenerator.kt @@ -0,0 +1,101 @@ +import org.gradle.api.DefaultTask +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction +import org.gradle.jvm.tasks.Jar +import org.objectweb.asm.* +import java.io.File +import java.util.jar.JarFile +import java.util.jar.JarOutputStream + +class ApiGenerator : Plugin { + override fun apply(target: Project) { + target.tasks.register("generateApi", GenerateApiTask::class.java) + } +} + +abstract class GenerateApiTask : DefaultTask() { + init { + group = "iris" + dependsOn("jar") + } + + @InputFile + val inputFile: Provider = project.tasks + .named("jar", Jar::class.java) + .flatMap { it.archiveFile } + .map { it.asFile } + + @OutputFile + val outputFile: Provider = inputFile.map { targetDirectory().resolve(it.name) } + + @TaskAction + fun generate() { + JarFile(inputFile.get()).use { jar -> + JarOutputStream(outputFile.get().outputStream()).use { out -> + jar.stream() + .parallel() + .filter { !it.isDirectory } + .filter { it.name.endsWith(".class") } + .forEach { + val bytes = jar.getInputStream(it).use { input -> + val writer = ClassWriter(ClassWriter.COMPUTE_MAXS) + val visitor = MethodClearingVisitor(writer) + ClassReader(input).accept(visitor, 0) + writer.toByteArray() + } + + synchronized(out) { + out.putNextEntry(it) + out.write(bytes) + out.closeEntry() + } + } + } + } + } + + fun targetDirectory(): File { + val dir = System.getenv("DEPLOY_DIR") ?: return project.layout.buildDirectory.dir("api").get().asFile + return File(dir) + } +} + +private class MethodClearingVisitor( + cv: ClassVisitor +) : ClassVisitor(Opcodes.ASM9, cv) { + + override fun visitMethod( + access: Int, + name: String?, + descriptor: String?, + signature: String?, + exceptions: Array? + ) = ExceptionThrowingMethodVisitor(super.visitMethod(access, name, descriptor, signature, exceptions)) +} + +private class ExceptionThrowingMethodVisitor( + mv: MethodVisitor +) : MethodVisitor(Opcodes.ASM9, mv) { + + override fun visitCode() { + if (mv == null) return + mv.visitCode() + + mv.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException") + mv.visitInsn(Opcodes.DUP) + mv.visitLdcInsn("Only API") + mv.visitMethodInsn( + Opcodes.INVOKESPECIAL, + "java/lang/IllegalStateException", + "", "(Ljava/lang/String;)V", false + ) + mv.visitInsn(Opcodes.ATHROW) + + mv.visitMaxs(0, 0) + mv.visitEnd() + } +} \ No newline at end of file From 2ecb5556192e4b2cf116a4632cd9de329535d2ec Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 7 Jul 2025 23:37:37 +0200 Subject: [PATCH 32/66] add publishing for the api artifact --- build.gradle.kts | 4 ++- buildSrc/src/main/kotlin/ApiGenerator.kt | 35 ++++++++++++++++++------ 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 733f6134e..d3cfd5fee 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -35,10 +35,12 @@ plugins { id("xyz.jpenilla.run-paper") version "2.3.1" id("io.sentry.jvm.gradle") version "5.7.0" } -apply() +group = "com.volmit" version = "3.6.11-1.20.1-1.21.5" +apply() + // ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED // ======================== WINDOWS ============================= registerCustomOutputTask("Cyberpwn", "C://Users/cyberpwn/Documents/development/server/plugins") diff --git a/buildSrc/src/main/kotlin/ApiGenerator.kt b/buildSrc/src/main/kotlin/ApiGenerator.kt index f1bd334d5..3c3a3ba3e 100644 --- a/buildSrc/src/main/kotlin/ApiGenerator.kt +++ b/buildSrc/src/main/kotlin/ApiGenerator.kt @@ -1,7 +1,9 @@ import org.gradle.api.DefaultTask import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.provider.Provider +import org.gradle.api.publish.PublishingExtension +import org.gradle.api.publish.maven.MavenPublication +import org.gradle.api.publish.maven.plugins.MavenPublishPlugin import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction @@ -12,8 +14,17 @@ import java.util.jar.JarFile import java.util.jar.JarOutputStream class ApiGenerator : Plugin { - override fun apply(target: Project) { - target.tasks.register("generateApi", GenerateApiTask::class.java) + override fun apply(target: Project): Unit = with(target) { + plugins.apply(MavenPublishPlugin::class.java) + val task = tasks.register("irisApi", GenerateApiTask::class.java) + extensions.findByType(PublishingExtension::class.java)!! + .publications + .create("maven", MavenPublication::class.java) { + it.groupId = group.toString() + it.artifactId = name + it.version = version.toString() + it.artifact(task) + } } } @@ -21,21 +32,27 @@ abstract class GenerateApiTask : DefaultTask() { init { group = "iris" dependsOn("jar") + finalizedBy("publishToMavenLocal") + doLast { + logger.lifecycle("The API is located at ${outputFile.absolutePath}") + } } @InputFile - val inputFile: Provider = project.tasks + val inputFile: File = project.tasks .named("jar", Jar::class.java) - .flatMap { it.archiveFile } - .map { it.asFile } + .get() + .archiveFile + .get() + .asFile @OutputFile - val outputFile: Provider = inputFile.map { targetDirectory().resolve(it.name) } + val outputFile: File = targetDirectory().resolve(inputFile.name) @TaskAction fun generate() { - JarFile(inputFile.get()).use { jar -> - JarOutputStream(outputFile.get().outputStream()).use { out -> + JarFile(inputFile.apply { mkdirs() }).use { jar -> + JarOutputStream(outputFile.apply { mkdirs() }.outputStream()).use { out -> jar.stream() .parallel() .filter { !it.isDirectory } From 9324b1b5c061e92420b844a7b58a72fd397595d1 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 7 Jul 2025 23:42:30 +0200 Subject: [PATCH 33/66] fix api file generation --- buildSrc/src/main/kotlin/ApiGenerator.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/ApiGenerator.kt b/buildSrc/src/main/kotlin/ApiGenerator.kt index 3c3a3ba3e..a844f0fd2 100644 --- a/buildSrc/src/main/kotlin/ApiGenerator.kt +++ b/buildSrc/src/main/kotlin/ApiGenerator.kt @@ -51,8 +51,8 @@ abstract class GenerateApiTask : DefaultTask() { @TaskAction fun generate() { - JarFile(inputFile.apply { mkdirs() }).use { jar -> - JarOutputStream(outputFile.apply { mkdirs() }.outputStream()).use { out -> + JarFile(inputFile).use { jar -> + JarOutputStream(outputFile.apply { parentFile?.mkdirs() }.outputStream()).use { out -> jar.stream() .parallel() .filter { !it.isDirectory } From 12777bc3f0c343a31520a36ec59eea9e43442c31 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 7 Jul 2025 23:59:42 +0200 Subject: [PATCH 34/66] does this shit work now?? --- build.gradle.kts | 1 + buildSrc/src/main/kotlin/ApiGenerator.kt | 2 -- settings.gradle.kts | 7 ------- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index d3cfd5fee..f06c0383d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,6 +30,7 @@ buildscript { plugins { java `java-library` + `maven-publish` id("com.gradleup.shadow") version "8.3.6" id("de.undercouch.download") version "5.0.1" id("xyz.jpenilla.run-paper") version "2.3.1" diff --git a/buildSrc/src/main/kotlin/ApiGenerator.kt b/buildSrc/src/main/kotlin/ApiGenerator.kt index a844f0fd2..b526a1379 100644 --- a/buildSrc/src/main/kotlin/ApiGenerator.kt +++ b/buildSrc/src/main/kotlin/ApiGenerator.kt @@ -3,7 +3,6 @@ import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.publish.PublishingExtension import org.gradle.api.publish.maven.MavenPublication -import org.gradle.api.publish.maven.plugins.MavenPublishPlugin import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction @@ -15,7 +14,6 @@ import java.util.jar.JarOutputStream class ApiGenerator : Plugin { override fun apply(target: Project): Unit = with(target) { - plugins.apply(MavenPublishPlugin::class.java) val task = tasks.register("irisApi", GenerateApiTask::class.java) extensions.findByType(PublishingExtension::class.java)!! .publications diff --git a/settings.gradle.kts b/settings.gradle.kts index 3ffcee083..18cbee3fe 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,13 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -pluginManagement { - repositories { - mavenLocal() - mavenCentral() - gradlePluginPortal() - } -} plugins { id ("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } From fbc5cee300885ba16cc9bb8c6b4b6a343c178eb4 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 8 Jul 2025 00:22:31 +0200 Subject: [PATCH 35/66] if it still doesn't work, idk what will --- build.gradle.kts | 1 - buildSrc/src/main/kotlin/ApiGenerator.kt | 25 ++++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index f06c0383d..d3cfd5fee 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,7 +30,6 @@ buildscript { plugins { java `java-library` - `maven-publish` id("com.gradleup.shadow") version "8.3.6" id("de.undercouch.download") version "5.0.1" id("xyz.jpenilla.run-paper") version "2.3.1" diff --git a/buildSrc/src/main/kotlin/ApiGenerator.kt b/buildSrc/src/main/kotlin/ApiGenerator.kt index b526a1379..a4138269f 100644 --- a/buildSrc/src/main/kotlin/ApiGenerator.kt +++ b/buildSrc/src/main/kotlin/ApiGenerator.kt @@ -14,15 +14,20 @@ import java.util.jar.JarOutputStream class ApiGenerator : Plugin { override fun apply(target: Project): Unit = with(target) { + plugins.apply("maven-publish") val task = tasks.register("irisApi", GenerateApiTask::class.java) - extensions.findByType(PublishingExtension::class.java)!! - .publications - .create("maven", MavenPublication::class.java) { - it.groupId = group.toString() - it.artifactId = name + extensions.findByType(PublishingExtension::class.java)!!.apply { + repositories.maven { + it.name = "deployDir" + it.url = targetDirectory.toURI() + } + + publications.create("maven", MavenPublication::class.java) { + it.groupId = name it.version = version.toString() it.artifact(task) } + } } } @@ -45,7 +50,7 @@ abstract class GenerateApiTask : DefaultTask() { .asFile @OutputFile - val outputFile: File = targetDirectory().resolve(inputFile.name) + val outputFile: File = project.targetDirectory.resolve(inputFile.name) @TaskAction fun generate() { @@ -72,11 +77,11 @@ abstract class GenerateApiTask : DefaultTask() { } } } +} - fun targetDirectory(): File { - val dir = System.getenv("DEPLOY_DIR") ?: return project.layout.buildDirectory.dir("api").get().asFile - return File(dir) - } +val Project.targetDirectory: File get() { + val dir = System.getenv("DEPLOY_DIR") ?: return project.layout.buildDirectory.dir("api").get().asFile + return File(dir) } private class MethodClearingVisitor( From f9888d19a594261aa07bc35bb2900bd434115ded Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 8 Jul 2025 00:24:03 +0200 Subject: [PATCH 36/66] whoops forgot to update publish task --- buildSrc/src/main/kotlin/ApiGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/ApiGenerator.kt b/buildSrc/src/main/kotlin/ApiGenerator.kt index a4138269f..530d4c6eb 100644 --- a/buildSrc/src/main/kotlin/ApiGenerator.kt +++ b/buildSrc/src/main/kotlin/ApiGenerator.kt @@ -35,7 +35,7 @@ abstract class GenerateApiTask : DefaultTask() { init { group = "iris" dependsOn("jar") - finalizedBy("publishToMavenLocal") + finalizedBy("publishMavenPublicationToDeployDirRepository") doLast { logger.lifecycle("The API is located at ${outputFile.absolutePath}") } From 2e2ea8f1e4388c650de2bf8f87e04ca253f69b5c Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 8 Jul 2025 09:19:57 +0200 Subject: [PATCH 37/66] use paper plugin loader to avoid maven central warning --- core/build.gradle.kts | 3 ++ core/paper-loader/build.gradle.kts | 3 ++ .../com/volmit/iris/IrisPluginLoader.java | 37 +++++++++++++++++++ core/src/main/resources/plugin.yml | 5 ++- settings.gradle.kts | 2 +- 5 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 core/paper-loader/build.gradle.kts create mode 100644 core/paper-loader/src/main/java/com/volmit/iris/IrisPluginLoader.java diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 17158627f..4d7f24b67 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -25,6 +25,7 @@ plugins { val apiVersion = "1.19" val main = "com.volmit.iris.Iris" +val loader = "com.volmit.iris.IrisPluginLoader" val dynamic: Configuration by configurations.creating configurations.compileOnly { extendsFrom(dynamic) } @@ -69,6 +70,7 @@ dependencies { implementation("net.kyori:adventure-platform-bukkit:4.3.4") implementation("net.kyori:adventure-api:4.17.0") implementation("org.bstats:bstats-bukkit:3.1.0") + implementation(project(":core:paper-loader")) // Dynamically Loaded dynamic("commons-io:commons-io:2.13.0") @@ -118,6 +120,7 @@ tasks { "version" to rootProject.version, "apiVersion" to apiVersion, "main" to main, + "loader" to loader, "libraries" to dynamic.allDependencies.map { "\n - $it" }.sorted().joinToString("") ) filesMatching("**/plugin.yml") { diff --git a/core/paper-loader/build.gradle.kts b/core/paper-loader/build.gradle.kts new file mode 100644 index 000000000..367c9bbc9 --- /dev/null +++ b/core/paper-loader/build.gradle.kts @@ -0,0 +1,3 @@ +dependencies { + compileOnly("io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT") +} \ No newline at end of file diff --git a/core/paper-loader/src/main/java/com/volmit/iris/IrisPluginLoader.java b/core/paper-loader/src/main/java/com/volmit/iris/IrisPluginLoader.java new file mode 100644 index 000000000..c032b5b22 --- /dev/null +++ b/core/paper-loader/src/main/java/com/volmit/iris/IrisPluginLoader.java @@ -0,0 +1,37 @@ +package com.volmit.iris; + +import io.papermc.paper.plugin.loader.PluginClasspathBuilder; +import io.papermc.paper.plugin.loader.PluginLoader; +import io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver; +import lombok.SneakyThrows; +import org.bukkit.configuration.file.YamlConfiguration; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.repository.RemoteRepository; +import org.jetbrains.annotations.NotNull; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URI; + +@SuppressWarnings("all") +public class IrisPluginLoader implements PluginLoader { + + @SneakyThrows + @Override + public void classloader(@NotNull PluginClasspathBuilder builder) { + var pluginUri = URI.create("jar:file:" + builder.getContext().getPluginSource().toAbsolutePath() + "!/plugin.yml"); + var plugin = YamlConfiguration.loadConfiguration(new BufferedReader(new InputStreamReader(pluginUri.toURL().openStream()))); + var repository = "https://maven-central.storage-download.googleapis.com/maven2"; + + try { + var field = MavenLibraryResolver.class.getDeclaredField("MAVEN_CENTRAL_DEFAULT_MIRROR"); + repository = (String) field.get(null); + } catch (Throwable e) {} + + var resolver = new MavenLibraryResolver(); + resolver.addRepository(new RemoteRepository.Builder("central", "default", repository).build()); + plugin.getStringList("libraries").forEach(library -> resolver.addDependency(new Dependency(new DefaultArtifact(library), null))); + builder.addLibrary(resolver); + } +} diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml index 89fbfb449..5b6fc940c 100644 --- a/core/src/main/resources/plugin.yml +++ b/core/src/main/resources/plugin.yml @@ -10,4 +10,7 @@ commands: iris: aliases: [ ir, irs ] api-version: '${apiVersion}' -hotload-dependencies: false \ No newline at end of file +hotload-dependencies: false + +paper-plugin-loader: ${loader} +paper-skip-libraries: true \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 18cbee3fe..138a3c25c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -21,7 +21,7 @@ plugins { rootProject.name = "Iris" -include(":core", ":core:agent") +include(":core", ":core:agent", ":core:paper-loader") include( ":nms:v1_21_R5", ":nms:v1_21_R4", From 6b193f695a6d5f7ebb508c4d76484ab3d343d6ea Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 8 Jul 2025 18:46:59 +0200 Subject: [PATCH 38/66] switch to slimjar --- build.gradle.kts | 2 +- core/build.gradle.kts | 82 +++++----- core/paper-loader/build.gradle.kts | 3 - .../com/volmit/iris/IrisPluginLoader.java | 37 ----- core/src/main/java/com/volmit/iris/Iris.java | 128 ++------------- .../iris/core/safeguard/IrisSafeguard.java | 5 + .../com/volmit/iris/util/misc/Bindings.java | 146 ++++++++++++++++++ core/src/main/resources/plugin.yml | 7 +- settings.gradle.kts | 2 +- 9 files changed, 215 insertions(+), 197 deletions(-) delete mode 100644 core/paper-loader/build.gradle.kts delete mode 100644 core/paper-loader/src/main/java/com/volmit/iris/IrisPluginLoader.java create mode 100644 core/src/main/java/com/volmit/iris/util/misc/Bindings.java diff --git a/build.gradle.kts b/build.gradle.kts index d3cfd5fee..44ef145a6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,7 +30,7 @@ buildscript { plugins { java `java-library` - id("com.gradleup.shadow") version "8.3.6" + id("com.gradleup.shadow") version "9.0.0-rc1" id("de.undercouch.download") version "5.0.1" id("xyz.jpenilla.run-paper") version "2.3.1" id("io.sentry.jvm.gradle") version "5.7.0" diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 4d7f24b67..9aa0f57a2 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,3 +1,7 @@ +import io.github.slimjar.func.slimjar +import io.github.slimjar.resolver.data.Mirror +import java.net.URI + /* * Iris is a World Generator for Minecraft Bukkit Servers * Copyright (c) 2021 Arcane Arts (Volmit Software) @@ -21,14 +25,11 @@ plugins { `java-library` id("com.gradleup.shadow") id("io.sentry.jvm.gradle") + id("de.crazydev22.slimjar") version "2.0.6" } val apiVersion = "1.19" val main = "com.volmit.iris.Iris" -val loader = "com.volmit.iris.IrisPluginLoader" - -val dynamic: Configuration by configurations.creating -configurations.compileOnly { extendsFrom(dynamic) } /** * Dependencies. @@ -64,30 +65,32 @@ dependencies { //implementation files("libs/CustomItems.jar") // Shaded - implementation("com.dfsek:paralithic:0.8.1") - implementation("io.papermc:paperlib:1.0.5") - implementation("net.kyori:adventure-text-minimessage:4.17.0") - implementation("net.kyori:adventure-platform-bukkit:4.3.4") - implementation("net.kyori:adventure-api:4.17.0") - implementation("org.bstats:bstats-bukkit:3.1.0") - implementation(project(":core:paper-loader")) + implementation(slimjar()) // Dynamically Loaded - dynamic("commons-io:commons-io:2.13.0") - dynamic("commons-lang:commons-lang:2.6") - dynamic("com.github.oshi:oshi-core:6.6.5") - dynamic("org.lz4:lz4-java:1.8.0") - dynamic("it.unimi.dsi:fastutil:8.5.8") - dynamic("com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2") - dynamic("org.zeroturnaround:zt-zip:1.14") - dynamic("com.google.code.gson:gson:2.10.1") - dynamic("org.ow2.asm:asm:9.8") - dynamic("bsf:bsf:2.4.0") - dynamic("rhino:js:1.7R2") - dynamic("com.github.ben-manes.caffeine:caffeine:3.0.6") - dynamic("org.apache.commons:commons-lang3:3.12.0") - dynamic("net.bytebuddy:byte-buddy:1.17.5") - dynamic("net.bytebuddy:byte-buddy-agent:1.17.5") + slim("com.dfsek:paralithic:0.8.1") + slim("io.papermc:paperlib:1.0.5") + slim("net.kyori:adventure-text-minimessage:4.17.0") + slim("net.kyori:adventure-platform-bukkit:4.3.4") + slim("net.kyori:adventure-api:4.17.0") + slim("org.bstats:bstats-bukkit:3.1.0") + slim("io.sentry:sentry:8.12.0") + + slim("commons-io:commons-io:2.13.0") + slim("commons-lang:commons-lang:2.6") + slim("com.github.oshi:oshi-core:6.6.5") + slim("org.lz4:lz4-java:1.8.0") + slim("it.unimi.dsi:fastutil:8.5.8") + slim("com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2") + slim("org.zeroturnaround:zt-zip:1.14") + slim("com.google.code.gson:gson:2.10.1") + slim("org.ow2.asm:asm:9.8") + slim("bsf:bsf:2.4.0") + slim("rhino:js:1.7R2") + slim("com.github.ben-manes.caffeine:caffeine:3.0.6") + slim("org.apache.commons:commons-lang3:3.12.0") + slim("net.bytebuddy:byte-buddy:1.17.5") + slim("net.bytebuddy:byte-buddy-agent:1.17.5") } java { @@ -95,6 +98,7 @@ java { } sentry { + autoInstallation.enabled = false includeSourceContext = true org = "volmit-software" @@ -102,6 +106,20 @@ sentry { authToken = findProperty("sentry.auth.token") as String? ?: System.getenv("SENTRY_AUTH_TOKEN") } +slimJar { + mirrors = listOf(Mirror( + URI.create("https://maven-central.storage-download.googleapis.com/maven2").toURL(), + URI.create("https://repo.maven.apache.org/maven2/").toURL() + )) + + val libs = "com.volmit.iris.util" + relocate("com.dfsek.paralithic", "$libs.paralithic") + relocate("io.papermc.lib", "$libs.paper") + relocate("net.kyori", "$libs.kyori") + relocate("org.bstats", "$libs.metrics") + relocate("io.sentry", "$libs.sentry") +} + tasks { /** * We need parameter meta for the decree command system @@ -120,8 +138,6 @@ tasks { "version" to rootProject.version, "apiVersion" to apiVersion, "main" to main, - "loader" to loader, - "libraries" to dynamic.allDependencies.map { "\n - $it" }.sorted().joinToString("") ) filesMatching("**/plugin.yml") { expand(inputs.properties) @@ -130,17 +146,7 @@ tasks { shadowJar { mergeServiceFiles() - relocate("com.dfsek.paralithic", "com.volmit.iris.util.paralithic") - relocate("io.papermc.lib", "com.volmit.iris.util.paper") - relocate("net.kyori", "com.volmit.iris.util.kyori") - relocate("org.bstats", "com.volmit.iris.util.metrics") - relocate("io.sentry", "com.volmit.iris.util.sentry") - //minimize() - dependencies { - exclude(dependency("org.ow2.asm:asm:")) - exclude(dependency("org.jetbrains:")) - } } } diff --git a/core/paper-loader/build.gradle.kts b/core/paper-loader/build.gradle.kts deleted file mode 100644 index 367c9bbc9..000000000 --- a/core/paper-loader/build.gradle.kts +++ /dev/null @@ -1,3 +0,0 @@ -dependencies { - compileOnly("io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT") -} \ No newline at end of file diff --git a/core/paper-loader/src/main/java/com/volmit/iris/IrisPluginLoader.java b/core/paper-loader/src/main/java/com/volmit/iris/IrisPluginLoader.java deleted file mode 100644 index c032b5b22..000000000 --- a/core/paper-loader/src/main/java/com/volmit/iris/IrisPluginLoader.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.volmit.iris; - -import io.papermc.paper.plugin.loader.PluginClasspathBuilder; -import io.papermc.paper.plugin.loader.PluginLoader; -import io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver; -import lombok.SneakyThrows; -import org.bukkit.configuration.file.YamlConfiguration; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.graph.Dependency; -import org.eclipse.aether.repository.RemoteRepository; -import org.jetbrains.annotations.NotNull; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.URI; - -@SuppressWarnings("all") -public class IrisPluginLoader implements PluginLoader { - - @SneakyThrows - @Override - public void classloader(@NotNull PluginClasspathBuilder builder) { - var pluginUri = URI.create("jar:file:" + builder.getContext().getPluginSource().toAbsolutePath() + "!/plugin.yml"); - var plugin = YamlConfiguration.loadConfiguration(new BufferedReader(new InputStreamReader(pluginUri.toURL().openStream()))); - var repository = "https://maven-central.storage-download.googleapis.com/maven2"; - - try { - var field = MavenLibraryResolver.class.getDeclaredField("MAVEN_CENTRAL_DEFAULT_MIRROR"); - repository = (String) field.get(null); - } catch (Throwable e) {} - - var resolver = new MavenLibraryResolver(); - resolver.addRepository(new RemoteRepository.Builder("central", "default", repository).build()); - plugin.getStringList("libraries").forEach(library -> resolver.addDependency(new Dependency(new DefaultArtifact(library), null))); - builder.addLibrary(resolver); - } -} diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 7904a6f20..7b9c53f4c 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -30,7 +30,6 @@ import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.v1X.NMSBinding1X; import com.volmit.iris.core.pregenerator.LazyPregenerator; -import com.volmit.iris.core.safeguard.ServerBootSFG; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.EnginePanic; @@ -39,11 +38,9 @@ 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.core.safeguard.IrisSafeguard; -import com.volmit.iris.core.safeguard.UtilsSFG; import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; -import com.volmit.iris.util.context.IrisContext; import com.volmit.iris.util.exceptions.IrisException; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; @@ -52,30 +49,19 @@ import com.volmit.iris.util.io.FileWatcher; import com.volmit.iris.util.io.IO; import com.volmit.iris.util.io.InstanceState; import com.volmit.iris.util.io.JarScanner; -import com.volmit.iris.util.json.JSONException; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.misc.Bindings; import com.volmit.iris.util.misc.getHardware; import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.plugin.IrisService; import com.volmit.iris.util.plugin.VolmitPlugin; import com.volmit.iris.util.plugin.VolmitSender; -import com.volmit.iris.util.reflect.ShadeFix; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.Queue; import com.volmit.iris.util.scheduling.ShurikenQueue; -import com.volmit.iris.util.sentry.Attachments; -import com.volmit.iris.util.sentry.IrisLogger; -import com.volmit.iris.util.sentry.ServerID; -import io.papermc.lib.PaperLib; -import io.sentry.Sentry; +import io.github.slimjar.app.builder.ApplicationBuilder; import lombok.NonNull; -import net.kyori.adventure.platform.bukkit.BukkitAudiences; -import net.kyori.adventure.text.serializer.ComponentSerializer; -import org.bstats.bukkit.Metrics; -import org.bstats.charts.DrilldownPie; -import org.bstats.charts.SimplePie; -import org.bstats.charts.SingleLineChart; import org.bukkit.*; import org.bukkit.block.data.BlockData; import org.bukkit.command.Command; @@ -91,17 +77,13 @@ import org.bukkit.plugin.IllegalPluginAccessException; import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import oshi.SystemInfo; import java.io.*; import java.lang.annotation.Annotation; -import java.math.RoundingMode; import java.net.URL; -import java.text.NumberFormat; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import static com.volmit.iris.core.safeguard.IrisSafeguard.*; import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware; @@ -111,7 +93,7 @@ public class Iris extends VolmitPlugin implements Listener { private static final Queue syncJobs = new ShurikenQueue<>(); public static Iris instance; - public static BukkitAudiences audiences; + public static Bindings.Adventure audiences; public static MultiverseCoreLink linkMultiverseCore; public static MythicMobsLink linkMythicMobs; public static IrisCompat compat; @@ -120,7 +102,6 @@ public class Iris extends VolmitPlugin implements Listener { static { try { - fixShading(); InstanceState.updateInstanceId(); } catch (Throwable ignored) { @@ -397,7 +378,7 @@ public class Iris extends VolmitPlugin implements Listener { } public static void reportError(Throwable e) { - Sentry.captureException(e); + Bindings.capture(e); if (IrisSettings.get().getGeneral().isDebug()) { String n = e.getClass().getCanonicalName() + "-" + e.getStackTrace()[0].getClassName() + "-" + e.getStackTrace()[0].getLineNumber(); @@ -455,14 +436,21 @@ public class Iris extends VolmitPlugin implements Listener { EnginePanic.add(s, v); } - private static void fixShading() { - ShadeFix.fix(ComponentSerializer.class); + public Iris() { + ApplicationBuilder.appending("Iris") + .downloadDirectoryPath(getDataFolder("cache", "libraries").toPath()) + .logger((message, args) -> { + if (!message.startsWith("Loaded library ")) return; + getLogger().info(message.formatted(args)); + }) + .build(); } + private void enable() { instance = this; services = new KMap<>(); setupAudience(); - setupSentry(); + Bindings.setupSentry(); initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class) i.getClass(), (IrisService) i)); IO.delete(new File("iris")); compat = IrisCompat.configured(getDataFile("compat.json")); @@ -476,7 +464,7 @@ public class Iris extends VolmitPlugin implements Listener { services.values().forEach(IrisService::onEnable); services.values().forEach(this::registerListener); J.s(() -> { - J.a(() -> PaperLib.suggestPaper(this)); + J.a(IrisSafeguard::suggestPaper); J.a(() -> IO.delete(getTemp())); J.a(LazyPregenerator::loadLazyGenerators, 100); J.a(this::bstats); @@ -556,7 +544,7 @@ public class Iris extends VolmitPlugin implements Listener { private void setupAudience() { try { - audiences = BukkitAudiences.create(this); + audiences = new Bindings.Adventure(this); } catch (Throwable e) { e.printStackTrace(); IrisSettings.get().getGeneral().setUseConsoleCustomColors(false); @@ -689,50 +677,7 @@ public class Iris extends VolmitPlugin implements Listener { private void bstats() { if (IrisSettings.get().getGeneral().isPluginMetrics()) { - J.s(() -> { - var metrics = new Metrics(Iris.instance, 24220); - metrics.addCustomChart(new SingleLineChart("custom_dimensions", () -> Bukkit.getWorlds() - .stream() - .filter(IrisToolbelt::isIrisWorld) - .mapToInt(w -> 1) - .sum())); - - metrics.addCustomChart(new DrilldownPie("used_packs", () -> Bukkit.getWorlds().stream() - .map(IrisToolbelt::access) - .filter(Objects::nonNull) - .map(PlatformChunkGenerator::getEngine) - .collect(Collectors.toMap(engine -> engine.getDimension().getLoadKey(), engine -> { - var hash32 = engine.getHash32().getNow(null); - if (hash32 == null) return Map.of(); - int version = engine.getDimension().getVersion(); - String checksum = Long.toHexString(hash32); - - return Map.of("v" + version + " (" + checksum + ")", 1); - }, (a, b) -> { - Map merged = new HashMap<>(a); - b.forEach((k, v) -> merged.merge(k, v, Integer::sum)); - return merged; - })))); - - - var info = new SystemInfo().getHardware(); - var cpu = info.getProcessor().getProcessorIdentifier(); - var mem = info.getMemory(); - metrics.addCustomChart(new SimplePie("cpu_model", cpu::getName)); - - var nf = NumberFormat.getInstance(Locale.ENGLISH); - nf.setMinimumFractionDigits(0); - nf.setMaximumFractionDigits(2); - nf.setRoundingMode(RoundingMode.HALF_UP); - - metrics.addCustomChart(new DrilldownPie("memory", () -> { - double total = mem.getTotal() * 1E-9; - double alloc = Math.min(total, Runtime.getRuntime().maxMemory() * 1E-9); - return Map.of(nf.format(alloc), Map.of(nf.format(total), 1)); - })); - - postShutdown.add(metrics::shutdown); - }); + Bindings.setupBstats(this); } } @@ -937,43 +882,4 @@ public class Iris extends VolmitPlugin implements Listener { return -1; } } - - private static boolean suppress(Throwable e) { - return (e instanceof IllegalStateException ex && "zip file closed".equals(ex.getMessage())) || e instanceof JSONException; - } - - private static void setupSentry() { - var settings = IrisSettings.get().getSentry(); - if (settings.disableAutoReporting || Sentry.isEnabled() || Boolean.getBoolean("iris.suppressReporting")) return; - Iris.info("Enabling Sentry for anonymous error reporting. You can disable this in the settings."); - Iris.info("Your server ID is: " + ServerID.ID); - Sentry.init(options -> { - options.setDsn("https://b16ecc222e9c1e0c48faecacb906fd89@o4509451052646400.ingest.de.sentry.io/4509452722765904"); - if (settings.debug) { - options.setLogger(new IrisLogger()); - options.setDebug(true); - } - - options.setAttachServerName(false); - options.setEnableUncaughtExceptionHandler(false); - options.setRelease(Iris.instance.getDescription().getVersion()); - options.setBeforeSend((event, hint) -> { - if (suppress(event.getThrowable())) return null; - event.setTag("iris.safeguard", IrisSafeguard.mode()); - event.setTag("iris.nms", INMS.get().getClass().getCanonicalName()); - var context = IrisContext.get(); - if (context != null) event.getContexts().set("engine", context.asContext()); - event.getContexts().set("safeguard", IrisSafeguard.asContext()); - return event; - }); - }); - Sentry.configureScope(scope -> { - if (settings.includeServerId) scope.setUser(ServerID.asUser()); - scope.addAttachment(Attachments.PLUGINS); - scope.setTag("server", Bukkit.getVersion()); - scope.setTag("server.type", Bukkit.getName()); - scope.setTag("server.api", Bukkit.getBukkitVersion()); - }); - Runtime.getRuntime().addShutdownHook(new Thread(Sentry::close)); - } } diff --git a/core/src/main/java/com/volmit/iris/core/safeguard/IrisSafeguard.java b/core/src/main/java/com/volmit/iris/core/safeguard/IrisSafeguard.java index 7a4ca9b5c..bef5f165a 100644 --- a/core/src/main/java/com/volmit/iris/core/safeguard/IrisSafeguard.java +++ b/core/src/main/java/com/volmit/iris/core/safeguard/IrisSafeguard.java @@ -4,6 +4,7 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; +import io.papermc.lib.PaperLib; import java.util.concurrent.atomic.AtomicBoolean; @@ -38,6 +39,10 @@ public class IrisSafeguard { } } + public static void suggestPaper() { + PaperLib.suggestPaper(Iris.instance); + } + public static KMap asContext() { KMap m = new KMap<>(); m.put("diskSpace", !ServerBootSFG.hasEnoughDiskSpace); diff --git a/core/src/main/java/com/volmit/iris/util/misc/Bindings.java b/core/src/main/java/com/volmit/iris/util/misc/Bindings.java new file mode 100644 index 000000000..308d3d235 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/misc/Bindings.java @@ -0,0 +1,146 @@ +package com.volmit.iris.util.misc; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.nms.INMS; +import com.volmit.iris.core.safeguard.IrisSafeguard; +import com.volmit.iris.core.tools.IrisToolbelt; +import com.volmit.iris.engine.platform.PlatformChunkGenerator; +import com.volmit.iris.util.context.IrisContext; +import com.volmit.iris.util.json.JSONException; +import com.volmit.iris.util.reflect.ShadeFix; +import com.volmit.iris.util.scheduling.J; +import com.volmit.iris.util.sentry.Attachments; +import com.volmit.iris.util.sentry.IrisLogger; +import com.volmit.iris.util.sentry.ServerID; +import io.sentry.Sentry; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.platform.bukkit.BukkitAudiences; +import net.kyori.adventure.text.serializer.ComponentSerializer; +import org.bstats.bukkit.Metrics; +import org.bstats.charts.DrilldownPie; +import org.bstats.charts.SimplePie; +import org.bstats.charts.SingleLineChart; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import oshi.SystemInfo; + +import java.math.RoundingMode; +import java.text.NumberFormat; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +public class Bindings { + + public static void capture(Throwable throwable) { + Sentry.captureException(throwable); + } + + public static void setupSentry() { + var settings = IrisSettings.get().getSentry(); + if (settings.disableAutoReporting || Sentry.isEnabled() || Boolean.getBoolean("iris.suppressReporting")) return; + Iris.info("Enabling Sentry for anonymous error reporting. You can disable this in the settings."); + Iris.info("Your server ID is: " + ServerID.ID); + Sentry.init(options -> { + options.setDsn("https://b16ecc222e9c1e0c48faecacb906fd89@o4509451052646400.ingest.de.sentry.io/4509452722765904"); + if (settings.debug) { + options.setLogger(new IrisLogger()); + options.setDebug(true); + } + + options.setAttachServerName(false); + options.setEnableUncaughtExceptionHandler(false); + options.setRelease(Iris.instance.getDescription().getVersion()); + options.setBeforeSend((event, hint) -> { + if (suppress(event.getThrowable())) return null; + event.setTag("iris.safeguard", IrisSafeguard.mode()); + event.setTag("iris.nms", INMS.get().getClass().getCanonicalName()); + var context = IrisContext.get(); + if (context != null) event.getContexts().set("engine", context.asContext()); + event.getContexts().set("safeguard", IrisSafeguard.asContext()); + return event; + }); + }); + Sentry.configureScope(scope -> { + if (settings.includeServerId) scope.setUser(ServerID.asUser()); + scope.addAttachment(Attachments.PLUGINS); + scope.setTag("server", Bukkit.getVersion()); + scope.setTag("server.type", Bukkit.getName()); + scope.setTag("server.api", Bukkit.getBukkitVersion()); + }); + Runtime.getRuntime().addShutdownHook(new Thread(Sentry::close)); + } + + private static boolean suppress(Throwable e) { + return (e instanceof IllegalStateException ex && "zip file closed".equals(ex.getMessage())) || e instanceof JSONException; + } + + + public static void setupBstats(Iris plugin) { + J.s(() -> { + var metrics = new Metrics(plugin, 24220); + metrics.addCustomChart(new SingleLineChart("custom_dimensions", () -> Bukkit.getWorlds() + .stream() + .filter(IrisToolbelt::isIrisWorld) + .mapToInt(w -> 1) + .sum())); + + metrics.addCustomChart(new DrilldownPie("used_packs", () -> Bukkit.getWorlds().stream() + .map(IrisToolbelt::access) + .filter(Objects::nonNull) + .map(PlatformChunkGenerator::getEngine) + .collect(Collectors.toMap(engine -> engine.getDimension().getLoadKey(), engine -> { + var hash32 = engine.getHash32().getNow(null); + if (hash32 == null) return Map.of(); + int version = engine.getDimension().getVersion(); + String checksum = Long.toHexString(hash32); + + return Map.of("v" + version + " (" + checksum + ")", 1); + }, (a, b) -> { + Map merged = new HashMap<>(a); + b.forEach((k, v) -> merged.merge(k, v, Integer::sum)); + return merged; + })))); + + + var info = new SystemInfo().getHardware(); + var cpu = info.getProcessor().getProcessorIdentifier(); + var mem = info.getMemory(); + metrics.addCustomChart(new SimplePie("cpu_model", cpu::getName)); + + var nf = NumberFormat.getInstance(Locale.ENGLISH); + nf.setMinimumFractionDigits(0); + nf.setMaximumFractionDigits(2); + nf.setRoundingMode(RoundingMode.HALF_UP); + + metrics.addCustomChart(new DrilldownPie("memory", () -> { + double total = mem.getTotal() * 1E-9; + double alloc = Math.min(total, Runtime.getRuntime().maxMemory() * 1E-9); + return Map.of(nf.format(alloc), Map.of(nf.format(total), 1)); + })); + + plugin.postShutdown(metrics::shutdown); + }); + } + + public static class Adventure { + private final BukkitAudiences audiences; + + public Adventure(Iris plugin) { + ShadeFix.fix(ComponentSerializer.class); + this.audiences = BukkitAudiences.create(plugin); + } + + public Audience player(Player player) { + return audiences.player(player); + } + + public Audience sender(CommandSender sender) { + return audiences.sender(sender); + } + } +} diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml index 5b6fc940c..99fa326be 100644 --- a/core/src/main/resources/plugin.yml +++ b/core/src/main/resources/plugin.yml @@ -5,12 +5,7 @@ load: STARTUP authors: [ cyberpwn, NextdoorPsycho, Vatuu ] website: volmit.com description: More than a Dimension! -libraries: ${libraries} commands: iris: aliases: [ ir, irs ] -api-version: '${apiVersion}' -hotload-dependencies: false - -paper-plugin-loader: ${loader} -paper-skip-libraries: true \ No newline at end of file +api-version: '${apiVersion}' \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 138a3c25c..18cbee3fe 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -21,7 +21,7 @@ plugins { rootProject.name = "Iris" -include(":core", ":core:agent", ":core:paper-loader") +include(":core", ":core:agent") include( ":nms:v1_21_R5", ":nms:v1_21_R4", From 03c5998c02dd4d83c9a567f6f7d0af20e3cf3372 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 8 Jul 2025 19:08:12 +0200 Subject: [PATCH 39/66] generate a dummy region for standalone focus biomes --- .../java/com/volmit/iris/engine/IrisComplex.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/IrisComplex.java b/core/src/main/java/com/volmit/iris/engine/IrisComplex.java index 652b728ca..70422c6a1 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisComplex.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisComplex.java @@ -42,6 +42,7 @@ import org.bukkit.Material; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; +import java.io.File; import java.util.UUID; @Data @@ -110,8 +111,6 @@ public class IrisComplex implements DataProvider { //@builder if (focusRegion != null) { focusRegion.getAllBiomes(this).forEach(this::registerGenerators); - } else if (focusBiome != null) { - registerGenerators(focusBiome); } else { engine.getDimension() .getRegions() @@ -252,7 +251,15 @@ public class IrisComplex implements DataProvider { } } - return null; + String key = UUID.randomUUID().toString(); + IrisRegion region = new IrisRegion(); + region.getLandBiomes().add(focus.getLoadKey()); + region.getSeaBiomes().add(focus.getLoadKey()); + region.getShoreBiomes().add(focus.getLoadKey()); + region.setLoadKey(key); + region.setLoader(data); + region.setLoadFile(new File(data.getDataFolder(), data.getRegionLoader().getFolderName() + "/" + key + ".json")); + return region; } private IrisDecorator decorateFor(IrisBiome b, double x, double z, IrisDecorationPart part) { From 0b1af51227e40a76f185f3bad8e4275426896ec9 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 8 Jul 2025 19:52:09 +0200 Subject: [PATCH 40/66] add option to disable specific mantle components for testing --- .../iris/core/project/SchemaBuilder.java | 20 ++++++++++ .../volmit/iris/engine/IrisEngineMantle.java | 14 ++++++- .../iris/engine/mantle/ComponentFlag.java | 14 +++++++ .../iris/engine/mantle/EngineMantle.java | 6 ++- .../engine/mantle/IrisMantleComponent.java | 1 + .../iris/engine/mantle/MantleComponent.java | 4 ++ .../components/MantleCarvingComponent.java | 2 + .../components/MantleFluidBodyComponent.java | 2 + .../components/MantleJigsawComponent.java | 2 + .../components/MantleObjectComponent.java | 2 + .../iris/engine/object/IrisDimension.java | 6 +++ .../functions/ComponentFlagFunction.java | 37 +++++++++++++++++++ 12 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/engine/mantle/ComponentFlag.java create mode 100644 core/src/main/java/com/volmit/iris/engine/object/annotations/functions/ComponentFlagFunction.java 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 2e133f944..d856d2b8e 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 @@ -466,6 +466,26 @@ public class SchemaBuilder { items.put("$ref", "#/definitions/" + key); prop.put("items", items); description.add(SYMBOL_TYPE__N + " Must be a valid Enchantment Type (use ctrl+space for auto complete!)"); + } else if (k.isAnnotationPresent(RegistryListFunction.class)) { + var functionClass = k.getDeclaredAnnotation(RegistryListFunction.class).value(); + try { + var instance = functionClass.getDeclaredConstructor().newInstance(); + String key = instance.key(); + fancyType = instance.fancyName(); + + if (!definitions.containsKey(key)) { + JSONObject j = new JSONObject(); + j.put("enum", instance.apply(data)); + definitions.put(key, j); + } + + JSONObject items = new JSONObject(); + items.put("$ref", "#/definitions/" + key); + prop.put("items", items); + description.add(SYMBOL_TYPE__N + " Must be a valid " + fancyType + " (use ctrl+space for auto complete!)"); + } catch (Throwable e) { + Iris.error("Could not execute apply method in " + functionClass.getName()); + } } else if (t.type().equals(PotionEffectType.class)) { fancyType = "List of Potion Effect Types"; String key = "enum-potion-effect-type"; diff --git a/core/src/main/java/com/volmit/iris/engine/IrisEngineMantle.java b/core/src/main/java/com/volmit/iris/engine/IrisEngineMantle.java index c3b385361..e58324ad7 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisEngineMantle.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisEngineMantle.java @@ -29,7 +29,9 @@ import com.volmit.iris.engine.mantle.components.MantleJigsawComponent; import com.volmit.iris.engine.mantle.components.MantleObjectComponent; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.mantle.Mantle; +import com.volmit.iris.util.mantle.MantleFlag; import lombok.*; import java.io.File; @@ -44,7 +46,7 @@ public class IrisEngineMantle implements EngineMantle { @Getter(AccessLevel.NONE) private final KMap> components; private final AtomicCache, Integer>>> componentsCache = new AtomicCache<>(); - private final AtomicCache radCache = new AtomicCache<>(); + private final AtomicCache> disabledFlags = new AtomicCache<>(); private final MantleObjectComponent object; private final MantleJigsawComponent jigsaw; @@ -101,10 +103,20 @@ public class IrisEngineMantle implements EngineMantle { @Override public void registerComponent(MantleComponent c) { + c.setEnabled(!getDimension().getDisabledComponents().contains(c.getFlag())); components.computeIfAbsent(c.getPriority(), k -> new KList<>()).add(c); componentsCache.reset(); } + @Override + public KList getComponentFlags() { + return components.values() + .stream() + .flatMap(KList::stream) + .map(MantleComponent::getFlag) + .collect(KList.collector()); + } + @Override public MantleJigsawComponent getJigsawComponent() { return jigsaw; diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/ComponentFlag.java b/core/src/main/java/com/volmit/iris/engine/mantle/ComponentFlag.java new file mode 100644 index 000000000..1c7fe20b2 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/mantle/ComponentFlag.java @@ -0,0 +1,14 @@ +package com.volmit.iris.engine.mantle; + +import com.volmit.iris.util.mantle.MantleFlag; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface ComponentFlag { + MantleFlag value(); +} diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java index ba0759c83..d37814e0c 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java @@ -65,6 +65,8 @@ public interface EngineMantle extends IObjectPlacer { void registerComponent(MantleComponent c); + KList getComponentFlags(); + default int getHighest(int x, int z) { return getHighest(x, z, getData()); } @@ -227,7 +229,9 @@ public interface EngineMantle extends IObjectPlacer { } default void generateMantleComponent(MantleWriter writer, int x, int z, MantleComponent c, MantleChunk mc, ChunkContext context) { - mc.raiseFlag(c.getFlag(), () -> c.generateLayer(writer, x, z, context)); + mc.raiseFlag(c.getFlag(), () -> { + if (c.isEnabled()) c.generateLayer(writer, x, z, context); + }); } @ChunkCoordinates diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/IrisMantleComponent.java b/core/src/main/java/com/volmit/iris/engine/mantle/IrisMantleComponent.java index 388518c0d..cfe72ae39 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/IrisMantleComponent.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/IrisMantleComponent.java @@ -30,4 +30,5 @@ public abstract class IrisMantleComponent implements MantleComponent { private final EngineMantle engineMantle; private final MantleFlag flag; private final int priority; + private boolean enabled = true; } diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/MantleComponent.java b/core/src/main/java/com/volmit/iris/engine/mantle/MantleComponent.java index 3c9c78dc5..64c69d5c6 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/MantleComponent.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/MantleComponent.java @@ -61,6 +61,10 @@ public interface MantleComponent extends Comparable { MantleFlag getFlag(); + boolean isEnabled(); + + void setEnabled(boolean b); + @ChunkCoordinates void generateLayer(MantleWriter writer, int x, int z, ChunkContext context); diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleCarvingComponent.java b/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleCarvingComponent.java index 8d067abfd..eca862c79 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleCarvingComponent.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleCarvingComponent.java @@ -19,6 +19,7 @@ package com.volmit.iris.engine.mantle.components; import com.volmit.iris.engine.data.cache.Cache; +import com.volmit.iris.engine.mantle.ComponentFlag; import com.volmit.iris.engine.mantle.EngineMantle; import com.volmit.iris.engine.mantle.IrisMantleComponent; import com.volmit.iris.engine.mantle.MantleWriter; @@ -32,6 +33,7 @@ import com.volmit.iris.util.math.RNG; import lombok.Getter; @Getter +@ComponentFlag(MantleFlag.CARVED) public class MantleCarvingComponent extends IrisMantleComponent { private final int radius = computeRadius(); diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleFluidBodyComponent.java b/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleFluidBodyComponent.java index bd45353c2..15389715e 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleFluidBodyComponent.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleFluidBodyComponent.java @@ -19,6 +19,7 @@ package com.volmit.iris.engine.mantle.components; import com.volmit.iris.engine.data.cache.Cache; +import com.volmit.iris.engine.mantle.ComponentFlag; import com.volmit.iris.engine.mantle.EngineMantle; import com.volmit.iris.engine.mantle.IrisMantleComponent; import com.volmit.iris.engine.mantle.MantleWriter; @@ -32,6 +33,7 @@ import com.volmit.iris.util.math.RNG; import lombok.Getter; @Getter +@ComponentFlag(MantleFlag.FLUID_BODIES) public class MantleFluidBodyComponent extends IrisMantleComponent { private final int radius = computeRadius(); diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleJigsawComponent.java b/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleJigsawComponent.java index 6ba27c542..e5f551872 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleJigsawComponent.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleJigsawComponent.java @@ -19,6 +19,7 @@ package com.volmit.iris.engine.mantle.components; import com.volmit.iris.engine.jigsaw.PlannedStructure; +import com.volmit.iris.engine.mantle.ComponentFlag; import com.volmit.iris.engine.mantle.EngineMantle; import com.volmit.iris.engine.mantle.IrisMantleComponent; import com.volmit.iris.engine.mantle.MantleWriter; @@ -39,6 +40,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; +@ComponentFlag(MantleFlag.JIGSAW) public class MantleJigsawComponent extends IrisMantleComponent { @Getter private final int radius = computeRadius(); diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleObjectComponent.java b/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleObjectComponent.java index b8d4f9fd8..a4ca6dd7a 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleObjectComponent.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleObjectComponent.java @@ -20,6 +20,7 @@ package com.volmit.iris.engine.mantle.components; import com.volmit.iris.Iris; import com.volmit.iris.engine.data.cache.Cache; +import com.volmit.iris.engine.mantle.ComponentFlag; import com.volmit.iris.engine.mantle.EngineMantle; import com.volmit.iris.engine.mantle.IrisMantleComponent; import com.volmit.iris.engine.mantle.MantleWriter; @@ -47,6 +48,7 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; @Getter +@ComponentFlag(MantleFlag.OBJECT) public class MantleObjectComponent extends IrisMantleComponent { private final int radius = computeRadius(); 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 6ff0fa44f..ef76eac9f 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 @@ -28,11 +28,13 @@ import com.volmit.iris.core.nms.datapack.IDataFixer; import com.volmit.iris.core.nms.datapack.IDataFixer.Dimension; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.object.annotations.*; +import com.volmit.iris.engine.object.annotations.functions.ComponentFlagFunction; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.data.DataProvider; import com.volmit.iris.util.io.IO; import com.volmit.iris.util.json.JSONObject; +import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.noise.CNG; @@ -238,6 +240,10 @@ public class IrisDimension extends IrisRegistrant { @MaxNumber(318) @Desc("The Subterrain Fluid Layer Height") private int caveLavaHeight = 8; + @RegistryListFunction(ComponentFlagFunction.class) + @ArrayType(type = MantleFlag.class) + @Desc("Collection of disabled components") + private KList disabledComponents = new KList<>(); public int getMaxHeight() { return (int) getDimensionHeight().getMax(); diff --git a/core/src/main/java/com/volmit/iris/engine/object/annotations/functions/ComponentFlagFunction.java b/core/src/main/java/com/volmit/iris/engine/object/annotations/functions/ComponentFlagFunction.java new file mode 100644 index 000000000..7a0c01755 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/object/annotations/functions/ComponentFlagFunction.java @@ -0,0 +1,37 @@ +package com.volmit.iris.engine.object.annotations.functions; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.engine.framework.ListFunction; +import com.volmit.iris.engine.mantle.ComponentFlag; +import com.volmit.iris.engine.mantle.MantleComponent; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.mantle.MantleFlag; + +import java.util.Objects; + +public class ComponentFlagFunction implements ListFunction> { + @Override + public String key() { + return "component-flag"; + } + + @Override + public String fancyName() { + return "Component Flag"; + } + + @Override + public KList apply(IrisData data) { + var engine = data.getEngine(); + if (engine != null) return engine.getMantle().getComponentFlags().toStringList(); + return Iris.getClasses("com.volmit.iris.engine.mantle.components", ComponentFlag.class) + .stream() + .filter(MantleComponent.class::isAssignableFrom) + .map(c -> c.getDeclaredAnnotation(ComponentFlag.class)) + .filter(Objects::nonNull) + .map(ComponentFlag::value) + .map(MantleFlag::toString) + .collect(KList.collector()); + } +} From a0543bbbf203545d01cbeaab246a90ff7e9dde72 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 8 Jul 2025 19:59:45 +0200 Subject: [PATCH 41/66] relocate slimjar --- core/build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 9aa0f57a2..be3b51086 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -30,6 +30,7 @@ plugins { val apiVersion = "1.19" val main = "com.volmit.iris.Iris" +val libs = "com.volmit.iris.util" /** * Dependencies. @@ -112,7 +113,6 @@ slimJar { URI.create("https://repo.maven.apache.org/maven2/").toURL() )) - val libs = "com.volmit.iris.util" relocate("com.dfsek.paralithic", "$libs.paralithic") relocate("io.papermc.lib", "$libs.paper") relocate("net.kyori", "$libs.kyori") @@ -147,6 +147,7 @@ tasks { shadowJar { mergeServiceFiles() //minimize() + relocate("io.github.slimjar", "$libs.slimjar") } } From 0edaeeec99ea07857d15efe74de0b17d25216a47 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 8 Jul 2025 23:40:10 +0200 Subject: [PATCH 42/66] massive cleanup of maven repos and update dependencies --- build.gradle.kts | 33 ++++++------ core/build.gradle.kts | 91 +++++++++++++++++----------------- gradle/libs.versions.toml | 102 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 64 deletions(-) create mode 100644 gradle/libs.versions.toml diff --git a/build.gradle.kts b/build.gradle.kts index 44ef145a6..fd1f9e400 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,10 +30,10 @@ buildscript { plugins { java `java-library` - id("com.gradleup.shadow") version "9.0.0-rc1" - id("de.undercouch.download") version "5.0.1" - id("xyz.jpenilla.run-paper") version "2.3.1" - id("io.sentry.jvm.gradle") version "5.7.0" + alias(libs.plugins.shadow) + alias(libs.plugins.sentry) + alias(libs.plugins.download) + alias(libs.plugins.runPaper) } group = "com.volmit" @@ -93,8 +93,8 @@ nmsBindings.forEach { key, value -> dependencies { compileOnly(project(":core")) - compileOnly("org.jetbrains:annotations:26.0.2") - compileOnly("net.bytebuddy:byte-buddy:1.17.5") + compileOnly(rootProject.libs.annotations) + compileOnly(rootProject.libs.byteBuddy.core) } } @@ -187,23 +187,20 @@ allprojects { mavenCentral() maven("https://repo.papermc.io/repository/maven-public/") maven("https://repo.codemc.org/repository/maven-public/") - maven("https://mvn.lumine.io/repository/maven-public/") - maven("https://jitpack.io") - maven("https://s01.oss.sonatype.org/content/repositories/snapshots") - maven("https://mvn.lumine.io/repository/maven/") - maven("https://repo.triumphteam.dev/snapshots") - maven("https://repo.mineinabyss.com/releases") - maven("https://hub.jeff-media.com/nexus/repository/jeff-media-public/") - maven("https://repo.nexomc.com/releases/") - maven("https://nexus.phoenixdevt.fr/repository/maven-public/") - maven("https://repo.onarandombox.com/content/groups/public/") + maven("https://jitpack.io") // EcoItems, score + maven("https://repo.nexomc.com/releases/") // nexo + maven("https://maven.devs.beer/") // itemsadder + maven("https://repo.extendedclip.com/releases/") // placeholderapi + maven("https://mvn.lumine.io/repository/maven-public/") // mythic + maven("https://nexus.phoenixdevt.fr/repository/maven-public/") //MMOItems + maven("https://repo.onarandombox.com/content/groups/public/") //Multiverse Core } dependencies { // Provided or Classpath - compileOnly("org.projectlombok:lombok:1.18.36") - annotationProcessor("org.projectlombok:lombok:1.18.36") + compileOnly(rootProject.libs.lombok) + annotationProcessor(rootProject.libs.lombok) } /** diff --git a/core/build.gradle.kts b/core/build.gradle.kts index be3b51086..ef7cc7168 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -23,14 +23,14 @@ import java.net.URI plugins { java `java-library` - id("com.gradleup.shadow") - id("io.sentry.jvm.gradle") - id("de.crazydev22.slimjar") version "2.0.6" + alias(libs.plugins.shadow) + alias(libs.plugins.sentry) + alias(libs.plugins.slimjar) } val apiVersion = "1.19" val main = "com.volmit.iris.Iris" -val libs = "com.volmit.iris.util" +val lib = "com.volmit.iris.util" /** * Dependencies. @@ -46,52 +46,51 @@ val libs = "com.volmit.iris.util" */ dependencies { // Provided or Classpath - compileOnly("org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT") - compileOnly("org.apache.logging.log4j:log4j-api:2.19.0") - compileOnly("org.apache.logging.log4j:log4j-core:2.19.0") + compileOnly(libs.spigot) + compileOnly(libs.log4j.api) + compileOnly(libs.log4j.core) // Third Party Integrations - compileOnly("com.nexomc:nexo:1.6.0") - compileOnly("com.github.LoneDev6:api-itemsadder:3.4.1-r4") - 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") - compileOnly("io.lumine:Mythic-Dist:5.2.1") - compileOnly("io.lumine:MythicCrucible-Dist:2.0.0") - compileOnly("me.kryniowesegryderiusz:kgenerators-core:7.3") { + compileOnly(libs.nexo) + compileOnly(libs.itemsadder) + compileOnly(libs.placeholderApi) + compileOnly(libs.score) + compileOnly(libs.mmoitems) + compileOnly(libs.ecoitems) + compileOnly(libs.mythic) + compileOnly(libs.mythicChrucible) + compileOnly(libs.kgenerators) { isTransitive = false } - compileOnly("org.mvplugins.multiverse.core:multiverse-core:5.1.0") - //implementation files("libs/CustomItems.jar") + compileOnly(libs.multiverseCore) // Shaded implementation(slimjar()) // Dynamically Loaded - slim("com.dfsek:paralithic:0.8.1") - slim("io.papermc:paperlib:1.0.5") - slim("net.kyori:adventure-text-minimessage:4.17.0") - slim("net.kyori:adventure-platform-bukkit:4.3.4") - slim("net.kyori:adventure-api:4.17.0") - slim("org.bstats:bstats-bukkit:3.1.0") - slim("io.sentry:sentry:8.12.0") + slim(libs.paralithic) + slim(libs.paperlib) + slim(libs.adventure.api) + slim(libs.adventure.minimessage) + slim(libs.adventure.platform) + slim(libs.bstats) + slim(libs.sentry) - slim("commons-io:commons-io:2.13.0") - slim("commons-lang:commons-lang:2.6") - slim("com.github.oshi:oshi-core:6.6.5") - slim("org.lz4:lz4-java:1.8.0") - slim("it.unimi.dsi:fastutil:8.5.8") - slim("com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2") - slim("org.zeroturnaround:zt-zip:1.14") - slim("com.google.code.gson:gson:2.10.1") - slim("org.ow2.asm:asm:9.8") - slim("bsf:bsf:2.4.0") - slim("rhino:js:1.7R2") - slim("com.github.ben-manes.caffeine:caffeine:3.0.6") - slim("org.apache.commons:commons-lang3:3.12.0") - slim("net.bytebuddy:byte-buddy:1.17.5") - slim("net.bytebuddy:byte-buddy-agent:1.17.5") + slim(libs.commons.io) + slim(libs.commons.lang) + slim(libs.commons.lang3) + slim(libs.oshi) + slim(libs.lz4) + slim(libs.fastutil) + slim(libs.lru) + slim(libs.zip) + slim(libs.gson) + slim(libs.asm) + slim(libs.bsf) + slim(libs.rhino) + slim(libs.caffeine) + slim(libs.byteBuddy.core) + slim(libs.byteBuddy.agent) } java { @@ -113,11 +112,11 @@ slimJar { URI.create("https://repo.maven.apache.org/maven2/").toURL() )) - relocate("com.dfsek.paralithic", "$libs.paralithic") - relocate("io.papermc.lib", "$libs.paper") - relocate("net.kyori", "$libs.kyori") - relocate("org.bstats", "$libs.metrics") - relocate("io.sentry", "$libs.sentry") + relocate("com.dfsek.paralithic", "$lib.paralithic") + relocate("io.papermc.lib", "$lib.paper") + relocate("net.kyori", "$lib.kyori") + relocate("org.bstats", "$lib.metrics") + relocate("io.sentry", "$lib.sentry") } tasks { @@ -147,7 +146,7 @@ tasks { shadowJar { mergeServiceFiles() //minimize() - relocate("io.github.slimjar", "$libs.slimjar") + relocate("io.github.slimjar", "$lib.slimjar") } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 000000000..81d36c3ee --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,102 @@ +# Version catalog is a central place for you to declare and version dependencies +# https://docs.gradle.org/current/userguide/platforms.html#sub:version-catalog +# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format + +[versions] +# Plugins +shadow = "9.0.0-rc1" # https://plugins.gradle.org/plugin/com.gradleup.shadow +slimjar = "2.0.6" # 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 + +# Core Libraries +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 + +annotations = "26.0.2" # https://central.sonatype.com/artifact/org.jetbrains/annotations +paralithic = "0.8.1" # https://github.com/PolyhedralDev/Paralithic/ +paperlib = "1.0.8" # https://github.com/PaperMC/PaperLib/ +bstats = "3.1.0" # https://github.com/Bastian/bstats-metrics/tree/master +sentry = "8.14.0" # https://github.com/getsentry/sentry-java +commons-io = "2.19.0" # https://central.sonatype.com/artifact/commons-io/commons-io +commons-lang = "2.6" # https://central.sonatype.com/artifact/commons-lang/commons-lang +commons-lang3 = "3.17.0" # https://central.sonatype.com/artifact/org.apache.commons/commons-lang3 +oshi = "6.8.2" # https://central.sonatype.com/artifact/com.github.oshi/oshi-core +fastutil = "8.5.16" # https://central.sonatype.com/artifact/it.unimi.dsi/fastutil +lz4 = "1.8.0" # https://central.sonatype.com/artifact/org.lz4/lz4-java +lru = "1.4.2" # https://central.sonatype.com/artifact/com.googlecode.concurrentlinkedhashmap/concurrentlinkedhashmap-lru +zip = "1.17" # https://central.sonatype.com/artifact/org.zeroturnaround/zt-zip +gson = "2.13.1" # https://central.sonatype.com/artifact/com.google.code.gson/gson +asm = "9.8" # https://central.sonatype.com/artifact/org.ow2.asm/asm +bsf = "2.4.0" # https://central.sonatype.com/artifact/bsf/bsf +rhino = "1.7R2" # https://central.sonatype.com/artifact/rhino/js +caffeine = "3.2.1" # https://central.sonatype.com/artifact/com.github.ben-manes.caffeine/caffeine +byte-buddy = "1.17.6" # https://central.sonatype.com/artifact/net.bytebuddy/byte-buddy + +# Third Party Integrations +nexo = "1.8.0" # https://repo.nexomc.com/#/releases/com/nexomc/nexo +itemsadder = "4.0.10" # https://github.com/LoneDev6/API-ItemsAdder +placeholderApi = "2.11.6" # https://repo.extendedclip.com/#/releases/me/clip/placeholderapi +score = "5.25.3.9" # https://github.com/Ssomar-Developement/SCore +mmoitems = "6.9.5-SNAPSHOT" # https://nexus.phoenixdevt.fr/repository/maven-public/net/Indyuce/MMOItems-API/maven-metadata.xml +ecoitems = "5.63.1" # https://github.com/Auxilor/EcoItems/tags +mythic = "5.9.5" +mythic-chrucible = "2.1.0" +kgenerators = "7.3" # https://repo.codemc.io/repository/maven-public/me/kryniowesegryderiusz/kgenerators-core/maven-metadata.xml +multiverseCore = "5.1.0" + +[libraries] +# Core Libraries +lombok = { module = "org.projectlombok:lombok", version.ref ="lombok" } +spigot = { module = "org.spigotmc:spigot-api", version.ref = "spigot" } +log4j-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j" } +log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" } +annotations = { module = "org.jetbrains:annotations", version.ref = "annotations" } + +# Dynamically Loaded +adventure-api = { module = "net.kyori:adventure-api", version.ref = "adventure-api" } +adventure-minimessage = { module = "net.kyori:adventure-text-minimessage", version.ref = "adventure-api" } +adventure-platform = { module = "net.kyori:adventure-platform-bukkit", version.ref = "adventure-platform" } + +paralithic = { module = "com.dfsek:paralithic", version.ref = "paralithic" } +paperlib = { module = "io.papermc:paperlib", version.ref = "paperlib" } +bstats = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" } +sentry = { module = "io.sentry:sentry", version.ref = "sentry" } +commons-io = { module = "commons-io:commons-io", version.ref = "commons-io" } +commons-lang = { module = "commons-lang:commons-lang", version.ref = "commons-lang" } +commons-lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "commons-lang3" } +oshi = { module = "com.github.oshi:oshi-core", version.ref = "oshi" } +lz4 = { module = "org.lz4:lz4-java", version.ref = "lz4" } +fastutil = { module = "it.unimi.dsi:fastutil", version.ref = "fastutil" } +lru = { module = "com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru", version.ref = "lru" } +zip = { module = "org.zeroturnaround:zt-zip", version.ref = "zip" } +gson = { module = "com.google.code.gson:gson", version.ref = "gson" } +asm = { module = "org.ow2.asm:asm", version.ref = "asm" } +bsf = { module = "bsf:bsf", version.ref = "bsf" } +rhino = { module = "rhino:js", version.ref = "rhino" } +caffeine = { module = "com.github.ben-manes.caffeine:caffeine", version.ref = "caffeine" } +byteBuddy-core = { module = "net.bytebuddy:byte-buddy", version.ref = "byte-buddy" } +byteBuddy-agent = { module = "net.bytebuddy:byte-buddy-agent", version.ref = "byte-buddy" } + +# Third Party Integrations +nexo = { module = "com.nexomc:nexo", version.ref = "nexo" } +itemsadder = { module = "dev.lone:api-itemsadder", version.ref = "itemsadder" } +placeholderApi = { module = "me.clip:placeholderapi", version.ref = "placeholderApi" } +score = { module = "com.github.Ssomar-Developement:SCore", version.ref = "score" } +mmoitems = { module = "net.Indyuce:MMOItems-API", version.ref = "mmoitems" } +ecoitems = { module = "com.willfp:EcoItems", version.ref = "ecoitems" } +mythic = { module = "io.lumine:Mythic-Dist", version.ref = "mythic" } +mythicChrucible = { module = "io.lumine:MythicCrucible-Dist", version.ref = "mythic-chrucible" } +kgenerators = { module = "me.kryniowesegryderiusz:kgenerators-core", version.ref = "kgenerators" } +multiverseCore = { module = "org.mvplugins.multiverse.core:multiverse-core", version.ref = "multiverseCore" } + +[plugins] +shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } +slimjar = { id = "de.crazydev22.slimjar", version.ref = "slimjar" } +download = { id = "de.undercouch.download", version.ref = "download" } +runPaper = { id = "xyz.jpenilla.run-paper", version.ref = "runPaper" } +sentry = { id = "io.sentry.jvm.gradle", version.ref = "sentryPlugin" } From cc49b0f54086f613c9628d6ff842575854525f3b Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 9 Jul 2025 17:37:58 +0200 Subject: [PATCH 43/66] hopefully fix eta --- .../volmit/iris/core/pregenerator/IrisPregenerator.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java b/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java index dbd734a56..e90307dc9 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java @@ -153,12 +153,11 @@ public class IrisPregenerator { } private long computeETA() { - double d = (long) (totalChunks.get() > 1024 ? // Generated chunks exceed 1/8th of total? + double d = (long) (generated.get() > 1024 ? // Generated chunks exceed 1/8th of total? // If yes, use smooth function (which gets more accurate over time since its less sensitive to outliers) - ((totalChunks.get() - generated.get() - cached.get()) * ((double) (M.ms() - startTime.get()) / ((double) generated.get() - cached.get()))) : + ((totalChunks.get() - generated.get()) * ((double) (M.ms() - startTime.get()) / (double) generated.get())) : // If no, use quick function (which is less accurate over time but responds better to the initial delay) - ((totalChunks.get() - generated.get() - cached.get()) / chunksPerSecond.getAverage()) * 1000 - ); + ((totalChunks.get() - generated.get()) / chunksPerSecond.getAverage()) * 1000); return Double.isFinite(d) && d != INVALID ? (long) d : 0; } From 94c578249033e4758b8d1a6e04850d5a8a58850c Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 9 Jul 2025 18:49:55 +0200 Subject: [PATCH 44/66] move loading message to debug --- core/src/main/java/com/volmit/iris/Iris.java | 13 ++--- .../com/volmit/iris/core/IrisSettings.java | 2 + .../com/volmit/iris/util/misc/SlimJar.java | 58 +++++++++++++++++++ gradle/libs.versions.toml | 2 +- 4 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/util/misc/SlimJar.java diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 7b9c53f4c..be5854cf7 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -52,6 +52,7 @@ import com.volmit.iris.util.io.JarScanner; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.misc.Bindings; +import com.volmit.iris.util.misc.SlimJar; import com.volmit.iris.util.misc.getHardware; import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.plugin.IrisService; @@ -60,7 +61,6 @@ import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.Queue; import com.volmit.iris.util.scheduling.ShurikenQueue; -import io.github.slimjar.app.builder.ApplicationBuilder; import lombok.NonNull; import org.bukkit.*; import org.bukkit.block.data.BlockData; @@ -437,17 +437,12 @@ public class Iris extends VolmitPlugin implements Listener { } public Iris() { - ApplicationBuilder.appending("Iris") - .downloadDirectoryPath(getDataFolder("cache", "libraries").toPath()) - .logger((message, args) -> { - if (!message.startsWith("Loaded library ")) return; - getLogger().info(message.formatted(args)); - }) - .build(); + instance = this; + SlimJar.debug(IrisSettings.get().getSentry().isDebug()); + SlimJar.load(getDataFolder("cache", "libraries")); } private void enable() { - instance = this; services = new KMap<>(); setupAudience(); Bindings.setupSentry(); 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 30216b29e..faaecc8f0 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/core/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -23,6 +23,7 @@ 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; @@ -86,6 +87,7 @@ 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 new file mode 100644 index 000000000..fa79b849d --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/misc/SlimJar.java @@ -0,0 +1,58 @@ +package com.volmit.iris.util.misc; + +import io.github.slimjar.app.builder.ApplicationBuilder; +import io.github.slimjar.logging.ProcessLogger; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class SlimJar { + private static final Logger LOGGER = Logger.getLogger("Iris"); + private static final ReentrantLock lock = new ReentrantLock(); + private static final AtomicBoolean loaded = new AtomicBoolean(); + + public static void debug(boolean debug) { + LOGGER.setLevel(debug ? Level.FINE : Level.INFO); + } + + public static void load(@Nullable File localRepository) { + if (loaded.get()) return; + lock.lock(); + + try { + if (loaded.getAndSet(true)) return; + if (localRepository == null) { + localRepository = new File(".iris/libraries"); + } + + LOGGER.info("Loading libraries..."); + ApplicationBuilder.appending("Iris") + .downloadDirectoryPath(localRepository.toPath()) + .logger(new ProcessLogger() { + @Override + public void info(@NotNull String message, @Nullable Object... args) { + LOGGER.fine(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) { + LOGGER.fine(message.formatted(args)); + } + }) + .build(); + LOGGER.info("Libraries loaded successfully!"); + } finally { + lock.unlock(); + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 81d36c3ee..bdc075162 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.6" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar +slimjar = "2.0.7" # 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 343dc429d5159b7b840736bc1b636ee3398b698e Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 10 Jul 2025 19:20:46 +0200 Subject: [PATCH 45/66] fix null pointer when failing to load a dimension --- .../src/main/java/com/volmit/iris/core/ServerConfigurator.java | 3 +++ 1 file changed, 3 insertions(+) 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 ca8b242d2..d249bfbcd 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -44,6 +44,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerArray; import java.util.stream.Stream; @@ -140,6 +141,7 @@ public class ServerConfigurator { var loader = data.getDimensionLoader(); return loader.loadAll(loader.getPossibleKeys()) .stream() + .filter(Objects::nonNull) .map(ServerConfigurator::verifyDataPackInstalled) .toList() .contains(false); @@ -280,6 +282,7 @@ public class ServerConfigurator { var loader = data.getDimensionLoader(); return loader.loadAll(loader.getPossibleKeys()) .stream() + .filter(Objects::nonNull) .peek(this::merge); } From 64bb81626c3ce146021089e27ef713ca53b7b5e4 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 11 Jul 2025 12:54:16 +0200 Subject: [PATCH 46/66] update overworld pack --- build.gradle.kts | 2 +- core/src/main/java/com/volmit/iris/core/nms/INMS.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index fd1f9e400..4def2b348 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,7 +37,7 @@ plugins { } group = "com.volmit" -version = "3.6.11-1.20.1-1.21.5" +version = "3.6.11-1.20.1-1.21.7" apply() 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 848b08879..8b998147c 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 @@ -40,6 +40,7 @@ public class INMS { "1.21.7", "v1_21_R5" ); private static final List PACKS = List.of( + new Version(21, 5, "31100"), new Version(21, 4, "31020"), new Version(21, 2, "31000"), new Version(20, 1, "3910") From f6590c26e70e6e259ee3ad51993209b7a7bedf90 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 11 Jul 2025 13:07:20 +0200 Subject: [PATCH 47/66] fix download failing for dimensions with snippets --- .../volmit/iris/core/service/StudioSVC.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) 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 118a11e13..bf070d063 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 @@ -18,7 +18,6 @@ package com.volmit.iris.core.service; -import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; @@ -250,30 +249,25 @@ public class StudioSVC implements IrisService { return; } - File dimensions = new File(dir, "dimensions"); + IrisData data = IrisData.get(dir); + String[] dimensions = data.getDimensionLoader().getPossibleKeys(); - if (!(dimensions.exists() && dimensions.isDirectory())) { - sender.sendMessage("Invalid Format. Missing dimensions folder"); - return; - } - - if (dimensions.listFiles() == null) { + if (dimensions == null || dimensions.length == 0) { sender.sendMessage("No dimension file found in the extracted zip file."); sender.sendMessage("Check it is there on GitHub and report this to staff!"); - } else if (dimensions.listFiles().length != 1) { + } else if (dimensions.length != 1) { sender.sendMessage("Dimensions folder must have 1 file in it"); return; } - File dim = dimensions.listFiles()[0]; + IrisDimension d = data.getDimensionLoader().load(dimensions[0]); - if (!dim.isFile()) { + if (d == null) { sender.sendMessage("Invalid dimension (folder) in dimensions folder"); return; } - String key = dim.getName().split("\\Q.\\E")[0]; - IrisDimension d = new Gson().fromJson(IO.readAll(dim), IrisDimension.class); + String key = d.getLoadKey(); sender.sendMessage("Importing " + d.getName() + " (" + key + ")"); File packEntry = new File(packs, key); From a9891e819abce21747047cde2b3469442d24f6c5 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 12 Jul 2025 12:51:04 +0200 Subject: [PATCH 48/66] v+ --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4def2b348..462d697a2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,7 +37,7 @@ plugins { } group = "com.volmit" -version = "3.6.11-1.20.1-1.21.7" +version = "3.7.0-1.20.1-1.21.7" apply() From 9ade90d9cafe36ab41653cf4ebc6d14520bfd901 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 12 Jul 2025 15:51:49 +0200 Subject: [PATCH 49/66] make the mythic mobs link a data provider and make adding custom mob plugins easier --- core/src/main/java/com/volmit/iris/Iris.java | 3 - .../iris/core/link/ExternalDataProvider.java | 59 ++++++- .../volmit/iris/core/link/data/DataType.java | 33 ++++ .../link/{ => data}/EcoItemsDataProvider.java | 44 ++--- .../ExecutableItemsDataProvider.java | 45 ++---- .../{ => data}/HMCLeavesDataProvider.java | 48 ++---- .../{ => data}/ItemAdderDataProvider.java | 152 +++++++++--------- .../{ => data}/KGeneratorsDataProvider.java | 36 ++--- .../link/{ => data}/MMOItemsDataProvider.java | 70 ++++---- .../MythicCrucibleDataProvider.java | 76 ++------- .../MythicMobsDataProvider.java} | 91 +++++------ .../link/{ => data}/NexoDataProvider.java | 85 ++++------ .../iris/core/project/SchemaBuilder.java | 16 +- .../iris/core/service/ExternalDataSVC.java | 89 +++++----- .../volmit/iris/engine/object/IrisEntity.java | 15 +- .../java/com/volmit/iris/util/data/B.java | 5 +- .../com/volmit/iris/util/scheduling/J.java | 15 ++ 17 files changed, 401 insertions(+), 481 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/core/link/data/DataType.java rename core/src/main/java/com/volmit/iris/core/link/{ => data}/EcoItemsDataProvider.java (57%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/ExecutableItemsDataProvider.java (50%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/HMCLeavesDataProvider.java (81%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/ItemAdderDataProvider.java (59%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/KGeneratorsDataProvider.java (73%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/MMOItemsDataProvider.java (64%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/MythicCrucibleDataProvider.java (64%) rename core/src/main/java/com/volmit/iris/core/link/{MythicMobsLink.java => data/MythicMobsDataProvider.java} (54%) rename core/src/main/java/com/volmit/iris/core/link/{ => data}/NexoDataProvider.java (63%) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index be5854cf7..f299e4409 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -25,7 +25,6 @@ import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.link.IrisPapiExpansion; import com.volmit.iris.core.link.MultiverseCoreLink; -import com.volmit.iris.core.link.MythicMobsLink; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.v1X.NMSBinding1X; @@ -95,7 +94,6 @@ public class Iris extends VolmitPlugin implements Listener { public static Iris instance; public static Bindings.Adventure audiences; public static MultiverseCoreLink linkMultiverseCore; - public static MythicMobsLink linkMythicMobs; public static IrisCompat compat; public static FileWatcher configWatcher; private static VolmitSender sender; @@ -454,7 +452,6 @@ public class Iris extends VolmitPlugin implements Listener { getSender().setTag(getTag()); IrisSafeguard.splash(true); linkMultiverseCore = new MultiverseCoreLink(); - linkMythicMobs = new MythicMobsLink(); configWatcher = new FileWatcher(getDataFile("settings.json")); services.values().forEach(IrisService::onEnable); services.values().forEach(this::registerListener); diff --git a/core/src/main/java/com/volmit/iris/core/link/ExternalDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/ExternalDataProvider.java index 02bf058a8..bbc7e8088 100644 --- a/core/src/main/java/com/volmit/iris/core/link/ExternalDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/ExternalDataProvider.java @@ -1,24 +1,33 @@ package com.volmit.iris.core.link; +import com.volmit.iris.core.link.data.DataType; +import com.volmit.iris.core.nms.container.Pair; +import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.data.IrisCustomData; +import com.volmit.iris.util.math.RNG; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; +import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collection; import java.util.MissingResourceException; @Getter @RequiredArgsConstructor -public abstract class ExternalDataProvider { +public abstract class ExternalDataProvider implements Listener { @NonNull private final String pluginId; @@ -53,7 +62,9 @@ public abstract class ExternalDataProvider { * @throws MissingResourceException when the blockId is invalid */ @NotNull - public abstract BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException; + public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException { + throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); + } /** * @see ExternalDataProvider#getItemStack(Identifier) @@ -73,7 +84,9 @@ public abstract class ExternalDataProvider { * @throws MissingResourceException when the itemId is invalid */ @NotNull - public abstract ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap customNbt) throws MissingResourceException; + public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap customNbt) throws MissingResourceException { + throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); + } /** * This method is used for placing blocks that need to use the plugins api @@ -85,9 +98,43 @@ public abstract class ExternalDataProvider { */ public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {} - public abstract @NotNull Identifier[] getBlockTypes(); + /** + * Spawns a mob in the specified location using the given engine and entity identifier. + * + * @param location The location in the world where the mob should spawn. Must not be null. + * @param entityId The identifier of the mob entity to spawn. Must not be null. + * @return The spawned {@link Entity} if successful, or null if the mob could not be spawned. + */ + @Nullable + public Entity spawnMob(@NotNull Location location, @NotNull Identifier entityId) throws MissingResourceException { + throw new MissingResourceException("Failed to find Entity!", entityId.namespace(), entityId.key()); + } - public abstract @NotNull Identifier[] getItemTypes(); + public abstract @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType); - public abstract boolean isValidProvider(@NotNull Identifier id, boolean isItem); + public abstract boolean isValidProvider(@NotNull Identifier id, DataType dataType); + + protected static Pair parseYawAndFace(@NotNull Engine engine, @NotNull Block block, @NotNull KMap<@NotNull String, @NotNull String> state) { + float yaw = 0; + BlockFace face = BlockFace.NORTH; + + long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY(); + RNG rng = new RNG(seed); + if ("true".equals(state.get("randomYaw"))) { + yaw = rng.f(0, 360); + } else if (state.containsKey("yaw")) { + yaw = Float.parseFloat(state.get("yaw")); + } + if ("true".equals(state.get("randomFace"))) { + BlockFace[] faces = BlockFace.values(); + face = faces[rng.i(0, faces.length - 1)]; + } else if (state.containsKey("face")) { + face = BlockFace.valueOf(state.get("face").toUpperCase()); + } + if (face == BlockFace.SELF) { + face = BlockFace.NORTH; + } + + return new Pair<>(yaw, face); + } } diff --git a/core/src/main/java/com/volmit/iris/core/link/data/DataType.java b/core/src/main/java/com/volmit/iris/core/link/data/DataType.java new file mode 100644 index 000000000..65edfc2a3 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/link/data/DataType.java @@ -0,0 +1,33 @@ +package com.volmit.iris.core.link.data; + +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; + +import java.util.MissingResourceException; +import java.util.function.BiPredicate; +import java.util.function.Predicate; + +public enum DataType implements BiPredicate { + ITEM, + BLOCK, + ENTITY; + + @Override + public boolean test(ExternalDataProvider dataProvider, Identifier identifier) { + if (!dataProvider.isValidProvider(identifier, this)) return false; + try { + switch (this) { + case ITEM -> dataProvider.getItemStack(identifier); + case BLOCK -> dataProvider.getBlockData(identifier); + case ENTITY -> {} + } + return true; + } catch (MissingResourceException e) { + return false; + } + } + + public Predicate asPredicate(ExternalDataProvider dataProvider) { + return i -> test(dataProvider, i); + } +} diff --git a/core/src/main/java/com/volmit/iris/core/link/EcoItemsDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/EcoItemsDataProvider.java similarity index 57% rename from core/src/main/java/com/volmit/iris/core/link/EcoItemsDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/EcoItemsDataProvider.java index 81eb9669a..05e9cd221 100644 --- a/core/src/main/java/com/volmit/iris/core/link/EcoItemsDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/EcoItemsDataProvider.java @@ -1,16 +1,18 @@ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; import com.volmit.iris.Iris; -import com.volmit.iris.util.collection.KList; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.util.collection.KMap; 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 org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.List; import java.util.MissingResourceException; public class EcoItemsDataProvider extends ExternalDataProvider { @@ -34,12 +36,6 @@ public class EcoItemsDataProvider extends ExternalDataProvider { } } - @NotNull - @Override - public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException { - throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); - } - @NotNull @Override public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap customNbt) throws MissingResourceException { @@ -48,30 +44,18 @@ public class EcoItemsDataProvider extends ExternalDataProvider { return itemStack.get(item).clone(); } - @NotNull @Override - public Identifier[] getBlockTypes() { - return new Identifier[0]; - } - - @NotNull - @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]); + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + if (dataType != DataType.ITEM) return List.of(); + return EcoItems.INSTANCE.values() + .stream() + .map(x -> Identifier.fromNamespacedKey(id.get(x))) + .filter(dataType.asPredicate(this)) + .toList(); } @Override - public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { - return id.namespace().equalsIgnoreCase("ecoitems") && isItem; + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + return id.namespace().equalsIgnoreCase("ecoitems") && dataType == DataType.ITEM; } } diff --git a/core/src/main/java/com/volmit/iris/core/link/ExecutableItemsDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/ExecutableItemsDataProvider.java similarity index 50% rename from core/src/main/java/com/volmit/iris/core/link/ExecutableItemsDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/ExecutableItemsDataProvider.java index 80fc25860..88a2dc943 100644 --- a/core/src/main/java/com/volmit/iris/core/link/ExecutableItemsDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/ExecutableItemsDataProvider.java @@ -1,13 +1,15 @@ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; import com.ssomar.score.api.executableitems.ExecutableItemsAPI; import com.volmit.iris.Iris; -import com.volmit.iris.util.collection.KList; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.util.collection.KMap; -import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.List; import java.util.MissingResourceException; import java.util.Optional; @@ -21,12 +23,6 @@ public class ExecutableItemsDataProvider extends ExternalDataProvider { Iris.info("Setting up ExecutableItems Link..."); } - @NotNull - @Override - public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException { - throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); - } - @NotNull @Override public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap customNbt) throws MissingResourceException { @@ -35,30 +31,19 @@ public class ExecutableItemsDataProvider extends ExternalDataProvider { .orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key())); } - @NotNull @Override - public Identifier[] getBlockTypes() { - return new Identifier[0]; - } - - @NotNull - @Override - public Identifier[] getItemTypes() { - KList names = new KList<>(); - for (String name : ExecutableItemsAPI.getExecutableItemsManager().getExecutableItemIdsList()) { - try { - Identifier key = new Identifier("executable_items", name); - if (getItemStack(key) != null) - names.add(key); - } catch (MissingResourceException ignored) { - } - } - - return names.toArray(new Identifier[0]); + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + if (dataType != DataType.ITEM) return List.of(); + return ExecutableItemsAPI.getExecutableItemsManager() + .getExecutableItemIdsList() + .stream() + .map(name -> new Identifier("executable_items", name)) + .filter(dataType.asPredicate(this)) + .toList(); } @Override - public boolean isValidProvider(@NotNull Identifier key, boolean isItem) { - return key.namespace().equalsIgnoreCase("executable_items") && isItem; + public boolean isValidProvider(@NotNull Identifier key, DataType dataType) { + return key.namespace().equalsIgnoreCase("executable_items") && dataType == DataType.ITEM; } } diff --git a/core/src/main/java/com/volmit/iris/core/link/HMCLeavesDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/HMCLeavesDataProvider.java similarity index 81% rename from core/src/main/java/com/volmit/iris/core/link/HMCLeavesDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/HMCLeavesDataProvider.java index 5f5a358fd..bbf2cd197 100644 --- a/core/src/main/java/com/volmit/iris/core/link/HMCLeavesDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/HMCLeavesDataProvider.java @@ -1,10 +1,11 @@ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.service.ExternalDataSVC; 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.data.IrisCustomData; import com.volmit.iris.util.reflect.WrappedField; @@ -18,6 +19,8 @@ import org.bukkit.block.data.type.Leaves; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.MissingResourceException; import java.util.function.Supplier; @@ -89,41 +92,20 @@ public class HMCLeavesDataProvider extends ExternalDataProvider { } } - @NotNull @Override - public Identifier[] getBlockTypes() { - KList names = new KList<>(); - for (String name : blockDataMap.keySet()) { - try { - Identifier key = new Identifier("hmcleaves", name); - if (getBlockData(key) != null) - names.add(key); - } catch (MissingResourceException ignored) { - } - } - - return names.toArray(new Identifier[0]); - } - - @NotNull - @Override - public Identifier[] getItemTypes() { - KList names = new KList<>(); - for (String name : itemDataField.keySet()) { - try { - Identifier key = new Identifier("hmcleaves", name); - if (getItemStack(key) != null) - names.add(key); - } catch (MissingResourceException ignored) { - } - } - - return names.toArray(new Identifier[0]); + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + if (dataType == DataType.ENTITY) return List.of(); + return (dataType == DataType.BLOCK ? blockDataMap.keySet() : itemDataField.keySet()) + .stream() + .map(x -> new Identifier("hmcleaves", x)) + .filter(dataType.asPredicate(this)) + .toList(); } @Override - public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { - return (isItem ? itemDataField.keySet() : blockDataMap.keySet()).contains(id.key()); + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + if (dataType == DataType.ENTITY) return false; + return (dataType == DataType.ITEM ? itemDataField.keySet() : blockDataMap.keySet()).contains(id.key()); } private Map getMap(C config, String name) { diff --git a/core/src/main/java/com/volmit/iris/core/link/ItemAdderDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java similarity index 59% rename from core/src/main/java/com/volmit/iris/core/link/ItemAdderDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java index d7e891da0..c0bf27ef4 100644 --- a/core/src/main/java/com/volmit/iris/core/link/ItemAdderDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java @@ -1,76 +1,76 @@ -package com.volmit.iris.core.link; - -import com.volmit.iris.Iris; -import com.volmit.iris.util.collection.KList; -import com.volmit.iris.util.collection.KMap; -import dev.lone.itemsadder.api.CustomBlock; -import dev.lone.itemsadder.api.CustomStack; -import org.bukkit.block.data.BlockData; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; - -import java.util.MissingResourceException; - -public class ItemAdderDataProvider extends ExternalDataProvider { - - private KList itemNamespaces, blockNamespaces; - - public ItemAdderDataProvider() { - super("ItemsAdder"); - } - - @Override - public void init() { - this.itemNamespaces = new KList<>(); - this.blockNamespaces = new KList<>(); - - for (Identifier i : getItemTypes()) { - itemNamespaces.addIfMissing(i.namespace()); - } - for (Identifier i : getBlockTypes()) { - blockNamespaces.addIfMissing(i.namespace()); - Iris.info("Found ItemAdder Block: " + i); - } - } - - @NotNull - @Override - public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException { - return CustomBlock.getBaseBlockData(blockId.toString()); - } - - @NotNull - @Override - public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap customNbt) throws MissingResourceException { - CustomStack stack = CustomStack.getInstance(itemId.toString()); - if (stack == null) { - throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); - } - return stack.getItemStack(); - } - - @NotNull - @Override - public Identifier[] getBlockTypes() { - KList keys = new KList<>(); - for (String s : CustomBlock.getNamespacedIdsInRegistry()) { - keys.add(Identifier.fromString(s)); - } - return keys.toArray(new Identifier[0]); - } - - @NotNull - @Override - public Identifier[] getItemTypes() { - KList keys = new KList<>(); - for (String s : CustomStack.getNamespacedIdsInRegistry()) { - keys.add(Identifier.fromString(s)); - } - return keys.toArray(new Identifier[0]); - } - - @Override - public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { - return isItem ? this.itemNamespaces.contains(id.namespace()) : this.blockNamespaces.contains(id.namespace()); - } -} +package com.volmit.iris.core.link.data; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import dev.lone.itemsadder.api.CustomBlock; +import dev.lone.itemsadder.api.CustomStack; +import org.bukkit.block.data.BlockData; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.List; +import java.util.MissingResourceException; + +public class ItemAdderDataProvider extends ExternalDataProvider { + + private KList itemNamespaces, blockNamespaces; + + public ItemAdderDataProvider() { + super("ItemsAdder"); + } + + @Override + public void init() { + this.itemNamespaces = new KList<>(); + this.blockNamespaces = new KList<>(); + + for (Identifier i : getTypes(DataType.ITEM)) { + itemNamespaces.addIfMissing(i.namespace()); + } + for (Identifier i : getTypes(DataType.BLOCK)) { + blockNamespaces.addIfMissing(i.namespace()); + Iris.info("Found ItemAdder Block: " + i); + } + } + + @NotNull + @Override + public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException { + return CustomBlock.getBaseBlockData(blockId.toString()); + } + + @NotNull + @Override + public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap customNbt) throws MissingResourceException { + CustomStack stack = CustomStack.getInstance(itemId.toString()); + if (stack == null) { + throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); + } + return stack.getItemStack(); + } + + @Override + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + return switch (dataType) { + case ENTITY -> List.of(); + case ITEM -> CustomStack.getNamespacedIdsInRegistry() + .stream() + .map(Identifier::fromString) + .toList(); + case BLOCK -> CustomBlock.getNamespacedIdsInRegistry() + .stream() + .map(Identifier::fromString) + .toList(); + }; + } + + @Override + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + if (dataType == DataType.ENTITY) return false; + return dataType == DataType.ITEM ? this.itemNamespaces.contains(id.namespace()) : this.blockNamespaces.contains(id.namespace()); + } +} diff --git a/core/src/main/java/com/volmit/iris/core/link/KGeneratorsDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/KGeneratorsDataProvider.java similarity index 73% rename from core/src/main/java/com/volmit/iris/core/link/KGeneratorsDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/KGeneratorsDataProvider.java index 618fe4ccc..ea4f6e4ef 100644 --- a/core/src/main/java/com/volmit/iris/core/link/KGeneratorsDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/KGeneratorsDataProvider.java @@ -1,5 +1,7 @@ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KMap; @@ -14,6 +16,8 @@ import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.List; import java.util.MissingResourceException; public class KGeneratorsDataProvider extends ExternalDataProvider { @@ -54,35 +58,17 @@ public class KGeneratorsDataProvider extends ExternalDataProvider { } @Override - public @NotNull Identifier[] getBlockTypes() { + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + if (dataType == DataType.ENTITY) return List.of(); return Main.getGenerators().getAll().stream() .map(gen -> new Identifier("kgenerators", gen.getId())) - .filter(i -> { - try { - return getBlockData(i) != null; - } catch (MissingResourceException e) { - return false; - } - }) - .toArray(Identifier[]::new); + .filter(dataType.asPredicate(this)) + .toList(); } @Override - public @NotNull Identifier[] getItemTypes() { - return Main.getGenerators().getAll().stream() - .map(gen -> new Identifier("kgenerators", gen.getId())) - .filter(i -> { - try { - return getItemStack(i) != null; - } catch (MissingResourceException e) { - return false; - } - }) - .toArray(Identifier[]::new); - } - - @Override - public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + if (dataType == DataType.ENTITY) return false; return "kgenerators".equalsIgnoreCase(id.namespace()); } } diff --git a/core/src/main/java/com/volmit/iris/core/link/MMOItemsDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/MMOItemsDataProvider.java similarity index 64% rename from core/src/main/java/com/volmit/iris/core/link/MMOItemsDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/MMOItemsDataProvider.java index 251665a54..0bf3fc490 100644 --- a/core/src/main/java/com/volmit/iris/core/link/MMOItemsDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/MMOItemsDataProvider.java @@ -1,21 +1,24 @@ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; import com.volmit.iris.Iris; -import com.volmit.iris.util.collection.KList; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.scheduling.J; import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.ItemTier; -import net.Indyuce.mmoitems.api.Type; import net.Indyuce.mmoitems.api.block.CustomBlock; import org.bukkit.Bukkit; import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.List; import java.util.MissingResourceException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; public class MMOItemsDataProvider extends ExternalDataProvider { @@ -85,52 +88,35 @@ public class MMOItemsDataProvider extends ExternalDataProvider { return item; } - @NotNull @Override - public Identifier[] getBlockTypes() { - KList names = new KList<>(); - for (Integer id : api().getCustomBlocks().getBlockIds()) { - try { - Identifier key = new Identifier("mmoitems", String.valueOf(id)); - if (getBlockData(key) != null) - names.add(key); - } catch (MissingResourceException ignored) { - } - } - return names.toArray(new Identifier[0]); - } + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + return switch (dataType) { + case ENTITY -> List.of(); + case BLOCK -> api().getCustomBlocks().getBlockIds().stream().map(id -> new Identifier("mmoitems", String.valueOf(id))) + .filter(dataType.asPredicate(this)) + .toList(); + case ITEM -> { + Supplier> supplier = () -> api().getTypes() + .getAll() + .stream() + .flatMap(type -> api() + .getTemplates() + .getTemplateNames(type) + .stream() + .map(name -> new Identifier("mmoitems_" + type.getId(), name))) + .filter(dataType.asPredicate(this)) + .toList(); - @NotNull - @Override - public Identifier[] getItemTypes() { - KList names = new KList<>(); - Runnable run = () -> { - for (Type type : api().getTypes().getAll()) { - for (String name : api().getTemplates().getTemplateNames(type)) { - try { - Identifier key = new Identifier("mmoitems_" + type.getId(), name); - if (getItemStack(key) != null) - names.add(key); - } catch (MissingResourceException ignored) { - } - } + if (Bukkit.isPrimaryThread()) yield supplier.get(); + else yield J.sfut(supplier).join(); } }; - if (Bukkit.isPrimaryThread()) run.run(); - else { - try { - J.sfut(run).get(); - } catch (InterruptedException | ExecutionException e) { - Iris.error("Failed getting MMOItems item types!"); - Iris.reportError(e); - } - } - return names.toArray(new Identifier[0]); } @Override - public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { - return isItem ? id.namespace().split("_", 2).length == 2 : id.namespace().equals("mmoitems"); + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + if (dataType == DataType.ENTITY) return false; + return dataType == DataType.ITEM ? id.namespace().split("_", 2).length == 2 : id.namespace().equals("mmoitems"); } private MMOItems api() { diff --git a/core/src/main/java/com/volmit/iris/core/link/MythicCrucibleDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/MythicCrucibleDataProvider.java similarity index 64% rename from core/src/main/java/com/volmit/iris/core/link/MythicCrucibleDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/MythicCrucibleDataProvider.java index d62462c38..4194f0c16 100644 --- a/core/src/main/java/com/volmit/iris/core/link/MythicCrucibleDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/MythicCrucibleDataProvider.java @@ -16,19 +16,18 @@ * along with this program. If not, see . */ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; import com.volmit.iris.Iris; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.service.ExternalDataSVC; -import com.volmit.iris.engine.data.cache.Cache; 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.data.B; import com.volmit.iris.util.data.IrisCustomData; -import com.volmit.iris.util.math.RNG; import io.lumine.mythic.bukkit.BukkitAdapter; import io.lumine.mythic.bukkit.utils.serialize.Chroma; import io.lumine.mythiccrucible.MythicCrucible; @@ -37,11 +36,11 @@ import io.lumine.mythiccrucible.items.ItemManager; import io.lumine.mythiccrucible.items.blocks.CustomBlockItemContext; import io.lumine.mythiccrucible.items.furniture.FurnitureItemContext; import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Collection; import java.util.MissingResourceException; import java.util.Optional; @@ -88,69 +87,27 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider { .generateItemStack(1)); } - @NotNull @Override - public Identifier[] getBlockTypes() { - KList names = new KList<>(); - for (CrucibleItem item : this.itemManager.getItems()) { - if (item.getBlockData() == null) continue; - try { - Identifier key = new Identifier("crucible", item.getInternalName()); - if (getBlockData(key) != null) { - Iris.info("getBlockTypes: Block loaded '" + item.getInternalName() + "'"); - names.add(key); - } - } catch (MissingResourceException ignored) {} - } - return names.toArray(new Identifier[0]); - } - - @NotNull - @Override - public Identifier[] getItemTypes() { - KList names = new KList<>(); - for (CrucibleItem item : this.itemManager.getItems()) { - try { - Identifier key = new Identifier("crucible", item.getInternalName()); - if (getItemStack(key) != null) { - Iris.info("getItemTypes: Item loaded '" + item.getInternalName() + "'"); - names.add(key); - } - } catch (MissingResourceException ignored) {} - } - return names.toArray(new Identifier[0]); + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + return itemManager.getItems() + .stream() + .map(i -> new Identifier("crucible", i.getInternalName())) + .filter(dataType.asPredicate(this)) + .toList(); } @Override public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) { - var pair = ExternalDataSVC.parseState(blockId); - var state = pair.getB(); - blockId = pair.getA(); + var parsedState = ExternalDataSVC.parseState(blockId); + var state = parsedState.getB(); + blockId = parsedState.getA(); Optional item = itemManager.getItem(blockId.key()); if (item.isEmpty()) return; FurnitureItemContext furniture = item.get().getFurnitureData(); if (furniture == null) return; - float yaw = 0; - BlockFace face = BlockFace.NORTH; - long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY(); - RNG rng = new RNG(seed); - if ("true".equals(state.get("randomYaw"))) { - yaw = rng.f(0, 360); - } else if (state.containsKey("yaw")) { - yaw = Float.parseFloat(state.get("yaw")); - } - if ("true".equals(state.get("randomFace"))) { - BlockFace[] faces = BlockFace.values(); - face = faces[rng.i(0, faces.length - 1)]; - } else if (state.containsKey("face")) { - face = BlockFace.valueOf(state.get("face").toUpperCase()); - } - if (face == BlockFace.SELF) { - face = BlockFace.NORTH; - } - + var pair = parseYawAndFace(engine, block, state); BiomeColor type = null; Chroma color = null; try { @@ -161,11 +118,12 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider { if (biomeColor == null) return; color = Chroma.of(biomeColor.getRGB()); } - furniture.place(block, face, yaw, color); + furniture.place(block, pair.getB(), pair.getA(), color); } @Override - public boolean isValidProvider(@NotNull Identifier key, boolean isItem) { + public boolean isValidProvider(@NotNull Identifier key, DataType dataType) { + if (dataType == DataType.ENTITY) return false; return key.namespace().equalsIgnoreCase("crucible"); } } diff --git a/core/src/main/java/com/volmit/iris/core/link/MythicMobsLink.java b/core/src/main/java/com/volmit/iris/core/link/data/MythicMobsDataProvider.java similarity index 54% rename from core/src/main/java/com/volmit/iris/core/link/MythicMobsLink.java rename to core/src/main/java/com/volmit/iris/core/link/data/MythicMobsDataProvider.java index 052952346..7c08b8e6a 100644 --- a/core/src/main/java/com/volmit/iris/core/link/MythicMobsLink.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/MythicMobsDataProvider.java @@ -1,25 +1,7 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +package com.volmit.iris.core.link.data; -package com.volmit.iris.core.link; - -import com.google.common.collect.Sets; -import com.volmit.iris.Iris; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.tools.IrisToolbelt; import io.lumine.mythic.api.adapters.AbstractLocation; import io.lumine.mythic.api.config.MythicLineConfig; @@ -30,60 +12,59 @@ import io.lumine.mythic.bukkit.events.MythicConditionLoadEvent; import io.lumine.mythic.core.skills.SkillCondition; import io.lumine.mythic.core.utils.annotations.MythicCondition; import io.lumine.mythic.core.utils.annotations.MythicField; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; -public class MythicMobsLink { - - public MythicMobsLink() { - if (getPlugin() == null) return; - Iris.instance.registerListener(new ConditionListener()); +public class MythicMobsDataProvider extends ExternalDataProvider { + public MythicMobsDataProvider() { + super("MythicMobs"); } - public boolean isEnabled() { - return getPlugin() != null; + @Override + public void init() { } - public Plugin getPlugin() { - return Bukkit.getPluginManager().getPlugin("MythicMobs"); + @Override + public @Nullable Entity spawnMob(@NotNull Location location, @NotNull Identifier entityId) throws MissingResourceException { + var mm = MythicBukkit.inst().getMobManager().spawnMob(entityId.key(), location); + if (mm == null) throw new MissingResourceException("Failed to find mob!", entityId.namespace(), entityId.key()); + return mm.getEntity().getBukkitEntity(); } - /** - * Spawn a mythic mob at this location - * - * @param mob The mob - * @param location The location - * @return The mob, or null if it can't be spawned - */ - public @Nullable Entity spawnMob(String mob, Location location) { - return isEnabled() ? MythicBukkit.inst().getMobManager().spawnMob(mob, location).getEntity().getBukkitEntity() : null; + @Override + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + if (dataType != DataType.ENTITY) return List.of(); + return MythicBukkit.inst() + .getMobManager() + .getMobNames() + .stream() + .map(name -> new Identifier("mythicmobs", name)) + .toList(); } - public Collection getMythicMobTypes() { - return isEnabled() ? MythicBukkit.inst().getMobManager().getMobNames() : List.of(); + @Override + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + return id.namespace().equalsIgnoreCase("mythicmobs") && dataType == DataType.ENTITY; } - private static class ConditionListener implements Listener { - @EventHandler - public void on(MythicConditionLoadEvent event) { - switch (event.getConditionName()) { - case "irisbiome" -> event.register(new IrisBiomeCondition(event.getConditionName(), event.getConfig())); - case "irisregion" -> event.register(new IrisRegionCondition(event.getConditionName(), event.getConfig())); - } + @EventHandler + public void on(MythicConditionLoadEvent event) { + switch (event.getConditionName()) { + case "irisbiome" -> event.register(new IrisBiomeCondition(event.getConditionName(), event.getConfig())); + case "irisregion" -> event.register(new IrisRegionCondition(event.getConditionName(), event.getConfig())); } } @MythicCondition(author = "CrazyDev22", name = "irisbiome", description = "Tests if the target is within the given list of biomes") public static class IrisBiomeCondition extends SkillCondition implements ILocationCondition { @MythicField(name = "biome", aliases = {"b"}, description = "A list of biomes to check") - private Set biomes = Sets.newConcurrentHashSet(); + private Set biomes = ConcurrentHashMap.newKeySet(); @MythicField(name = "surface", aliases = {"s"}, description = "If the biome check should only be performed on the surface") private boolean surface; @@ -107,10 +88,10 @@ public class MythicMobsLink { } } - @MythicCondition(author = "CrazyDev22", name = "irisbiome", description = "Tests if the target is within the given list of biomes") + @MythicCondition(author = "CrazyDev22", name = "irisregion", description = "Tests if the target is within the given list of biomes") public static class IrisRegionCondition extends SkillCondition implements ILocationCondition { @MythicField(name = "region", aliases = {"r"}, description = "A list of regions to check") - private Set regions = Sets.newConcurrentHashSet(); + private Set regions = ConcurrentHashMap.newKeySet(); public IrisRegionCondition(String line, MythicLineConfig mlc) { super(line); diff --git a/core/src/main/java/com/volmit/iris/core/link/NexoDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/NexoDataProvider.java similarity index 63% rename from core/src/main/java/com/volmit/iris/core/link/NexoDataProvider.java rename to core/src/main/java/com/volmit/iris/core/link/data/NexoDataProvider.java index 066fb448b..998fbf06f 100644 --- a/core/src/main/java/com/volmit/iris/core/link/NexoDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/NexoDataProvider.java @@ -1,28 +1,30 @@ -package com.volmit.iris.core.link; +package com.volmit.iris.core.link.data; import com.nexomc.nexo.api.NexoBlocks; import com.nexomc.nexo.api.NexoFurniture; import com.nexomc.nexo.api.NexoItems; import com.nexomc.nexo.items.ItemBuilder; +import com.volmit.iris.core.link.ExternalDataProvider; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.service.ExternalDataSVC; -import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.IrisCustomData; -import com.volmit.iris.util.math.RNG; import org.bukkit.Color; import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import org.bukkit.entity.ItemDisplay; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.bukkit.inventory.meta.MapMeta; import org.bukkit.inventory.meta.PotionMeta; import org.jetbrains.annotations.NotNull; -import java.util.Arrays; +import java.util.Collection; +import java.util.List; import java.util.MissingResourceException; import java.util.concurrent.atomic.AtomicBoolean; @@ -69,9 +71,9 @@ public class NexoDataProvider extends ExternalDataProvider { @Override public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) { - var pair = ExternalDataSVC.parseState(blockId); - var state = pair.getB(); - blockId = pair.getA(); + var statePair = ExternalDataSVC.parseState(blockId); + var state = statePair.getB(); + blockId = statePair.getA(); if (NexoBlocks.isCustomBlock(blockId.key())) { NexoBlocks.place(blockId.key(), block.getLocation()); @@ -81,26 +83,8 @@ public class NexoDataProvider extends ExternalDataProvider { if (!NexoFurniture.isFurniture(blockId.key())) return; - float yaw = 0; - BlockFace face = BlockFace.NORTH; - - long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY(); - RNG rng = new RNG(seed); - if ("true".equals(state.get("randomYaw"))) { - yaw = rng.f(0, 360); - } else if (state.containsKey("yaw")) { - yaw = Float.parseFloat(state.get("yaw")); - } - if ("true".equals(state.get("randomFace"))) { - BlockFace[] faces = BlockFace.values(); - face = faces[rng.i(0, faces.length - 1)]; - } else if (state.containsKey("face")) { - face = BlockFace.valueOf(state.get("face").toUpperCase()); - } - if (face == BlockFace.SELF) { - face = BlockFace.NORTH; - } - ItemDisplay display = NexoFurniture.place(blockId.key(), block.getLocation(), yaw, face); + var pair = parseYawAndFace(engine, block, state); + ItemDisplay display = NexoFurniture.place(blockId.key(), block.getLocation(), pair.getA(), pair.getB()); if (display == null) return; ItemStack itemStack = display.getItemStack(); if (itemStack == null) return; @@ -114,46 +98,31 @@ public class NexoDataProvider extends ExternalDataProvider { var biomeColor = INMS.get().getBiomeColor(block.getLocation(), type); if (biomeColor == null) return; var potionColor = Color.fromARGB(biomeColor.getAlpha(), biomeColor.getRed(), biomeColor.getGreen(), biomeColor.getBlue()); - if (itemStack.getItemMeta() instanceof PotionMeta meta) { - meta.setColor(potionColor); - itemStack.setItemMeta(meta); + var meta = itemStack.getItemMeta(); + switch (meta) { + case LeatherArmorMeta armor -> armor.setColor(potionColor); + case PotionMeta potion -> potion.setColor(potionColor); + case MapMeta map -> map.setColor(potionColor); + case null, default -> {} } + itemStack.setItemMeta(meta); } display.setItemStack(itemStack); } - @NotNull @Override - public Identifier[] getBlockTypes() { - return NexoItems.itemNames().stream() + public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { + if (dataType == DataType.ENTITY) return List.of(); + return NexoItems.itemNames() + .stream() .map(i -> new Identifier("nexo", i)) - .filter(i -> { - try { - return getBlockData(i) != null; - } catch (MissingResourceException e) { - return false; - } - }) - .toArray(Identifier[]::new); - } - - @NotNull - @Override - public Identifier[] getItemTypes() { - return NexoItems.itemNames().stream() - .map(i -> new Identifier("nexo", i)) - .filter(i -> { - try { - return getItemStack(i) != null; - } catch (MissingResourceException e) { - return false; - } - }) - .toArray(Identifier[]::new); + .filter(dataType.asPredicate(this)) + .toList(); } @Override - public boolean isValidProvider(@NotNull Identifier id, boolean isItem) { + public boolean isValidProvider(@NotNull Identifier id, DataType dataType) { + if (dataType == DataType.ENTITY) return false; return "nexo".equalsIgnoreCase(id.namespace()); } 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 d856d2b8e..50ff64886 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 @@ -19,9 +19,12 @@ package com.volmit.iris.core.project; import com.volmit.iris.Iris; +import com.volmit.iris.core.link.Identifier; +import com.volmit.iris.core.link.data.DataType; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.loader.ResourceLoader; +import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; @@ -39,7 +42,6 @@ import java.lang.reflect.Modifier; import java.util.List; import java.util.Map; import java.util.function.Function; -import java.util.stream.Collectors; public class SchemaBuilder { private static final String SYMBOL_LIMIT__N = "*"; @@ -266,16 +268,18 @@ public class SchemaBuilder { if (!definitions.containsKey(key)) { JSONObject j = new JSONObject(); - KList list = new KList<>(); - list.addAll(Iris.linkMythicMobs.getMythicMobTypes().stream().map(s -> "MythicMobs:" + s).collect(Collectors.toList())); - //TODO add Citizens stuff here too + KList list = Iris.service(ExternalDataSVC.class) + .getAllIdentifiers(DataType.ENTITY) + .stream() + .map(Identifier::toString) + .collect(KList.collector()); j.put("enum", list.toJSONStringArray()); definitions.put(key, j); } - fancyType = "Mythic Mob Type"; + fancyType = "Custom Mob Type"; prop.put("$ref", "#/definitions/" + key); - description.add(SYMBOL_TYPE__N + " Must be a valid Mythic Mob Type (use ctrl+space for auto complete!) Define mythic mobs with the mythic mobs plugin configuration files."); + description.add(SYMBOL_TYPE__N + " Must be a valid Custom Mob Type (use ctrl+space for auto complete!)"); } else if (k.isAnnotationPresent(RegistryListFont.class)) { String key = "enum-font"; 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 4d9596278..69fec1912 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 @@ -20,16 +20,21 @@ package com.volmit.iris.core.service; import com.volmit.iris.Iris; import com.volmit.iris.core.link.*; +import com.volmit.iris.core.link.data.DataType; import com.volmit.iris.core.nms.container.Pair; 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.io.JarScanner; import com.volmit.iris.util.plugin.IrisService; +import com.volmit.iris.util.scheduling.J; import lombok.Data; import lombok.NonNull; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.inventory.ItemStack; @@ -47,43 +52,12 @@ public class ExternalDataSVC implements IrisService { Iris.info("Loading ExternalDataProvider..."); Bukkit.getPluginManager().registerEvents(this, Iris.instance); - providers.add(new NexoDataProvider()); - if (Bukkit.getPluginManager().getPlugin("Nexo") != null) { - Iris.info("Nexo found, loading NexoDataProvider..."); - } - providers.add(new MythicCrucibleDataProvider()); - if (Bukkit.getPluginManager().getPlugin("MythicCrucible") != null) { - Iris.info("MythicCrucible found, loading MythicCrucibleDataProvider..."); - } - providers.add(new ItemAdderDataProvider()); - if (Bukkit.getPluginManager().getPlugin("ItemAdder") != null) { - Iris.info("ItemAdder found, loading ItemAdderDataProvider..."); - } - providers.add(new ExecutableItemsDataProvider()); - if (Bukkit.getPluginManager().getPlugin("ExecutableItems") != null) { - Iris.info("ExecutableItems found, loading ExecutableItemsDataProvider..."); - } - providers.add(new HMCLeavesDataProvider()); - if (Bukkit.getPluginManager().getPlugin("HMCLeaves") != null) { - Iris.info("BlockAdder found, loading HMCLeavesDataProvider..."); - } - providers.add(new MMOItemsDataProvider()); - 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..."); - } - providers.add(new KGeneratorsDataProvider()); - if (Bukkit.getPluginManager().getPlugin("KGenerators") != null) { - Iris.info("KGenerators found, loading KGeneratorsDataProvider..."); - } - + providers.addAll(createProviders()); for (ExternalDataProvider p : providers) { if (p.isReady()) { activeProviders.add(p); p.init(); + Iris.instance.registerListener(p); Iris.info("Enabled ExternalDataProvider for %s.", p.getPluginId()); } } @@ -99,6 +73,7 @@ public class ExternalDataSVC implements IrisService { providers.stream().filter(p -> p.isReady() && p.getPlugin().equals(e.getPlugin())).findFirst().ifPresent(edp -> { activeProviders.add(edp); edp.init(); + Iris.instance.registerListener(edp); Iris.info("Enabled ExternalDataProvider for %s.", edp.getPluginId()); }); } @@ -113,6 +88,7 @@ public class ExternalDataSVC implements IrisService { if (provider.isReady()) { activeProviders.add(provider); provider.init(); + Iris.instance.registerListener(provider); } } @@ -120,7 +96,7 @@ public class ExternalDataSVC implements IrisService { var pair = parseState(key); Identifier mod = pair.getA(); - Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(mod, false)).findFirst(); + Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(mod, DataType.BLOCK)).findFirst(); if (provider.isEmpty()) return Optional.empty(); try { @@ -132,7 +108,7 @@ public class ExternalDataSVC implements IrisService { } public Optional getItemStack(Identifier key, KMap customNbt) { - Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(key, true)).findFirst(); + Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(key, DataType.ITEM)).findFirst(); if (provider.isEmpty()) { Iris.warn("No matching Provider found for modded material \"%s\"!", key); return Optional.empty(); @@ -146,7 +122,7 @@ public class ExternalDataSVC implements IrisService { } public void processUpdate(Engine engine, Block block, Identifier blockId) { - Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(blockId, false)).findFirst(); + Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(blockId, DataType.BLOCK)).findFirst(); if (provider.isEmpty()) { Iris.warn("No matching Provider found for modded material \"%s\"!", blockId); return; @@ -154,16 +130,24 @@ public class ExternalDataSVC implements IrisService { provider.get().processUpdate(engine, block, blockId); } - public Identifier[] getAllBlockIdentifiers() { - KList names = new KList<>(); - activeProviders.forEach(p -> names.add(p.getBlockTypes())); - return names.toArray(new Identifier[0]); + public Entity spawnMob(Location location, Identifier mobId) { + Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(mobId, DataType.ENTITY)).findFirst(); + if (provider.isEmpty()) { + Iris.warn("No matching Provider found for modded mob \"%s\"!", mobId); + return null; + } + try { + return provider.get().spawnMob(location, mobId); + } catch (MissingResourceException e) { + Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]"); + return null; + } } - public Identifier[] getAllItemIdentifiers() { - KList names = new KList<>(); - activeProviders.forEach(p -> names.add(p.getItemTypes())); - return names.toArray(new Identifier[0]); + public Collection getAllIdentifiers(DataType dataType) { + return activeProviders.stream() + .flatMap(p -> p.getTypes(dataType).stream()) + .toList(); } public static Pair> parseState(Identifier key) { @@ -188,4 +172,21 @@ public class ExternalDataSVC implements IrisService { .collect(Collectors.joining(",", key.key() + "[", "]")); return new Identifier(key.namespace(), path); } + + private static KList createProviders() { + JarScanner jar = new JarScanner(Iris.instance.getJarFile(), "com.volmit.iris.core.link.data"); + J.attempt(jar::scan); + KList providers = new KList<>(); + + for (Class c : jar.getClasses()) { + if (ExternalDataProvider.class.isAssignableFrom(c)) { + try { + ExternalDataProvider p = (ExternalDataProvider) c.getDeclaredConstructor().newInstance(); + if (p.getPlugin() != null) Iris.info(p.getPluginId() + " found, loading " + c.getSimpleName() + "..."); + providers.add(p); + } catch (Throwable ignored) {} + } + } + return providers; + } } 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 dfb2508d0..a87c319d0 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 @@ -20,8 +20,10 @@ package com.volmit.iris.engine.object; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.nms.INMS; +import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.util.collection.KList; @@ -455,24 +457,13 @@ public class IrisEntity extends IrisRegistrant { } if (isSpecialType()) { - if (specialType.toLowerCase().startsWith("mythicmobs:")) { - return Iris.linkMythicMobs.spawnMob(specialType.substring(11), at); - } else { - Iris.warn("Invalid mob type to spawn: '" + specialType + "'!"); - return null; - } + return Iris.service(ExternalDataSVC.class).spawnMob(at, Identifier.fromString(specialType)); } return INMS.get().spawnEntity(at, getType(), getReason()); } - public boolean isCitizens() { - return false; - - // TODO: return Iris.linkCitizens.supported() && someType is not empty; - } - public boolean isSpecialType() { return specialType != null && !specialType.equals(""); } 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 1c7a521cb..7e71d39f3 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 @@ -21,6 +21,7 @@ package com.volmit.iris.util.data; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.link.Identifier; +import com.volmit.iris.core.link.data.DataType; import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; @@ -673,7 +674,7 @@ public class B { } } - for (Identifier id : Iris.service(ExternalDataSVC.class).getAllBlockIdentifiers()) + for (Identifier id : Iris.service(ExternalDataSVC.class).getAllIdentifiers(DataType.BLOCK)) bt.add(id.toString()); bt.addAll(custom.k()); @@ -688,7 +689,7 @@ public class B { bt.add(v); } - for (Identifier id : Iris.service(ExternalDataSVC.class).getAllItemIdentifiers()) + for (Identifier id : Iris.service(ExternalDataSVC.class).getAllIdentifiers(DataType.ITEM)) bt.add(id.toString()); return bt.toArray(new String[0]); diff --git a/core/src/main/java/com/volmit/iris/util/scheduling/J.java b/core/src/main/java/com/volmit/iris/util/scheduling/J.java index a669317df..550b94092 100644 --- a/core/src/main/java/com/volmit/iris/util/scheduling/J.java +++ b/core/src/main/java/com/volmit/iris/util/scheduling/J.java @@ -240,6 +240,21 @@ public class J { return f; } + public static CompletableFuture sfut(Supplier r) { + CompletableFuture f = new CompletableFuture<>(); + if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { + return null; + } + Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> { + try { + f.complete(r.get()); + } catch (Throwable e) { + f.completeExceptionally(e); + } + }); + return f; + } + public static CompletableFuture sfut(Runnable r, int delay) { CompletableFuture f = new CompletableFuture(); From 387e8adfe2639de66464fed00ed7b584c58b9433 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 12 Jul 2025 18:10:39 +0200 Subject: [PATCH 50/66] ignore errors when scanning for external data providers --- .../main/java/com/volmit/iris/core/service/ExternalDataSVC.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 69fec1912..49303b60c 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 @@ -174,7 +174,7 @@ public class ExternalDataSVC implements IrisService { } private static KList createProviders() { - JarScanner jar = new JarScanner(Iris.instance.getJarFile(), "com.volmit.iris.core.link.data"); + JarScanner jar = new JarScanner(Iris.instance.getJarFile(), "com.volmit.iris.core.link.data", false); J.attempt(jar::scan); KList providers = new KList<>(); From 106a3834ab96707a19a46c4a21633a642555b556 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 13 Jul 2025 17:42:10 +0200 Subject: [PATCH 51/66] fix iris create command failing --- .../iris/core/commands/CommandIris.java | 1279 ++++++++--------- 1 file changed, 631 insertions(+), 648 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 4723ed3e1..38e2266e3 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 @@ -1,648 +1,631 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -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.core.safeguard.UtilsSFG; -import com.volmit.iris.engine.object.IrisWorld; -import com.volmit.iris.engine.platform.BukkitChunkGenerator; -import com.volmit.iris.engine.platform.DummyChunkGenerator; -import com.volmit.iris.util.collection.KList; -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.plugin.VolmitSender; -import com.volmit.iris.util.scheduling.J; -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.File; -import java.io.IOException; -import java.util.Collections; -import java.util.List; - -import static com.volmit.iris.Iris.service; -import static com.volmit.iris.core.service.EditSVC.deletingWorld; -import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode; -import static com.volmit.iris.core.safeguard.ServerBootSFG.incompatibilities; -import static org.bukkit.Bukkit.getServer; - -@Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command") -public class CommandIris implements DecreeExecutor { - private CommandStudio studio; - private CommandPregen pregen; - private CommandSettings settings; - private CommandObject object; - private CommandJigsaw jigsaw; - private CommandWhat what; - private CommandEdit edit; - private CommandFind find; - private CommandDeveloper developer; - public static boolean worldCreation = false; - String WorldEngine; - String worldNameToCheck = "YourWorldName"; - VolmitSender sender = Iris.getSender(); - - @Decree(description = "Create a new world", aliases = {"+", "c"}) - public void create( - @Param(aliases = "world-name", description = "The name of the world to create") - String name, - @Param(aliases = "dimension", description = "The dimension type to create the world with", defaultValue = "default") - IrisDimension type, - @Param(description = "The seed to generate the world with", defaultValue = "1337") - long seed - ) { - if(sender() instanceof Player) { - if (incompatibilities.get("Multiverse-Core")) { - sender().sendMessage(C.RED + "Your server has an incompatibility that may corrupt all worlds on the server if not handled properly."); - sender().sendMessage(C.RED + "it is strongly advised for you to take action. see log for full detail"); - sender().sendMessage(C.RED + "----------------------------------------------------------------"); - sender().sendMessage(C.RED + "Command ran: /iris create"); - sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings()); - sender().sendMessage(C.RED + "----------------------------------------------------------------"); - } - if (unstablemode && !incompatibilities.get("Multiverse-Core")) { - sender().sendMessage(C.RED + "Your server is experiencing an incompatibility with the Iris plugin."); - sender().sendMessage(C.RED + "Please rectify this problem to avoid further complications."); - sender().sendMessage(C.RED + "----------------------------------------------------------------"); - sender().sendMessage(C.RED + "Command ran: /iris create"); - sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings()); - sender().sendMessage(C.RED + "----------------------------------------------------------------"); - } - } - if (name.equals("iris")) { - sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds."); - sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?"); - return; - } - if (name.equals("Benchmark")) { - sender().sendMessage(C.RED + "You cannot use the world name \"Benchmark\" for creating worlds as Iris uses this directory for Benchmarking Packs."); - sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?"); - return; - } - - if (new File(Bukkit.getWorldContainer(), name).exists()) { - sender().sendMessage(C.RED + "That folder already exists!"); - return; - } - - try { - worldCreation = true; - IrisToolbelt.createWorld() - .dimension(type.getLoadKey()) - .name(name) - .seed(seed) - .sender(sender()) - .studio(false) - .create(); - } catch (Throwable e) { - sender().sendMessage(C.RED + "Exception raised during creation. See the console for more details."); - Iris.error("Exception raised during world creation: " + e.getMessage()); - Iris.reportError(e); - worldCreation = false; - return; - } - worldCreation = false; - sender().sendMessage(C.GREEN + "Successfully created your world!"); - } - - @Decree(description = "Teleport to another world", aliases = {"tp"}, sync = true) - public void teleport( - @Param(description = "World to teleport to") - World world, - @Param(description = "Player to teleport", defaultValue = "---", customHandler = NullablePlayerHandler.class) - Player player - ) { - if (player == null && sender().isPlayer()) - player = sender().player(); - - final Player target = player; - if (target == null) { - sender().sendMessage(C.RED + "The specified player does not exist."); - return; - } - - new BukkitRunnable() { - @Override - public void run() { - target.teleport(world.getSpawnLocation()); - new VolmitSender(target).sendMessage(C.GREEN + "You have been teleported to " + world.getName() + "."); - } - }.runTask(Iris.instance); - } - - @Decree(description = "Print version information") - public void version() { - sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software"); - } - - /* - /todo - @Decree(description = "Benchmark a pack", origin = DecreeOrigin.CONSOLE) - public void packbenchmark( - @Param(description = "Dimension to benchmark") - IrisDimension type - ) throws InterruptedException { - - BenchDimension = type.getLoadKey(); - - IrisPackBenchmarking.runBenchmark(); - } */ - - @Decree(description = "Print world height information", origin = DecreeOrigin.PLAYER) - public void height() { - if (sender().isPlayer()) { - sender().sendMessage(C.GREEN + "" + sender().player().getWorld().getMinHeight() + " to " + sender().player().getWorld().getMaxHeight()); - sender().sendMessage(C.GREEN + "Total Height: " + (sender().player().getWorld().getMaxHeight() - sender().player().getWorld().getMinHeight())); - } else { - World mainWorld = getServer().getWorlds().get(0); - Iris.info(C.GREEN + "" + mainWorld.getMinHeight() + " to " + mainWorld.getMaxHeight()); - Iris.info(C.GREEN + "Total Height: " + (mainWorld.getMaxHeight() - mainWorld.getMinHeight())); - } - } - - @Decree(description = "QOL command to open a overworld studio world.", sync = true) - public void so() { - sender().sendMessage(C.GREEN + "Opening studio for the \"Overworld\" pack (seed: 1337)"); - Iris.service(StudioSVC.class).open(sender(), 1337, "overworld"); - } - - @Decree(description = "Check access of all worlds.", aliases = {"accesslist"}) - public void worlds() { - KList IrisWorlds = new KList<>(); - KList BukkitWorlds = new KList<>(); - - for (World w : Bukkit.getServer().getWorlds()) { - try { - Engine engine = IrisToolbelt.access(w).getEngine(); - if (engine != null) { - IrisWorlds.add(w); - } - } catch (Exception e) { - BukkitWorlds.add(w); - } - } - - if (sender().isPlayer()) { - sender().sendMessage(C.BLUE + "Iris Worlds: "); - for (World IrisWorld : IrisWorlds.copy()) { - sender().sendMessage(C.IRIS + "- " +IrisWorld.getName()); - } - sender().sendMessage(C.GOLD + "Bukkit Worlds: "); - for (World BukkitWorld : BukkitWorlds.copy()) { - sender().sendMessage(C.GRAY + "- " +BukkitWorld.getName()); - } - } else { - Iris.info(C.BLUE + "Iris Worlds: "); - for (World IrisWorld : IrisWorlds.copy()) { - Iris.info(C.IRIS + "- " +IrisWorld.getName()); - } - Iris.info(C.GOLD + "Bukkit Worlds: "); - for (World BukkitWorld : BukkitWorlds.copy()) { - Iris.info(C.GRAY + "- " +BukkitWorld.getName()); - } - - } - } - - @Decree(description = "Remove an Iris world", aliases = {"del", "rm", "delete"}, sync = true) - public void remove( - @Param(description = "The world to remove") - World world, - @Param(description = "Whether to also remove the folder (if set to false, just does not load the world)", defaultValue = "true") - boolean delete - ) { - if (!IrisToolbelt.isIrisWorld(world)) { - sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); - return; - } - sender().sendMessage(C.GREEN + "Removing world: " + world.getName()); - - if (!IrisToolbelt.evacuate(world)) { - sender().sendMessage(C.RED + "Failed to evacuate world: " + world.getName()); - return; - } - - if (!Bukkit.unloadWorld(world, false)) { - sender().sendMessage(C.RED + "Failed to unload world: " + world.getName()); - return; - } - - try { - if (IrisToolbelt.removeWorld(world)) { - sender().sendMessage(C.GREEN + "Successfully removed " + world.getName() + " from bukkit.yml"); - } else { - sender().sendMessage(C.YELLOW + "Looks like the world was already removed from bukkit.yml"); - } - } catch (IOException e) { - sender().sendMessage(C.RED + "Failed to save bukkit.yml because of " + e.getMessage()); - e.printStackTrace(); - } - IrisToolbelt.evacuate(world, "Deleting world"); - deletingWorld = true; - if (!delete) { - deletingWorld = false; - return; - } - VolmitSender sender = sender(); - J.a(() -> { - int retries = 12; - - if (deleteDirectory(world.getWorldFolder())) { - sender.sendMessage(C.GREEN + "Successfully removed world folder"); - } else { - while(true){ - if (deleteDirectory(world.getWorldFolder())){ - sender.sendMessage(C.GREEN + "Successfully removed world folder"); - break; - } - retries--; - if (retries == 0){ - sender.sendMessage(C.RED + "Failed to remove world folder"); - break; - } - J.sleep(3000); - } - } - deletingWorld = false; - }); - } - - public static boolean deleteDirectory(File dir) { - if (dir.isDirectory()) { - File[] children = dir.listFiles(); - for (int i = 0; i < children.length; i++) { - boolean success = deleteDirectory(children[i]); - if (!success) { - return false; - } - } - } - return dir.delete(); - } - - @Decree(description = "Updates all chunk in the specified world") - public void updater( - @Param(description = "World to update chunks at") - World world - ) { - if (!IrisToolbelt.isIrisWorld(world)) { - sender().sendMessage(C.GOLD + "This is not an Iris world"); - return; - } - ChunkUpdater updater = new ChunkUpdater(world); - if (sender().isPlayer()) { - sender().sendMessage(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks())); - } else { - Iris.info(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks())); - } - updater.start(); - } - - @Decree(description = "Set aura spins") - public void aura( - @Param(description = "The h color value", defaultValue = "-20") - int h, - @Param(description = "The s color value", defaultValue = "7") - int s, - @Param(description = "The b color value", defaultValue = "8") - int b - ) { - IrisSettings.get().getGeneral().setSpinh(h); - IrisSettings.get().getGeneral().setSpins(s); - IrisSettings.get().getGeneral().setSpinb(b); - IrisSettings.get().forceSave(); - sender().sendMessage("Aura Spins updated to " + h + " " + s + " " + b); - } - - @Decree(description = "Bitwise calculations") - public void bitwise( - @Param(description = "The first value to run calculations on") - int value1, - @Param(description = "The operator: | & ^ ≺≺ ≻≻ %") - String operator, - @Param(description = "The second value to run calculations on") - int value2 - ) { - Integer v = null; - switch (operator) { - case "|" -> v = value1 | value2; - case "&" -> v = value1 & value2; - case "^" -> v = value1 ^ value2; - case "%" -> v = value1 % value2; - case ">>" -> v = value1 >> value2; - case "<<" -> v = value1 << value2; - } - if (v == null) { - sender().sendMessage(C.RED + "The operator you entered: (" + operator + ") is invalid!"); - return; - } - sender().sendMessage(C.GREEN + "" + value1 + " " + C.GREEN + operator.replaceAll("<", "≺").replaceAll(">", "≻").replaceAll("%", "%") + " " + C.GREEN + value2 + C.GREEN + " returns " + C.GREEN + v); - } - - @Decree(description = "Toggle debug") - public void debug( - @Param(name = "on", description = "Whether or not debug should be on", defaultValue = "other") - Boolean on - ) { - boolean to = on == null ? !IrisSettings.get().getGeneral().isDebug() : on; - IrisSettings.get().getGeneral().setDebug(to); - IrisSettings.get().forceSave(); - sender().sendMessage(C.GREEN + "Set debug to: " + to); - } - - @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 = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false") - boolean overwrite - ) { - 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"; - Iris.service(StudioSVC.class).downloadRelease(sender(), url, trim, overwrite); - } else { - Iris.service(StudioSVC.class).downloadSearch(sender(), "IrisDimensions/" + pack + "/" + branch, trim, overwrite); - } - } - - @Decree(description = "Get metrics for your world", aliases = "measure", origin = DecreeOrigin.PLAYER) - public void metrics() { - if (!IrisToolbelt.isIrisWorld(world())) { - sender().sendMessage(C.RED + "You must be in an Iris world"); - return; - } - sender().sendMessage(C.GREEN + "Sending metrics..."); - engine().printMetrics(sender()); - } - - @Decree(description = "Reload configuration file (this is also done automatically)") - public void reload() { - IrisSettings.invalidate(); - IrisSettings.get(); - sender().sendMessage(C.GREEN + "Hotloaded settings"); - } - - @Decree(description = "Update the pack of a world (UNSAFE!)", name = "^world", aliases = "update-world") - public void updateWorld( - @Param(description = "The world to update", contextual = true) - World world, - @Param(description = "The pack to install into the world", contextual = true, aliases = "dimension") - IrisDimension pack, - @Param(description = "Make sure to make a backup & read the warnings first!", defaultValue = "false", aliases = "c") - boolean confirm, - @Param(description = "Should Iris download the pack again for you", defaultValue = "false", name = "fresh-download", aliases = {"fresh", "new"}) - boolean freshDownload - ) { - if (!confirm) { - sender().sendMessage(new String[]{ - C.RED + "You should always make a backup before using this", - C.YELLOW + "Issues caused by this can be, but are not limited to:", - C.YELLOW + " - Broken chunks (cut-offs) between old and new chunks (before & after the update)", - C.YELLOW + " - Regenerated chunks that do not fit in with the old chunks", - C.YELLOW + " - Structures not spawning again when regenerating", - C.YELLOW + " - Caves not lining up", - C.YELLOW + " - Terrain layers not lining up", - C.RED + "Now that you are aware of the risks, and have made a back-up:", - C.RED + "/iris ^world " + world.getName() + " " + pack.getLoadKey() + " confirm=true" - }); - return; - } - - File folder = world.getWorldFolder(); - folder.mkdirs(); - - if (freshDownload) { - Iris.service(StudioSVC.class).downloadSearch(sender(), pack.getLoadKey(), false, true); - } - - Iris.service(StudioSVC.class).installIntoWorld(sender(), pack.getLoadKey(), folder); - } - - @Decree(description = "Unload an Iris World", origin = DecreeOrigin.PLAYER, sync = true) - public void unloadWorld( - @Param(description = "The world to unload") - World world - ) { - if (!IrisToolbelt.isIrisWorld(world)) { - sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); - return; - } - sender().sendMessage(C.GREEN + "Unloading world: " + world.getName()); - try { - IrisToolbelt.evacuate(world); - Bukkit.unloadWorld(world, false); - sender().sendMessage(C.GREEN + "World unloaded successfully."); - } catch (Exception e) { - sender().sendMessage(C.RED + "Failed to unload the world: " + e.getMessage()); - e.printStackTrace(); - } - } - - @Decree(description = "Load an Iris World", origin = DecreeOrigin.PLAYER, sync = true, aliases = {"import"}) - public void loadWorld( - @Param(description = "The name of the world to load") - String world - ) { - World worldloaded = Bukkit.getWorld(world); - worldNameToCheck = world; - boolean worldExists = doesWorldExist(worldNameToCheck); - WorldEngine = world; - - if (!worldExists) { - sender().sendMessage(C.YELLOW + world + " Doesnt exist on the server."); - 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); - - String dimension = null; - if (directory.exists() && directory.isDirectory()) { - File[] files = directory.listFiles(); - if (files != null) { - for (File file : files) { - if (file.isFile()) { - String fileName = file.getName(); - if (fileName.endsWith(".json")) { - dimension = fileName.substring(0, fileName.length() - 5); - sender().sendMessage(C.BLUE + "Generator: " + dimension); - } - } - } - } - } else { - sender().sendMessage(C.GOLD + world + " is not an iris world."); - return; - } - sender().sendMessage(C.GREEN + "Loading world: " + world); - - YamlConfiguration yml = YamlConfiguration.loadConfiguration(BUKKIT_YML); - String gen = "Iris:" + dimension; - ConfigurationSection section = yml.contains("worlds") ? yml.getConfigurationSection("worlds") : yml.createSection("worlds"); - if (!section.contains(world)) { - section.createSection(world).set("generator", gen); - try { - yml.save(BUKKIT_YML); - Iris.info("Registered \"" + world + "\" in bukkit.yml"); - } catch (IOException e) { - Iris.error("Failed to update bukkit.yml!"); - e.printStackTrace(); - return; - } - } - checkForBukkitWorlds(world); - sender().sendMessage(C.GREEN + world + " loaded successfully."); - } - @Decree(description = "Evacuate an iris world", origin = DecreeOrigin.PLAYER, sync = true) - public void evacuate( - @Param(description = "Evacuate the world") - World world - ) { - if (!IrisToolbelt.isIrisWorld(world)) { - sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); - return; - } - sender().sendMessage(C.GREEN + "Evacuating world" + world.getName()); - IrisToolbelt.evacuate(world); - } - - boolean doesWorldExist(String worldName) { - File worldContainer = Bukkit.getWorldContainer(); - 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); - if (worldName.equals("test")) { - try { - throw new RuntimeException(); - } catch (Throwable e) { - Iris.info(e.getStackTrace()[1].getClassName()); - if (e.getStackTrace()[1].getClassName().contains("com.onarandombox.MultiverseCore")) { - Iris.debug("MVC Test detected, Quick! Send them the dummy!"); - return new DummyChunkGenerator(); - } - } - } - 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()); - } -} +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2022 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +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.core.safeguard.UtilsSFG; +import com.volmit.iris.engine.object.IrisWorld; +import com.volmit.iris.engine.platform.BukkitChunkGenerator; +import com.volmit.iris.engine.platform.DummyChunkGenerator; +import com.volmit.iris.util.collection.KList; +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.plugin.VolmitSender; +import com.volmit.iris.util.scheduling.J; +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.File; +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +import static com.volmit.iris.Iris.service; +import static com.volmit.iris.core.service.EditSVC.deletingWorld; +import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode; +import static com.volmit.iris.core.safeguard.ServerBootSFG.incompatibilities; +import static org.bukkit.Bukkit.getServer; + +@Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command") +public class CommandIris implements DecreeExecutor { + private CommandStudio studio; + private CommandPregen pregen; + private CommandSettings settings; + private CommandObject object; + private CommandJigsaw jigsaw; + private CommandWhat what; + private CommandEdit edit; + private CommandFind find; + private CommandDeveloper developer; + public static boolean worldCreation = false; + String WorldEngine; + String worldNameToCheck = "YourWorldName"; + VolmitSender sender = Iris.getSender(); + + @Decree(description = "Create a new world", aliases = {"+", "c"}) + public void create( + @Param(aliases = "world-name", description = "The name of the world to create") + String name, + @Param(aliases = "dimension", description = "The dimension type to create the world with", defaultValue = "default") + IrisDimension type, + @Param(description = "The seed to generate the world with", defaultValue = "1337") + long seed + ) { + if (name.equalsIgnoreCase("iris")) { + sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds."); + sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?"); + return; + } + + if (name.equalsIgnoreCase("benchmark")) { + sender().sendMessage(C.RED + "You cannot use the world name \"benchmark\" for creating worlds as Iris uses this directory for Benchmarking Packs."); + sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?"); + return; + } + + if (new File(Bukkit.getWorldContainer(), name).exists()) { + sender().sendMessage(C.RED + "That folder already exists!"); + return; + } + + try { + worldCreation = true; + IrisToolbelt.createWorld() + .dimension(type.getLoadKey()) + .name(name) + .seed(seed) + .sender(sender()) + .studio(false) + .create(); + } catch (Throwable e) { + sender().sendMessage(C.RED + "Exception raised during creation. See the console for more details."); + Iris.error("Exception raised during world creation: " + e.getMessage()); + Iris.reportError(e); + worldCreation = false; + return; + } + worldCreation = false; + sender().sendMessage(C.GREEN + "Successfully created your world!"); + } + + @Decree(description = "Teleport to another world", aliases = {"tp"}, sync = true) + public void teleport( + @Param(description = "World to teleport to") + World world, + @Param(description = "Player to teleport", defaultValue = "---", customHandler = NullablePlayerHandler.class) + Player player + ) { + if (player == null && sender().isPlayer()) + player = sender().player(); + + final Player target = player; + if (target == null) { + sender().sendMessage(C.RED + "The specified player does not exist."); + return; + } + + new BukkitRunnable() { + @Override + public void run() { + target.teleport(world.getSpawnLocation()); + new VolmitSender(target).sendMessage(C.GREEN + "You have been teleported to " + world.getName() + "."); + } + }.runTask(Iris.instance); + } + + @Decree(description = "Print version information") + public void version() { + sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software"); + } + + /* + /todo + @Decree(description = "Benchmark a pack", origin = DecreeOrigin.CONSOLE) + public void packbenchmark( + @Param(description = "Dimension to benchmark") + IrisDimension type + ) throws InterruptedException { + + BenchDimension = type.getLoadKey(); + + IrisPackBenchmarking.runBenchmark(); + } */ + + @Decree(description = "Print world height information", origin = DecreeOrigin.PLAYER) + public void height() { + if (sender().isPlayer()) { + sender().sendMessage(C.GREEN + "" + sender().player().getWorld().getMinHeight() + " to " + sender().player().getWorld().getMaxHeight()); + sender().sendMessage(C.GREEN + "Total Height: " + (sender().player().getWorld().getMaxHeight() - sender().player().getWorld().getMinHeight())); + } else { + World mainWorld = getServer().getWorlds().get(0); + Iris.info(C.GREEN + "" + mainWorld.getMinHeight() + " to " + mainWorld.getMaxHeight()); + Iris.info(C.GREEN + "Total Height: " + (mainWorld.getMaxHeight() - mainWorld.getMinHeight())); + } + } + + @Decree(description = "QOL command to open a overworld studio world.", sync = true) + public void so() { + sender().sendMessage(C.GREEN + "Opening studio for the \"Overworld\" pack (seed: 1337)"); + Iris.service(StudioSVC.class).open(sender(), 1337, "overworld"); + } + + @Decree(description = "Check access of all worlds.", aliases = {"accesslist"}) + public void worlds() { + KList IrisWorlds = new KList<>(); + KList BukkitWorlds = new KList<>(); + + for (World w : Bukkit.getServer().getWorlds()) { + try { + Engine engine = IrisToolbelt.access(w).getEngine(); + if (engine != null) { + IrisWorlds.add(w); + } + } catch (Exception e) { + BukkitWorlds.add(w); + } + } + + if (sender().isPlayer()) { + sender().sendMessage(C.BLUE + "Iris Worlds: "); + for (World IrisWorld : IrisWorlds.copy()) { + sender().sendMessage(C.IRIS + "- " +IrisWorld.getName()); + } + sender().sendMessage(C.GOLD + "Bukkit Worlds: "); + for (World BukkitWorld : BukkitWorlds.copy()) { + sender().sendMessage(C.GRAY + "- " +BukkitWorld.getName()); + } + } else { + Iris.info(C.BLUE + "Iris Worlds: "); + for (World IrisWorld : IrisWorlds.copy()) { + Iris.info(C.IRIS + "- " +IrisWorld.getName()); + } + Iris.info(C.GOLD + "Bukkit Worlds: "); + for (World BukkitWorld : BukkitWorlds.copy()) { + Iris.info(C.GRAY + "- " +BukkitWorld.getName()); + } + + } + } + + @Decree(description = "Remove an Iris world", aliases = {"del", "rm", "delete"}, sync = true) + public void remove( + @Param(description = "The world to remove") + World world, + @Param(description = "Whether to also remove the folder (if set to false, just does not load the world)", defaultValue = "true") + boolean delete + ) { + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); + return; + } + sender().sendMessage(C.GREEN + "Removing world: " + world.getName()); + + if (!IrisToolbelt.evacuate(world)) { + sender().sendMessage(C.RED + "Failed to evacuate world: " + world.getName()); + return; + } + + if (!Bukkit.unloadWorld(world, false)) { + sender().sendMessage(C.RED + "Failed to unload world: " + world.getName()); + return; + } + + try { + if (IrisToolbelt.removeWorld(world)) { + sender().sendMessage(C.GREEN + "Successfully removed " + world.getName() + " from bukkit.yml"); + } else { + sender().sendMessage(C.YELLOW + "Looks like the world was already removed from bukkit.yml"); + } + } catch (IOException e) { + sender().sendMessage(C.RED + "Failed to save bukkit.yml because of " + e.getMessage()); + e.printStackTrace(); + } + IrisToolbelt.evacuate(world, "Deleting world"); + deletingWorld = true; + if (!delete) { + deletingWorld = false; + return; + } + VolmitSender sender = sender(); + J.a(() -> { + int retries = 12; + + if (deleteDirectory(world.getWorldFolder())) { + sender.sendMessage(C.GREEN + "Successfully removed world folder"); + } else { + while(true){ + if (deleteDirectory(world.getWorldFolder())){ + sender.sendMessage(C.GREEN + "Successfully removed world folder"); + break; + } + retries--; + if (retries == 0){ + sender.sendMessage(C.RED + "Failed to remove world folder"); + break; + } + J.sleep(3000); + } + } + deletingWorld = false; + }); + } + + public static boolean deleteDirectory(File dir) { + if (dir.isDirectory()) { + File[] children = dir.listFiles(); + for (int i = 0; i < children.length; i++) { + boolean success = deleteDirectory(children[i]); + if (!success) { + return false; + } + } + } + return dir.delete(); + } + + @Decree(description = "Updates all chunk in the specified world") + public void updater( + @Param(description = "World to update chunks at") + World world + ) { + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage(C.GOLD + "This is not an Iris world"); + return; + } + ChunkUpdater updater = new ChunkUpdater(world); + if (sender().isPlayer()) { + sender().sendMessage(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks())); + } else { + Iris.info(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks())); + } + updater.start(); + } + + @Decree(description = "Set aura spins") + public void aura( + @Param(description = "The h color value", defaultValue = "-20") + int h, + @Param(description = "The s color value", defaultValue = "7") + int s, + @Param(description = "The b color value", defaultValue = "8") + int b + ) { + IrisSettings.get().getGeneral().setSpinh(h); + IrisSettings.get().getGeneral().setSpins(s); + IrisSettings.get().getGeneral().setSpinb(b); + IrisSettings.get().forceSave(); + sender().sendMessage("Aura Spins updated to " + h + " " + s + " " + b); + } + + @Decree(description = "Bitwise calculations") + public void bitwise( + @Param(description = "The first value to run calculations on") + int value1, + @Param(description = "The operator: | & ^ ≺≺ ≻≻ %") + String operator, + @Param(description = "The second value to run calculations on") + int value2 + ) { + Integer v = null; + switch (operator) { + case "|" -> v = value1 | value2; + case "&" -> v = value1 & value2; + case "^" -> v = value1 ^ value2; + case "%" -> v = value1 % value2; + case ">>" -> v = value1 >> value2; + case "<<" -> v = value1 << value2; + } + if (v == null) { + sender().sendMessage(C.RED + "The operator you entered: (" + operator + ") is invalid!"); + return; + } + sender().sendMessage(C.GREEN + "" + value1 + " " + C.GREEN + operator.replaceAll("<", "≺").replaceAll(">", "≻").replaceAll("%", "%") + " " + C.GREEN + value2 + C.GREEN + " returns " + C.GREEN + v); + } + + @Decree(description = "Toggle debug") + public void debug( + @Param(name = "on", description = "Whether or not debug should be on", defaultValue = "other") + Boolean on + ) { + boolean to = on == null ? !IrisSettings.get().getGeneral().isDebug() : on; + IrisSettings.get().getGeneral().setDebug(to); + IrisSettings.get().forceSave(); + sender().sendMessage(C.GREEN + "Set debug to: " + to); + } + + @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 = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false") + boolean overwrite + ) { + 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"; + Iris.service(StudioSVC.class).downloadRelease(sender(), url, trim, overwrite); + } else { + Iris.service(StudioSVC.class).downloadSearch(sender(), "IrisDimensions/" + pack + "/" + branch, trim, overwrite); + } + } + + @Decree(description = "Get metrics for your world", aliases = "measure", origin = DecreeOrigin.PLAYER) + public void metrics() { + if (!IrisToolbelt.isIrisWorld(world())) { + sender().sendMessage(C.RED + "You must be in an Iris world"); + return; + } + sender().sendMessage(C.GREEN + "Sending metrics..."); + engine().printMetrics(sender()); + } + + @Decree(description = "Reload configuration file (this is also done automatically)") + public void reload() { + IrisSettings.invalidate(); + IrisSettings.get(); + sender().sendMessage(C.GREEN + "Hotloaded settings"); + } + + @Decree(description = "Update the pack of a world (UNSAFE!)", name = "^world", aliases = "update-world") + public void updateWorld( + @Param(description = "The world to update", contextual = true) + World world, + @Param(description = "The pack to install into the world", contextual = true, aliases = "dimension") + IrisDimension pack, + @Param(description = "Make sure to make a backup & read the warnings first!", defaultValue = "false", aliases = "c") + boolean confirm, + @Param(description = "Should Iris download the pack again for you", defaultValue = "false", name = "fresh-download", aliases = {"fresh", "new"}) + boolean freshDownload + ) { + if (!confirm) { + sender().sendMessage(new String[]{ + C.RED + "You should always make a backup before using this", + C.YELLOW + "Issues caused by this can be, but are not limited to:", + C.YELLOW + " - Broken chunks (cut-offs) between old and new chunks (before & after the update)", + C.YELLOW + " - Regenerated chunks that do not fit in with the old chunks", + C.YELLOW + " - Structures not spawning again when regenerating", + C.YELLOW + " - Caves not lining up", + C.YELLOW + " - Terrain layers not lining up", + C.RED + "Now that you are aware of the risks, and have made a back-up:", + C.RED + "/iris ^world " + world.getName() + " " + pack.getLoadKey() + " confirm=true" + }); + return; + } + + File folder = world.getWorldFolder(); + folder.mkdirs(); + + if (freshDownload) { + Iris.service(StudioSVC.class).downloadSearch(sender(), pack.getLoadKey(), false, true); + } + + Iris.service(StudioSVC.class).installIntoWorld(sender(), pack.getLoadKey(), folder); + } + + @Decree(description = "Unload an Iris World", origin = DecreeOrigin.PLAYER, sync = true) + public void unloadWorld( + @Param(description = "The world to unload") + World world + ) { + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); + return; + } + sender().sendMessage(C.GREEN + "Unloading world: " + world.getName()); + try { + IrisToolbelt.evacuate(world); + Bukkit.unloadWorld(world, false); + sender().sendMessage(C.GREEN + "World unloaded successfully."); + } catch (Exception e) { + sender().sendMessage(C.RED + "Failed to unload the world: " + e.getMessage()); + e.printStackTrace(); + } + } + + @Decree(description = "Load an Iris World", origin = DecreeOrigin.PLAYER, sync = true, aliases = {"import"}) + public void loadWorld( + @Param(description = "The name of the world to load") + String world + ) { + World worldloaded = Bukkit.getWorld(world); + worldNameToCheck = world; + boolean worldExists = doesWorldExist(worldNameToCheck); + WorldEngine = world; + + if (!worldExists) { + sender().sendMessage(C.YELLOW + world + " Doesnt exist on the server."); + 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); + + String dimension = null; + if (directory.exists() && directory.isDirectory()) { + File[] files = directory.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isFile()) { + String fileName = file.getName(); + if (fileName.endsWith(".json")) { + dimension = fileName.substring(0, fileName.length() - 5); + sender().sendMessage(C.BLUE + "Generator: " + dimension); + } + } + } + } + } else { + sender().sendMessage(C.GOLD + world + " is not an iris world."); + return; + } + sender().sendMessage(C.GREEN + "Loading world: " + world); + + YamlConfiguration yml = YamlConfiguration.loadConfiguration(BUKKIT_YML); + String gen = "Iris:" + dimension; + ConfigurationSection section = yml.contains("worlds") ? yml.getConfigurationSection("worlds") : yml.createSection("worlds"); + if (!section.contains(world)) { + section.createSection(world).set("generator", gen); + try { + yml.save(BUKKIT_YML); + Iris.info("Registered \"" + world + "\" in bukkit.yml"); + } catch (IOException e) { + Iris.error("Failed to update bukkit.yml!"); + e.printStackTrace(); + return; + } + } + checkForBukkitWorlds(world); + sender().sendMessage(C.GREEN + world + " loaded successfully."); + } + @Decree(description = "Evacuate an iris world", origin = DecreeOrigin.PLAYER, sync = true) + public void evacuate( + @Param(description = "Evacuate the world") + World world + ) { + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); + return; + } + sender().sendMessage(C.GREEN + "Evacuating world" + world.getName()); + IrisToolbelt.evacuate(world); + } + + boolean doesWorldExist(String worldName) { + File worldContainer = Bukkit.getWorldContainer(); + 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); + if (worldName.equals("test")) { + try { + throw new RuntimeException(); + } catch (Throwable e) { + Iris.info(e.getStackTrace()[1].getClassName()); + if (e.getStackTrace()[1].getClassName().contains("com.onarandombox.MultiverseCore")) { + Iris.debug("MVC Test detected, Quick! Send them the dummy!"); + return new DummyChunkGenerator(); + } + } + } + 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()); + } +} From d49f7d7821733751989d12e269367ab285f27dbf Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 13 Jul 2025 17:43:11 +0200 Subject: [PATCH 52/66] add parameter to the create command to make it your main world --- .../iris/core/commands/CommandIris.java | 50 ++++++++++++------- .../main/java/com/volmit/iris/util/io/IO.java | 20 ++++++++ 2 files changed, 52 insertions(+), 18 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 38e2266e3..84f601642 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 @@ -27,10 +27,8 @@ 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.core.safeguard.UtilsSFG; import com.volmit.iris.engine.object.IrisWorld; import com.volmit.iris.engine.platform.BukkitChunkGenerator; -import com.volmit.iris.engine.platform.DummyChunkGenerator; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeOrigin; @@ -39,8 +37,11 @@ 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.io.IO; +import com.volmit.iris.util.misc.ServerProperties; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; +import lombok.SneakyThrows; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.WorldCreator; @@ -51,15 +52,13 @@ import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import org.bukkit.scheduler.BukkitRunnable; -import java.io.File; -import java.io.IOException; +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.core.safeguard.IrisSafeguard.unstablemode; -import static com.volmit.iris.core.safeguard.ServerBootSFG.incompatibilities; import static org.bukkit.Bukkit.getServer; @Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command") @@ -74,6 +73,7 @@ public class CommandIris implements DecreeExecutor { private CommandFind find; private CommandDeveloper developer; public static boolean worldCreation = false; + private static final AtomicReference mainWorld = new AtomicReference<>(); String WorldEngine; String worldNameToCheck = "YourWorldName"; VolmitSender sender = Iris.getSender(); @@ -85,7 +85,9 @@ public class CommandIris implements DecreeExecutor { @Param(aliases = "dimension", description = "The dimension type to create the world with", defaultValue = "default") IrisDimension type, @Param(description = "The seed to generate the world with", defaultValue = "1337") - long seed + long seed, + @Param(aliases = "main-world", description = "Whether or not to automatically use this world as the main world", defaultValue = "false") + boolean main ) { if (name.equalsIgnoreCase("iris")) { sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds."); @@ -113,6 +115,12 @@ public class CommandIris implements DecreeExecutor { .sender(sender()) .studio(false) .create(); + if (main) { + Runtime.getRuntime().addShutdownHook(mainWorld.updateAndGet(old -> { + if (old != null) Runtime.getRuntime().removeShutdownHook(old); + return new Thread(() -> updateMainWorld(name)); + })); + } } catch (Throwable e) { sender().sendMessage(C.RED + "Exception raised during creation. See the console for more details."); Iris.error("Exception raised during world creation: " + e.getMessage()); @@ -124,6 +132,23 @@ public class CommandIris implements DecreeExecutor { sender().sendMessage(C.GREEN + "Successfully created your world!"); } + @SneakyThrows + private void updateMainWorld(String newName) { + File worlds = Bukkit.getWorldContainer(); + var data = ServerProperties.DATA; + try (var in = new FileInputStream(ServerProperties.SERVER_PROPERTIES)) { + data.load(in); + } + for (String sub : List.of("datapacks", "playerdata", "advancements", "stats")) { + IO.copyDirectory(new File(worlds, ServerProperties.LEVEL_NAME + "/" + sub).toPath(), new File(worlds, newName + "/" + sub).toPath()); + } + + data.setProperty("level-name", newName); + try (var out = new FileOutputStream(ServerProperties.SERVER_PROPERTIES)) { + data.store(out, null); + } + } + @Decree(description = "Teleport to another world", aliases = {"tp"}, sync = true) public void teleport( @Param(description = "World to teleport to") @@ -580,17 +605,6 @@ public class CommandIris implements DecreeExecutor { } public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { Iris.debug("Default World Generator Called for " + worldName + " using ID: " + id); - if (worldName.equals("test")) { - try { - throw new RuntimeException(); - } catch (Throwable e) { - Iris.info(e.getStackTrace()[1].getClassName()); - if (e.getStackTrace()[1].getClassName().contains("com.onarandombox.MultiverseCore")) { - Iris.debug("MVC Test detected, Quick! Send them the dummy!"); - return new DummyChunkGenerator(); - } - } - } IrisDimension dim; if (id == null || id.isEmpty()) { dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType()); diff --git a/core/src/main/java/com/volmit/iris/util/io/IO.java b/core/src/main/java/com/volmit/iris/util/io/IO.java index 61deb3670..247dfefb1 100644 --- a/core/src/main/java/com/volmit/iris/util/io/IO.java +++ b/core/src/main/java/com/volmit/iris/util/io/IO.java @@ -30,6 +30,7 @@ import org.apache.commons.io.function.IOFunction; import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.security.DigestInputStream; import java.security.MessageDigest; @@ -592,6 +593,25 @@ public class IO { } } + public static void copyDirectory(Path source, Path target) throws IOException { + Files.walk(source).forEach(sourcePath -> { + Path targetPath = target.resolve(source.relativize(sourcePath)); + + try { + if (Files.isDirectory(sourcePath)) { + if (!Files.exists(targetPath)) { + Files.createDirectories(targetPath); + } + } else { + Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); + } + } catch (IOException e) { + Iris.error("Failed to copy " + targetPath); + e.printStackTrace(); + } + }); + } + /** * Unconditionally close an Reader. *

From a8892b04ef6074096d2500e5f2079f8ade2b4c52 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 19 Jul 2025 12:59:50 +0200 Subject: [PATCH 53/66] bump nms for 1.21.8 support --- .../java/com/volmit/iris/core/nms/INMS.java | 37 ++++++++++--------- gradle/libs.versions.toml | 2 +- 2 files changed, 21 insertions(+), 18 deletions(-) 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 8b998147c..e4d6bc682 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 @@ -24,21 +24,21 @@ import com.volmit.iris.core.nms.v1X.NMSBinding1X; import org.bukkit.Bukkit; import java.util.List; -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", - "1.21", "v1_21_R1", - "1.21.1", "v1_21_R1", - "1.21.2", "v1_21_R2", - "1.21.3", "v1_21_R2", - "1.21.4", "v1_21_R3", - "1.21.5", "v1_21_R4", - "1.21.6", "v1_21_R5", - "1.21.7", "v1_21_R5" + private static final Version CURRENT = Boolean.getBoolean("iris.no-version-limit") ? + new Version(Integer.MAX_VALUE, Integer.MAX_VALUE, null) : + new Version(21, 8, null); + + private static final List REVISION = List.of( + new Version(21, 6, "v1_21_R5"), + new Version(21, 5, "v1_21_R4"), + new Version(21, 4, "v1_21_R3"), + new Version(21, 2, "v1_21_R2"), + new Version(21, 0, "v1_21_R1"), + new Version(20, 5, "v1_20_R4") ); + private static final List PACKS = List.of( new Version(21, 5, "31100"), new Version(21, 4, "31020"), @@ -48,7 +48,7 @@ public class INMS { //@done private static final INMSBinding binding = bind(); - public static final String OVERWORLD_TAG = getOverworldTag(); + public static final String OVERWORLD_TAG = getTag(PACKS, "3910"); public static INMSBinding get() { return binding; @@ -62,7 +62,7 @@ public class INMS { try { String name = Bukkit.getServer().getClass().getCanonicalName(); if (name.equals("org.bukkit.craftbukkit.CraftServer")) { - return REVISION.getOrDefault(Bukkit.getServer().getBukkitVersion().split("-")[0], "BUKKIT"); + return getTag(REVISION, "BUKKIT"); } else { return name.split("\\Q.\\E")[3]; } @@ -100,7 +100,7 @@ public class INMS { return new NMSBinding1X(); } - private static String getOverworldTag() { + private static String getTag(List versions, String def) { var version = Bukkit.getServer().getBukkitVersion().split("-")[0].split("\\.", 3); int major = 0; int minor = 0; @@ -111,13 +111,16 @@ public class INMS { } else if (version.length == 2) { major = Integer.parseInt(version[1]); } + if (CURRENT.major < major || CURRENT.minor < minor) { + return versions.getFirst().tag; + } - for (var p : PACKS) { + for (var p : versions) { if (p.major > major || p.minor > minor) continue; return p.tag; } - return "3910"; + return def; } private record Version(int major, int minor, String tag) {} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bdc075162..f697c836e 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.7" # https://plugins.gradle.org/plugin/de.crazydev22.slimjar +slimjar = "2.0.8" # 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 dee46a42843b6a8965e1cc7e631ee4172c2cc0e7 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 19 Jul 2025 17:48:58 +0200 Subject: [PATCH 54/66] cleanup object mask rotation --- .../iris/engine/object/IrisCaveShape.java | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java index f5001befb..4972ce516 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCaveShape.java @@ -6,6 +6,7 @@ import com.volmit.iris.engine.object.annotations.RegistryListResource; import com.volmit.iris.engine.object.annotations.Snippet; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.noise.CNG; import lombok.AllArgsConstructor; @@ -36,17 +37,40 @@ public class IrisCaveShape { public KSet getMasked(RNG rng, Engine engine) { if (object == null) return null; - return cache.computeIfAbsent(new IrisPosition( - rng.i(0, 360), - rng.i(0, 360), - rng.i(0, 360)), - pos -> { - var rotated = new KSet(); - engine.getData().getObjectLoader().load(object).getBlocks().forEach((vector, data) -> { - if (data.getMaterial().isAir()) return; - rotated.add(new IrisPosition(objectRotation.rotate(vector, pos.getX(), pos.getY(), pos.getZ()))); - }); - return rotated; - }); + return cache.computeIfAbsent(randomRotation(rng), pos -> { + var rotated = new KSet(); + engine.getData().getObjectLoader().load(object).getBlocks().forEach((vector, data) -> { + if (data.getMaterial().isAir()) return; + rotated.add(new IrisPosition(objectRotation.rotate(vector, pos.getX(), pos.getY(), pos.getZ()))); + }); + return rotated; + }); + } + + private IrisPosition randomRotation(RNG rng) { + if (objectRotation == null || !objectRotation.canRotate()) + return new IrisPosition(0,0,0); + return new IrisPosition( + randomDegree(rng, objectRotation.getXAxis()), + randomDegree(rng, objectRotation.getYAxis()), + randomDegree(rng, objectRotation.getZAxis()) + ); + } + + private int randomDegree(RNG rng, IrisAxisRotationClamp clamp) { + if (!clamp.isEnabled()) return 0; + if (clamp.isLocked()) return (int) clamp.getMax(); + double interval = clamp.getInterval(); + if (interval < 1) interval = 1; + + double min = clamp.getMin(), max = clamp.getMax(); + double value = (interval * (Math.ceil(Math.abs(rng.d(0, 360) / interval)))) % 360D; + if (clamp.isUnlimited()) return (int) value; + + if (min > max) { + max = clamp.getMin(); + min = clamp.getMax(); + } + return (int) (double) M.clip(value, min, max); } } From 8262e52893e216757cde2af313bcf8be2ef47248 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 30 Mar 2025 13:48:43 +0200 Subject: [PATCH 55/66] cleanup regen --- .../iris/core/commands/CommandStudio.java | 140 +++++++++--------- .../engine/platform/BukkitChunkGenerator.java | 74 ++++----- .../platform/PlatformChunkGenerator.java | 4 +- .../iris/util/parallel/SyncExecutor.java | 46 ++++++ 4 files changed, 160 insertions(+), 104 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/util/parallel/SyncExecutor.java 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 0abb77a15..1635dd3bb 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 @@ -46,18 +46,20 @@ 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.mantle.MantleChunk; +import com.volmit.iris.util.mantle.MantleFlag; 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.parallel.SyncExecutor; 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 com.volmit.iris.util.scheduling.jobs.ParallelQueueJob; import io.papermc.lib.PaperLib; import org.bukkit.*; import org.bukkit.event.inventory.InventoryType; @@ -76,8 +78,7 @@ import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.Date; import java.util.Objects; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; @@ -161,70 +162,77 @@ public class CommandStudio implements DecreeExecutor { @Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5") int radius ) { - if (IrisToolbelt.isIrisWorld(player().getWorld())) { - VolmitSender sender = sender(); - J.a(() -> { - DecreeContext.touch(sender); - PlatformChunkGenerator plat = IrisToolbelt.access(player().getWorld()); - Engine engine = plat.getEngine(); - try { - Chunk cx = player().getLocation().getChunk(); - KList js = new KList<>(); - BurstExecutor b = MultiBurst.burst.burst(); - b.setMulticore(false); - int rad = engine.getMantle().getRadius(); - for (int i = -(radius + rad); i <= radius + rad; i++) { - for (int j = -(radius + rad); j <= radius + rad; j++) { - engine.getMantle().getMantle().deleteChunk(i + cx.getX(), j + cx.getZ()); - } - } - - for (int i = -radius; i <= radius; i++) { - for (int j = -radius; j <= radius; j++) { - int finalJ = j; - int finalI = i; - b.queue(() -> plat.injectChunkReplacement(player().getWorld(), finalI + cx.getX(), finalJ + cx.getZ(), (f) -> { - synchronized (js) { - js.add(f); - } - })); - } - } - - b.complete(); - sender().sendMessage(C.GREEN + "Regenerating " + Form.f(js.size()) + " Sections"); - QueueJob r = new QueueJob<>() { - final KList> futures = new KList<>(); - - @Override - public void execute(Runnable runnable) { - futures.add(J.sfut(runnable)); - - if (futures.size() > 64) { - while (futures.isNotEmpty()) { - try { - futures.remove(0).get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - } - } - } - } - - @Override - public String getName() { - return "Regenerating"; - } - }; - r.queue(js); - r.execute(sender()); - } catch (Throwable e) { - sender().sendMessage("Unable to parse view-distance"); - } - }); - } else { + World world = player().getWorld(); + if (!IrisToolbelt.isIrisWorld(world)) { sender().sendMessage(C.RED + "You must be in an Iris World to use regen!"); } + + VolmitSender sender = sender(); + var loc = player().getLocation().clone(); + + J.a(() -> { + DecreeContext.touch(sender); + PlatformChunkGenerator plat = IrisToolbelt.access(world); + Engine engine = plat.getEngine(); + try (SyncExecutor executor = new SyncExecutor(20)) { + int x = loc.getBlockX() >> 4; + int z = loc.getBlockZ() >> 4; + + int rad = engine.getMantle().getRadius(); + var mantle = engine.getMantle().getMantle(); + var chunkMap = new KMap(); + for (int i = -(radius + rad); i <= radius + rad; i++) { + for (int j = -(radius + rad); j <= radius + rad; j++) { + int xx = i + x, zz = j + z; + if (Math.abs(i) <= radius && Math.abs(j) <= radius) { + mantle.deleteChunk(xx, zz); + continue; + } + chunkMap.put(new Position2(xx, zz), mantle.getChunk(xx, zz)); + mantle.deleteChunk(xx, zz); + } + } + + ParallelQueueJob job = new ParallelQueueJob<>() { + @Override + public void execute(Position2 p) { + plat.injectChunkReplacement(world, p.getX(), p.getZ(), executor); + } + + @Override + public String getName() { + return "Regenerating"; + } + }; + for (int i = -radius; i <= radius; i++) { + for (int j = -radius; j <= radius; j++) { + job.queue(new Position2(i + x, j + z)); + } + } + + CountDownLatch latch = new CountDownLatch(1); + job.execute(sender(), latch::countDown); + latch.await(); + + int sections = mantle.getWorldHeight() >> 4; + chunkMap.forEach((pos, chunk) -> { + var c = mantle.getChunk(pos.getX(), pos.getZ()); + for (MantleFlag flag : MantleFlag.values()) { + c.flag(flag, chunk.isFlagged(flag)); + } + c.clear(); + for (int y = 0; y < sections; y++) { + var slice = chunk.get(y); + if (slice == null) continue; + var s = c.getOrCreate(y); + slice.getSliceMap().forEach(s::putSlice); + } + }); + } catch (Throwable e) { + sender().sendMessage("Error while regenerating chunks"); + e.printStackTrace(); + } + }); } @Decree(description = "Convert objects in the \"convert\" folder") diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index 2e6035534..1f7fbd9a6 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -64,12 +64,10 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.List; import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Semaphore; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Consumer; @EqualsAndHashCode(callSuper = true) @Data @@ -95,8 +93,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun @Setter private volatile StudioGenerator studioGenerator; - private boolean initialized = false; - public BukkitChunkGenerator(IrisWorld world, boolean studio, File dataLocation, String dimensionKey) { setup = new AtomicBoolean(false); studioGenerator = null; @@ -114,8 +110,8 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun @EventHandler(priority = EventPriority.LOWEST) public void onWorldInit(WorldInitEvent event) { - if (initialized || !world.name().equals(event.getWorld().getName())) - return; + if (!world.name().equals(event.getWorld().getName())) return; + Iris.instance.unregisterListener(this); world.setRawWorldSeed(event.getWorld().getSeed()); if (initialize(event.getWorld())) return; @@ -140,7 +136,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun } spawnChunks.complete(INMS.get().getSpawnChunkCount(world)); Iris.instance.unregisterListener(this); - initialized = true; IrisWorlds.get().put(world.getName(), dimensionKey); return true; } @@ -205,50 +200,57 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun } @Override - public void injectChunkReplacement(World world, int x, int z, Consumer jobs) { + public void injectChunkReplacement(World world, int x, int z, Executor syncExecutor) { try { loadLock.acquire(); IrisBiomeStorage st = new IrisBiomeStorage(); TerrainChunk tc = TerrainChunk.createUnsafe(world, st); - Hunk blocks = Hunk.view(tc); - Hunk biomes = Hunk.view(tc, tc.getMinHeight(), tc.getMaxHeight()); this.world.bind(world); - getEngine().generate(x << 4, z << 4, blocks, biomes, true); - Iris.debug("Regenerated " + x + " " + z); - int t = 0; + getEngine().generate(x << 4, z << 4, tc, false); + + Chunk c = PaperLib.getChunkAtAsync(world, x, z) + .thenApply(d -> { + d.addPluginChunkTicket(Iris.instance); + + for (Entity ee : d.getEntities()) { + if (ee instanceof Player) { + continue; + } + + ee.remove(); + } + + engine.getWorldManager().onChunkLoad(d, false); + return d; + }).get(); + + + KList> futures = new KList<>(1 + getEngine().getHeight() >> 4); for (int i = getEngine().getHeight() >> 4; i >= 0; i--) { - if (!world.isChunkLoaded(x, z)) { - continue; - } - - Chunk c = world.getChunkAt(x, z); - for (Entity ee : c.getEntities()) { - if (ee instanceof Player) { - continue; - } - - J.s(ee::remove); - } - - J.s(() -> engine.getWorldManager().onChunkLoad(c, false)); - - int finalI = i; - jobs.accept(() -> { - + int finalI = i << 4; + futures.add(CompletableFuture.runAsync(() -> { for (int xx = 0; xx < 16; xx++) { for (int yy = 0; yy < 16; yy++) { for (int zz = 0; zz < 16; zz++) { - if (yy + (finalI << 4) >= engine.getHeight() || yy + (finalI << 4) < 0) { + if (yy + finalI >= engine.getHeight() || yy + finalI < 0) { continue; } - c.getBlock(xx, yy + (finalI << 4) + world.getMinHeight(), zz) - .setBlockData(tc.getBlockData(xx, yy + (finalI << 4) + world.getMinHeight(), zz), false); + int y = yy + finalI + world.getMinHeight(); + c.getBlock(xx, y, zz).setBlockData(tc.getBlockData(xx, y, zz), false); } } } - }); + }, syncExecutor)); } + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenRunAsync(() -> { + c.removePluginChunkTicket(Iris.instance); + c.unload(); + }, syncExecutor) + .get(); + Iris.debug("Regenerated " + x + " " + z); + loadLock.release(); } catch (Throwable e) { loadLock.release(); diff --git a/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java index 687788527..93066fb62 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java @@ -28,7 +28,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; +import java.util.concurrent.Executor; public interface PlatformChunkGenerator extends Hotloadable, DataProvider { @Nullable @@ -42,7 +42,7 @@ public interface PlatformChunkGenerator extends Hotloadable, DataProvider { @NotNull EngineTarget getTarget(); - void injectChunkReplacement(World world, int x, int z, Consumer jobs); + void injectChunkReplacement(World world, int x, int z, Executor syncExecutor); void close(); diff --git a/core/src/main/java/com/volmit/iris/util/parallel/SyncExecutor.java b/core/src/main/java/com/volmit/iris/util/parallel/SyncExecutor.java new file mode 100644 index 000000000..00966b226 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/parallel/SyncExecutor.java @@ -0,0 +1,46 @@ +package com.volmit.iris.util.parallel; + +import com.volmit.iris.util.math.M; +import com.volmit.iris.util.scheduling.SR; +import org.jetbrains.annotations.NotNull; + +import java.util.Queue; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; + +public class SyncExecutor implements Executor, AutoCloseable { + private final CountDownLatch latch = new CountDownLatch(1); + private final Queue queue = new ConcurrentLinkedQueue<>(); + private final AtomicBoolean closed = new AtomicBoolean(false); + + public SyncExecutor(int msPerTick) { + new SR() { + @Override + public void run() { + var time = M.ms() + msPerTick; + while (time > M.ms()) { + Runnable r = queue.poll(); + if (r == null) break; + r.run(); + } + + if (closed.get() && queue.isEmpty()) { + cancel(); + latch.countDown(); + } + } + }; + } + + @Override + public void execute(@NotNull Runnable command) { + if (closed.get()) throw new IllegalStateException("Executor is closed!"); + queue.add(command); + } + + @Override + public void close() throws Exception { + closed.set(true); + latch.await(); + } +} From f50e964d4f53e36bb7f65852e8a695da02fc3ece Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 21 Jul 2025 17:14:45 +0200 Subject: [PATCH 56/66] hopefully fix unsafe mantle chunk operations --- .../com/volmit/iris/util/mantle/Mantle.java | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java index 6e1e56e54..6851c4cea 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java @@ -421,19 +421,19 @@ public class Mantle { throw new RuntimeException("The Mantle is closed"); } - adjustedIdleDuration.set(baseIdleDuration); + double idleDuration = baseIdleDuration; if (loadedRegions.size() > tectonicLimit) { // todo update this correctly and maybe do something when its above a 100% - adjustedIdleDuration.set(Math.max(adjustedIdleDuration.get() - (1000 * (((loadedRegions.size() - tectonicLimit) / (double) tectonicLimit) * 100) * 0.4), 4000)); + idleDuration = Math.max(idleDuration - (1000 * (((loadedRegions.size() - tectonicLimit) / (double) tectonicLimit) * 100) * 0.4), 4000); } + adjustedIdleDuration.set(idleDuration); ioTrim.set(true); try { - double adjustedIdleDuration = this.adjustedIdleDuration.get(); - Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration, 0)); + Iris.debug("Trimming Tectonic Plates older than " + Form.duration(idleDuration, 0)); if (lastUse.isEmpty()) return; - double unloadTime = M.ms() - adjustedIdleDuration; + double unloadTime = M.ms() - idleDuration; for (long id : lastUse.keySet()) { hyperLock.withLong(id, () -> { Long lastUseTime = lastUse.get(id); @@ -462,6 +462,7 @@ public class Mantle { ioTectonicUnload.set(true); try { for (long id : toUnload) { + double unloadTime = M.ms() - adjustedIdleDuration.get(); burst.queue(() -> hyperLock.withLong(id, () -> { TectonicPlate m = loadedRegions.get(id); if (m == null) { @@ -470,6 +471,11 @@ public class Mantle { return; } + var used = lastUse.getOrDefault(id, 0L); + if (!toUnload.contains(id) || used >= unloadTime) { + return; + } + if (m.inUse()) { Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ()); lastUse.put(id, M.ms()); @@ -522,9 +528,11 @@ public class Mantle { } } - TectonicPlate p = loadedRegions.get(key(x, z)); + Long key = key(x, z); + TectonicPlate p = loadedRegions.get(key); if (p != null) { + use(key); return p; } @@ -556,12 +564,12 @@ public class Mantle { TectonicPlate p = loadedRegions.get(k); if (p != null) { - lastUse.put(k, M.ms()); + use(k); return CompletableFuture.completedFuture(p); } return ioBurst.completeValue(() -> hyperLock.withResult(x, z, () -> { - lastUse.put(k, M.ms()); + use(k); TectonicPlate region = loadedRegions.get(k); if (region != null) { @@ -602,6 +610,11 @@ public class Mantle { })); } + private void use(Long key) { + lastUse.put(key, M.ms()); + toUnload.remove(key); + } + public void saveAll() { } From 9d6e4e87d8477aae5ef12e8f4d430b589f8c6acc Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 22 Jul 2025 12:11:41 +0200 Subject: [PATCH 57/66] fix custom blocks not placing --- core/src/main/java/com/volmit/iris/engine/framework/Engine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 010628b7d..1e39c8667 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 @@ -262,7 +262,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat getMantle().updateBlock(x, y, z); } if (data instanceof IrisCustomData) { - getMantle().getMantle().flag(x >> 4, z >> 4, MantleFlag.CUSTOM, true); + getMantle().getMantle().flag(x >> 4, z >> 4, MantleFlag.CUSTOM_ACTIVE, true); } } From fc54fcb7eb70c1206cb509806d029a6aa81a0398 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Tue, 22 Jul 2025 12:12:13 +0200 Subject: [PATCH 58/66] make itemsadder data provider standalone --- .../core/link/data/ItemAdderDataProvider.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java index c0bf27ef4..f030fc6a8 100644 --- a/core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/data/ItemAdderDataProvider.java @@ -3,10 +3,14 @@ package com.volmit.iris.core.link.data; import com.volmit.iris.Iris; import com.volmit.iris.core.link.ExternalDataProvider; import com.volmit.iris.core.link.Identifier; +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.data.B; +import com.volmit.iris.util.data.IrisCustomData; import dev.lone.itemsadder.api.CustomBlock; import dev.lone.itemsadder.api.CustomStack; +import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -40,7 +44,11 @@ public class ItemAdderDataProvider extends ExternalDataProvider { @NotNull @Override public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap state) throws MissingResourceException { - return CustomBlock.getBaseBlockData(blockId.toString()); + CustomBlock block = CustomBlock.getInstance(blockId.toString()); + if (block == null) { + throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); + } + return new IrisCustomData(B.getAir(), blockId); } @NotNull @@ -53,6 +61,11 @@ public class ItemAdderDataProvider extends ExternalDataProvider { return stack.getItemStack(); } + @Override + public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) { + CustomBlock.place(blockId.toString(), block.getLocation()); + } + @Override public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { return switch (dataType) { From 3949468a6080bbb4ba300ad936ff155b71f8932d Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 23 Jul 2025 14:45:54 +0200 Subject: [PATCH 59/66] inject into the library loader to make sure libraries can always be loaded --- .../com/volmit/iris/util/misc/SlimJar.java | 122 +++++++++++++++--- 1 file changed, 104 insertions(+), 18 deletions(-) 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 fa79b849d..e4c882b74 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,20 +1,35 @@ package com.volmit.iris.util.misc; +import com.volmit.iris.Iris; +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.logging.ProcessLogger; +import io.github.slimjar.resolver.data.Repository; 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.Level; import java.util.logging.Logger; public class SlimJar { - private static final Logger LOGGER = Logger.getLogger("Iris"); + 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 DISABLE_REMAPPER = Boolean.getBoolean("iris.disable-remapper"); public static void debug(boolean debug) { LOGGER.setLevel(debug ? Level.FINE : Level.INFO); @@ -31,28 +46,99 @@ public class SlimJar { } LOGGER.info("Loading libraries..."); - ApplicationBuilder.appending("Iris") - .downloadDirectoryPath(localRepository.toPath()) - .logger(new ProcessLogger() { - @Override - public void info(@NotNull String message, @Nullable Object... args) { - LOGGER.fine(message.formatted(args)); - } + load(localRepository.toPath(), new ProcessLogger() { + @Override + public void info(@NotNull String message, @Nullable Object... args) { + LOGGER.fine(message.formatted(args)); + } - @Override - public void error(@NotNull String message, @Nullable Object... args) { - LOGGER.severe(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) { - LOGGER.fine(message.formatted(args)); - } - }) - .build(); + @Override + public void debug(@NotNull String message, @Nullable Object... args) { + LOGGER.fine(message.formatted(args)); + } + }); 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) + .downloadDirectoryPath(downloadPath) + .logger(logger) + .build(); + } + } + + 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"); + + 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 injecting = InjectableFactory.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(); + } + }) + .downloadDirectoryPath(downloadPath) + .logger(logger) + .build(); + + libraryLoader.set(current, libraries); + } + + 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); + } } From e5f2fee926045c983053f6de520c7c499518db62 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 23 Jul 2025 15:07:06 +0200 Subject: [PATCH 60/66] add info about used commit to sentry reports --- core/build.gradle.kts | 8 ++++++++ .../src/main/java/com/volmit/iris/util/misc/Bindings.java | 7 +++++++ core/src/main/resources/plugin.yml | 2 ++ 3 files changed, 17 insertions(+) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index ef7cc7168..a559f2b7f 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -137,6 +137,14 @@ tasks { "version" to rootProject.version, "apiVersion" to apiVersion, "main" to main, + "environment" to if (project.hasProperty("release")) "production" else "development", + "commit" to provider { + ProcessBuilder("git", "rev-parse", "HEAD") + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .start() + .inputStream.bufferedReader().readText().trim() + .takeIf { it.length == 40 } ?: "unknown" + } ) filesMatching("**/plugin.yml") { expand(inputs.properties) diff --git a/core/src/main/java/com/volmit/iris/util/misc/Bindings.java b/core/src/main/java/com/volmit/iris/util/misc/Bindings.java index 308d3d235..6dea9f4a8 100644 --- a/core/src/main/java/com/volmit/iris/util/misc/Bindings.java +++ b/core/src/main/java/com/volmit/iris/util/misc/Bindings.java @@ -23,9 +23,11 @@ import org.bstats.charts.SimplePie; import org.bstats.charts.SingleLineChart; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import oshi.SystemInfo; +import java.io.InputStreamReader; import java.math.RoundingMode; import java.text.NumberFormat; import java.util.HashMap; @@ -45,6 +47,9 @@ public class Bindings { if (settings.disableAutoReporting || Sentry.isEnabled() || Boolean.getBoolean("iris.suppressReporting")) return; Iris.info("Enabling Sentry for anonymous error reporting. You can disable this in the settings."); Iris.info("Your server ID is: " + ServerID.ID); + var resource = Iris.instance.getResource("plugin.yml"); + YamlConfiguration desc = resource != null ? YamlConfiguration.loadConfiguration(new InputStreamReader(resource)) : new YamlConfiguration(); + Sentry.init(options -> { options.setDsn("https://b16ecc222e9c1e0c48faecacb906fd89@o4509451052646400.ingest.de.sentry.io/4509452722765904"); if (settings.debug) { @@ -55,6 +60,7 @@ public class Bindings { options.setAttachServerName(false); options.setEnableUncaughtExceptionHandler(false); options.setRelease(Iris.instance.getDescription().getVersion()); + options.setEnvironment(desc.getString("environment", "production")); options.setBeforeSend((event, hint) -> { if (suppress(event.getThrowable())) return null; event.setTag("iris.safeguard", IrisSafeguard.mode()); @@ -71,6 +77,7 @@ public class Bindings { scope.setTag("server", Bukkit.getVersion()); scope.setTag("server.type", Bukkit.getName()); scope.setTag("server.api", Bukkit.getBukkitVersion()); + scope.setTag("iris.commit", desc.getString("commit", "unknown")); }); Runtime.getRuntime().addShutdownHook(new Thread(Sentry::close)); } diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml index 99fa326be..f871ec1e3 100644 --- a/core/src/main/resources/plugin.yml +++ b/core/src/main/resources/plugin.yml @@ -5,6 +5,8 @@ load: STARTUP authors: [ cyberpwn, NextdoorPsycho, Vatuu ] website: volmit.com description: More than a Dimension! +environment: '${environment}' +commit: '${commit}' commands: iris: aliases: [ ir, irs ] From 16a4d20c90352ff579497c5368e058084b5d1bc1 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 23 Jul 2025 18:06:52 +0200 Subject: [PATCH 61/66] use grgit to resolve current commit --- core/build.gradle.kts | 9 ++++----- gradle/libs.versions.toml | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index a559f2b7f..ef3c51465 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -26,6 +26,7 @@ plugins { alias(libs.plugins.shadow) alias(libs.plugins.sentry) alias(libs.plugins.slimjar) + alias(libs.plugins.grgit) } val apiVersion = "1.19" @@ -139,11 +140,9 @@ tasks { "main" to main, "environment" to if (project.hasProperty("release")) "production" else "development", "commit" to provider { - ProcessBuilder("git", "rev-parse", "HEAD") - .redirectOutput(ProcessBuilder.Redirect.PIPE) - .start() - .inputStream.bufferedReader().readText().trim() - .takeIf { it.length == 40 } ?: "unknown" + runCatching { grgit.head().id } + .getOrDefault("") + .takeIf { it.length == 40 } ?: "unknown" } ) filesMatching("**/plugin.yml") { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f697c836e..cc74057db 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ slimjar = "2.0.8" # 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 +grgit = "5.3.2" # https://github.com/ajoberstar/grgit # Core Libraries lombok = "1.18.38" @@ -100,3 +101,4 @@ slimjar = { id = "de.crazydev22.slimjar", version.ref = "slimjar" } download = { id = "de.undercouch.download", version.ref = "download" } runPaper = { id = "xyz.jpenilla.run-paper", version.ref = "runPaper" } sentry = { id = "io.sentry.jvm.gradle", version.ref = "sentryPlugin" } +grgit = { id = "org.ajoberstar.grgit", version.ref = "grgit" } From 556bef6e4309440da14ca18a47537009920794f8 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 25 Jul 2025 12:44:01 +0200 Subject: [PATCH 62/66] fix more unsafe mantle chunk accesses --- .../com/volmit/iris/util/mantle/Mantle.java | 90 ++++++++++--------- .../iris/util/mantle/TectonicPlate.java | 8 ++ 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java index 6851c4cea..c48c43bd8 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java @@ -47,7 +47,6 @@ import org.bukkit.Chunk; import java.io.EOFException; import java.io.File; import java.io.IOException; -import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -58,16 +57,18 @@ import java.util.concurrent.atomic.AtomicInteger; */ public class Mantle { + private static final int LOCK_SIZE = Short.MAX_VALUE; + private final File dataFolder; @Getter private final int worldHeight; - private final Map lastUse; - private final Map loadedRegions; + private final KMap lastUse; + private final KMap loadedRegions; private final HyperLock hyperLock; private final AtomicBoolean closed; private final MultiBurst ioBurst; - private final AtomicBoolean ioTrim; - private final AtomicBoolean ioTectonicUnload; + private final Semaphore ioTrim; + private final Semaphore ioTectonicUnload; private final AtomicDouble adjustedIdleDuration; private final KSet toUnload; @@ -83,8 +84,8 @@ public class Mantle { this.closed = new AtomicBoolean(false); this.dataFolder = dataFolder; this.worldHeight = worldHeight; - this.ioTrim = new AtomicBoolean(false); - this.ioTectonicUnload = new AtomicBoolean(false); + this.ioTrim = new Semaphore(LOCK_SIZE, true); + this.ioTectonicUnload = new Semaphore(LOCK_SIZE, true); loadedRegions = new KMap<>(); lastUse = new KMap<>(); ioBurst = MultiBurst.burst; @@ -428,7 +429,7 @@ public class Mantle { } adjustedIdleDuration.set(idleDuration); - ioTrim.set(true); + ioTrim.acquireUninterruptibly(LOCK_SIZE); try { Iris.debug("Trimming Tectonic Plates older than " + Form.duration(idleDuration, 0)); @@ -446,7 +447,7 @@ public class Mantle { } catch (Throwable e) { Iris.reportError(e); } finally { - ioTrim.set(false); + ioTrim.release(LOCK_SIZE); } } @@ -459,7 +460,7 @@ public class Mantle { BurstExecutor burst = ioBurst.burst(toUnload.size()); burst.setMulticore(toUnload.size() > tectonicLimit); - ioTectonicUnload.set(true); + ioTectonicUnload.acquireUninterruptibly(LOCK_SIZE); try { for (long id : toUnload) { double unloadTime = M.ms() - adjustedIdleDuration.get(); @@ -478,15 +479,14 @@ public class Mantle { if (m.inUse()) { Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ()); - lastUse.put(id, M.ms()); - toUnload.remove(id); + use(id); return; } try { m.write(fileForRegion(dataFolder, id, false)); oldFileForRegion(dataFolder, id).delete(); - loadedRegions.remove(id); + loadedRegions.remove(id, m); lastUse.remove(id); toUnload.remove(id); i.incrementAndGet(); @@ -502,7 +502,7 @@ public class Mantle { e.printStackTrace(); burst.complete(); } finally { - ioTectonicUnload.set(false); + ioTectonicUnload.release(LOCK_SIZE); } return i.get(); } @@ -518,32 +518,39 @@ public class Mantle { */ @RegionCoordinates private TectonicPlate get(int x, int z) { - if (ioTrim.get() || ioTectonicUnload.get()) { + boolean trim = ioTrim.tryAcquire(); + boolean unload = ioTectonicUnload.tryAcquire(); + try { + if (!trim || !unload) { + try { + return getSafe(x, z).get(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + } + + Long key = key(x, z); + TectonicPlate p = loadedRegions.get(key); + + if (p != null && !p.isClosed()) { + use(key); + return p; + } + try { return getSafe(x, z).get(); } catch (InterruptedException e) { - e.printStackTrace(); + Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread intterruption (hotload?)"); + Iris.reportError(e); } catch (ExecutionException e) { - e.printStackTrace(); + Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread execution exception (engine close?)"); + Iris.reportError(e); } - } - - Long key = key(x, z); - TectonicPlate p = loadedRegions.get(key); - - if (p != null) { - use(key); - return p; - } - - try { - return getSafe(x, z).get(); - } catch (InterruptedException e) { - Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread intterruption (hotload?)"); - Iris.reportError(e); - } catch (ExecutionException e) { - Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread execution exception (engine close?)"); - Iris.reportError(e); + } finally { + if (trim) ioTrim.release(); + if (unload) ioTectonicUnload.release(); } Iris.warn("Retrying to get " + x + " " + z + " Mantle Region"); @@ -560,19 +567,12 @@ public class Mantle { */ @RegionCoordinates private Future getSafe(int x, int z) { - Long k = key(x, z); - TectonicPlate p = loadedRegions.get(k); - - if (p != null) { - use(k); - return CompletableFuture.completedFuture(p); - } - return ioBurst.completeValue(() -> hyperLock.withResult(x, z, () -> { + Long k = key(x, z); use(k); TectonicPlate region = loadedRegions.get(k); - if (region != null) { + if (region != null && !region.isClosed()) { return region; } @@ -600,12 +600,14 @@ public class Mantle { Iris.debug("Created new Tectonic Plate (Due to Load Failure) " + C.DARK_GREEN + x + " " + z); } + use(k); return region; } region = new TectonicPlate(worldHeight, x, z); loadedRegions.put(k, region); Iris.debug("Created new Tectonic Plate " + C.DARK_GREEN + x + " " + z); + use(k); return region; })); } diff --git a/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java b/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java index 101019023..181ce9cd2 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java @@ -39,6 +39,7 @@ import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReferenceArray; /** @@ -52,6 +53,7 @@ public class TectonicPlate { private final int sectionHeight; private final AtomicReferenceArray chunks; + private final AtomicBoolean closed; @Getter private final int x; @@ -67,6 +69,7 @@ public class TectonicPlate { public TectonicPlate(int worldHeight, int x, int z) { this.sectionHeight = worldHeight >> 4; this.chunks = new AtomicReferenceArray<>(1024); + this.closed = new AtomicBoolean(false); this.x = x; this.z = z; } @@ -143,6 +146,7 @@ public class TectonicPlate { } public void close() throws InterruptedException { + closed.set(true); for (int i = 0; i < chunks.length(); i++) { MantleChunk chunk = chunks.get(i); if (chunk != null) { @@ -151,6 +155,10 @@ public class TectonicPlate { } } + public boolean isClosed() { + return closed.get(); + } + /** * Check if a chunk exists in this plate or not (same as get(x, z) != null) * From 08b9058c8f0ba3ee967da80b46caaf295627b4df Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 25 Jul 2025 13:07:13 +0200 Subject: [PATCH 63/66] make git commit retrieval fail safe --- core/build.gradle.kts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index ef3c51465..7365bde48 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,5 +1,6 @@ import io.github.slimjar.func.slimjar import io.github.slimjar.resolver.data.Mirror +import org.ajoberstar.grgit.Grgit import java.net.URI /* @@ -140,10 +141,13 @@ tasks { "main" to main, "environment" to if (project.hasProperty("release")) "production" else "development", "commit" to provider { - runCatching { grgit.head().id } + runCatching { extensions.getByType().head().id } .getOrDefault("") - .takeIf { it.length == 40 } ?: "unknown" - } + .takeIf { it.length == 40 } ?: { + project.logger.error("Git commit hash not found") + "unknown" + }() + }, ) filesMatching("**/plugin.yml") { expand(inputs.properties) From b0ca0e36170c668fe15a5aeeef8a0b497b3cc077 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 25 Jul 2025 13:21:16 +0200 Subject: [PATCH 64/66] whoops messed up the extension retrieval --- core/build.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 7365bde48..7f8361822 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -141,10 +141,10 @@ tasks { "main" to main, "environment" to if (project.hasProperty("release")) "production" else "development", "commit" to provider { - runCatching { extensions.getByType().head().id } - .getOrDefault("") + val res = runCatching { project.extensions.getByType().head().id } + res.getOrDefault("") .takeIf { it.length == 40 } ?: { - project.logger.error("Git commit hash not found") + logger.error("Git commit hash not found", res.exceptionOrNull()) "unknown" }() }, From 76a6f1465adfe79acad417606d561715b117914c Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 26 Jul 2025 14:31:45 +0200 Subject: [PATCH 65/66] 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 66/66] 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