diff --git a/build.gradle b/build.gradle index 768d73742..490234148 100644 --- a/build.gradle +++ b/build.gradle @@ -18,6 +18,15 @@ import java.util.function.Consumer * along with this program. If not, see . */ +buildscript() { + repositories { + maven { url 'https://jitpack.io'} + } + dependencies { + classpath 'com.github.VolmitSoftware:NMSTools:1.0.0' + } +} + plugins { id 'java' id 'java-library' @@ -26,7 +35,6 @@ plugins { } version '3.3.1-1.19.2-1.20.6' -def specialSourceVersion = '1.11.4' //[NMS] // ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED // ======================== WINDOWS ============================= @@ -41,9 +49,11 @@ registerCustomOutputTask('Pixel', 'C://Users/repix/Iris Dimension Engine/1.20.4 // ========================== UNIX ============================== registerCustomOutputTaskUnix('CyberpwnLT', '/Users/danielmills/development/server/plugins') registerCustomOutputTaskUnix('PsychoLT', '/Volumes/PRO-G40/Minecraft/MinecraftDevelopment/Server/plugins') +registerCustomOutputTaskUnix('CrazyDev22LT', '/home/julian/Desktop/server/plugins') // ============================================================== def NMS_BINDINGS = Map.of( + "v1_21_R1", "1.21-R0.1-SNAPSHOT", "v1_20_R4", "1.20.6-R0.1-SNAPSHOT", "v1_20_R3", "1.20.4-R0.1-SNAPSHOT", "v1_20_R2", "1.20.2-R0.1-SNAPSHOT", @@ -53,166 +63,29 @@ def NMS_BINDINGS = Map.of( "v1_19_R1", "1.19.2-R0.1-SNAPSHOT" ) def JVM_VERSION = Map.of( + "v1_21_R1", 21, "v1_20_R4", 21, ) -NMS_BINDINGS.each { - def key = it.key - def value = it.value - def nms = value.split("-")[0]; - project(":nms:${key}") { +NMS_BINDINGS.each { nms -> + project(":nms:${nms.key}") { apply plugin: 'java' - apply plugin: 'java-library' - apply plugin: 'de.undercouch.download' + apply plugin: 'com.volmit.nmstools' + + nmsTools { + it.jvm = JVM_VERSION.getOrDefault(nms.key, 17) + it.version = nms.value + } dependencies { implementation project(":core") - compileOnly "org.spigotmc:spigot-api:${value}" - compileOnly "org.bukkit:craftbukkit:${value}:remapped-mojang" //[NMS] - } - def buildToolsJar = new File(rootProject.layout.buildDirectory.asFile.get(), "tools/BuildTools.jar") - def specialSourceJar = new File(rootProject.layout.buildDirectory.asFile.get(), "tools/SpecialSource.jar") - - def buildDir = layout.buildDirectory.asFile.get(); - def buildToolsFolder = new File(buildDir, "buildtools") - def specialSourceFolder = new File(buildDir, "specialsource") - def buildToolsHint = new File(buildDir, "buildtools/craftbukkit-" + nms + ".jar") - - def outputJar = new File(buildDir, "libs/${key}.jar") - def ssiJar = new File(buildDir, "specialsource/${key}.jar") - def ssobfJar = new File(buildDir, "specialsource/${key}-rmo.jar") - def ssJar = new File(buildDir, "specialsource/${key}-rma.jar") - - def homePath = System.properties['user.home'] - def m2 = new File(homePath + "/.m2/repository") - def m2s = m2.getAbsolutePath(); - - // ======================== Building Mapped Jars ============================= - def targetJavaVersion = JVM_VERSION.getOrDefault(key, 17) - def javaVersion = JavaVersion.toVersion(targetJavaVersion) - def javaLanguageVersion = JavaLanguageVersion.of(targetJavaVersion) - project.java.sourceCompatibility = javaVersion - project.java.targetCompatibility = javaVersion - project.java.toolchain.languageVersion = javaLanguageVersion - def launcher = javaToolchains.launcherFor(java.toolchain).get() - def javaHome = launcher.executablePath.getAsFile().parentFile.parentFile.getAbsolutePath() - - tasks.withType(JavaCompile).configureEach { - options.release.set(targetJavaVersion) - } - - tasks.withType(JavaExec).configureEach { - javaLauncher.set(launcher) - } - - ext { - executeBuildTools = new Runnable() { - @Override - void run() { - //Download - if (!buildToolsJar.exists()) { - download.run { - src 'https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar' - dest buildToolsJar - } - } - - //Execute - if (!buildToolsHint.exists()) { - buildToolsFolder.mkdirs() - project.javaexec { - executable = launcher.executablePath - classpath = files(buildToolsJar) - workingDir = buildToolsFolder - args = [ - "--rev", - nms, - "--compile", - "craftbukkit", - "--remap" - ] - def env = new HashMap(environment) - env.put("JAVA_HOME", javaHome) - environment = env - } - } - } - } - } - - tasks.build.doLast { - //Download - if (!specialSourceJar.exists()) { - download.run { - src 'https://repo.maven.apache.org/maven2/net/md-5/SpecialSource/' + specialSourceVersion + '/SpecialSource-'+specialSourceVersion+'-shaded.jar' - dest specialSourceJar - } - } - specialSourceFolder.mkdirs(); - - //Copy - copy { - from outputJar - into specialSourceFolder - } - - //obfuscate - javaexec { - executable = launcher.executablePath - workingDir = specialSourceFolder - classpath = files(specialSourceJar, - new File(m2s + "/org/spigotmc/spigot/" + value + "/spigot-" + value + "-remapped-mojang.jar")) - mainClass = "net.md_5.specialsource.SpecialSource" - args = [ - "--live", - "-i", - ssiJar.getName(), - "-o", - ssobfJar.getName(), - "-m", - m2s + "/org/spigotmc/minecraft-server/" + value + "/minecraft-server-" + value + "-maps-mojang.txt", - "--reverse", - ] - def env = new HashMap(environment) - env.put("JAVA_HOME", javaHome) - environment = env - } - - //remap - javaexec { - executable = launcher.executablePath - workingDir = specialSourceFolder - classpath = files(specialSourceJar, - new File(m2s + "/org/spigotmc/spigot/" + value + "/spigot-" + value + "-remapped-obf.jar")) - mainClass = "net.md_5.specialsource.SpecialSource" - args = [ - "--live", - "-i", - ssobfJar.getName(), - "-o", - ssJar.getName(), - "-m", - m2s + "/org/spigotmc/minecraft-server/" + value + "/minecraft-server-" + value + "-maps-spigot.csrg" - ] - def env = new HashMap(environment) - env.put("JAVA_HOME", javaHome) - environment = env - } - //copy - copy { - from ssJar - into outputJar.getParentFile() - rename { - outputJar.getName() - } - } } } } shadowJar { NMS_BINDINGS.each { - dependsOn(":nms:${it.key}:build") - from("${project(":nms:${it.key}").layout.buildDirectory.asFile.get()}/libs/${it.key}.jar") + dependsOn(":nms:${it.key}:remap") + from("${project(":nms:${it.key}").layout.buildDirectory.asFile.get()}/libs/${it.key}-mapped.jar") } NMS_BINDINGS.each {dependsOn(":nms:${it.key}:build")} //dependsOn(':com.volmit.gui:build') @@ -238,12 +111,6 @@ allprojects { apply plugin: 'java' repositories { - mavenLocal { - content { - includeGroup("org.bukkit") - includeGroup("org.spigotmc") - } - } mavenCentral() maven { url "https://repo.papermc.io/repository/maven-public/"} maven { url "https://repo.codemc.org/repository/maven-public" } @@ -255,6 +122,7 @@ allprojects { maven { url "https://repo.triumphteam.dev/snapshots" } maven { url "https://repo.mineinabyss.com/releases" } maven { url 'https://hub.jeff-media.com/nexus/repository/jeff-media-public/' } + maven { url "https://repo.oraxen.com/releases" } } dependencies { @@ -324,31 +192,6 @@ task iris(type: Copy) { dependsOn(build) } -task setup() { - group "iris" - dependsOn(clean) - NMS_BINDINGS.each { - dependsOn(":nms:${it.key}:clean"); - } - - doLast { - NMS_BINDINGS.each { - project(":nms:${it.key}").property("executeBuildTools").run(); - } - } -} - -NMS_BINDINGS.keySet().forEach { - def nms = it - tasks.register("setup-${nms}") { - group "iris" - dependsOn(":nms:${nms}:clean") - doLast { - project(":nms:${nms}").property("executeBuildTools").run(); - } - } -} - def registerCustomOutputTask(name, path) { if (!System.properties['os.name'].toLowerCase().contains('windows')) { return; diff --git a/core/build.gradle b/core/build.gradle index d1c25950d..70d2adbc7 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -62,7 +62,7 @@ dependencies { // Third Party Integrations compileOnly 'com.ticxo.playeranimator:PlayerAnimator:R1.2.7' - compileOnly 'com.github.oraxen:oraxen:1.158.0' + compileOnly 'io.th0rgal:oraxen:1.173.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' diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java index 7f6a0786f..f4c2d1465 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java @@ -76,6 +76,7 @@ import java.util.zip.GZIPOutputStream; @Decree(name = "Developer", origin = DecreeOrigin.BOTH, description = "Iris World Manager", aliases = {"dev"}) public class CommandDeveloper implements DecreeExecutor { private CommandTurboPregen turboPregen; + private CommandUpdater updater; @Decree(description = "Get Loaded TectonicPlates Count", origin = DecreeOrigin.BOTH, sync = true) public void EngineStatus() { @@ -164,18 +165,6 @@ public class CommandDeveloper implements DecreeExecutor { } - @Decree(description = "Test") - public void updater( - @Param(description = "Updater for chunks") - World world - ) { - Iris.info("test"); - ChunkUpdater updater = new ChunkUpdater(world); - updater.start(); - - - } - @Decree(description = "test") public void mca ( @Param(description = "String") World world) { diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandUpdater.java b/core/src/main/java/com/volmit/iris/core/commands/CommandUpdater.java index cb1ff6eeb..bd910ad5d 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandUpdater.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandUpdater.java @@ -30,13 +30,13 @@ import com.volmit.iris.util.decree.annotations.Param; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; -@Decree(name = "Updater", origin = DecreeOrigin.BOTH, description = "Iris World Updater") +@Decree(name = "updater", origin = DecreeOrigin.BOTH, description = "Iris World Updater") public class CommandUpdater implements DecreeExecutor { private ChunkUpdater chunkUpdater; @Decree(description = "Updates all chunk in the specified world") public void start( - @Param(description = "World to update chunks at") + @Param(description = "World to update chunks at", contextual = true) World world ) { if (!IrisToolbelt.isIrisWorld(world)) { diff --git a/core/src/main/java/com/volmit/iris/core/link/EcoItemsDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/EcoItemsDataProvider.java index 615256e66..d42684e7e 100644 --- a/core/src/main/java/com/volmit/iris/core/link/EcoItemsDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/EcoItemsDataProvider.java @@ -2,6 +2,7 @@ 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 com.volmit.iris.util.reflect.WrappedField; import com.willfp.ecoitems.items.EcoItem; import com.willfp.ecoitems.items.EcoItems; @@ -33,12 +34,12 @@ public class EcoItemsDataProvider extends ExternalDataProvider { } @Override - public BlockData getBlockData(Identifier blockId) throws MissingResourceException { + public BlockData getBlockData(Identifier blockId, KMap state) throws MissingResourceException { throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); } @Override - public ItemStack getItemStack(Identifier itemId) throws MissingResourceException { + public ItemStack getItemStack(Identifier itemId, KMap customNbt) throws MissingResourceException { EcoItem item = EcoItems.INSTANCE.getByID(itemId.key()); if (item == null) throw new MissingResourceException("Failed to find Item!", itemId.namespace(), itemId.key()); return itemStack.get(item).clone(); diff --git a/core/src/main/java/com/volmit/iris/core/link/ExecutableItemsDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/ExecutableItemsDataProvider.java index 8112a4595..27a3251b2 100644 --- a/core/src/main/java/com/volmit/iris/core/link/ExecutableItemsDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/ExecutableItemsDataProvider.java @@ -3,6 +3,7 @@ package com.volmit.iris.core.link; import com.ssomar.score.api.executableitems.ExecutableItemsAPI; import com.volmit.iris.Iris; import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; @@ -20,12 +21,12 @@ public class ExecutableItemsDataProvider extends ExternalDataProvider { } @Override - public BlockData getBlockData(Identifier blockId) throws MissingResourceException { + public BlockData getBlockData(Identifier blockId, KMap state) throws MissingResourceException { throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); } @Override - public ItemStack getItemStack(Identifier itemId) throws MissingResourceException { + public ItemStack getItemStack(Identifier itemId, KMap customNbt) throws MissingResourceException { return ExecutableItemsAPI.getExecutableItemsManager().getExecutableItem(itemId.key()) .map(item -> item.buildItem(1, Optional.empty())) .orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key())); 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 7e3b4d00e..77e2b9c90 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,6 +1,7 @@ package com.volmit.iris.core.link; import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.util.collection.KMap; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.bukkit.Bukkit; @@ -27,10 +28,19 @@ public abstract class ExternalDataProvider { public abstract void init(); - public abstract BlockData getBlockData(Identifier blockId) throws MissingResourceException; + public BlockData getBlockData(Identifier blockId) throws MissingResourceException { + return getBlockData(blockId, new KMap<>()); + } - public abstract ItemStack getItemStack(Identifier itemId) throws MissingResourceException; - public void processUpdate(Engine engine, Block block, Identifier blockId) {}; + public abstract BlockData getBlockData(Identifier blockId, KMap state) throws MissingResourceException; + + public ItemStack getItemStack(Identifier itemId) throws MissingResourceException { + return getItemStack(itemId, new KMap<>()); + } + + public abstract ItemStack getItemStack(Identifier itemId, KMap customNbt) throws MissingResourceException; + + public void processUpdate(Engine engine, Block block, Identifier blockId) {} public abstract Identifier[] getBlockTypes(); diff --git a/core/src/main/java/com/volmit/iris/core/link/HMCLeavesDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/HMCLeavesDataProvider.java index 44c695a28..21207a22f 100644 --- a/core/src/main/java/com/volmit/iris/core/link/HMCLeavesDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/HMCLeavesDataProvider.java @@ -2,8 +2,10 @@ package com.volmit.iris.core.link; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; +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.IrisBlockData; import com.volmit.iris.util.reflect.WrappedField; import com.volmit.iris.util.reflect.WrappedReturningMethod; @@ -50,7 +52,7 @@ public class HMCLeavesDataProvider extends ExternalDataProvider { } @Override - public BlockData getBlockData(Identifier blockId) throws MissingResourceException { + public BlockData getBlockData(Identifier blockId, KMap state) throws MissingResourceException { Object o = blockDataMap.get(blockId.key()); if (o == null) throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); @@ -60,11 +62,11 @@ public class HMCLeavesDataProvider extends ExternalDataProvider { BlockData blockData = Bukkit.createBlockData(material); if (IrisSettings.get().getGenerator().preventLeafDecay && blockData instanceof Leaves leaves) leaves.setPersistent(true); - return new IrisBlockData(blockData, blockId); + return new IrisBlockData(blockData, ExternalDataSVC.buildState(blockId, state)); } @Override - public ItemStack getItemStack(Identifier itemId) throws MissingResourceException { + public ItemStack getItemStack(Identifier itemId, KMap customNbt) throws MissingResourceException { if (!itemDataField.containsKey(itemId.key())) throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); return itemDataField.get(itemId.key()).get(); @@ -72,6 +74,8 @@ public class HMCLeavesDataProvider extends ExternalDataProvider { @Override public void processUpdate(Engine engine, Block block, Identifier blockId) { + var pair = ExternalDataSVC.parseState(blockId); + blockId = pair.getA(); Boolean result = setCustomBlock.invoke(apiInstance, new Object[]{block.getLocation(), blockId.key(), false}); if (result == null || !result) Iris.warn("Failed to set custom block! " + blockId.key() + " " + block.getX() + " " + block.getY() + " " + block.getZ()); diff --git a/core/src/main/java/com/volmit/iris/core/link/ItemAdderDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/ItemAdderDataProvider.java index 67f594323..e08e8fd7d 100644 --- a/core/src/main/java/com/volmit/iris/core/link/ItemAdderDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/ItemAdderDataProvider.java @@ -2,6 +2,7 @@ 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; @@ -32,12 +33,12 @@ public class ItemAdderDataProvider extends ExternalDataProvider { } @Override - public BlockData getBlockData(Identifier blockId) throws MissingResourceException { + public BlockData getBlockData(Identifier blockId, KMap state) throws MissingResourceException { return CustomBlock.getBaseBlockData(blockId.toString()); } @Override - public ItemStack getItemStack(Identifier itemId) throws MissingResourceException { + public ItemStack getItemStack(Identifier itemId, KMap customNbt) throws MissingResourceException { CustomStack stack = CustomStack.getInstance(itemId.toString()); if (stack == null) { throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); diff --git a/core/src/main/java/com/volmit/iris/core/link/MMOItemsDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/MMOItemsDataProvider.java index 4445f3e9d..b402f32ab 100644 --- a/core/src/main/java/com/volmit/iris/core/link/MMOItemsDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/MMOItemsDataProvider.java @@ -2,6 +2,7 @@ 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 com.volmit.iris.util.scheduling.J; import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.Type; @@ -26,7 +27,7 @@ public class MMOItemsDataProvider extends ExternalDataProvider { } @Override - public BlockData getBlockData(Identifier blockId) throws MissingResourceException { + public BlockData getBlockData(Identifier blockId, KMap state) throws MissingResourceException { int id = -1; try { id = Integer.parseInt(blockId.key()); @@ -37,12 +38,33 @@ public class MMOItemsDataProvider extends ExternalDataProvider { } @Override - public ItemStack getItemStack(Identifier itemId) throws MissingResourceException { + public ItemStack getItemStack(Identifier itemId, KMap customNbt) throws MissingResourceException { String[] parts = itemId.namespace().split("_", 2); if (parts.length != 2) throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); CompletableFuture future = new CompletableFuture<>(); - Runnable run = () -> future.complete(api().getItem(parts[1], itemId.key())); + Runnable run = () -> { + try { + var type = api().getTypes().get(parts[1]); + int level = customNbt.containsKey("level") ? (int) customNbt.get("level") : -1; + var tier = api().getTiers().get(String.valueOf(customNbt.get("tier"))); + + ItemStack itemStack; + if (type == null) { + future.complete(null); + return; + } + + if (level != -1 && tier != null) { + itemStack = api().getItem(type, itemId.key(), level, tier); + } else { + itemStack = api().getItem(type, itemId.key()); + } + future.complete(itemStack); + } catch (Throwable e) { + future.completeExceptionally(e); + } + }; if (Bukkit.isPrimaryThread()) run.run(); else J.s(run); ItemStack item = null; diff --git a/core/src/main/java/com/volmit/iris/core/link/OraxenDataProvider.java b/core/src/main/java/com/volmit/iris/core/link/OraxenDataProvider.java index 58e21883d..233701866 100644 --- a/core/src/main/java/com/volmit/iris/core/link/OraxenDataProvider.java +++ b/core/src/main/java/com/volmit/iris/core/link/OraxenDataProvider.java @@ -19,10 +19,16 @@ package com.volmit.iris.core.link; import com.volmit.iris.Iris; +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.IrisBlockData; +import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.reflect.WrappedField; import io.th0rgal.oraxen.api.OraxenItems; import io.th0rgal.oraxen.items.ItemBuilder; @@ -36,15 +42,22 @@ import io.th0rgal.oraxen.mechanics.provided.gameplay.furniture.FurnitureMechanic import io.th0rgal.oraxen.mechanics.provided.gameplay.noteblock.NoteBlockMechanicFactory; import io.th0rgal.oraxen.mechanics.provided.gameplay.stringblock.StringBlockMechanicFactory; import org.bukkit.Bukkit; +import org.bukkit.Color; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.MultipleFacing; +import org.bukkit.entity.Entity; +import org.bukkit.entity.ItemDisplay; +import org.bukkit.entity.ItemFrame; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.PotionMeta; import java.util.Map; import java.util.MissingResourceException; import java.util.Optional; +import java.util.function.Consumer; public class OraxenDataProvider extends ExternalDataProvider { @@ -66,7 +79,7 @@ public class OraxenDataProvider extends ExternalDataProvider { } @Override - public BlockData getBlockData(Identifier blockId) throws MissingResourceException { + public BlockData getBlockData(Identifier blockId, KMap state) throws MissingResourceException { MechanicFactory factory = getFactory(blockId); if (factory instanceof NoteBlockMechanicFactory f) return f.createNoteBlockData(blockId.key()); @@ -77,22 +90,71 @@ public class OraxenDataProvider extends ExternalDataProvider { } else if (factory instanceof StringBlockMechanicFactory f) { return f.createTripwireData(blockId.key()); } else if (factory instanceof FurnitureFactory) { - return new IrisBlockData(B.getAir(), blockId); + return new IrisBlockData(B.getAir(), ExternalDataSVC.buildState(blockId, state)); } else throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); } @Override - public ItemStack getItemStack(Identifier itemId) throws MissingResourceException { + public ItemStack getItemStack(Identifier itemId, KMap customNbt) throws MissingResourceException { Optional opt = OraxenItems.getOptionalItemById(itemId.key()); return opt.orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key())).build(); } @Override public void processUpdate(Engine engine, Block block, Identifier blockId) { + var pair = ExternalDataSVC.parseState(blockId); + var state = pair.getB(); + blockId = pair.getA(); Mechanic mechanic = getFactory(blockId).getMechanic(blockId.key()); if (mechanic instanceof FurnitureMechanic f) { - f.place(block.getLocation()); + 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; + } + ItemStack itemStack = OraxenItems.getItemById(f.getItemID()).build(); + Entity entity = f.place(block.getLocation(), itemStack, yaw, face, false); + + Consumer setter = null; + if (entity instanceof ItemFrame frame) { + itemStack = frame.getItem(); + setter = frame::setItem; + } else if (entity instanceof ItemDisplay display) { + itemStack = display.getItemStack(); + setter = display::setItemStack; + } + if (setter == null || itemStack == null) return; + + BiomeColor type = null; + try { + type = BiomeColor.valueOf(state.get("matchBiome").toUpperCase()); + } catch (NullPointerException | IllegalArgumentException ignored) {} + + if (type != null) { + 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); + } + } + setter.accept(itemStack); } } diff --git a/core/src/main/java/com/volmit/iris/core/link/WorldEditLink.java b/core/src/main/java/com/volmit/iris/core/link/WorldEditLink.java index 168b8c066..42e335a10 100644 --- a/core/src/main/java/com/volmit/iris/core/link/WorldEditLink.java +++ b/core/src/main/java/com/volmit/iris/core/link/WorldEditLink.java @@ -1,12 +1,19 @@ package com.volmit.iris.core.link; +import com.volmit.iris.Iris; +import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.util.data.Cuboid; +import com.volmit.iris.util.data.KCache; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Player; +import java.lang.reflect.InvocationTargetException; +import java.time.Duration; +import java.util.UUID; + public class WorldEditLink { - private static Boolean enabled = null; + private static final AtomicCache active = new AtomicCache<>(); public static Cuboid getSelection(Player p) { if (!hasWorldEdit()) @@ -15,29 +22,38 @@ public class WorldEditLink { try { Object instance = Class.forName("com.sk89q.worldedit.WorldEdit").getDeclaredMethod("getInstance").invoke(null); Object sessionManager = instance.getClass().getDeclaredMethod("getSessionManager").invoke(instance); - Object player = Class.forName("com.sk89q.worldedit.bukkit.BukkitAdapter").getDeclaredMethod("adapt", Player.class).invoke(null, p); + Class bukkitAdapter = Class.forName("com.sk89q.worldedit.bukkit.BukkitAdapter"); + Object world = bukkitAdapter.getDeclaredMethod("adapt", World.class).invoke(null, p.getWorld()); + Object player = bukkitAdapter.getDeclaredMethod("adapt", Player.class).invoke(null, p); Object localSession = sessionManager.getClass().getDeclaredMethod("getIfPresent", Class.forName("com.sk89q.worldedit.session.SessionOwner")).invoke(sessionManager, player); - Object world = Class.forName("com.sk89q.worldedit.bukkit.BukkitAdapter").getDeclaredMethod("adapt", World.class).invoke(null, p.getWorld()); - Object region = localSession.getClass().getDeclaredMethod("getSelection", world.getClass()).invoke(localSession, world); + if (localSession == null) return null; + + Object region = null; + try { + region = localSession.getClass().getDeclaredMethod("getSelection", Class.forName("com.sk89q.worldedit.world.World")).invoke(localSession, world); + } catch (InvocationTargetException ignored) {} + if (region == null) return null; + Object min = region.getClass().getDeclaredMethod("getMinimumPoint").invoke(region); Object max = region.getClass().getDeclaredMethod("getMaximumPoint").invoke(region); return new Cuboid(p.getWorld(), - (int) min.getClass().getDeclaredMethod("getX").invoke(min), - (int) min.getClass().getDeclaredMethod("getY").invoke(min), - (int) min.getClass().getDeclaredMethod("getZ").invoke(min), - (int) min.getClass().getDeclaredMethod("getX").invoke(max), - (int) min.getClass().getDeclaredMethod("getY").invoke(max), - (int) min.getClass().getDeclaredMethod("getZ").invoke(max) + (int) min.getClass().getDeclaredMethod("x").invoke(min), + (int) min.getClass().getDeclaredMethod("y").invoke(min), + (int) min.getClass().getDeclaredMethod("z").invoke(min), + (int) min.getClass().getDeclaredMethod("x").invoke(max), + (int) min.getClass().getDeclaredMethod("y").invoke(max), + (int) min.getClass().getDeclaredMethod("z").invoke(max) ); - } catch (Throwable ignored) { - + } catch (Throwable e) { + Iris.error("Could not get selection"); + e.printStackTrace(); + active.reset(); + active.aquire(() -> false); } return null; } public static boolean hasWorldEdit() { - if (enabled == null) - enabled = Bukkit.getPluginManager().isPluginEnabled("WorldEdit"); - return enabled; + return active.aquire(() -> Bukkit.getPluginManager().isPluginEnabled("WorldEdit")); } } diff --git a/core/src/main/java/com/volmit/iris/core/loader/ResourceLoader.java b/core/src/main/java/com/volmit/iris/core/loader/ResourceLoader.java index dd0a1b068..6575abd37 100644 --- a/core/src/main/java/com/volmit/iris/core/loader/ResourceLoader.java +++ b/core/src/main/java/com/volmit/iris/core/loader/ResourceLoader.java @@ -362,7 +362,12 @@ public class ResourceLoader implements MeteredCache { if (folderCache.get() == null) { KList fc = new KList<>(); - for (File i : root.listFiles()) { + File[] files = root.listFiles(); + if (files == null) { + throw new IllegalStateException("Failed to list files in " + root); + } + + for (File i : files) { if (i.isDirectory()) { if (i.getName().equals(folderName)) { fc.add(i); 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 85b3778e9..36b26dcb9 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 @@ -28,7 +28,8 @@ 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.20.6", "v1_20_R4", + "1.21", "v1_21_R1" ); //@done private static final INMSBinding binding = bind(); 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 7f72c84d7..0ad25e7b2 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java +++ b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java @@ -18,6 +18,7 @@ package com.volmit.iris.core.nms; +import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisBiomeCustom; @@ -41,6 +42,8 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import java.awt.*; + public interface INMSBinding { boolean hasTile(Location l); @@ -114,6 +117,8 @@ public interface INMSBinding { Entity spawnEntity(Location location, EntityType type, CreatureSpawnEvent.SpawnReason reason); + Color getBiomeColor(Location location, BiomeColor type); + default DataVersion getDataVersion() { return DataVersion.V1192; } diff --git a/core/src/main/java/com/volmit/iris/core/nms/container/BiomeColor.java b/core/src/main/java/com/volmit/iris/core/nms/container/BiomeColor.java new file mode 100644 index 000000000..58bc4a5a1 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/nms/container/BiomeColor.java @@ -0,0 +1,10 @@ +package com.volmit.iris.core.nms.container; + +public enum BiomeColor { + FOG, + WATER, + WATER_FOG, + SKY, + FOLIAGE, + GRASS +} 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 d54ee7f6a..e52e80a44 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.google.common.base.Preconditions; 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.container.BlockPos; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisBiomeCustom; @@ -49,6 +50,8 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import java.awt.*; + import java.io.File; public class NMSBinding1X implements INMSBinding { @@ -118,6 +121,11 @@ public class NMSBinding1X implements INMSBinding { return false; } + @Override + public Color getBiomeColor(Location location, BiomeColor type) { + return Color.GREEN; + } + @Override public void deserializeTile(CompoundTag s, Location newPosition) { 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 e70e1c1d4..4c31f2312 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,8 +20,10 @@ package com.volmit.iris.core.service; import com.volmit.iris.Iris; import com.volmit.iris.core.link.*; +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.plugin.IrisService; import lombok.Data; import org.bukkit.Bukkit; @@ -31,8 +33,8 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.inventory.ItemStack; -import java.util.MissingResourceException; -import java.util.Optional; +import java.util.*; +import java.util.stream.Collectors; @Data public class ExternalDataSVC implements IrisService { @@ -93,26 +95,29 @@ public class ExternalDataSVC implements IrisService { } } - public Optional getBlockData(Identifier key) { - Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(key, false)).findFirst(); + public Optional getBlockData(final Identifier key) { + var pair = parseState(key); + Identifier mod = pair.getA(); + + Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(mod, false)).findFirst(); if (provider.isEmpty()) return Optional.empty(); try { - return Optional.of(provider.get().getBlockData(key)); + return Optional.of(provider.get().getBlockData(mod, pair.getB())); } catch (MissingResourceException e) { Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]"); return Optional.empty(); } } - public Optional getItemStack(Identifier key) { + public Optional getItemStack(Identifier key, KMap customNbt) { Optional provider = activeProviders.stream().filter(p -> p.isValidProvider(key, true)).findFirst(); if (provider.isEmpty()) { Iris.warn("No matching Provider found for modded material \"%s\"!", key); return Optional.empty(); } try { - return Optional.of(provider.get().getItemStack(key)); + return Optional.of(provider.get().getItemStack(key, customNbt)); } catch (MissingResourceException e) { Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]"); return Optional.empty(); @@ -139,4 +144,27 @@ public class ExternalDataSVC implements IrisService { activeProviders.forEach(p -> names.add(p.getItemTypes())); return names.toArray(new Identifier[0]); } + + public static Pair> parseState(Identifier key) { + if (!key.key().contains("[") || !key.key().contains("]")) { + return new Pair<>(key, new KMap<>()); + } + String state = key.key().split("\\Q[\\E")[1].split("\\Q]\\E")[0]; + KMap stateMap = new KMap<>(); + if (!state.isEmpty()) { + Arrays.stream(state.split(",")).forEach(s -> stateMap.put(s.split("=")[0], s.split("=")[1])); + } + return new Pair<>(new Identifier(key.namespace(), key.key().split("\\Q[\\E")[0]), stateMap); + } + + public static Identifier buildState(Identifier key, KMap state) { + if (state.isEmpty()) { + return key; + } + String path = state.entrySet() + .stream() + .map(e -> e.getKey() + "=" + e.getValue()) + .collect(Collectors.joining(",", key.key() + "[", "]")); + return new Identifier(key.namespace(), path); + } } diff --git a/core/src/main/java/com/volmit/iris/core/service/TreeSVC.java b/core/src/main/java/com/volmit/iris/core/service/TreeSVC.java index edbf05993..72b5593c4 100644 --- a/core/src/main/java/com/volmit/iris/core/service/TreeSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/TreeSVC.java @@ -240,7 +240,7 @@ public class TreeSVC implements IrisService { boolean isUseAll = worldAccess.getEngine().getDimension().getTreeSettings().getMode().equals(IrisTreeModes.ALL); // Retrieve objectPlacements of type `species` from biome - IrisBiome biome = worldAccess.getEngine().getBiome(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + IrisBiome biome = worldAccess.getEngine().getBiome(location.getBlockX(), location.getBlockY()-worldAccess.getTarget().getWorld().minHeight(), location.getBlockZ()); placements.addAll(matchObjectPlacements(biome.getObjects(), size, type)); // Add more or find any in the region diff --git a/core/src/main/java/com/volmit/iris/core/service/WandSVC.java b/core/src/main/java/com/volmit/iris/core/service/WandSVC.java index e71392c89..559d3629f 100644 --- a/core/src/main/java/com/volmit/iris/core/service/WandSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/WandSVC.java @@ -318,7 +318,7 @@ public class WandSVC implements IrisService { Vector gx = Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65); d[0].getWorld().spawnParticle(CRIT_MAGIC, d[0], 1, 0.5 + gx.getX(), 0.5 + gx.getY(), 0.5 + gx.getZ(), 0, null, false); Vector gxx = Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65); - d[1].getWorld().spawnParticle(Particle.CRIT, d[1], 1, 0.5 + gxx.getX(), 0.5 + gxx.getY(), 0.5 + gxx.getZ(), 0, null, false); + d[1].getWorld().spawnParticle(CRIT_MAGIC, d[1], 1, 0.5 + gxx.getX(), 0.5 + gxx.getY(), 0.5 + gxx.getZ(), 0, null, false); if (!d[0].getWorld().equals(d[1].getWorld())) { return; @@ -388,7 +388,7 @@ public class WandSVC implements IrisService { if (e.getHand() != EquipmentSlot.HAND) return; try { - if (isHoldingWand(e.getPlayer())) { + if (isHoldingIrisWand(e.getPlayer())) { if (e.getAction().equals(Action.LEFT_CLICK_BLOCK)) { e.setCancelled(true); e.getPlayer().getInventory().setItemInMainHand(update(true, Objects.requireNonNull(e.getClickedBlock()).getLocation(), e.getPlayer().getInventory().getItemInMainHand())); 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 3b271951f..cc3dc996e 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisComplex.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisComplex.java @@ -124,6 +124,7 @@ public class IrisComplex implements DataProvider { ProceduralStream.of((x, z) -> focusRegion, Interpolated.of(a -> 0D, a -> focusRegion)) : regionStyleStream + .zoom(engine.getDimension().getRegionZoom()) .selectRarity(data.getRegionLoader().loadAll(engine.getDimension().getRegions())) .cache2D("regionStream", engine, cacheSize).waste("Region Stream"); regionIDStream = regionIdentityStream.convertCached((i) -> new UUID(Double.doubleToLongBits(i), @@ -131,6 +132,7 @@ public class IrisComplex implements DataProvider { caveBiomeStream = regionStream.contextInjecting((c, x, z) -> IrisContext.getOr(engine).getChunkContext().getRegion().get(x, z)) .convert((r) -> engine.getDimension().getCaveBiomeStyle().create(rng.nextParallelRNG(InferredType.CAVE.ordinal()), getData()).stream() + .zoom(engine.getDimension().getBiomeZoom()) .zoom(r.getCaveBiomeZoom()) .selectRarity(data.getBiomeLoader().loadAll(r.getCaveBiomes())) .onNull(emptyBiome) @@ -139,6 +141,8 @@ public class IrisComplex implements DataProvider { landBiomeStream = regionStream.contextInjecting((c, x, z) -> IrisContext.getOr(engine).getChunkContext().getRegion().get(x, z)) .convert((r) -> engine.getDimension().getLandBiomeStyle().create(rng.nextParallelRNG(InferredType.LAND.ordinal()), getData()).stream() + .zoom(engine.getDimension().getBiomeZoom()) + .zoom(engine.getDimension().getLandZoom()) .zoom(r.getLandBiomeZoom()) .selectRarity(data.getBiomeLoader().loadAll(r.getLandBiomes(), (t) -> t.setInferredType(InferredType.LAND))) ).convertAware2D(ProceduralStream::get) @@ -147,6 +151,8 @@ public class IrisComplex implements DataProvider { seaBiomeStream = regionStream.contextInjecting((c, x, z) -> IrisContext.getOr(engine).getChunkContext().getRegion().get(x, z)) .convert((r) -> engine.getDimension().getSeaBiomeStyle().create(rng.nextParallelRNG(InferredType.SEA.ordinal()), getData()).stream() + .zoom(engine.getDimension().getBiomeZoom()) + .zoom(engine.getDimension().getSeaZoom()) .zoom(r.getSeaBiomeZoom()) .selectRarity(data.getBiomeLoader().loadAll(r.getSeaBiomes(), (t) -> t.setInferredType(InferredType.SEA))) ).convertAware2D(ProceduralStream::get) @@ -155,6 +161,7 @@ public class IrisComplex implements DataProvider { shoreBiomeStream = regionStream.contextInjecting((c, x, z) -> IrisContext.getOr(engine).getChunkContext().getRegion().get(x, z)) .convert((r) -> engine.getDimension().getShoreBiomeStyle().create(rng.nextParallelRNG(InferredType.SHORE.ordinal()), getData()).stream() + .zoom(engine.getDimension().getBiomeZoom()) .zoom(r.getShoreBiomeZoom()) .selectRarity(data.getBiomeLoader().loadAll(r.getShoreBiomes(), (t) -> t.setInferredType(InferredType.SHORE))) ).convertAware2D(ProceduralStream::get).cache2D("shoreBiomeStream", engine, cacheSize).waste("Shore Biome Stream"); diff --git a/core/src/main/java/com/volmit/iris/engine/decorator/IrisSeaFloorDecorator.java b/core/src/main/java/com/volmit/iris/engine/decorator/IrisSeaFloorDecorator.java index b7aa7298e..27b69ecc2 100644 --- a/core/src/main/java/com/volmit/iris/engine/decorator/IrisSeaFloorDecorator.java +++ b/core/src/main/java/com/volmit/iris/engine/decorator/IrisSeaFloorDecorator.java @@ -39,6 +39,10 @@ public class IrisSeaFloorDecorator extends IrisEngineDecorator { if (decorator != null) { if (!decorator.isStacking()) { + if (!decorator.isForcePlace() && !decorator.getSlopeCondition().isDefault() + && !decorator.getSlopeCondition().isValid(getComplex().getSlopeStream().get(realX, realZ))) { + return; + } if (height >= 0 || height < getEngine().getHeight()) { if (null != decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())) { if (height == getDimension().getFluidHeight() - 1) { diff --git a/core/src/main/java/com/volmit/iris/engine/decorator/IrisShoreLineDecorator.java b/core/src/main/java/com/volmit/iris/engine/decorator/IrisShoreLineDecorator.java index bd8bb2ef2..6585f0a40 100644 --- a/core/src/main/java/com/volmit/iris/engine/decorator/IrisShoreLineDecorator.java +++ b/core/src/main/java/com/volmit/iris/engine/decorator/IrisShoreLineDecorator.java @@ -45,6 +45,11 @@ public class IrisShoreLineDecorator extends IrisEngineDecorator { IrisDecorator decorator = getDecorator(biome, realX, realZ); if (decorator != null) { + if (!decorator.isForcePlace() && !decorator.getSlopeCondition().isDefault() + && !decorator.getSlopeCondition().isValid(getComplex().getSlopeStream().get(realX, realZ))) { + return; + } + if (!decorator.isStacking()) { if (null != decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())) { data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData())); diff --git a/core/src/main/java/com/volmit/iris/engine/decorator/IrisSurfaceDecorator.java b/core/src/main/java/com/volmit/iris/engine/decorator/IrisSurfaceDecorator.java index fce2e413c..49e636220 100644 --- a/core/src/main/java/com/volmit/iris/engine/decorator/IrisSurfaceDecorator.java +++ b/core/src/main/java/com/volmit/iris/engine/decorator/IrisSurfaceDecorator.java @@ -53,6 +53,11 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator { boolean underwater = height < getDimension().getFluidHeight(); if (decorator != null) { + if (!decorator.isForcePlace() && !decorator.getSlopeCondition().isDefault() + && !decorator.getSlopeCondition().isValid(getComplex().getSlopeStream().get(realX, realZ))) { + return; + } + if (!decorator.isStacking()) { bd = decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()); 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 0809d0932..6ea338104 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 @@ -269,77 +269,80 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat @ChunkCoordinates @Override default void updateChunk(Chunk c) { - if (c.getWorld().isChunkLoaded(c.getX() + 1, c.getZ() + 1) - && c.getWorld().isChunkLoaded(c.getX(), c.getZ() + 1) - && c.getWorld().isChunkLoaded(c.getX() + 1, c.getZ()) - && c.getWorld().isChunkLoaded(c.getX() - 1, c.getZ() - 1) - && c.getWorld().isChunkLoaded(c.getX(), c.getZ() - 1) - && c.getWorld().isChunkLoaded(c.getX() - 1, c.getZ()) - && c.getWorld().isChunkLoaded(c.getX() + 1, c.getZ() - 1) - && c.getWorld().isChunkLoaded(c.getX() - 1, c.getZ() + 1) && getMantle().getMantle().isLoaded(c)) { - - getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.TILE, () -> J.s(() -> { - getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, tile) -> { - int betterY = y + getWorld().minHeight(); - if (!TileData.setTileState(c.getBlock(x, betterY, z), tile.getData())) - Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), tile.getData().getTileId()); - }); - })); - getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.CUSTOM, () -> J.s(() -> { - getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> { - Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v); - }); - })); - - getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.UPDATE, () -> J.s(() -> { - PrecisionStopwatch p = PrecisionStopwatch.start(); - KMap updates = new KMap<>(); - RNG r = new RNG(Cache.key(c.getX(), c.getZ())); - getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), MatterCavern.class, (x, yf, z, v) -> { - int y = yf + getWorld().minHeight(); - if (!B.isFluid(c.getBlock(x & 15, y, z & 15).getBlockData())) { - return; - } - boolean u = false; - if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.DOWN).getBlockData())) { - u = true; - } else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.WEST).getBlockData())) { - u = true; - } else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.EAST).getBlockData())) { - u = true; - } else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.SOUTH).getBlockData())) { - u = true; - } else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.NORTH).getBlockData())) { - u = true; - } - - if (u) { - updates.compute(Cache.key(x & 15, z & 15), (k, vv) -> { - if (vv != null) { - return Math.max(vv, y); - } - - return y; - }); - } - }); - - updates.forEach((k, v) -> update(Cache.keyX(k), v, Cache.keyZ(k), c, r)); - getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), MatterUpdate.class, (x, yf, z, v) -> { - int y = yf + getWorld().minHeight(); - if (v != null && v.isUpdate()) { - int vx = x & 15; - int vz = z & 15; - update(x, y, z, c, new RNG(Cache.key(c.getX(), c.getZ()))); - if (vx > 0 && vx < 15 && vz > 0 && vz < 15) { - updateLighting(x, y, z, c); - } - } - }); - getMantle().getMantle().deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class); - getMetrics().getUpdates().put(p.getMilliseconds()); - }, RNG.r.i(0, 20))); + for (int x = -1; x <= 1; x++) { + for (int z = -1; z <= 1; z++) { + if (c.getWorld().isChunkLoaded(c.getX() + x, c.getZ() + z)) + continue; + Iris.debug("Chunk %s, %s [%s, %s] is not loaded".formatted(c.getX() + x, c.getZ() + z, x, z)); + return; + } } + if (!getMantle().getMantle().isLoaded(c)) { + Iris.debug("Mantle Chunk " + c.getX() + c.getX() + " is not loaded"); + return; + } + + getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.TILE, () -> J.s(() -> { + getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, tile) -> { + int betterY = y + getWorld().minHeight(); + if (!TileData.setTileState(c.getBlock(x, betterY, z), tile.getData())) + Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), tile.getData().getTileId()); + }); + })); + getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.CUSTOM, () -> J.s(() -> { + getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> { + Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v); + }); + })); + + getMantle().getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.UPDATE, () -> J.s(() -> { + PrecisionStopwatch p = PrecisionStopwatch.start(); + KMap updates = new KMap<>(); + RNG r = new RNG(Cache.key(c.getX(), c.getZ())); + getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), MatterCavern.class, (x, yf, z, v) -> { + int y = yf + getWorld().minHeight(); + if (!B.isFluid(c.getBlock(x & 15, y, z & 15).getBlockData())) { + return; + } + boolean u = false; + if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.DOWN).getBlockData())) { + u = true; + } else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.WEST).getBlockData())) { + u = true; + } else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.EAST).getBlockData())) { + u = true; + } else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.SOUTH).getBlockData())) { + u = true; + } else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.NORTH).getBlockData())) { + u = true; + } + + if (u) { + updates.compute(Cache.key(x & 15, z & 15), (k, vv) -> { + if (vv != null) { + return Math.max(vv, y); + } + + return y; + }); + } + }); + + updates.forEach((k, v) -> update(Cache.keyX(k), v, Cache.keyZ(k), c, r)); + getMantle().getMantle().iterateChunk(c.getX(), c.getZ(), MatterUpdate.class, (x, yf, z, v) -> { + int y = yf + getWorld().minHeight(); + if (v != null && v.isUpdate()) { + int vx = x & 15; + int vz = z & 15; + update(x, y, z, c, new RNG(Cache.key(c.getX(), c.getZ()))); + if (vx > 0 && vx < 15 && vz > 0 && vz < 15) { + updateLighting(x, y, z, c); + } + } + }); + getMantle().getMantle().deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class); + getMetrics().getUpdates().put(p.getMilliseconds()); + }, RNG.r.i(0, 20))); } @BlockCoordinates diff --git a/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java b/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java index 77d4157f7..9ee15169b 100644 --- a/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java +++ b/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java @@ -25,6 +25,7 @@ import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.placer.WorldObjectPlacer; import com.volmit.iris.engine.object.*; import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.RNG; @@ -149,6 +150,9 @@ public class PlannedStructure { return v.place(xx, height, zz, placer, options, rng, (b, data) -> { e.set(b.getX(), b.getY(), b.getZ(), v.getLoadKey() + "@" + id); e.set(b.getX(), b.getY(), b.getZ(), container); + if (data instanceof IrisBlockData d) { + e.set(b.getX(), b.getY(), b.getZ(), d.getCustom()); + } }, null, getData().getEngine() != null ? getData() : eng.getData()) != -1; } 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 8333e796f..d8ee933f0 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 @@ -27,6 +27,7 @@ import com.volmit.iris.engine.object.*; import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.data.B; +import com.volmit.iris.util.data.IrisBlockData; import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.mantle.MantleFlag; @@ -103,6 +104,9 @@ public class MantleObjectComponent extends IrisMantleComponent { if (objectPlacement.isDolphinTarget() && objectPlacement.isUnderwater() && B.isStorageChest(data)) { writer.setData(b.getX(), b.getY(), b.getZ(), MatterStructurePOI.BURIED_TREASURE); } + if (data instanceof IrisBlockData d) { + writer.setData(b.getX(), b.getY(), b.getZ(), d.getCustom()); + } }, null, getData()); } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisDecorator.java b/core/src/main/java/com/volmit/iris/engine/object/IrisDecorator.java index 50f8e112d..8bdd2ec91 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisDecorator.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisDecorator.java @@ -55,6 +55,8 @@ public class IrisDecorator { @ArrayType(min = 1, type = IrisBlockData.class) @Desc("When set, the decorator will never place onto any of these blocks.") private KList blacklist; + @Desc("The slope at which this decorator can be placed. Range from 0 to 10 by default. Calculated from a 3-block radius from the center of the decorator placement.") + private IrisSlopeClip slopeCondition = new IrisSlopeClip(); @DependsOn({"scaleStack", "stackMin", "stackMax"}) @Desc("If stackMax is set to true, use this to limit its max height for large caverns") private int absoluteMaxStack = 30; 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 c0b7dbcd3..6c7c95621 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 @@ -163,7 +163,7 @@ public class IrisDimension extends IrisRegistrant { @MinNumber(0.0001) @MaxNumber(512) @Desc("Zoom in or out the biome size. Higher = bigger biomes") - private double biomeZoom = 5D; + private double biomeZoom = 1D; @MinNumber(0) @MaxNumber(360) @Desc("You can rotate the input coordinates by an angle. This can make terrain appear more natural (less sharp corners and lines). This literally rotates the entire dimension by an angle. Hint: Try 12 degrees or something not on a 90 or 45 degree angle.") diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisLoot.java b/core/src/main/java/com/volmit/iris/engine/object/IrisLoot.java index d7001f233..ae7f5e121 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisLoot.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisLoot.java @@ -29,7 +29,6 @@ import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.data.B; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; -import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.noise.CNG; import lombok.AllArgsConstructor; @@ -146,7 +145,7 @@ public class IrisLoot { // TODO Better Third Party Item Acquisition private ItemStack getItemStack(RNG rng) { if (!type.startsWith("minecraft:") && type.contains(":")) { - Optional opt = Iris.service(ExternalDataSVC.class).getItemStack(Identifier.fromString(type)); + Optional opt = Iris.service(ExternalDataSVC.class).getItemStack(Identifier.fromString(type), customNbt); if (opt.isEmpty()) { Iris.warn("Unknown Material: " + type); return new ItemStack(Material.AIR); diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisLootTable.java b/core/src/main/java/com/volmit/iris/engine/object/IrisLootTable.java index 089ec86fd..38964c72a 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisLootTable.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisLootTable.java @@ -59,6 +59,10 @@ public class IrisLootTable extends IrisRegistrant { @Desc("The minimum amount of loot that can be picked in this table at a time.") private int minPicked = 1; + @MinNumber(1) + @Desc("The maximum amount of tries to generate loot") + private int maxTries = 10; + @Desc("The loot in this table") @ArrayType(min = 1, type = IrisLoot.class) private KList loot = new KList<>(); @@ -67,9 +71,10 @@ public class IrisLootTable extends IrisRegistrant { KList lootf = new KList<>(); int m = 0; + int c = 0; int mx = rng.i(getMinPicked(), getMaxPicked()); - while (m < mx) { + while (m < mx && c++ < getMaxTries()) { int num = rng.i(loot.size()); IrisLoot l = loot.get(num); diff --git a/gradle.properties b/gradle.properties index e6344586b..718870da5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,4 +19,8 @@ org.gradle.daemon=true org.gradle.parallel=true org.gradle.jvmargs=-Xmx3072m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 org.gradle.caching=true -org.gradle.configureondemand=false \ No newline at end of file +org.gradle.configureondemand=false + +nmsTools.useBuildTools=false +nmsTools.repo-url=https://repo.codemc.org/repository/nms/ +nmsTools.specialSourceVersion=1.11.4 \ No newline at end of file diff --git a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java index 264d0abce..aaf718a2f 100644 --- a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java +++ b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java @@ -1,5 +1,6 @@ package com.volmit.iris.core.nms.v1_19_R1; +import java.awt.Color; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -17,6 +18,8 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; +import com.volmit.iris.core.nms.container.BiomeColor; +import net.minecraft.world.level.LevelReader; import com.google.common.base.Preconditions; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -694,6 +697,30 @@ public class NMSBinding implements INMSBinding { } + @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()) { diff --git a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java index 6af6c20bb..e189057c4 100644 --- a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java +++ b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java @@ -1,5 +1,6 @@ package com.volmit.iris.core.nms.v1_19_R2; +import java.awt.Color; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -17,6 +18,8 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; +import com.volmit.iris.core.nms.container.BiomeColor; +import net.minecraft.world.level.LevelReader; import com.google.common.base.Preconditions; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -695,6 +698,30 @@ public class NMSBinding implements INMSBinding { } } + @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()) { diff --git a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java index 4a33fed2d..3b44c0ef8 100644 --- a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java +++ b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java @@ -1,5 +1,6 @@ package com.volmit.iris.core.nms.v1_19_R3; +import java.awt.Color; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -17,6 +18,8 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; +import com.volmit.iris.core.nms.container.BiomeColor; +import net.minecraft.world.level.LevelReader; import com.google.common.base.Preconditions; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -699,6 +702,30 @@ public class NMSBinding implements INMSBinding { } } + @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()) { 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 1451edd92..c90ca78b0 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 @@ -10,6 +10,7 @@ import com.mojang.serialization.JsonOps; import com.mojang.serialization.Lifecycle; 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.object.IrisBiomeCustom; @@ -44,6 +45,8 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityDimensions; +import net.minecraft.world.level.LevelReader; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.util.GsonHelper; import net.minecraft.world.RandomSequences; @@ -79,6 +82,7 @@ import org.bukkit.inventory.ItemStack; 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; @@ -696,6 +700,30 @@ public class NMSBinding implements INMSBinding { biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource); } + @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()) { 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 d74e7c125..378c7c9fc 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,5 +1,6 @@ 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; @@ -17,6 +18,8 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; +import com.volmit.iris.core.nms.container.BiomeColor; +import net.minecraft.world.level.LevelReader; import com.google.common.base.Preconditions; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -697,6 +700,30 @@ public class NMSBinding implements INMSBinding { } + @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()) { 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 79ec5e942..9ee990ce6 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,5 +1,6 @@ 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; @@ -50,6 +51,8 @@ import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; +import com.volmit.iris.core.nms.container.BiomeColor; +import net.minecraft.world.level.LevelReader; import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; @@ -706,6 +709,30 @@ public class NMSBinding implements INMSBinding { } } + @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()) { 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 1ecfd0f7e..dd776ad0d 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,5 +1,6 @@ package com.volmit.iris.core.nms.v1_20_R4; +import java.awt.Color; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -17,6 +18,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; +import com.volmit.iris.core.nms.container.BiomeColor; import com.google.common.base.Preconditions; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -40,6 +42,7 @@ import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.util.GsonHelper; import net.minecraft.world.RandomSequences; import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.Level; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.dimension.DimensionType; @@ -555,6 +558,30 @@ public class NMSBinding implements INMSBinding { 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()) { diff --git a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/CustomBiomeSource.java b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/CustomBiomeSource.java new file mode 100644 index 000000000..464b9f57f --- /dev/null +++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/CustomBiomeSource.java @@ -0,0 +1,168 @@ +package com.volmit.iris.core.nms.v1_21_R1; + +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_R1.CraftServer; +import org.bukkit.craftbukkit.v1_21_R1.CraftWorld; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +public class CustomBiomeSource extends BiomeSource { + + private final long seed; + private final Engine engine; + private final Registry biomeCustomRegistry; + private final Registry biomeRegistry; + private final AtomicCache registryAccess = new AtomicCache<>(); + private final RNG rng; + private final KMap> customBiomes; + + public CustomBiomeSource(long seed, Engine engine, World world) { + this.engine = engine; + this.seed = seed; + this.biomeCustomRegistry = registry().registry(Registries.BIOME).orElse(null); + this.biomeRegistry = ((RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer())).registry(Registries.BIOME).orElse(null); + this.rng = new RNG(engine.getSeedManager().getBiome()); + this.customBiomes = fillCustomBiomes(biomeCustomRegistry, engine); + } + + private static List> getAllBiomes(Registry customRegistry, Registry registry, Engine engine) { + List> b = new ArrayList<>(); + + for (IrisBiome i : engine.getAllBiomes()) { + if (i.isCustom()) { + for (IrisBiomeCustom j : i.getCustomDerivitives()) { + b.add(customRegistry.getHolder(customRegistry.getResourceKey(customRegistry + .get(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())) + .registry(Registries.BIOME).orElse(null), + ((CraftWorld) engine.getWorld().realWorld()).getHandle().registryAccess().registry(Registries.BIOME).orElse(null), + engine).stream(); + } + private KMap> fillCustomBiomes(Registry customRegistry, Engine engine) { + KMap> m = new KMap<>(); + + for (IrisBiome i : engine.getAllBiomes()) { + if (i.isCustom()) { + for (IrisBiomeCustom j : i.getCustomDerivitives()) { + ResourceLocation resourceLocation = ResourceLocation.fromNamespaceAndPath(engine.getDimension().getLoadKey(), j.getId()); + Biome biome = customRegistry.get(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.getHolder(biomeKey); + if (optionalReferenceHolder.isEmpty()) { + Iris.error("Cannot find reference to biome " + biomeKey + " for engine " + engine.getName()); + continue; + } + m.put(j.getId(), optionalReferenceHolder.get()); + } + } + } + + return m; + } + + private RegistryAccess registry() { + return registryAccess.aquire(() -> (RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer())); + } + + @Override + protected MapCodec codec() { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public Holder getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) { + int m = (y - engine.getMinHeight()) << 2; + IrisBiome ib = engine.getComplex().getTrueBiomeStream().get(x << 2, z << 2); + if (ib.isCustom()) { + return customBiomes.get(ib.getCustomBiome(rng, x << 2, m, z << 2).getId()); + } else { + org.bukkit.block.Biome v = ib.getSkyBiome(rng, x << 2, m, z << 2); + return NMSBinding.biomeToBiomeBase(biomeRegistry, v); + } + } +} \ No newline at end of file diff --git a/nms/v1_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 new file mode 100644 index 000000000..0e19dae15 --- /dev/null +++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java @@ -0,0 +1,584 @@ +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.Iterator; +import java.util.List; +import java.util.Vector; +import java.util.concurrent.atomic.AtomicInteger; + +import com.volmit.iris.core.nms.container.BiomeColor; +import com.volmit.iris.core.nms.datapack.DataVersion; +import net.minecraft.core.component.DataComponents; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.WorldGenContext; +import org.bukkit.*; +import org.bukkit.block.Biome; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_21_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_21_R1.CraftServer; +import org.bukkit.craftbukkit.v1_21_R1.CraftWorld; +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.ChunkGenerator; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMSBinding; +import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.hunk.Hunk; +import com.volmit.iris.util.json.JSONObject; +import com.volmit.iris.util.mantle.Mantle; +import com.volmit.iris.util.math.Vector3d; +import com.volmit.iris.util.matter.MatterBiomeInject; +import com.volmit.iris.util.nbt.io.NBTUtil; +import com.volmit.iris.util.nbt.mca.NBTWorld; +import com.volmit.iris.util.nbt.mca.palette.*; +import com.volmit.iris.util.nbt.tag.CompoundTag; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.TagParser; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import sun.misc.Unsafe; + +public class NMSBinding implements INMSBinding { + private final KMap baseBiomeCache = new KMap<>(); + private final BlockData AIR = Material.AIR.createBlockData(); + private final AtomicCache> biomeMapCache = new AtomicCache<>(); + private final AtomicCache> registryCache = new AtomicCache<>(); + private final AtomicCache> globalCache = new AtomicCache<>(); + private final AtomicCache registryAccess = new AtomicCache<>(); + private final AtomicCache byIdRef = new AtomicCache<>(); + private Field biomeStorageCache = null; + + private static Object getFor(Class type, Object source) { + Object o = fieldFor(type, source); + + if (o != null) { + return o; + } + + return invokeFor(type, source); + } + + private static Object invokeFor(Class returns, Object in) { + for (Method i : in.getClass().getMethods()) { + if (i.getReturnType().equals(returns)) { + i.setAccessible(true); + try { + Iris.debug("[NMS] Found " + returns.getSimpleName() + " in " + in.getClass().getSimpleName() + "." + i.getName() + "()"); + return i.invoke(in); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + return null; + } + + private static Object fieldFor(Class returns, Object in) { + return fieldForClass(returns, in.getClass(), in); + } + + @SuppressWarnings("unchecked") + private static T fieldForClass(Class returnType, Class sourceType, Object in) { + for (Field i : sourceType.getDeclaredFields()) { + if (i.getType().equals(returnType)) { + i.setAccessible(true); + try { + Iris.debug("[NMS] Found " + returnType.getSimpleName() + " in " + sourceType.getSimpleName() + "." + i.getName()); + return (T) i.get(in); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + return null; + } + + private static Class getClassType(Class type, int ordinal) { + return type.getDeclaredClasses()[ordinal]; + } + + @Override + public boolean hasTile(Location l) { + return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null; + } + + @Override + public CompoundTag serializeTile(Location location) { + BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true); + + if (e == null) { + return null; + } + + net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata(registry()); + return convert(tag); + } + + private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) { + try { + ByteArrayOutputStream boas = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(boas); + tag.write(dos); + dos.close(); + return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag(); + } catch (Throwable ex) { + ex.printStackTrace(); + } + + return null; + } + + private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) { + try { + ByteArrayOutputStream boas = new ByteArrayOutputStream(); + NBTUtil.write(tag, boas, false); + DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray())); + net.minecraft.nbt.CompoundTag c = NbtIo.read(din); + din.close(); + return c; + } catch (Throwable e) { + e.printStackTrace(); + } + + return null; + } + + @Override + public void deserializeTile(CompoundTag c, Location pos) { + ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); + } + + @Override + public CompoundTag serializeEntity(Entity location) { + return null;// TODO: + } + + @Override + public Entity deserializeEntity(CompoundTag s, Location newPosition) { + return null;// TODO: + } + + @Override + public boolean supportsCustomHeight() { + return true; + } + + private RegistryAccess registry() { + return registryAccess.aquire(() -> (RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer())); + } + + private Registry getCustomBiomeRegistry() { + return registry().registry(Registries.BIOME).orElse(null); + } + + private Registry getBlockRegistry() { + return registry().registry(Registries.BLOCK).orElse(null); + } + + @Override + public Object getBiomeBaseFromId(int id) { + return getCustomBiomeRegistry().getHolder(id); + } + + @Override + public int getMinHeight(World world) { + return world.getMinHeight(); + } + + @Override + public boolean supportsCustomBiomes() { + return true; + } + + @Override + public int getTrueBiomeBaseId(Object biomeBase) { + return getCustomBiomeRegistry().getId(((Holder) biomeBase).value()); + } + + @Override + public Object getTrueBiomeBase(Location location) { + return ((CraftWorld) location.getWorld()).getHandle().getBiome(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ())); + } + + @Override + public String getTrueBiomeBaseKey(Location location) { + return getKeyForBiomeBase(getTrueBiomeBase(location)); + } + + @Override + public Object getCustomBiomeBaseFor(String mckey) { + return getCustomBiomeRegistry().get(ResourceLocation.parse(mckey)); + } + + @Override + public Object getCustomBiomeBaseHolderFor(String mckey) { + return getCustomBiomeRegistry().getHolder(getTrueBiomeBaseId(getCustomBiomeRegistry().get(ResourceLocation.parse(mckey)))).get(); + } + + public int getBiomeBaseIdForKey(String key) { + return getCustomBiomeRegistry().getId(getCustomBiomeRegistry().get(ResourceLocation.parse(key))); + } + + @Override + public String getKeyForBiomeBase(Object biomeBase) { + return getCustomBiomeRegistry().getKey((net.minecraft.world.level.biome.Biome) biomeBase).getPath(); // something, not something:something + } + + @Override + public Object getBiomeBase(World world, Biome biome) { + return biomeToBiomeBase(((CraftWorld) world).getHandle() + .registryAccess().registry(Registries.BIOME).orElse(null), biome); + } + + @Override + public Object getBiomeBase(Object registry, Biome biome) { + Object v = baseBiomeCache.get(biome); + + if (v != null) { + return v; + } + //noinspection unchecked + v = biomeToBiomeBase((Registry) registry, biome); + if (v == null) { + // Ok so there is this new biome name called "CUSTOM" in Paper's new releases. + // But, this does NOT exist within CraftBukkit which makes it return an error. + // So, we will just return the ID that the plains biome returns instead. + //noinspection unchecked + return biomeToBiomeBase((Registry) registry, Biome.PLAINS); + } + baseBiomeCache.put(biome, v); + return v; + } + + @Override + public KList getBiomes() { + return new KList<>(Biome.values()).qadd(Biome.CHERRY_GROVE).qdel(Biome.CUSTOM); + } + + @Override + public boolean isBukkit() { + return true; + } + + @Override + public int getBiomeId(Biome biome) { + for (World i : Bukkit.getWorlds()) { + if (i.getEnvironment().equals(World.Environment.NORMAL)) { + Registry registry = ((CraftWorld) i).getHandle().registryAccess().registry(Registries.BIOME).orElse(null); + return registry.getId((net.minecraft.world.level.biome.Biome) getBiomeBase(registry, biome)); + } + } + + return biome.ordinal(); + } + + private MCAIdMap getBiomeMapping() { + return biomeMapCache.aquire(() -> new MCAIdMap<>() { + @NotNull + @Override + public Iterator iterator() { + return getCustomBiomeRegistry().iterator(); + } + + @Override + public int getId(net.minecraft.world.level.biome.Biome paramT) { + return getCustomBiomeRegistry().getId(paramT); + } + + @Override + public net.minecraft.world.level.biome.Biome byId(int paramInt) { + return (net.minecraft.world.level.biome.Biome) getBiomeBaseFromId(paramInt); + } + }); + } + + @NotNull + private MCABiomeContainer getBiomeContainerInterface(MCAIdMap biomeMapping, MCAChunkBiomeContainer base) { + return new MCABiomeContainer() { + @Override + public int[] getData() { + return base.writeBiomes(); + } + + @Override + public void setBiome(int x, int y, int z, int id) { + base.setBiome(x, y, z, biomeMapping.byId(id)); + } + + @Override + public int getBiome(int x, int y, int z) { + return biomeMapping.getId(base.getBiome(x, y, z)); + } + }; + } + + @Override + public MCABiomeContainer newBiomeContainer(int min, int max) { + MCAChunkBiomeContainer base = new MCAChunkBiomeContainer<>(getBiomeMapping(), min, max); + return getBiomeContainerInterface(getBiomeMapping(), base); + } + + @Override + public MCABiomeContainer newBiomeContainer(int min, int max, int[] data) { + MCAChunkBiomeContainer base = new MCAChunkBiomeContainer<>(getBiomeMapping(), min, max, data); + return getBiomeContainerInterface(getBiomeMapping(), base); + } + + @Override + public int countCustomBiomes() { + AtomicInteger a = new AtomicInteger(0); + + getCustomBiomeRegistry().keySet().forEach((i) -> { + if (i.getNamespace().equals("minecraft")) { + return; + } + + a.incrementAndGet(); + Iris.debug("Custom Biome: " + i); + }); + + return a.get(); + } + + public boolean supportsDataPacks() { + return true; + } + + public void setBiomes(int cx, int cz, World world, Hunk biomes) { + LevelChunk c = ((CraftWorld) world).getHandle().getChunk(cx, cz); + biomes.iterateSync((x, y, z, b) -> c.setBiome(x, y, z, (Holder) b)); + c.setUnsaved(true); + } + + @Override + public void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk) { + try { + ChunkAccess s = (ChunkAccess) getFieldForBiomeStorage(chunk).get(chunk); + Holder biome = (Holder) somethingVeryDirty; + s.setBiome(x, y, z, biome); + } catch (IllegalAccessException e) { + Iris.reportError(e); + e.printStackTrace(); + } + } + + private Field getFieldForBiomeStorage(Object storage) { + Field f = biomeStorageCache; + + if (f != null) { + return f; + } + try { + f = storage.getClass().getDeclaredField("biome"); + f.setAccessible(true); + return f; + } catch (Throwable e) { + Iris.reportError(e); + e.printStackTrace(); + Iris.error(storage.getClass().getCanonicalName()); + } + + biomeStorageCache = f; + return null; + } + + @Override + public MCAPaletteAccess createPalette() { + MCAIdMapper registry = registryCache.aquireNasty(() -> { + Field cf = net.minecraft.core.IdMapper.class.getDeclaredField("tToId"); + Field df = net.minecraft.core.IdMapper.class.getDeclaredField("idToT"); + Field bf = net.minecraft.core.IdMapper.class.getDeclaredField("nextId"); + cf.setAccessible(true); + df.setAccessible(true); + bf.setAccessible(true); + net.minecraft.core.IdMapper blockData = Block.BLOCK_STATE_REGISTRY; + int b = bf.getInt(blockData); + Object2IntMap c = (Object2IntMap) cf.get(blockData); + List d = (List) df.get(blockData); + return new MCAIdMapper(c, d, b); + }); + MCAPalette global = globalCache.aquireNasty(() -> new MCAGlobalPalette<>(registry, ((CraftBlockData) AIR).getState())); + MCAPalettedContainer container = new MCAPalettedContainer<>(global, registry, + i -> ((CraftBlockData) NBTWorld.getBlockData(i)).getState(), + i -> NBTWorld.getCompound(CraftBlockData.fromData(i)), + ((CraftBlockData) AIR).getState()); + return new MCAWrappedPalettedContainer<>(container, + i -> NBTWorld.getCompound(CraftBlockData.fromData(i)), + i -> ((CraftBlockData) NBTWorld.getBlockData(i)).getState()); + } + + @Override + public void injectBiomesFromMantle(Chunk e, Mantle mantle) { + ChunkAccess chunk = ((CraftChunk) e).getHandle(ChunkStatus.FULL); + AtomicInteger c = new AtomicInteger(); + AtomicInteger r = new AtomicInteger(); + mantle.iterateChunk(e.getX(), e.getZ(), MatterBiomeInject.class, (x, y, z, b) -> { + if (b != null) { + if (b.isCustom()) { + chunk.setBiome(x, y, z, getCustomBiomeRegistry().getHolder(b.getBiomeId()).get()); + c.getAndIncrement(); + } else { + chunk.setBiome(x, y, z, (Holder) getBiomeBase(e.getWorld(), b.getBiome())); + r.getAndIncrement(); + } + } + }); + } + + public ItemStack applyCustomNbt(ItemStack itemStack, KMap customNbt) throws IllegalArgumentException { + if (customNbt != null && !customNbt.isEmpty()) { + net.minecraft.world.item.ItemStack s = CraftItemStack.asNMSCopy(itemStack); + + try { + net.minecraft.nbt.CompoundTag tag = TagParser.parseTag((new JSONObject(customNbt)).toString()); + tag.merge(s.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).getUnsafe()); + s.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); + } catch (CommandSyntaxException var5) { + throw new IllegalArgumentException(var5); + } + + return CraftItemStack.asBukkitCopy(s); + } else { + return itemStack; + } + } + + public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) { + CraftDolphin cd = (CraftDolphin)dolphin; + cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ())); + cd.getHandle().setGotFish(true); + } + + public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { + var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap; + var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class); + worldGenContextField.setAccessible(true); + var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap); + Class clazz = worldGenContext.generator().getClass(); + Field biomeSource = getField(clazz, BiomeSource.class); + biomeSource.setAccessible(true); + Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + Unsafe unsafe = (Unsafe)unsafeField.get(null); + CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world); + unsafe.putObject(biomeSource.get(worldGenContext.generator()), unsafe.objectFieldOffset(biomeSource), customBiomeSource); + biomeSource.set(worldGenContext.generator(), customBiomeSource); + } + + public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) { + Field[] fields = EntityType.class.getDeclaredFields(); + for (Field field : fields) { + if (Modifier.isStatic(field.getModifiers()) && field.getType().equals(EntityType.class)) { + try { + EntityType entityType = (EntityType) field.get(null); + if (entityType.getDescriptionId().equals("entity.minecraft." + entity.name().toLowerCase())) { + Vector v1 = new Vector<>(); + v1.add(entityType.getHeight()); + entityType.getDimensions(); + Vector3d box = new Vector3d( entityType.getWidth(), entityType.getHeight(), entityType.getWidth()); + //System.out.println("Entity Type: " + entityType.getDescriptionId() + ", " + "Height: " + height + ", Width: " + width); + return box; + } + } catch (IllegalAccessException e) { + Iris.error("Unable to get entity dimensions!"); + e.printStackTrace(); + } + } + } + return null; + } + + + @Override + public Entity spawnEntity(Location location, org.bukkit.entity.EntityType type, CreatureSpawnEvent.SpawnReason reason) { + return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); + } + + @Override + public java.awt.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.getHolderOrThrow(ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(biome.getKey()))); + } + + @Override + public DataVersion getDataVersion() { + return DataVersion.V1205; + } +} diff --git a/settings.gradle b/settings.gradle index 9227e91e6..9809b35e0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -30,6 +30,7 @@ rootProject.name = 'Iris' //include 'app', 'com.volmit.gui' include(':core') include( + ':nms:v1_21_R1', ':nms:v1_20_R4', ':nms:v1_20_R3', ':nms:v1_20_R2',