diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 5036603cd..000000000 --- a/build.gradle +++ /dev/null @@ -1,330 +0,0 @@ -import xyz.jpenilla.runpaper.task.RunServer - -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2021 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -buildscript() { - repositories { - maven { url 'https://jitpack.io'} - } - dependencies { - classpath 'com.github.VolmitSoftware:NMSTools:1.0.1' - } -} - -plugins { - id 'java' - id 'java-library' - id "io.github.goooler.shadow" version "8.1.7" - id "de.undercouch.download" version "5.0.1" - id "xyz.jpenilla.run-paper" version "2.3.1" - id "io.sentry.jvm.gradle" version "5.7.0" -} - - -version '3.6.10-1.20.1-1.21.5' - -// ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED -// ======================== WINDOWS ============================= -registerCustomOutputTask('Cyberpwn', 'C://Users/cyberpwn/Documents/development/server/plugins') -registerCustomOutputTask('Psycho', 'C://Dan/MinecraftDevelopment/Server/plugins') -registerCustomOutputTask('ArcaneArts', 'C://Users/arcane/Documents/development/server/plugins') -registerCustomOutputTask('Coco', 'D://mcsm/plugins') -registerCustomOutputTask('Strange', 'D://Servers/1.17 Test Server/plugins') -registerCustomOutputTask('Vatuu', 'D://Minecraft/Servers/1.19.4/plugins') -registerCustomOutputTask('CrazyDev22', 'C://Users/Julian/Desktop/server/plugins') -registerCustomOutputTask('PixelFury', 'C://Users/repix/workplace/Iris/1.21.3 - Development-Public-v3/plugins') -registerCustomOutputTask('PixelFuryDev', 'C://Users/repix/workplace/Iris/1.21 - Development-v3/plugins') -// ========================== UNIX ============================== -registerCustomOutputTaskUnix('CyberpwnLT', '/Users/danielmills/development/server/plugins') -registerCustomOutputTaskUnix('PsychoLT', '/Users/brianfopiano/Developer/RemoteGit/Server/plugins') -registerCustomOutputTaskUnix('PixelMac', '/Users/test/Desktop/mcserver/plugins') -registerCustomOutputTaskUnix('CrazyDev22LT', '/home/julian/Desktop/server/plugins') -// ============================================================== - -def MIN_HEAP_SIZE = "2G" -def MAX_HEAP_SIZE = "8G" -//Valid values are: none, truecolor, indexed256, indexed16, indexed8 -def COLOR = "truecolor" - -def NMS_BINDINGS = Map.of( - "v1_21_R4", "1.21.5-R0.1-SNAPSHOT", - "v1_21_R3", "1.21.4-R0.1-SNAPSHOT", - "v1_21_R2", "1.21.3-R0.1-SNAPSHOT", - "v1_21_R1", "1.21.1-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", - "v1_20_R1", "1.20.1-R0.1-SNAPSHOT", -) -def JVM_VERSION = Map.of() -NMS_BINDINGS.forEach { key, value -> - project(":nms:$key") { - apply plugin: 'java' - apply plugin: 'com.volmit.nmstools' - - nmsTools { - it.jvm = JVM_VERSION.getOrDefault(key, 21) - it.version = value - } - - dependencies { - implementation project(":core") - } - } - - tasks.register("runServer-$key", RunServer) { - group("servers") - minecraftVersion(value.split("-")[0]) - minHeapSize(MIN_HEAP_SIZE) - maxHeapSize(MAX_HEAP_SIZE) - pluginJars(tasks.shadowJar.archiveFile) - javaLauncher = javaToolchains.launcherFor { it.languageVersion = JavaLanguageVersion.of(JVM_VERSION.getOrDefault(key, 21))} - runDirectory.convention(layout.buildDirectory.dir("run/$key")) - systemProperty("disable.watchdog", "") - systemProperty("net.kyori.ansi.colorLevel", COLOR) - systemProperty("com.mojang.eula.agree", true) - } -} - -shadowJar { - NMS_BINDINGS.each { - dependsOn(":nms:${it.key}:remap") - from("${project(":nms:${it.key}").layout.buildDirectory.asFile.get()}/libs/${it.key}-mapped.jar") - } - - //minimize() - append("plugin.yml") - relocate 'com.dfsek.paralithic', 'com.volmit.iris.util.paralithic' - relocate 'io.papermc.lib', 'com.volmit.iris.util.paper' - relocate 'net.kyori', 'com.volmit.iris.util.kyori' - relocate 'org.bstats', 'com.volmit.util.metrics' - relocate "io.sentry", "com.volmit.iris.util.sentry" - archiveFileName.set("Iris-${project.version}.jar") - - dependencies { - exclude(dependency("org.ow2.asm:asm:")) - exclude(dependency("org.jetbrains:")) - } -} - -dependencies { - implementation project(':core') -} - -configurations.configureEach { - resolutionStrategy.cacheChangingModulesFor 60, 'minutes' - resolutionStrategy.cacheDynamicVersionsFor 60, 'minutes' -} - -allprojects { - apply plugin: 'java' - apply plugin: 'io.sentry.jvm.gradle' - - repositories { - mavenCentral() - maven { url "https://repo.papermc.io/repository/maven-public/" } - maven { url "https://repo.codemc.org/repository/maven-public" } - maven { url "https://mvn.lumine.io/repository/maven-public/" } - maven { url "https://jitpack.io" } - - maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots" } - maven { url "https://mvn.lumine.io/repository/maven/" } - 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.nexomc.com/releases/" } - maven { url "https://libraries.minecraft.net" } - } - - dependencies { - // Provided or Classpath - compileOnly 'org.projectlombok:lombok:1.18.36' - annotationProcessor 'org.projectlombok:lombok:1.18.36' - - // Shaded - implementation 'com.dfsek:paralithic:0.8.1' - implementation 'io.papermc:paperlib:1.0.5' - implementation "net.kyori:adventure-text-minimessage:4.17.0" - implementation 'net.kyori:adventure-platform-bukkit:4.3.4' - implementation 'net.kyori:adventure-api:4.17.0' - implementation 'org.bstats:bstats-bukkit:3.1.0' - //implementation 'org.bytedeco:javacpp:1.5.10' - //implementation 'org.bytedeco:cuda-platform:12.3-8.9-1.5.10' - compileOnly 'io.lumine:Mythic-Dist:5.2.1' - compileOnly 'io.lumine:MythicCrucible-Dist:2.0.0' - - // Dynamically Loaded - compileOnly 'io.timeandspace:smoothie-map:2.0.2' - compileOnly 'it.unimi.dsi:fastutil:8.5.8' - compileOnly 'com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2' - compileOnly 'org.zeroturnaround:zt-zip:1.14' - compileOnly 'com.google.code.gson:gson:2.10.1' - compileOnly 'org.ow2.asm:asm:9.2' - compileOnly 'com.google.guava:guava:33.0.0-jre' - compileOnly 'bsf:bsf:2.4.0' - compileOnly 'rhino:js:1.7R2' - compileOnly 'com.github.ben-manes.caffeine:caffeine:3.0.6' - compileOnly 'org.apache.commons:commons-lang3:3.12.0' - compileOnly 'com.github.oshi:oshi-core:6.6.5' - } - - /** - * We need parameter meta for the decree command system - */ - compileJava { - options.compilerArgs << '-parameters' - options.encoding = "UTF-8" - } - - javadoc { - options.encoding = "UTF-8" - options.addStringOption('Xdoclint:none', '-quiet') - } - - task sourcesJar(type: Jar, dependsOn: classes) { - archiveClassifier.set('sources') - from sourceSets.main.allSource - } - - task javadocJar(type: Jar, dependsOn: javadoc) { - archiveClassifier.set('javadoc') - from javadoc.destinationDir - } - - sentry { - includeSourceContext = true - - org = "volmit-software" - projectName = "iris" - authToken = hasProperty("sentry.auth.token") ? - property("sentry.auth.token") : - System.getenv("SENTRY_AUTH_TOKEN") - } -} - -if (JavaVersion.current().toString() != "21") { - System.err.println() - System.err.println("=========================================================================================================") - System.err.println("You must run gradle on Java 21. You are using " + JavaVersion.current()) - System.err.println() - System.err.println("=== For IDEs ===") - System.err.println("1. Configure the project for Java 21") - System.err.println("2. Configure the bundled gradle to use Java 21 in settings") - System.err.println() - System.err.println("=== For Command Line (gradlew) ===") - System.err.println("1. Install JDK 21 from https://www.oracle.com/java/technologies/javase/jdk21-archive-downloads.html") - System.err.println("2. Set JAVA_HOME environment variable to the new jdk installation folder such as C:\\Program Files\\Java\\jdk-21.0.4") - System.err.println("3. Open a new command prompt window to get the new environment variables if need be.") - System.err.println("=========================================================================================================") - System.err.println() - System.exit(69); -} - -task iris(type: Copy) { - group "iris" - from new File(layout.buildDirectory.asFile.get(), "libs/Iris-${version}.jar") - into layout.buildDirectory.asFile.get() - dependsOn(build) -} - -// with classifier: 'javadoc' and 'sources' -task irisDev(type: Copy) { - group "iris" - from("core/build/libs/core-javadoc.jar", "core/build/libs/core-sources.jar") - rename { String fileName -> - fileName.replace("core", "Iris-${version}") - } - into layout.buildDirectory.asFile.get() - dependsOn(iris) - dependsOn("core:sourcesJar") - dependsOn("core:javadocJar") -} - - -def registerCustomOutputTask(name, path) { - if (!System.properties['os.name'].toLowerCase().contains('windows')) { - return; - } - - tasks.register('build' + name, Copy) { - group('development') - outputs.upToDateWhen { false } - dependsOn(iris) - from(new File(buildDir, "Iris-" + version + ".jar")) - into(file(path)) - rename { String fileName -> - fileName.replace("Iris-" + version + ".jar", "Iris.jar") - } - } -} - -def registerCustomOutputTaskUnix(name, path) { - if (System.properties['os.name'].toLowerCase().contains('windows')) { - return; - } - - tasks.register('build' + name, Copy) { - group('development') - outputs.upToDateWhen { false } - dependsOn(iris) - from(new File(buildDir, "Iris-" + version + ".jar")) - into(file(path)) - rename { String fileName -> - fileName.replace("Iris-" + version + ".jar", "Iris.jar") - } - } -} - -tasks.build.dependsOn(shadowJar) - -def cli = file("sentry-cli.exe") -tasks.register("downloadCli", Download) { - group = "sentry" - src "https://release-registry.services.sentry.io/apps/sentry-cli/latest?response=download&arch=x86_64&platform=${System.getProperty("os.name")}&package=sentry-cli" - dest cli - - doLast { - cli.setExecutable(true) - } -} - -tasks.register("release") { - group = "sentry" - dependsOn("downloadCli") - doLast { - def authToken = project.hasProperty("sentry.auth.token") ? - project.property("sentry.auth.token") : - System.getenv("SENTRY_AUTH_TOKEN") - def org = "volmit-software" - def projectName = "iris" - exec { - executable(cli) - args("releases", "new", "--auth-token", authToken, "-o", org, "-p", projectName, version) - } - exec { - executable(cli) - args("releases", "set-commits", "--auth-token", authToken, "-o", org, "-p", projectName, version, "--auto") - } - exec { - executable(cli) - args("releases", "finalize", "--auth-token", authToken, "-o", org, "-p", projectName, version) - } - cli.delete() - } -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 000000000..86a2170c1 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,278 @@ +import com.volmit.nmstools.NMSToolsExtension +import com.volmit.nmstools.NMSToolsPlugin +import de.undercouch.gradle.tasks.download.Download +import xyz.jpenilla.runpaper.task.RunServer +import kotlin.system.exitProcess + +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +buildscript { + repositories.maven("https://jitpack.io") + dependencies.classpath("com.github.VolmitSoftware:NMSTools:c5cbc46ce6") +} + +plugins { + java + `java-library` + id("com.gradleup.shadow") version "8.3.6" + id("de.undercouch.download") version "5.0.1" + id("xyz.jpenilla.run-paper") version "2.3.1" + id("io.sentry.jvm.gradle") version "5.7.0" +} + +version = "3.6.10-1.20.1-1.21.5" + +// ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED +// ======================== WINDOWS ============================= +registerCustomOutputTask("Cyberpwn", "C://Users/cyberpwn/Documents/development/server/plugins") +registerCustomOutputTask("Psycho", "C://Dan/MinecraftDevelopment/Server/plugins") +registerCustomOutputTask("ArcaneArts", "C://Users/arcane/Documents/development/server/plugins") +registerCustomOutputTask("Coco", "D://mcsm/plugins") +registerCustomOutputTask("Strange", "D://Servers/1.17 Test Server/plugins") +registerCustomOutputTask("Vatuu", "D://Minecraft/Servers/1.19.4/plugins") +registerCustomOutputTask("CrazyDev22", "C://Users/Julian/Desktop/server/plugins") +registerCustomOutputTask("PixelFury", "C://Users/repix/workplace/Iris/1.21.3 - Development-Public-v3/plugins") +registerCustomOutputTask("PixelFuryDev", "C://Users/repix/workplace/Iris/1.21 - Development-v3/plugins") +// ========================== UNIX ============================== +registerCustomOutputTaskUnix("CyberpwnLT", "/Users/danielmills/development/server/plugins") +registerCustomOutputTaskUnix("PsychoLT", "/Users/brianfopiano/Developer/RemoteGit/Server/plugins") +registerCustomOutputTaskUnix("PixelMac", "/Users/test/Desktop/mcserver/plugins") +registerCustomOutputTaskUnix("CrazyDev22LT", "/home/julian/Desktop/server/plugins") +// ============================================================== + +val serverMinHeap = "2G" +val serverMaxHeap = "8G" +//Valid values are: none, truecolor, indexed256, indexed16, indexed8 +val color = "truecolor" +val errorReporting = false + +val nmsBindings = mapOf( + "v1_21_R4" to "1.21.5-R0.1-SNAPSHOT", + "v1_21_R3" to "1.21.4-R0.1-SNAPSHOT", + "v1_21_R2" to "1.21.3-R0.1-SNAPSHOT", + "v1_21_R1" to "1.21.1-R0.1-SNAPSHOT", + "v1_20_R4" to "1.20.6-R0.1-SNAPSHOT", + "v1_20_R3" to "1.20.4-R0.1-SNAPSHOT", + "v1_20_R2" to "1.20.2-R0.1-SNAPSHOT", + "v1_20_R1" to "1.20.1-R0.1-SNAPSHOT", +) +val jvmVersion = mapOf() +nmsBindings.forEach { key, value -> + project(":nms:$key") { + apply() + apply() + + repositories { + maven("https://libraries.minecraft.net") + } + + extensions.configure(NMSToolsExtension::class) { + jvm = jvmVersion.getOrDefault(key, 21) + version = value + } + + dependencies { + compileOnly(project(":core")) + compileOnly("org.jetbrains:annotations:26.0.2") + } + } + + tasks.register("runServer-$key") { + group = "servers" + minecraftVersion(value.split("-")[0]) + minHeapSize = serverMinHeap + maxHeapSize = serverMaxHeap + pluginJars(tasks.jar.flatMap { it.archiveFile }) + javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(jvmVersion.getOrDefault(key, 21))} + runDirectory.convention(layout.buildDirectory.dir("run/$key")) + systemProperty("disable.watchdog", "") + systemProperty("net.kyori.ansi.colorLevel", color) + systemProperty("com.mojang.eula.agree", true) + systemProperty("iris.errorReporting", errorReporting) + } +} + +tasks { + jar { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + nmsBindings.forEach { key, _ -> + from(project(":nms:$key").tasks.named("remap").map { zipTree(it.outputs.files.singleFile) }) + } + from(project(":core").tasks.shadowJar.flatMap { it.archiveFile }.map { zipTree(it) }) + archiveFileName.set("Iris-${project.version}.jar") + } + + register("iris") { + group = "iris" + dependsOn("jar") + from(layout.buildDirectory.file("libs/Iris-${project.version}.jar")) + into(layout.buildDirectory) + } + + register("irisDev") { + group = "iris" + from(project(":core").layout.buildDirectory.files("libs/core-javadoc.jar", "libs/core-sources.jar")) + rename { it.replace("core", "Iris-${project.version}") } + into(layout.buildDirectory) + dependsOn(":core:sourcesJar") + dependsOn(":core:javadocJar") + } + + val cli = file("sentry-cli.exe") + register("downloadCli") { + group = "io.sentry" + src("https://release-registry.services.sentry.io/apps/sentry-cli/latest?response=download&arch=x86_64&platform=${System.getProperty("os.name")}&package=sentry-cli") + dest(cli) + + doLast { + cli.setExecutable(true) + } + } + + register("release") { + group = "io.sentry" + dependsOn("downloadCli") + doLast { + val authToken = project.findProperty("sentry.auth.token") ?: System.getenv("SENTRY_AUTH_TOKEN") + val org = "volmit-software" + val projectName = "iris" + exec(cli, "releases", "new", "--auth-token", authToken, "-o", org, "-p", projectName, version) + exec(cli, "releases", "set-commits", "--auth-token", authToken, "-o", org, "-p", projectName, version, "--auto", "--ignore-missing") + exec(cli, "releases", "finalize", "--auth-token", authToken, "-o", org, "-p", projectName, version) + cli.delete() + } + } +} + +fun exec(vararg command: Any) { + val p = ProcessBuilder(command.map { it.toString() }) + .start() + p.inputStream.reader().useLines { it.forEach(::println) } + p.errorStream.reader().useLines { it.forEach(::println) } + p.waitFor() +} + +dependencies { + implementation(project(":core")) +} + +configurations.configureEach { + resolutionStrategy.cacheChangingModulesFor(60, "minutes") + resolutionStrategy.cacheDynamicVersionsFor(60, "minutes") +} + +allprojects { + apply() + + repositories { + mavenCentral() + maven("https://repo.papermc.io/repository/maven-public/") + maven("https://repo.codemc.org/repository/maven-public/") + maven("https://mvn.lumine.io/repository/maven-public/") + maven("https://jitpack.io") + + maven("https://s01.oss.sonatype.org/content/repositories/snapshots") + maven("https://mvn.lumine.io/repository/maven/") + maven("https://repo.triumphteam.dev/snapshots") + maven("https://repo.mineinabyss.com/releases") + maven("https://hub.jeff-media.com/nexus/repository/jeff-media-public/") + maven("https://repo.nexomc.com/releases/") + } + + dependencies { + // Provided or Classpath + compileOnly("org.projectlombok:lombok:1.18.36") + annotationProcessor("org.projectlombok:lombok:1.18.36") + } + + /** + * We need parameter meta for the decree command system + */ + tasks { + compileJava { + options.compilerArgs.add("-parameters") + options.encoding = "UTF-8" + } + + javadoc { + options.encoding = "UTF-8" + options.quiet() + //options.addStringOption("Xdoclint:none") // TODO: Re-enable this + } + + register("sourcesJar") { + archiveClassifier.set("sources") + from(sourceSets.main.map { it.allSource }) + } + + register("javadocJar") { + archiveClassifier.set("javadoc") + from(javadoc.map { it.destinationDir!! }) + } + } +} + +if (JavaVersion.current().toString() != "21") { + System.err.println() + System.err.println("=========================================================================================================") + System.err.println("You must run gradle on Java 21. You are using " + JavaVersion.current()) + System.err.println() + System.err.println("=== For IDEs ===") + System.err.println("1. Configure the project for Java 21") + System.err.println("2. Configure the bundled gradle to use Java 21 in settings") + System.err.println() + System.err.println("=== For Command Line (gradlew) ===") + System.err.println("1. Install JDK 21 from https://www.oracle.com/java/technologies/javase/jdk21-archive-downloads.html") + System.err.println("2. Set JAVA_HOME environment variable to the new jdk installation folder such as C:\\Program Files\\Java\\jdk-21.0.4") + System.err.println("3. Open a new command prompt window to get the new environment variables if need be.") + System.err.println("=========================================================================================================") + System.err.println() + exitProcess(69) +} + + +fun registerCustomOutputTask(name: String, path: String) { + if (!System.getProperty("os.name").lowercase().contains("windows")) { + return + } + + tasks.register("build$name") { + group = "development" + outputs.upToDateWhen { false } + dependsOn("iris") + from(layout.buildDirectory.file("Iris-${project.version}.jar")) + into(file(path)) + rename { "Iris.jar" } + } +} + +fun registerCustomOutputTaskUnix(name: String, path: String) { + if (System.getProperty("os.name").lowercase().contains("windows")) { + return + } + + tasks.register("build$name") { + group = "development" + outputs.upToDateWhen { false } + dependsOn("iris") + from(layout.buildDirectory.file("Iris-${project.version}.jar")) + into(file(path)) + rename { "Iris.jar" } + } +} \ No newline at end of file diff --git a/core/build.gradle b/core/build.gradle deleted file mode 100644 index 9effb5654..000000000 --- a/core/build.gradle +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2021 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -plugins { - id 'java' - id 'java-library' - id "io.freefair.lombok" version "8.6" -} - -def apiVersion = '1.19' -def main = 'com.volmit.iris.Iris' - -/** - * We need parameter meta for the decree command system - */ -compileJava { - options.compilerArgs << '-parameters' - options.encoding = "UTF-8" -} - -repositories { - maven { url 'https://nexus.phoenixdevt.fr/repository/maven-public/'} - maven { url 'https://repo.auxilor.io/repository/maven-public/' } -} - -/** - * Dependencies. - * - * Provided or classpath dependencies are not shaded and are available on the runtime classpath - * - * Shaded dependencies are not available at runtime, nor are they available on mvn central so they - * need to be shaded into the jar (increasing binary size) - * - * Dynamically loaded dependencies are defined in the plugin.yml (updating these must be updated in the - * plugin.yml also, otherwise they wont be available). These do not increase binary size). Only declare - * these dependencies if they are available on mvn central. - */ -dependencies { - // Provided or Classpath - compileOnly 'org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT' - compileOnly 'org.apache.logging.log4j:log4j-api:2.19.0' - compileOnly 'org.apache.logging.log4j:log4j-core:2.19.0' - compileOnly 'commons-io:commons-io:2.13.0' - compileOnly 'commons-lang:commons-lang:2.6' - compileOnly 'com.github.oshi:oshi-core:5.8.5' - compileOnly 'org.lz4:lz4-java:1.8.0' - - // Third Party Integrations - compileOnly 'com.ticxo.playeranimator:PlayerAnimator:R1.2.7' - compileOnly 'com.nexomc:nexo:1.6.0' - compileOnly 'com.github.LoneDev6:api-itemsadder:3.4.1-r4' - compileOnly 'com.github.PlaceholderAPI:placeholderapi:2.11.3' - compileOnly 'com.github.Ssomar-Developement:SCore:4.23.10.8' - compileOnly 'net.Indyuce:MMOItems-API:6.9.5-SNAPSHOT' - compileOnly 'com.willfp:EcoItems:5.44.0' - //implementation files('libs/CustomItems.jar') -} - -java { - disableAutoTargetJvm() -} - -/** - * Gradle is weird sometimes, we need to delete the plugin yml from the build folder to actually filter properly. - */ -file(jar.archiveFile.get().getAsFile().getParentFile().getParentFile().getParentFile().getAbsolutePath() + '/build/resources/main/plugin.yml').delete() - -/** - * Expand properties into plugin yml - */ -processResources { - filesMatching('**/plugin.yml') { - expand( - 'name': rootProject.name.toString(), - 'version': rootProject.version.toString(), - 'main': main.toString(), - 'apiversion': apiVersion.toString() - ) - } -} \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts new file mode 100644 index 000000000..cebfbc6c5 --- /dev/null +++ b/core/build.gradle.kts @@ -0,0 +1,151 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +plugins { + java + `java-library` + id("com.gradleup.shadow") + id("io.sentry.jvm.gradle") +} + +val apiVersion = "1.19" +val main = "com.volmit.iris.Iris" + +repositories { + maven("https://nexus.phoenixdevt.fr/repository/maven-public/") + maven("https://repo.auxilor.io/repository/maven-public/") +} + +/** + * Dependencies. + * + * Provided or classpath dependencies are not shaded and are available on the runtime classpath + * + * Shaded dependencies are not available at runtime, nor are they available on mvn central so they + * need to be shaded into the jar (increasing binary size) + * + * Dynamically loaded dependencies are defined in the plugin.yml (updating these must be updated in the + * plugin.yml also, otherwise they wont be available). These do not increase binary size). Only declare + * these dependencies if they are available on mvn central. + */ +dependencies { + // Provided or Classpath + compileOnly("org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT") + compileOnly("org.apache.logging.log4j:log4j-api:2.19.0") + compileOnly("org.apache.logging.log4j:log4j-core:2.19.0") + compileOnly("commons-io:commons-io:2.13.0") + compileOnly("commons-lang:commons-lang:2.6") + compileOnly("com.github.oshi:oshi-core:5.8.5") + compileOnly("org.lz4:lz4-java:1.8.0") + + // Third Party Integrations + compileOnly("com.nexomc:nexo:1.6.0") + compileOnly("com.github.LoneDev6:api-itemsadder:3.4.1-r4") + compileOnly("com.github.PlaceholderAPI:placeholderapi:2.11.3") + compileOnly("com.github.Ssomar-Developement:SCore:4.23.10.8") + compileOnly("net.Indyuce:MMOItems-API:6.9.5-SNAPSHOT") + compileOnly("com.willfp:EcoItems:5.44.0") + //implementation files("libs/CustomItems.jar") + + + // Shaded + implementation("com.dfsek:paralithic:0.8.1") + implementation("io.papermc:paperlib:1.0.5") + implementation("net.kyori:adventure-text-minimessage:4.17.0") + implementation("net.kyori:adventure-platform-bukkit:4.3.4") + implementation("net.kyori:adventure-api:4.17.0") + implementation("org.bstats:bstats-bukkit:3.1.0") + + //implementation("org.bytedeco:javacpp:1.5.10") + //implementation("org.bytedeco:cuda-platform:12.3-8.9-1.5.10") + compileOnly("io.lumine:Mythic-Dist:5.2.1") + compileOnly("io.lumine:MythicCrucible-Dist:2.0.0") + + // Dynamically Loaded + compileOnly("io.timeandspace:smoothie-map:2.0.2") + compileOnly("it.unimi.dsi:fastutil:8.5.8") + compileOnly("com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2") + compileOnly("org.zeroturnaround:zt-zip:1.14") + compileOnly("com.google.code.gson:gson:2.10.1") + compileOnly("org.ow2.asm:asm:9.2") + compileOnly("com.google.guava:guava:33.0.0-jre") + compileOnly("bsf:bsf:2.4.0") + compileOnly("rhino:js:1.7R2") + compileOnly("com.github.ben-manes.caffeine:caffeine:3.0.6") + compileOnly("org.apache.commons:commons-lang3:3.12.0") + compileOnly("com.github.oshi:oshi-core:6.6.5") +} + +java { + disableAutoTargetJvm() +} + +sentry { + includeSourceContext = true + + org = "volmit-software" + projectName = "iris" + authToken = findProperty("sentry.auth.token") as String? ?: System.getenv("SENTRY_AUTH_TOKEN") +} + +tasks { + /** + * We need parameter meta for the decree command system + */ + compileJava { + options.compilerArgs.add("-parameters") + options.encoding = "UTF-8" + } + + /** + * Expand properties into plugin yml + */ + processResources { + inputs.properties( + "name" to rootProject.name, + "version" to rootProject.version, + "apiVersion" to apiVersion, + "main" to main + ) + filesMatching("**/plugin.yml") { + expand(inputs.properties) + } + } + + shadowJar { + mergeServiceFiles() + relocate("com.dfsek.paralithic", "com.volmit.iris.util.paralithic") + relocate("io.papermc.lib", "com.volmit.iris.util.paper") + relocate("net.kyori", "com.volmit.iris.util.kyori") + relocate("org.bstats", "com.volmit.iris.util.metrics") + relocate("io.sentry", "com.volmit.iris.util.sentry") + + //minimize() + dependencies { + exclude(dependency("org.ow2.asm:asm:")) + exclude(dependency("org.jetbrains:")) + } + } +} + +/** + * Gradle is weird sometimes, we need to delete the plugin yml from the build folder to actually filter properly. + */ +afterEvaluate { + layout.buildDirectory.file("resources/main/plugin.yml").get().asFile.delete() +} \ No newline at end of file diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 43384f127..65b78aa43 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -1,977 +1,991 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.volmit.iris; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonParser; -import com.volmit.iris.core.IrisSettings; -import com.volmit.iris.core.ServerConfigurator; -import com.volmit.iris.core.link.IrisPapiExpansion; -import com.volmit.iris.core.link.MultiverseCoreLink; -import com.volmit.iris.core.link.MythicMobsLink; -import com.volmit.iris.core.loader.IrisData; -import com.volmit.iris.core.nms.INMS; -import com.volmit.iris.core.nms.v1X.NMSBinding1X; -import com.volmit.iris.core.pregenerator.LazyPregenerator; -import com.volmit.iris.core.service.StudioSVC; -import com.volmit.iris.core.tools.IrisToolbelt; -import com.volmit.iris.engine.EnginePanic; -import com.volmit.iris.engine.object.IrisCompat; -import com.volmit.iris.engine.object.IrisContextInjector; -import com.volmit.iris.engine.object.IrisDimension; -import com.volmit.iris.engine.object.IrisWorld; -import com.volmit.iris.engine.platform.BukkitChunkGenerator; -import com.volmit.iris.engine.platform.DummyChunkGenerator; -import com.volmit.iris.core.safeguard.IrisSafeguard; -import com.volmit.iris.core.safeguard.UtilsSFG; -import com.volmit.iris.engine.platform.PlatformChunkGenerator; -import com.volmit.iris.util.collection.KList; -import com.volmit.iris.util.collection.KMap; -import com.volmit.iris.util.exceptions.IrisException; -import com.volmit.iris.util.format.C; -import com.volmit.iris.util.format.Form; -import com.volmit.iris.util.function.NastyRunnable; -import com.volmit.iris.util.io.FileWatcher; -import com.volmit.iris.util.io.IO; -import com.volmit.iris.util.io.InstanceState; -import com.volmit.iris.util.io.JarScanner; -import com.volmit.iris.util.math.M; -import com.volmit.iris.util.math.RNG; -import com.volmit.iris.util.misc.getHardware; -import com.volmit.iris.util.parallel.MultiBurst; -import com.volmit.iris.util.plugin.IrisService; -import com.volmit.iris.util.plugin.VolmitPlugin; -import com.volmit.iris.util.plugin.VolmitSender; -import com.volmit.iris.util.reflect.ShadeFix; -import com.volmit.iris.util.scheduling.J; -import com.volmit.iris.util.scheduling.Queue; -import com.volmit.iris.util.scheduling.ShurikenQueue; -import com.volmit.iris.util.sentry.Attachments; -import com.volmit.iris.util.sentry.IrisLogger; -import io.papermc.lib.PaperLib; -import io.sentry.Sentry; -import net.kyori.adventure.platform.bukkit.BukkitAudiences; -import net.kyori.adventure.text.serializer.ComponentSerializer; -import org.bstats.bukkit.Metrics; -import org.bstats.charts.DrilldownPie; -import org.bstats.charts.SimplePie; -import org.bstats.charts.SingleLineChart; -import org.bukkit.*; -import org.bukkit.block.data.BlockData; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import org.bukkit.event.*; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.ChunkGenerator; -import org.bukkit.plugin.IllegalPluginAccessException; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import oshi.SystemInfo; - -import java.io.*; -import java.lang.annotation.Annotation; -import java.math.RoundingMode; -import java.net.URL; -import java.text.NumberFormat; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import static com.volmit.iris.core.safeguard.IrisSafeguard.*; -import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware; - -@SuppressWarnings("CanBeFinal") -public class Iris extends VolmitPlugin implements Listener { - private static final Queue syncJobs = new ShurikenQueue<>(); - - public static Iris instance; - public static BukkitAudiences audiences; - public static MultiverseCoreLink linkMultiverseCore; - public static MythicMobsLink linkMythicMobs; - public static IrisCompat compat; - public static FileWatcher configWatcher; - private static VolmitSender sender; - - static { - try { - fixShading(); - InstanceState.updateInstanceId(); - } catch (Throwable ignored) { - - } - } - - private final KList postShutdown = new KList<>(); - private KMap, IrisService> services; - - public static VolmitSender getSender() { - if (sender == null) { - sender = new VolmitSender(Bukkit.getConsoleSender()); - sender.setTag(instance.getTag()); - } - return sender; - } - - @SuppressWarnings("unchecked") - public static T service(Class c) { - return (T) instance.services.get(c); - } - - public static void callEvent(Event e) { - if (!e.isAsynchronous()) { - J.s(() -> Bukkit.getPluginManager().callEvent(e)); - } else { - Bukkit.getPluginManager().callEvent(e); - } - } - - public static KList initialize(String s, Class slicedClass) { - JarScanner js = new JarScanner(instance.getJarFile(), s); - KList v = new KList<>(); - J.attempt(js::scan); - for (Class i : js.getClasses()) { - if (slicedClass == null || i.isAnnotationPresent(slicedClass)) { - try { - v.add(i.getDeclaredConstructor().newInstance()); - } catch (Throwable ignored) { - - } - } - } - - return v; - } - - public static KList> getClasses(String s, Class slicedClass) { - JarScanner js = new JarScanner(instance.getJarFile(), s); - KList> v = new KList<>(); - J.attempt(js::scan); - for (Class i : js.getClasses()) { - if (slicedClass == null || i.isAnnotationPresent(slicedClass)) { - try { - v.add(i); - } catch (Throwable ignored) { - - } - } - } - - return v; - } - - public static KList initialize(String s) { - return initialize(s, null); - } - - public static void sq(Runnable r) { - synchronized (syncJobs) { - syncJobs.queue(r); - } - } - - public static File getTemp() { - return instance.getDataFolder("cache", "temp"); - } - - public static void msg(String string) { - try { - getSender().sendMessage(string); - } catch (Throwable e) { - try { - instance.getLogger().info(instance.getTag() + string.replaceAll("(<([^>]+)>)", "")); - } catch (Throwable ignored1) { - - } - } - } - - public static File getCached(String name, String url) { - String h = IO.hash(name + "@" + url); - File f = Iris.instance.getDataFile("cache", h.substring(0, 2), h.substring(3, 5), h); - - if (!f.exists()) { - try (BufferedInputStream in = new BufferedInputStream(new URL(url).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) { - byte[] dataBuffer = new byte[1024]; - int bytesRead; - while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) { - fileOutputStream.write(dataBuffer, 0, bytesRead); - Iris.verbose("Aquiring " + name); - } - } catch (IOException e) { - Iris.reportError(e); - } - } - - return f.exists() ? f : null; - } - - public static String getNonCached(String name, String url) { - String h = IO.hash(name + "*" + url); - File f = Iris.instance.getDataFile("cache", h.substring(0, 2), h.substring(3, 5), h); - - try (BufferedInputStream in = new BufferedInputStream(new URL(url).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) { - byte[] dataBuffer = new byte[1024]; - int bytesRead; - while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) { - fileOutputStream.write(dataBuffer, 0, bytesRead); - } - } catch (IOException e) { - Iris.reportError(e); - } - - try { - return IO.readAll(f); - } catch (IOException e) { - Iris.reportError(e); - } - - return ""; - } - - public static File getNonCachedFile(String name, String url) { - String h = IO.hash(name + "*" + url); - File f = Iris.instance.getDataFile("cache", h.substring(0, 2), h.substring(3, 5), h); - Iris.verbose("Download " + name + " -> " + url); - try (BufferedInputStream in = new BufferedInputStream(new URL(url).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) { - byte[] dataBuffer = new byte[1024]; - int bytesRead; - while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) { - fileOutputStream.write(dataBuffer, 0, bytesRead); - } - - fileOutputStream.flush(); - } catch (IOException e) { - e.printStackTrace(); - Iris.reportError(e); - } - - return f; - } - - public static void warn(String format, Object... objs) { - msg(C.YELLOW + String.format(format, objs)); - } - - public static void error(String format, Object... objs) { - msg(C.RED + String.format(format, objs)); - } - - public static void debug(String string) { - if (!IrisSettings.get().getGeneral().isDebug()) { - return; - } - - try { - throw new RuntimeException(); - } catch (Throwable e) { - try { - String[] cc = e.getStackTrace()[1].getClassName().split("\\Q.\\E"); - - if (cc.length > 5) { - debug(cc[3] + "/" + cc[4] + "/" + cc[cc.length - 1], e.getStackTrace()[1].getLineNumber(), string); - } else { - debug(cc[3] + "/" + cc[4], e.getStackTrace()[1].getLineNumber(), string); - } - } catch (Throwable ex) { - debug("Origin", -1, string); - } - } - } - - public static void debug(String category, int line, String string) { - if (!IrisSettings.get().getGeneral().isDebug()) { - return; - } - if (IrisSettings.get().getGeneral().isUseConsoleCustomColors()) { - msg("" + category + " <#bf3b76>" + line + " " + C.LIGHT_PURPLE + string.replaceAll("\\Q<\\E", "[").replaceAll("\\Q>\\E", "]")); - } else { - msg(C.BLUE + category + ":" + C.AQUA + line + C.RESET + C.LIGHT_PURPLE + " " + string.replaceAll("\\Q<\\E", "[").replaceAll("\\Q>\\E", "]")); - - } - } - - public static void verbose(String string) { - debug(string); - } - - public static void success(String string) { - msg(C.IRIS + string); - } - - public static void info(String format, Object... args) { - msg(C.WHITE + String.format(format, args)); - } - public static void safeguard(String format, Object... args) { - msg(C.RESET + String.format(format, args)); - } - - @SuppressWarnings("deprecation") - public static void later(NastyRunnable object) { - try { - Bukkit.getScheduler().scheduleAsyncDelayedTask(instance, () -> - { - try { - object.run(); - } catch (Throwable e) { - e.printStackTrace(); - Iris.reportError(e); - } - }, RNG.r.i(100, 1200)); - } catch (IllegalPluginAccessException ignored) { - - } - } - - public static int jobCount() { - return syncJobs.size(); - } - - public static void clearQueues() { - synchronized (syncJobs) { - syncJobs.clear(); - } - } - - public static int getJavaVersion() { - String version = System.getProperty("java.version"); - if (version.startsWith("1.")) { - version = version.substring(2, 3); - } else { - int dot = version.indexOf("."); - if (dot != -1) { - version = version.substring(0, dot); - } - } - return Integer.parseInt(version); - } - - public static String getJava() { - String javaRuntimeName = System.getProperty("java.vm.name"); - String javaRuntimeVendor = System.getProperty("java.vendor"); - String javaRuntimeVersion = System.getProperty("java.vm.version"); - return String.format("%s %s (build %s)", javaRuntimeName, javaRuntimeVendor, javaRuntimeVersion); - } - - public static void reportErrorChunk(int x, int z, Throwable e, String extra) { - if (IrisSettings.get().getGeneral().isDebug()) { - File f = instance.getDataFile("debug", "chunk-errors", "chunk." + x + "." + z + ".txt"); - - if (!f.exists()) { - J.attempt(() -> { - PrintWriter pw = new PrintWriter(f); - pw.println("Thread: " + Thread.currentThread().getName()); - pw.println("First: " + new Date(M.ms())); - e.printStackTrace(pw); - pw.close(); - }); - } - - Iris.debug("Chunk " + x + "," + z + " Exception Logged: " + e.getClass().getSimpleName() + ": " + C.RESET + "" + C.LIGHT_PURPLE + e.getMessage()); - } - } - - public static void reportError(Throwable e) { - Sentry.captureException(e); - if (IrisSettings.get().getGeneral().isDebug()) { - String n = e.getClass().getCanonicalName() + "-" + e.getStackTrace()[0].getClassName() + "-" + e.getStackTrace()[0].getLineNumber(); - - if (e.getCause() != null) { - n += "-" + e.getCause().getStackTrace()[0].getClassName() + "-" + e.getCause().getStackTrace()[0].getLineNumber(); - } - - File f = instance.getDataFile("debug", "caught-exceptions", n + ".txt"); - - if (!f.exists()) { - J.attempt(() -> { - PrintWriter pw = new PrintWriter(f); - pw.println("Thread: " + Thread.currentThread().getName()); - pw.println("First: " + new Date(M.ms())); - e.printStackTrace(pw); - pw.close(); - }); - } - - Iris.debug("Exception Logged: " + e.getClass().getSimpleName() + ": " + C.RESET + "" + C.LIGHT_PURPLE + e.getMessage()); - } - } - - public static void dump() { - try { - File fi = Iris.instance.getDataFile("dump", "td-" + new java.sql.Date(M.ms()) + ".txt"); - FileOutputStream fos = new FileOutputStream(fi); - Map f = Thread.getAllStackTraces(); - PrintWriter pw = new PrintWriter(fos); - for (Thread i : f.keySet()) { - pw.println("========================================"); - pw.println("Thread: '" + i.getName() + "' ID: " + i.getId() + " STATUS: " + i.getState().name()); - - for (StackTraceElement j : f.get(i)) { - pw.println(" @ " + j.toString()); - } - - pw.println("========================================"); - pw.println(); - pw.println(); - } - - pw.close(); - Iris.info("DUMPED! See " + fi.getAbsolutePath()); - } catch (Throwable e) { - e.printStackTrace(); - } - } - - public static void panic() { - EnginePanic.panic(); - } - - public static void addPanic(String s, String v) { - EnginePanic.add(s, v); - } - - private static void fixShading() { - ShadeFix.fix(ComponentSerializer.class); - } - private void enable() { - instance = this; - services = new KMap<>(); - setupAudience(); - setupSentry(); - initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class) i.getClass(), (IrisService) i)); - INMS.get(); - IO.delete(new File("iris")); - compat = IrisCompat.configured(getDataFile("compat.json")); - ServerConfigurator.configure(); - new IrisContextInjector(); - IrisSafeguard.IrisSafeguardSystem(); - getSender().setTag(getTag()); - IrisSafeguard.earlySplash(); - linkMultiverseCore = new MultiverseCoreLink(); - linkMythicMobs = new MythicMobsLink(); - configWatcher = new FileWatcher(getDataFile("settings.json")); - services.values().forEach(IrisService::onEnable); - services.values().forEach(this::registerListener); - J.s(() -> { - J.a(() -> PaperLib.suggestPaper(this)); - J.a(() -> IO.delete(getTemp())); - J.a(LazyPregenerator::loadLazyGenerators, 100); - J.a(this::bstats); - J.ar(this::checkConfigHotload, 60); - J.sr(this::tickQueue, 0); - J.s(this::setupPapi); - J.a(ServerConfigurator::configure, 20); - splash(); - UtilsSFG.splash(); - - autoStartStudio(); - checkForBukkitWorlds(); - IrisToolbelt.retainMantleDataForSlice(String.class.getCanonicalName()); - IrisToolbelt.retainMantleDataForSlice(BlockData.class.getCanonicalName()); - }); - } - - private void checkForBukkitWorlds() { - FileConfiguration fc = new YamlConfiguration(); - try { - fc.load(new File("bukkit.yml")); - ConfigurationSection section = fc.getConfigurationSection("worlds"); - if (section == null) { - return; - } - - for (String s : section.getKeys(false)) { - ConfigurationSection entry = section.getConfigurationSection(s); - if (!entry.contains("generator", true)) { - continue; - } - - String generator = entry.getString("generator"); - if (generator.startsWith("Iris:")) { - generator = generator.split("\\Q:\\E")[1]; - } else if (generator.equalsIgnoreCase("Iris")) { - generator = IrisSettings.get().getGenerator().getDefaultWorldType(); - } else { - continue; - } - - if (Bukkit.getWorld(s) != null) - continue; - - Iris.info("Loading World: %s | Generator: %s", s, generator); - - Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "..."); - WorldCreator c = new WorldCreator(s) - .generator(getDefaultWorldGenerator(s, generator)) - .environment(IrisData.loadAnyDimension(generator).getEnvironment()); - INMS.get().createWorld(c); - Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"); - } - } catch (Throwable e) { - e.printStackTrace(); - reportError(e); - } - } - - private void autoStartStudio() { - if (IrisSettings.get().getStudio().isAutoStartDefaultStudio()) { - Iris.info("Starting up auto Studio!"); - try { - Player r = new KList<>(getServer().getOnlinePlayers()).getRandom(); - Iris.service(StudioSVC.class).open(r != null ? new VolmitSender(r) : getSender(), 1337, IrisSettings.get().getGenerator().getDefaultWorldType(), (w) -> { - J.s(() -> { - for (Player i : getServer().getOnlinePlayers()) { - i.setGameMode(GameMode.SPECTATOR); - i.teleport(new Location(w, 0, 200, 0)); - } - }); - }); - } catch (IrisException e) { - reportError(e); - } - } - } - - private void setupAudience() { - try { - audiences = BukkitAudiences.create(this); - } catch (Throwable e) { - e.printStackTrace(); - IrisSettings.get().getGeneral().setUseConsoleCustomColors(false); - IrisSettings.get().getGeneral().setUseCustomColorsIngame(false); - Iris.error("Failed to setup Adventure API... No custom colors :("); - } - } - - public void postShutdown(Runnable r) { - postShutdown.add(r); - } - - public void onEnable() { - enable(); - super.onEnable(); - Bukkit.getPluginManager().registerEvents(this, this); - setupChecks(); - } - - public void onDisable() { - services.values().forEach(IrisService::onDisable); - Bukkit.getScheduler().cancelTasks(this); - HandlerList.unregisterAll((Plugin) this); - postShutdown.forEach(Runnable::run); - super.onDisable(); - - J.attempt(new JarScanner(instance.getJarFile(), "", false)::scan); - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - Bukkit.getWorlds() - .stream() - .map(IrisToolbelt::access) - .filter(Objects::nonNull) - .forEach(PlatformChunkGenerator::close); - - MultiBurst.burst.close(); - services.clear(); - })); - } - - private void setupPapi() { - if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { - new IrisPapiExpansion().register(); - } - } - - @Override - public void start() { - - } - - @Override - public void stop() { - - } - - @Override - public String getTag(String subTag) { - if (unstablemode) { - return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.RED + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": "; - } - if (warningmode) { - return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.GOLD + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": "; - } - return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.IRIS + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": "; - - } - - private boolean setupChecks() { - boolean passed = true; - Iris.info("Version Information: " + instance.getServer().getVersion() + " | " + instance.getServer().getBukkitVersion()); - if (INMS.get() instanceof NMSBinding1X) { - passed = false; - Iris.warn("============================================"); - Iris.warn("="); - Iris.warn("="); - Iris.warn("="); - Iris.warn("Iris is not compatible with this version of Minecraft."); - Iris.warn("="); - Iris.warn("="); - Iris.warn("="); - Iris.warn("============================================"); - } - - try { - Class.forName("io.papermc.paper.configuration.PaperConfigurations"); - } catch (ClassNotFoundException e) { - Iris.info(C.RED + "Iris requires paper or above to function properly.."); - return false; - } - - try { - Class.forName("org.purpurmc.purpur.PurpurConfig"); - } catch (ClassNotFoundException e) { - Iris.info("We recommend using Purpur for the best experience with Iris."); - Iris.info("Purpur is a fork of Paper that is optimized for performance and stability."); - Iris.info("Plugins that work on Spigot / Paper work on Purpur."); - Iris.info("You can download it here: https://purpurmc.org"); - return false; - } - return passed; - } - - private void checkConfigHotload() { - if (configWatcher.checkModified()) { - IrisSettings.invalidate(); - IrisSettings.get(); - configWatcher.checkModified(); - Iris.info("Hotloaded settings.json "); - } - } - - private void tickQueue() { - synchronized (Iris.syncJobs) { - if (!Iris.syncJobs.hasNext()) { - return; - } - - long ms = M.ms(); - - while (Iris.syncJobs.hasNext() && M.ms() - ms < 25) { - try { - Iris.syncJobs.next().run(); - } catch (Throwable e) { - e.printStackTrace(); - Iris.reportError(e); - } - } - } - } - - private void bstats() { - if (IrisSettings.get().getGeneral().isPluginMetrics()) { - J.s(() -> { - var metrics = new Metrics(Iris.instance, 24220); - metrics.addCustomChart(new SingleLineChart("custom_dimensions", () -> Bukkit.getWorlds() - .stream() - .filter(IrisToolbelt::isIrisWorld) - .mapToInt(w -> 1) - .sum())); - - metrics.addCustomChart(new DrilldownPie("used_packs", () -> Bukkit.getWorlds().stream() - .map(IrisToolbelt::access) - .filter(Objects::nonNull) - .map(PlatformChunkGenerator::getEngine) - .collect(Collectors.toMap(engine -> engine.getDimension().getLoadKey(), engine -> { - var hash32 = engine.getHash32().getNow(null); - if (hash32 == null) return Map.of(); - int version = engine.getDimension().getVersion(); - String checksum = Long.toHexString(hash32); - - return Map.of("v" + version + " (" + checksum + ")", 1); - }, (a, b) -> { - Map merged = new HashMap<>(a); - b.forEach((k, v) -> merged.merge(k, v, Integer::sum)); - return merged; - })))); - - - var info = new SystemInfo().getHardware(); - var cpu = info.getProcessor().getProcessorIdentifier(); - var mem = info.getMemory(); - metrics.addCustomChart(new SimplePie("cpu_model", cpu::getName)); - - var nf = NumberFormat.getInstance(Locale.ENGLISH); - nf.setMinimumFractionDigits(0); - nf.setMaximumFractionDigits(2); - nf.setRoundingMode(RoundingMode.HALF_UP); - - metrics.addCustomChart(new DrilldownPie("memory", () -> { - double total = mem.getTotal() * 1E-9; - double alloc = Math.min(total, Runtime.getRuntime().maxMemory() * 1E-9); - return Map.of(nf.format(alloc), Map.of(nf.format(total), 1)); - })); - - postShutdown.add(metrics::shutdown); - }); - } - } - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - return super.onCommand(sender, command, label, args); - } - - public void imsg(CommandSender s, String msg) { - s.sendMessage(C.IRIS + "[" + C.DARK_GRAY + "Iris" + C.IRIS + "]" + C.GRAY + ": " + msg); - } - - @Nullable - @Override - public BiomeProvider getDefaultBiomeProvider(@NotNull String worldName, @Nullable String id) { - Iris.debug("Biome Provider Called for " + worldName + " using ID: " + id); - return super.getDefaultBiomeProvider(worldName, id); - } - - @Override - public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { - Iris.debug("Default World Generator Called for " + worldName + " using ID: " + id); - if (worldName.equals("test")) { - try { - throw new RuntimeException(); - } catch (Throwable e) { - Iris.info(e.getStackTrace()[1].getClassName()); - if (e.getStackTrace()[1].getClassName().contains("com.onarandombox.MultiverseCore")) { - Iris.debug("MVC Test detected, Quick! Send them the dummy!"); - return new DummyChunkGenerator(); - } - } - } - - IrisDimension dim; - if (id == null || id.isEmpty()) { - dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType()); - } else { - dim = IrisData.loadAnyDimension(id); - } - Iris.debug("Generator ID: " + id + " requested by bukkit/plugin"); - - if (dim == null) { - Iris.warn("Unable to find dimension type " + id + " Looking for online packs..."); - - service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, true); - dim = IrisData.loadAnyDimension(id); - - if (dim == null) { - throw new RuntimeException("Can't find dimension " + id + "!"); - } else { - Iris.info("Resolved missing dimension, proceeding with generation."); - } - } - - Iris.debug("Assuming IrisDimension: " + dim.getName()); - - IrisWorld w = IrisWorld.builder() - .name(worldName) - .seed(1337) - .environment(dim.getEnvironment()) - .worldFolder(new File(Bukkit.getWorldContainer(), worldName)) - .minHeight(dim.getMinHeight()) - .maxHeight(dim.getMaxHeight()) - .build(); - - Iris.debug("Generator Config: " + w.toString()); - - File ff = new File(w.worldFolder(), "iris/pack"); - if (!ff.exists() || ff.listFiles().length == 0) { - ff.mkdirs(); - service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w.worldFolder()); - } - - return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey()); - } - - public void splash() { - if (!IrisSettings.get().getGeneral().isSplashLogoStartup()) { - return; - } - - String padd = Form.repeat(" ", 8); - String padd2 = Form.repeat(" ", 4); - String[] info = {"", "", "", "", "", padd2 + C.IRIS + " Iris", padd2 + C.GRAY + " by " + "Volmit Software", padd2 + C.GRAY + " v" + C.IRIS + getDescription().getVersion()}; - if (unstablemode) { - info = new String[]{"", "", "", "", "", padd2 + C.RED + " Iris", padd2 + C.GRAY + " by " + C.DARK_RED + "Volmit Software", padd2 + C.GRAY + " v" + C.RED + getDescription().getVersion()}; - } - if (warningmode) { - info = new String[]{"", "", "", "", "", padd2 + C.GOLD + " Iris", padd2 + C.GRAY + " by " + C.GOLD + "Volmit Software", padd2 + C.GRAY + " v" + C.GOLD + getDescription().getVersion()}; - } - - String[] splashstable = { - padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@", - padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.IRIS + " .(((()))). ", - padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.IRIS + " .((((((())))))). ", - padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.IRIS + " ((((((((())))))))) " + C.GRAY + " @", - padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.IRIS + " ((((((((-))))))))) " + C.GRAY + " @@", - padd + C.GRAY + "@@@&&" + C.IRIS + " ((((((({ })))))))) " + C.GRAY + " &&@@@", - padd + C.GRAY + "@@" + C.IRIS + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@", - padd + C.GRAY + "@" + C.IRIS + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@", - padd + C.GRAY + "" + C.IRIS + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@", - padd + C.GRAY + "" + C.IRIS + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@", - padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@" - }; - - String[] splashunstable = { - padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@", - padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.RED + " .(((()))). ", - padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.RED + " .((((((())))))). ", - padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.RED + " ((((((((())))))))) " + C.GRAY + " @", - padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.RED + " ((((((((-))))))))) " + C.GRAY + " @@", - padd + C.GRAY + "@@@&&" + C.RED + " ((((((({ })))))))) " + C.GRAY + " &&@@@", - padd + C.GRAY + "@@" + C.RED + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@", - padd + C.GRAY + "@" + C.RED + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@", - padd + C.GRAY + "" + C.RED + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@", - padd + C.GRAY + "" + C.RED + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@", - padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@" - }; - String[] splashwarning = { - padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@", - padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.GOLD + " .(((()))). ", - padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.GOLD + " .((((((())))))). ", - padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.GOLD + " ((((((((())))))))) " + C.GRAY + " @", - padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.GOLD + " ((((((((-))))))))) " + C.GRAY + " @@", - padd + C.GRAY + "@@@&&" + C.GOLD + " ((((((({ })))))))) " + C.GRAY + " &&@@@", - padd + C.GRAY + "@@" + C.GOLD + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@", - padd + C.GRAY + "@" + C.GOLD + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@", - padd + C.GRAY + "" + C.GOLD + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@", - padd + C.GRAY + "" + C.GOLD + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@", - padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@" - }; - String[] splash; - File freeSpace = new File(Bukkit.getWorldContainer() + "."); - if (unstablemode) { - splash = splashunstable; - } else if (warningmode) { - splash = splashwarning; - } else { - splash = splashstable; - } - - if (!passedserversoftware) { - Iris.info("Server type & version: " + C.RED + Bukkit.getVersion()); - } else { Iris.info("Server type & version: " + Bukkit.getVersion()); } - Iris.info("Java: " + getJava()); - if (getHardware.getProcessMemory() < 5999) { - Iris.warn("6GB+ Ram is recommended"); - Iris.warn("Process Memory: " + getHardware.getProcessMemory() + " MB"); - } - Iris.info("Bukkit distro: " + Bukkit.getName()); - Iris.info("Custom Biomes: " + INMS.get().countCustomBiomes()); - setupChecks(); - printPacks(); - - for (int i = 0; i < info.length; i++) { - splash[i] += info[i]; - } - - Iris.info("\n\n " + new KList<>(splash).toString("\n") + "\n"); - } - - private void printPacks() { - File packFolder = Iris.service(StudioSVC.class).getWorkspaceFolder(); - File[] packs = packFolder.listFiles(File::isDirectory); - if (packs == null || packs.length == 0) - return; - Iris.info("Custom Dimensions: " + packs.length); - for (File f : packs) - printPack(f); - } - - private void printPack(File pack) { - String dimName = pack.getName(); - String version = "???"; - try (FileReader r = new FileReader(new File(pack, "dimensions/" + dimName + ".json"))) { - JsonObject json = JsonParser.parseReader(r).getAsJsonObject(); - if (json.has("version")) - version = json.get("version").getAsString(); - } catch (IOException | JsonParseException ignored) { - } - Iris.info(" " + dimName + " v" + version); - } - - public int getIrisVersion() { - String input = Iris.instance.getDescription().getVersion(); - int hyphenIndex = input.indexOf('-'); - if (hyphenIndex != -1) { - String result = input.substring(0, hyphenIndex); - result = result.replaceAll("\\.", ""); - return Integer.parseInt(result); - } - return -1; - } - - public int getMCVersion() { - try { - String version = Bukkit.getVersion(); - Matcher matcher = Pattern.compile("\\(MC: ([\\d.]+)\\)").matcher(version); - if (matcher.find()) { - version = matcher.group(1).replaceAll("\\.", ""); - long versionNumber = Long.parseLong(version); - if (versionNumber > Integer.MAX_VALUE) { - return -1; - } - return (int) versionNumber; - } - return -1; - } catch (Exception e) { - return -1; - } - } - - private static void setupSentry() { - var settings = IrisSettings.get().getSentry(); - if (settings.disableAutoReporting || Sentry.isEnabled()) return; - Iris.info("Enabling Sentry for anonymous error reporting. You can disable this in the settings."); - Sentry.init(options -> { - options.setDsn("https://b16ecc222e9c1e0c48faecacb906fd89@o4509451052646400.ingest.de.sentry.io/4509452722765904"); - if (settings.debug) { - options.setLogger(new IrisLogger()); - options.setDebug(true); - } - - options.setAttachServerName(false); - options.setEnableUncaughtExceptionHandler(false); - options.setRelease(Iris.instance.getDescription().getVersion()); - options.setBeforeSend((event, hint) -> { - event.setTag("iris.safeguard", IrisSafeguard.mode()); - event.setTag("iris.nms", INMS.get().getClass().getCanonicalName()); - return event; - }); - }); - Sentry.configureScope(scope -> { - scope.addAttachment(Attachments.PLUGINS); - scope.setTag("server", Bukkit.getVersion()); - scope.setTag("server.type", Bukkit.getName()); - scope.setTag("server.api", Bukkit.getBukkitVersion()); - }); - Runtime.getRuntime().addShutdownHook(new Thread(Sentry::close)); - } -} +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2022 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.volmit.iris; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; +import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.ServerConfigurator; +import com.volmit.iris.core.link.IrisPapiExpansion; +import com.volmit.iris.core.link.MultiverseCoreLink; +import com.volmit.iris.core.link.MythicMobsLink; +import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.core.nms.INMS; +import com.volmit.iris.core.nms.v1X.NMSBinding1X; +import com.volmit.iris.core.pregenerator.LazyPregenerator; +import com.volmit.iris.core.safeguard.ServerBootSFG; +import com.volmit.iris.core.service.StudioSVC; +import com.volmit.iris.core.tools.IrisToolbelt; +import com.volmit.iris.engine.EnginePanic; +import com.volmit.iris.engine.object.IrisCompat; +import com.volmit.iris.engine.object.IrisContextInjector; +import com.volmit.iris.engine.object.IrisDimension; +import com.volmit.iris.engine.object.IrisWorld; +import com.volmit.iris.engine.platform.BukkitChunkGenerator; +import com.volmit.iris.engine.platform.DummyChunkGenerator; +import com.volmit.iris.core.safeguard.IrisSafeguard; +import com.volmit.iris.core.safeguard.UtilsSFG; +import com.volmit.iris.engine.platform.PlatformChunkGenerator; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.context.IrisContext; +import com.volmit.iris.util.exceptions.IrisException; +import com.volmit.iris.util.format.C; +import com.volmit.iris.util.format.Form; +import com.volmit.iris.util.function.NastyRunnable; +import com.volmit.iris.util.io.FileWatcher; +import com.volmit.iris.util.io.IO; +import com.volmit.iris.util.io.InstanceState; +import com.volmit.iris.util.io.JarScanner; +import com.volmit.iris.util.json.JSONException; +import com.volmit.iris.util.math.M; +import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.misc.getHardware; +import com.volmit.iris.util.parallel.MultiBurst; +import com.volmit.iris.util.plugin.IrisService; +import com.volmit.iris.util.plugin.VolmitPlugin; +import com.volmit.iris.util.plugin.VolmitSender; +import com.volmit.iris.util.reflect.ShadeFix; +import com.volmit.iris.util.scheduling.J; +import com.volmit.iris.util.scheduling.Queue; +import com.volmit.iris.util.scheduling.ShurikenQueue; +import com.volmit.iris.util.sentry.Attachments; +import com.volmit.iris.util.sentry.IrisLogger; +import com.volmit.iris.util.sentry.ServerID; +import io.papermc.lib.PaperLib; +import io.sentry.Sentry; +import net.kyori.adventure.platform.bukkit.BukkitAudiences; +import net.kyori.adventure.text.serializer.ComponentSerializer; +import org.bstats.bukkit.Metrics; +import org.bstats.charts.DrilldownPie; +import org.bstats.charts.SimplePie; +import org.bstats.charts.SingleLineChart; +import org.bukkit.*; +import org.bukkit.block.data.BlockData; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.event.*; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.plugin.IllegalPluginAccessException; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import oshi.SystemInfo; + +import java.io.*; +import java.lang.annotation.Annotation; +import java.math.RoundingMode; +import java.net.URL; +import java.text.NumberFormat; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static com.volmit.iris.core.safeguard.IrisSafeguard.*; +import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware; + +@SuppressWarnings("CanBeFinal") +public class Iris extends VolmitPlugin implements Listener { + private static final Queue syncJobs = new ShurikenQueue<>(); + + public static Iris instance; + public static BukkitAudiences audiences; + public static MultiverseCoreLink linkMultiverseCore; + public static MythicMobsLink linkMythicMobs; + public static IrisCompat compat; + public static FileWatcher configWatcher; + private static VolmitSender sender; + + static { + try { + fixShading(); + InstanceState.updateInstanceId(); + } catch (Throwable ignored) { + + } + } + + private final KList postShutdown = new KList<>(); + private KMap, IrisService> services; + + public static VolmitSender getSender() { + if (sender == null) { + sender = new VolmitSender(Bukkit.getConsoleSender()); + sender.setTag(instance.getTag()); + } + return sender; + } + + @SuppressWarnings("unchecked") + public static T service(Class c) { + return (T) instance.services.get(c); + } + + public static void callEvent(Event e) { + if (!e.isAsynchronous()) { + J.s(() -> Bukkit.getPluginManager().callEvent(e)); + } else { + Bukkit.getPluginManager().callEvent(e); + } + } + + public static KList initialize(String s, Class slicedClass) { + JarScanner js = new JarScanner(instance.getJarFile(), s); + KList v = new KList<>(); + J.attempt(js::scan); + for (Class i : js.getClasses()) { + if (slicedClass == null || i.isAnnotationPresent(slicedClass)) { + try { + v.add(i.getDeclaredConstructor().newInstance()); + } catch (Throwable ignored) { + + } + } + } + + return v; + } + + public static KList> getClasses(String s, Class slicedClass) { + JarScanner js = new JarScanner(instance.getJarFile(), s); + KList> v = new KList<>(); + J.attempt(js::scan); + for (Class i : js.getClasses()) { + if (slicedClass == null || i.isAnnotationPresent(slicedClass)) { + try { + v.add(i); + } catch (Throwable ignored) { + + } + } + } + + return v; + } + + public static KList initialize(String s) { + return initialize(s, null); + } + + public static void sq(Runnable r) { + synchronized (syncJobs) { + syncJobs.queue(r); + } + } + + public static File getTemp() { + return instance.getDataFolder("cache", "temp"); + } + + public static void msg(String string) { + try { + getSender().sendMessage(string); + } catch (Throwable e) { + try { + instance.getLogger().info(instance.getTag() + string.replaceAll("(<([^>]+)>)", "")); + } catch (Throwable ignored1) { + + } + } + } + + public static File getCached(String name, String url) { + String h = IO.hash(name + "@" + url); + File f = Iris.instance.getDataFile("cache", h.substring(0, 2), h.substring(3, 5), h); + + if (!f.exists()) { + try (BufferedInputStream in = new BufferedInputStream(new URL(url).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) { + byte[] dataBuffer = new byte[1024]; + int bytesRead; + while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) { + fileOutputStream.write(dataBuffer, 0, bytesRead); + Iris.verbose("Aquiring " + name); + } + } catch (IOException e) { + Iris.reportError(e); + } + } + + return f.exists() ? f : null; + } + + public static String getNonCached(String name, String url) { + String h = IO.hash(name + "*" + url); + File f = Iris.instance.getDataFile("cache", h.substring(0, 2), h.substring(3, 5), h); + + try (BufferedInputStream in = new BufferedInputStream(new URL(url).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) { + byte[] dataBuffer = new byte[1024]; + int bytesRead; + while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) { + fileOutputStream.write(dataBuffer, 0, bytesRead); + } + } catch (IOException e) { + Iris.reportError(e); + } + + try { + return IO.readAll(f); + } catch (IOException e) { + Iris.reportError(e); + } + + return ""; + } + + public static File getNonCachedFile(String name, String url) { + String h = IO.hash(name + "*" + url); + File f = Iris.instance.getDataFile("cache", h.substring(0, 2), h.substring(3, 5), h); + Iris.verbose("Download " + name + " -> " + url); + try (BufferedInputStream in = new BufferedInputStream(new URL(url).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) { + byte[] dataBuffer = new byte[1024]; + int bytesRead; + while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) { + fileOutputStream.write(dataBuffer, 0, bytesRead); + } + + fileOutputStream.flush(); + } catch (IOException e) { + e.printStackTrace(); + Iris.reportError(e); + } + + return f; + } + + public static void warn(String format, Object... objs) { + msg(C.YELLOW + String.format(format, objs)); + } + + public static void error(String format, Object... objs) { + msg(C.RED + String.format(format, objs)); + } + + public static void debug(String string) { + if (!IrisSettings.get().getGeneral().isDebug()) { + return; + } + + try { + throw new RuntimeException(); + } catch (Throwable e) { + try { + String[] cc = e.getStackTrace()[1].getClassName().split("\\Q.\\E"); + + if (cc.length > 5) { + debug(cc[3] + "/" + cc[4] + "/" + cc[cc.length - 1], e.getStackTrace()[1].getLineNumber(), string); + } else { + debug(cc[3] + "/" + cc[4], e.getStackTrace()[1].getLineNumber(), string); + } + } catch (Throwable ex) { + debug("Origin", -1, string); + } + } + } + + public static void debug(String category, int line, String string) { + if (!IrisSettings.get().getGeneral().isDebug()) { + return; + } + if (IrisSettings.get().getGeneral().isUseConsoleCustomColors()) { + msg("" + category + " <#bf3b76>" + line + " " + C.LIGHT_PURPLE + string.replaceAll("\\Q<\\E", "[").replaceAll("\\Q>\\E", "]")); + } else { + msg(C.BLUE + category + ":" + C.AQUA + line + C.RESET + C.LIGHT_PURPLE + " " + string.replaceAll("\\Q<\\E", "[").replaceAll("\\Q>\\E", "]")); + + } + } + + public static void verbose(String string) { + debug(string); + } + + public static void success(String string) { + msg(C.IRIS + string); + } + + public static void info(String format, Object... args) { + msg(C.WHITE + String.format(format, args)); + } + public static void safeguard(String format, Object... args) { + msg(C.RESET + String.format(format, args)); + } + + @SuppressWarnings("deprecation") + public static void later(NastyRunnable object) { + try { + Bukkit.getScheduler().scheduleAsyncDelayedTask(instance, () -> + { + try { + object.run(); + } catch (Throwable e) { + e.printStackTrace(); + Iris.reportError(e); + } + }, RNG.r.i(100, 1200)); + } catch (IllegalPluginAccessException ignored) { + + } + } + + public static int jobCount() { + return syncJobs.size(); + } + + public static void clearQueues() { + synchronized (syncJobs) { + syncJobs.clear(); + } + } + + public static int getJavaVersion() { + String version = System.getProperty("java.version"); + if (version.startsWith("1.")) { + version = version.substring(2, 3); + } else { + int dot = version.indexOf("."); + if (dot != -1) { + version = version.substring(0, dot); + } + } + return Integer.parseInt(version); + } + + public static String getJava() { + String javaRuntimeName = System.getProperty("java.vm.name"); + String javaRuntimeVendor = System.getProperty("java.vendor"); + String javaRuntimeVersion = System.getProperty("java.vm.version"); + return String.format("%s %s (build %s)", javaRuntimeName, javaRuntimeVendor, javaRuntimeVersion); + } + + public static void reportErrorChunk(int x, int z, Throwable e, String extra) { + if (IrisSettings.get().getGeneral().isDebug()) { + File f = instance.getDataFile("debug", "chunk-errors", "chunk." + x + "." + z + ".txt"); + + if (!f.exists()) { + J.attempt(() -> { + PrintWriter pw = new PrintWriter(f); + pw.println("Thread: " + Thread.currentThread().getName()); + pw.println("First: " + new Date(M.ms())); + e.printStackTrace(pw); + pw.close(); + }); + } + + Iris.debug("Chunk " + x + "," + z + " Exception Logged: " + e.getClass().getSimpleName() + ": " + C.RESET + "" + C.LIGHT_PURPLE + e.getMessage()); + } + } + + public static void reportError(Throwable e) { + Sentry.captureException(e); + if (IrisSettings.get().getGeneral().isDebug()) { + String n = e.getClass().getCanonicalName() + "-" + e.getStackTrace()[0].getClassName() + "-" + e.getStackTrace()[0].getLineNumber(); + + if (e.getCause() != null) { + n += "-" + e.getCause().getStackTrace()[0].getClassName() + "-" + e.getCause().getStackTrace()[0].getLineNumber(); + } + + File f = instance.getDataFile("debug", "caught-exceptions", n + ".txt"); + + if (!f.exists()) { + J.attempt(() -> { + PrintWriter pw = new PrintWriter(f); + pw.println("Thread: " + Thread.currentThread().getName()); + pw.println("First: " + new Date(M.ms())); + e.printStackTrace(pw); + pw.close(); + }); + } + + Iris.debug("Exception Logged: " + e.getClass().getSimpleName() + ": " + C.RESET + "" + C.LIGHT_PURPLE + e.getMessage()); + } + } + + public static void dump() { + try { + File fi = Iris.instance.getDataFile("dump", "td-" + new java.sql.Date(M.ms()) + ".txt"); + FileOutputStream fos = new FileOutputStream(fi); + Map f = Thread.getAllStackTraces(); + PrintWriter pw = new PrintWriter(fos); + for (Thread i : f.keySet()) { + pw.println("========================================"); + pw.println("Thread: '" + i.getName() + "' ID: " + i.getId() + " STATUS: " + i.getState().name()); + + for (StackTraceElement j : f.get(i)) { + pw.println(" @ " + j.toString()); + } + + pw.println("========================================"); + pw.println(); + pw.println(); + } + + pw.close(); + Iris.info("DUMPED! See " + fi.getAbsolutePath()); + } catch (Throwable e) { + e.printStackTrace(); + } + } + + public static void panic() { + EnginePanic.panic(); + } + + public static void addPanic(String s, String v) { + EnginePanic.add(s, v); + } + + private static void fixShading() { + ShadeFix.fix(ComponentSerializer.class); + } + private void enable() { + instance = this; + services = new KMap<>(); + setupAudience(); + setupSentry(); + initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class) i.getClass(), (IrisService) i)); + INMS.get(); + IO.delete(new File("iris")); + compat = IrisCompat.configured(getDataFile("compat.json")); + ServerConfigurator.configure(); + new IrisContextInjector(); + IrisSafeguard.IrisSafeguardSystem(); + getSender().setTag(getTag()); + IrisSafeguard.earlySplash(); + linkMultiverseCore = new MultiverseCoreLink(); + linkMythicMobs = new MythicMobsLink(); + configWatcher = new FileWatcher(getDataFile("settings.json")); + services.values().forEach(IrisService::onEnable); + services.values().forEach(this::registerListener); + J.s(() -> { + J.a(() -> PaperLib.suggestPaper(this)); + J.a(() -> IO.delete(getTemp())); + J.a(LazyPregenerator::loadLazyGenerators, 100); + J.a(this::bstats); + J.ar(this::checkConfigHotload, 60); + J.sr(this::tickQueue, 0); + J.s(this::setupPapi); + J.a(ServerConfigurator::configure, 20); + splash(); + UtilsSFG.splash(); + + autoStartStudio(); + checkForBukkitWorlds(); + IrisToolbelt.retainMantleDataForSlice(String.class.getCanonicalName()); + IrisToolbelt.retainMantleDataForSlice(BlockData.class.getCanonicalName()); + }); + } + + private void checkForBukkitWorlds() { + FileConfiguration fc = new YamlConfiguration(); + try { + fc.load(new File("bukkit.yml")); + ConfigurationSection section = fc.getConfigurationSection("worlds"); + if (section == null) { + return; + } + + for (String s : section.getKeys(false)) { + ConfigurationSection entry = section.getConfigurationSection(s); + if (!entry.contains("generator", true)) { + continue; + } + + String generator = entry.getString("generator"); + if (generator.startsWith("Iris:")) { + generator = generator.split("\\Q:\\E")[1]; + } else if (generator.equalsIgnoreCase("Iris")) { + generator = IrisSettings.get().getGenerator().getDefaultWorldType(); + } else { + continue; + } + + if (Bukkit.getWorld(s) != null) + continue; + + Iris.info("Loading World: %s | Generator: %s", s, generator); + + Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "..."); + WorldCreator c = new WorldCreator(s) + .generator(getDefaultWorldGenerator(s, generator)) + .environment(IrisData.loadAnyDimension(generator).getEnvironment()); + INMS.get().createWorld(c); + Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"); + } + } catch (Throwable e) { + e.printStackTrace(); + reportError(e); + } + } + + private void autoStartStudio() { + if (IrisSettings.get().getStudio().isAutoStartDefaultStudio()) { + Iris.info("Starting up auto Studio!"); + try { + Player r = new KList<>(getServer().getOnlinePlayers()).getRandom(); + Iris.service(StudioSVC.class).open(r != null ? new VolmitSender(r) : getSender(), 1337, IrisSettings.get().getGenerator().getDefaultWorldType(), (w) -> { + J.s(() -> { + for (Player i : getServer().getOnlinePlayers()) { + i.setGameMode(GameMode.SPECTATOR); + i.teleport(new Location(w, 0, 200, 0)); + } + }); + }); + } catch (IrisException e) { + reportError(e); + } + } + } + + private void setupAudience() { + try { + audiences = BukkitAudiences.create(this); + } catch (Throwable e) { + e.printStackTrace(); + IrisSettings.get().getGeneral().setUseConsoleCustomColors(false); + IrisSettings.get().getGeneral().setUseCustomColorsIngame(false); + Iris.error("Failed to setup Adventure API... No custom colors :("); + } + } + + public void postShutdown(Runnable r) { + postShutdown.add(r); + } + + public void onEnable() { + enable(); + super.onEnable(); + Bukkit.getPluginManager().registerEvents(this, this); + setupChecks(); + } + + public void onDisable() { + services.values().forEach(IrisService::onDisable); + Bukkit.getScheduler().cancelTasks(this); + HandlerList.unregisterAll((Plugin) this); + postShutdown.forEach(Runnable::run); + super.onDisable(); + + J.attempt(new JarScanner(instance.getJarFile(), "", false)::scan); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + Bukkit.getWorlds() + .stream() + .map(IrisToolbelt::access) + .filter(Objects::nonNull) + .forEach(PlatformChunkGenerator::close); + + MultiBurst.burst.close(); + services.clear(); + })); + } + + private void setupPapi() { + if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { + new IrisPapiExpansion().register(); + } + } + + @Override + public void start() { + + } + + @Override + public void stop() { + + } + + @Override + public String getTag(String subTag) { + if (unstablemode) { + return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.RED + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": "; + } + if (warningmode) { + return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.GOLD + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": "; + } + return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.IRIS + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": "; + + } + + private boolean setupChecks() { + boolean passed = true; + Iris.info("Version Information: " + instance.getServer().getVersion() + " | " + instance.getServer().getBukkitVersion()); + if (INMS.get() instanceof NMSBinding1X) { + passed = false; + Iris.warn("============================================"); + Iris.warn("="); + Iris.warn("="); + Iris.warn("="); + Iris.warn("Iris is not compatible with this version of Minecraft."); + Iris.warn("="); + Iris.warn("="); + Iris.warn("="); + Iris.warn("============================================"); + } + + try { + Class.forName("io.papermc.paper.configuration.PaperConfigurations"); + } catch (ClassNotFoundException e) { + Iris.info(C.RED + "Iris requires paper or above to function properly.."); + return false; + } + + try { + Class.forName("org.purpurmc.purpur.PurpurConfig"); + } catch (ClassNotFoundException e) { + Iris.info("We recommend using Purpur for the best experience with Iris."); + Iris.info("Purpur is a fork of Paper that is optimized for performance and stability."); + Iris.info("Plugins that work on Spigot / Paper work on Purpur."); + Iris.info("You can download it here: https://purpurmc.org"); + return false; + } + return passed; + } + + private void checkConfigHotload() { + if (configWatcher.checkModified()) { + IrisSettings.invalidate(); + IrisSettings.get(); + configWatcher.checkModified(); + Iris.info("Hotloaded settings.json "); + } + } + + private void tickQueue() { + synchronized (Iris.syncJobs) { + if (!Iris.syncJobs.hasNext()) { + return; + } + + long ms = M.ms(); + + while (Iris.syncJobs.hasNext() && M.ms() - ms < 25) { + try { + Iris.syncJobs.next().run(); + } catch (Throwable e) { + e.printStackTrace(); + Iris.reportError(e); + } + } + } + } + + private void bstats() { + if (IrisSettings.get().getGeneral().isPluginMetrics()) { + J.s(() -> { + var metrics = new Metrics(Iris.instance, 24220); + metrics.addCustomChart(new SingleLineChart("custom_dimensions", () -> Bukkit.getWorlds() + .stream() + .filter(IrisToolbelt::isIrisWorld) + .mapToInt(w -> 1) + .sum())); + + metrics.addCustomChart(new DrilldownPie("used_packs", () -> Bukkit.getWorlds().stream() + .map(IrisToolbelt::access) + .filter(Objects::nonNull) + .map(PlatformChunkGenerator::getEngine) + .collect(Collectors.toMap(engine -> engine.getDimension().getLoadKey(), engine -> { + var hash32 = engine.getHash32().getNow(null); + if (hash32 == null) return Map.of(); + int version = engine.getDimension().getVersion(); + String checksum = Long.toHexString(hash32); + + return Map.of("v" + version + " (" + checksum + ")", 1); + }, (a, b) -> { + Map merged = new HashMap<>(a); + b.forEach((k, v) -> merged.merge(k, v, Integer::sum)); + return merged; + })))); + + + var info = new SystemInfo().getHardware(); + var cpu = info.getProcessor().getProcessorIdentifier(); + var mem = info.getMemory(); + metrics.addCustomChart(new SimplePie("cpu_model", cpu::getName)); + + var nf = NumberFormat.getInstance(Locale.ENGLISH); + nf.setMinimumFractionDigits(0); + nf.setMaximumFractionDigits(2); + nf.setRoundingMode(RoundingMode.HALF_UP); + + metrics.addCustomChart(new DrilldownPie("memory", () -> { + double total = mem.getTotal() * 1E-9; + double alloc = Math.min(total, Runtime.getRuntime().maxMemory() * 1E-9); + return Map.of(nf.format(alloc), Map.of(nf.format(total), 1)); + })); + + postShutdown.add(metrics::shutdown); + }); + } + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + return super.onCommand(sender, command, label, args); + } + + public void imsg(CommandSender s, String msg) { + s.sendMessage(C.IRIS + "[" + C.DARK_GRAY + "Iris" + C.IRIS + "]" + C.GRAY + ": " + msg); + } + + @Nullable + @Override + public BiomeProvider getDefaultBiomeProvider(@NotNull String worldName, @Nullable String id) { + Iris.debug("Biome Provider Called for " + worldName + " using ID: " + id); + return super.getDefaultBiomeProvider(worldName, id); + } + + @Override + public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { + Iris.debug("Default World Generator Called for " + worldName + " using ID: " + id); + if (worldName.equals("test")) { + try { + throw new RuntimeException(); + } catch (Throwable e) { + Iris.info(e.getStackTrace()[1].getClassName()); + if (e.getStackTrace()[1].getClassName().contains("com.onarandombox.MultiverseCore")) { + Iris.debug("MVC Test detected, Quick! Send them the dummy!"); + return new DummyChunkGenerator(); + } + } + } + + IrisDimension dim; + if (id == null || id.isEmpty()) { + dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType()); + } else { + dim = IrisData.loadAnyDimension(id); + } + Iris.debug("Generator ID: " + id + " requested by bukkit/plugin"); + + if (dim == null) { + Iris.warn("Unable to find dimension type " + id + " Looking for online packs..."); + + service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, true); + dim = IrisData.loadAnyDimension(id); + + if (dim == null) { + throw new RuntimeException("Can't find dimension " + id + "!"); + } else { + Iris.info("Resolved missing dimension, proceeding with generation."); + } + } + + Iris.debug("Assuming IrisDimension: " + dim.getName()); + + IrisWorld w = IrisWorld.builder() + .name(worldName) + .seed(1337) + .environment(dim.getEnvironment()) + .worldFolder(new File(Bukkit.getWorldContainer(), worldName)) + .minHeight(dim.getMinHeight()) + .maxHeight(dim.getMaxHeight()) + .build(); + + Iris.debug("Generator Config: " + w.toString()); + + File ff = new File(w.worldFolder(), "iris/pack"); + if (!ff.exists() || ff.listFiles().length == 0) { + ff.mkdirs(); + service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w.worldFolder()); + } + + return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey()); + } + + public void splash() { + if (!IrisSettings.get().getGeneral().isSplashLogoStartup()) { + return; + } + + String padd = Form.repeat(" ", 8); + String padd2 = Form.repeat(" ", 4); + String[] info = {"", "", "", "", "", padd2 + C.IRIS + " Iris", padd2 + C.GRAY + " by " + "Volmit Software", padd2 + C.GRAY + " v" + C.IRIS + getDescription().getVersion()}; + if (unstablemode) { + info = new String[]{"", "", "", "", "", padd2 + C.RED + " Iris", padd2 + C.GRAY + " by " + C.DARK_RED + "Volmit Software", padd2 + C.GRAY + " v" + C.RED + getDescription().getVersion()}; + } + if (warningmode) { + info = new String[]{"", "", "", "", "", padd2 + C.GOLD + " Iris", padd2 + C.GRAY + " by " + C.GOLD + "Volmit Software", padd2 + C.GRAY + " v" + C.GOLD + getDescription().getVersion()}; + } + + String[] splashstable = { + padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@", + padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.IRIS + " .(((()))). ", + padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.IRIS + " .((((((())))))). ", + padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.IRIS + " ((((((((())))))))) " + C.GRAY + " @", + padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.IRIS + " ((((((((-))))))))) " + C.GRAY + " @@", + padd + C.GRAY + "@@@&&" + C.IRIS + " ((((((({ })))))))) " + C.GRAY + " &&@@@", + padd + C.GRAY + "@@" + C.IRIS + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@", + padd + C.GRAY + "@" + C.IRIS + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@", + padd + C.GRAY + "" + C.IRIS + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@", + padd + C.GRAY + "" + C.IRIS + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@", + padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@" + }; + + String[] splashunstable = { + padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@", + padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.RED + " .(((()))). ", + padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.RED + " .((((((())))))). ", + padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.RED + " ((((((((())))))))) " + C.GRAY + " @", + padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.RED + " ((((((((-))))))))) " + C.GRAY + " @@", + padd + C.GRAY + "@@@&&" + C.RED + " ((((((({ })))))))) " + C.GRAY + " &&@@@", + padd + C.GRAY + "@@" + C.RED + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@", + padd + C.GRAY + "@" + C.RED + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@", + padd + C.GRAY + "" + C.RED + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@", + padd + C.GRAY + "" + C.RED + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@", + padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@" + }; + String[] splashwarning = { + padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@", + padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.GOLD + " .(((()))). ", + padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.GOLD + " .((((((())))))). ", + padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.GOLD + " ((((((((())))))))) " + C.GRAY + " @", + padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.GOLD + " ((((((((-))))))))) " + C.GRAY + " @@", + padd + C.GRAY + "@@@&&" + C.GOLD + " ((((((({ })))))))) " + C.GRAY + " &&@@@", + padd + C.GRAY + "@@" + C.GOLD + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@", + padd + C.GRAY + "@" + C.GOLD + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@", + padd + C.GRAY + "" + C.GOLD + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@", + padd + C.GRAY + "" + C.GOLD + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@", + padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@" + }; + String[] splash; + File freeSpace = new File(Bukkit.getWorldContainer() + "."); + if (unstablemode) { + splash = splashunstable; + } else if (warningmode) { + splash = splashwarning; + } else { + splash = splashstable; + } + + if (!passedserversoftware) { + Iris.info("Server type & version: " + C.RED + Bukkit.getVersion()); + } else { Iris.info("Server type & version: " + Bukkit.getVersion()); } + Iris.info("Java: " + getJava()); + if (getHardware.getProcessMemory() < 5999) { + Iris.warn("6GB+ Ram is recommended"); + Iris.warn("Process Memory: " + getHardware.getProcessMemory() + " MB"); + } + Iris.info("Bukkit distro: " + Bukkit.getName()); + Iris.info("Custom Biomes: " + INMS.get().countCustomBiomes()); + setupChecks(); + printPacks(); + + for (int i = 0; i < info.length; i++) { + splash[i] += info[i]; + } + + Iris.info("\n\n " + new KList<>(splash).toString("\n") + "\n"); + } + + private void printPacks() { + File packFolder = Iris.service(StudioSVC.class).getWorkspaceFolder(); + File[] packs = packFolder.listFiles(File::isDirectory); + if (packs == null || packs.length == 0) + return; + Iris.info("Custom Dimensions: " + packs.length); + for (File f : packs) + printPack(f); + } + + private void printPack(File pack) { + String dimName = pack.getName(); + String version = "???"; + try (FileReader r = new FileReader(new File(pack, "dimensions/" + dimName + ".json"))) { + JsonObject json = JsonParser.parseReader(r).getAsJsonObject(); + if (json.has("version")) + version = json.get("version").getAsString(); + } catch (IOException | JsonParseException ignored) { + } + Iris.info(" " + dimName + " v" + version); + } + + public int getIrisVersion() { + String input = Iris.instance.getDescription().getVersion(); + int hyphenIndex = input.indexOf('-'); + if (hyphenIndex != -1) { + String result = input.substring(0, hyphenIndex); + result = result.replaceAll("\\.", ""); + return Integer.parseInt(result); + } + return -1; + } + + public int getMCVersion() { + try { + String version = Bukkit.getVersion(); + Matcher matcher = Pattern.compile("\\(MC: ([\\d.]+)\\)").matcher(version); + if (matcher.find()) { + version = matcher.group(1).replaceAll("\\.", ""); + long versionNumber = Long.parseLong(version); + if (versionNumber > Integer.MAX_VALUE) { + return -1; + } + return (int) versionNumber; + } + return -1; + } catch (Exception e) { + return -1; + } + } + + private static boolean suppress(Throwable e) { + return (e instanceof IllegalStateException ex && "zip file closed".equals(ex.getMessage())) || e instanceof JSONException; + } + + private static void setupSentry() { + var settings = IrisSettings.get().getSentry(); + if (settings.disableAutoReporting || Sentry.isEnabled() || !Boolean.getBoolean("iris.errorReporting")) return; + Iris.info("Enabling Sentry for anonymous error reporting. You can disable this in the settings."); + Iris.info("Your server ID is: " + ServerID.ID); + Sentry.init(options -> { + options.setDsn("https://b16ecc222e9c1e0c48faecacb906fd89@o4509451052646400.ingest.de.sentry.io/4509452722765904"); + if (settings.debug) { + options.setLogger(new IrisLogger()); + options.setDebug(true); + } + + options.setAttachServerName(false); + options.setEnableUncaughtExceptionHandler(false); + options.setRelease(Iris.instance.getDescription().getVersion()); + options.setBeforeSend((event, hint) -> { + if (suppress(event.getThrowable())) return null; + event.setTag("iris.safeguard", IrisSafeguard.mode()); + event.setTag("iris.nms", INMS.get().getClass().getCanonicalName()); + var context = IrisContext.get(); + if (context != null) event.getContexts().set("engine", context.asContext()); + event.getContexts().set("safeguard", ServerBootSFG.allIncompatibilities); + return event; + }); + }); + Sentry.configureScope(scope -> { + if (settings.includeServerId) scope.setUser(ServerID.asUser()); + scope.addAttachment(Attachments.PLUGINS); + scope.setTag("server", Bukkit.getVersion()); + scope.setTag("server.type", Bukkit.getName()); + scope.setTag("server.api", Bukkit.getBukkitVersion()); + }); + Runtime.getRuntime().addShutdownHook(new Thread(Sentry::close)); + } +} diff --git a/core/src/main/java/com/volmit/iris/core/IrisSettings.java b/core/src/main/java/com/volmit/iris/core/IrisSettings.java index 20c0fa265..c409c1f9d 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/core/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -132,7 +132,7 @@ public class IrisSettings { public boolean markerEntitySpawningSystem = true; public boolean effectSystem = true; public boolean worldEditWandCUI = true; - public boolean globalPregenCache = true; + public boolean globalPregenCache = false; } @Data @@ -225,6 +225,7 @@ public class IrisSettings { @Data public static class IrisSettingsSentry { + public boolean includeServerId = true; public boolean disableAutoReporting = false; public boolean debug = false; } 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 29d4fd80f..e96eb29ed 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 @@ -26,6 +26,7 @@ import com.volmit.iris.core.tools.IrisPackBenchmarking; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisDimension; +import com.volmit.iris.util.context.IrisContext; import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeOrigin; import com.volmit.iris.util.decree.annotations.Decree; @@ -73,6 +74,8 @@ public class CommandDeveloper implements DecreeExecutor { @Decree(description = "Send a test exception to sentry") public void Sentry() { + Engine engine = engine(); + if (engine != null) IrisContext.getOr(engine); Iris.reportError(new Exception("This is a test")); } diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java b/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java index 899ff7270..ccbf91c11 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java @@ -241,7 +241,8 @@ public class CommandObject implements DecreeExecutor { Location[] b = WandSVC.getCuboid(player()); - if (b == null) { + if (b == null || b[0] == null || b[1] == null) { + sender().sendMessage("No area selected."); return; } Location a1 = b[0].clone(); @@ -417,6 +418,10 @@ public class CommandObject implements DecreeExecutor { } Location[] b = WandSVC.getCuboid(player()); + if (b == null || b[0] == null || b[1] == null) { + sender().sendMessage("No area selected."); + return; + } Location a1 = b[0].clone(); Location a2 = b[1].clone(); Direction d = Direction.closest(player().getLocation().getDirection()).reverse(); @@ -477,6 +482,10 @@ public class CommandObject implements DecreeExecutor { } Location[] b = WandSVC.getCuboid(player()); + if (b == null || b[0] == null || b[1] == null) { + sender().sendMessage("No area selected."); + return; + } Location a1 = b[0].clone(); Location a2 = b[1].clone(); Location a1x = b[0].clone(); @@ -524,6 +533,10 @@ public class CommandObject implements DecreeExecutor { } Location[] b = WandSVC.getCuboid(player()); + if (b == null || b[0] == null || b[1] == null) { + sender().sendMessage("No area selected."); + return; + } b[0].add(new Vector(0, 1, 0)); b[1].add(new Vector(0, 1, 0)); Location a1 = b[0].clone(); diff --git a/core/src/main/java/com/volmit/iris/core/link/MythicMobsLink.java b/core/src/main/java/com/volmit/iris/core/link/MythicMobsLink.java index 8a7d1d7be..052952346 100644 --- a/core/src/main/java/com/volmit/iris/core/link/MythicMobsLink.java +++ b/core/src/main/java/com/volmit/iris/core/link/MythicMobsLink.java @@ -18,20 +18,33 @@ package com.volmit.iris.core.link; +import com.google.common.collect.Sets; +import com.volmit.iris.Iris; +import com.volmit.iris.core.tools.IrisToolbelt; +import io.lumine.mythic.api.adapters.AbstractLocation; +import io.lumine.mythic.api.config.MythicLineConfig; +import io.lumine.mythic.api.skills.conditions.ILocationCondition; import io.lumine.mythic.bukkit.MythicBukkit; +import io.lumine.mythic.bukkit.adapters.BukkitWorld; +import io.lumine.mythic.bukkit.events.MythicConditionLoadEvent; +import io.lumine.mythic.core.skills.SkillCondition; +import io.lumine.mythic.core.utils.annotations.MythicCondition; +import io.lumine.mythic.core.utils.annotations.MythicField; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Entity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; import org.bukkit.plugin.Plugin; import javax.annotation.Nullable; -import java.util.Collection; -import java.util.List; +import java.util.*; public class MythicMobsLink { public MythicMobsLink() { - + if (getPlugin() == null) return; + Iris.instance.registerListener(new ConditionListener()); } public boolean isEnabled() { @@ -49,12 +62,70 @@ public class MythicMobsLink { * @param location The location * @return The mob, or null if it can't be spawned */ - public @Nullable - Entity spawnMob(String mob, Location location) { + public @Nullable Entity spawnMob(String mob, Location location) { return isEnabled() ? MythicBukkit.inst().getMobManager().spawnMob(mob, location).getEntity().getBukkitEntity() : null; } public Collection getMythicMobTypes() { return isEnabled() ? MythicBukkit.inst().getMobManager().getMobNames() : List.of(); } + + private static class ConditionListener implements Listener { + @EventHandler + public void on(MythicConditionLoadEvent event) { + switch (event.getConditionName()) { + case "irisbiome" -> event.register(new IrisBiomeCondition(event.getConditionName(), event.getConfig())); + case "irisregion" -> event.register(new IrisRegionCondition(event.getConditionName(), event.getConfig())); + } + } + } + + @MythicCondition(author = "CrazyDev22", name = "irisbiome", description = "Tests if the target is within the given list of biomes") + public static class IrisBiomeCondition extends SkillCondition implements ILocationCondition { + @MythicField(name = "biome", aliases = {"b"}, description = "A list of biomes to check") + private Set biomes = Sets.newConcurrentHashSet(); + @MythicField(name = "surface", aliases = {"s"}, description = "If the biome check should only be performed on the surface") + private boolean surface; + + public IrisBiomeCondition(String line, MythicLineConfig mlc) { + super(line); + String b = mlc.getString(new String[]{"biome", "b"}, ""); + biomes.addAll(Arrays.asList(b.split(","))); + surface = mlc.getBoolean(new String[]{"surface", "s"}, false); + } + + @Override + public boolean check(AbstractLocation target) { + var access = IrisToolbelt.access(((BukkitWorld) target.getWorld()).getBukkitWorld()); + if (access == null) return false; + var engine = access.getEngine(); + if (engine == null) return false; + var biome = surface ? + engine.getSurfaceBiome(target.getBlockX(), target.getBlockZ()) : + engine.getBiomeOrMantle(target.getBlockX(), target.getBlockY() - engine.getMinHeight(), target.getBlockZ()); + return biomes.contains(biome.getLoadKey()); + } + } + + @MythicCondition(author = "CrazyDev22", name = "irisbiome", description = "Tests if the target is within the given list of biomes") + public static class IrisRegionCondition extends SkillCondition implements ILocationCondition { + @MythicField(name = "region", aliases = {"r"}, description = "A list of regions to check") + private Set regions = Sets.newConcurrentHashSet(); + + public IrisRegionCondition(String line, MythicLineConfig mlc) { + super(line); + String b = mlc.getString(new String[]{"region", "r"}, ""); + regions.addAll(Arrays.asList(b.split(","))); + } + + @Override + public boolean check(AbstractLocation target) { + var access = IrisToolbelt.access(((BukkitWorld) target.getWorld()).getBukkitWorld()); + if (access == null) return false; + var engine = access.getEngine(); + if (engine == null) return false; + var region = engine.getRegion(target.getBlockX(), target.getBlockZ()); + return regions.contains(region.getLoadKey()); + } + } } 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 6575abd37..a9b468e57 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 @@ -45,6 +45,7 @@ import lombok.ToString; import java.io.*; import java.util.Locale; +import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -240,8 +241,10 @@ public class ResourceLoader implements MeteredCache { for (String i : s) { burst.queue(() -> { T t = load(i); + if (t == null) + return; - if (t != null) { + synchronized (m) { m.add(t); } }); diff --git a/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java b/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java index 51351f657..df3951ea1 100644 --- a/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java @@ -187,7 +187,7 @@ public class IrisEngineSVC implements IrisService { return; try { - engine.getMantle().trim(tectonicLimit.get() / worlds.size()); + engine.getMantle().trim(tectonicLimit()); } catch (Throwable e) { Iris.reportError(e); Iris.error("EngineSVC: Failed to trim for " + name); @@ -204,7 +204,7 @@ public class IrisEngineSVC implements IrisService { try { long unloadStart = System.currentTimeMillis(); - int count = engine.getMantle().unloadTectonicPlate(tectonicLimit.get() / worlds.size()); + int count = engine.getMantle().unloadTectonicPlate(tectonicLimit()); if (count > 0) { Iris.debug(C.GOLD + "Unloaded " + C.YELLOW + count + " TectonicPlates in " + C.RED + Form.duration(System.currentTimeMillis() - unloadStart, 2)); } @@ -217,6 +217,10 @@ public class IrisEngineSVC implements IrisService { } } + private int tectonicLimit() { + return tectonicLimit.get() / Math.max(worlds.size(), 1); + } + @Synchronized private void close() { if (closed) return; 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 53d3800ac..8d984ba91 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 @@ -51,6 +51,7 @@ import org.bukkit.util.Vector; import java.awt.Color; import java.util.ArrayList; +import java.util.Arrays; import java.util.Objects; import java.util.concurrent.CountDownLatch; @@ -80,6 +81,8 @@ public class WandSVC implements IrisService { try { Location[] f = getCuboid(p); + if (f == null || f[0] == null || f[1] == null) + return null; Cuboid c = new Cuboid(f[0], f[1]); IrisObject s = new IrisObject(c.getSizeX(), c.getSizeY(), c.getSizeZ()); @@ -198,7 +201,9 @@ public class WandSVC implements IrisService { public static Location stringToLocation(String s) { try { String[] f = s.split("\\Q in \\E"); + if (f.length != 2) return null; String[] g = f[0].split("\\Q,\\E"); + if (g.length != 3) return null; return new Location(Bukkit.getWorld(f[1]), Integer.parseInt(g[0]), Integer.parseInt(g[1]), Integer.parseInt(g[2])); } catch (Throwable e) { Iris.reportError(e); @@ -357,6 +362,7 @@ public class WandSVC implements IrisService { try { if ((IrisSettings.get().getWorld().worldEditWandCUI && isHoldingWand(p)) || isWand(p.getInventory().getItemInMainHand())) { Location[] d = getCuboid(p); + if (d == null || d[0] == null || d[1] == null) return; new WandSelection(new Cuboid(d[0], d[1]), p).draw(); } } catch (Throwable e) { diff --git a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java index 7224ea295..2f9bd5a88 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -96,7 +96,6 @@ public class IrisEngine implements Engine { private EngineExecutionEnvironment execution; private EngineWorldManager worldManager; private volatile int parallelism; - private volatile int minHeight; private boolean failing; private boolean closed; private int cacheId; @@ -129,7 +128,6 @@ public class IrisEngine implements Engine { getData().setEngine(this); getData().loadPrefetch(this); Iris.info("Initializing Engine: " + target.getWorld().name() + "/" + target.getDimension().getLoadKey() + " (" + target.getDimension().getDimensionHeight() + " height) Seed: " + getSeedManager().getSeed()); - minHeight = 0; failing = false; closed = false; art = J.ar(this::tickRandomPlayer, 0); @@ -475,7 +473,7 @@ public class IrisEngine implements Engine { getEngineData().getStatistics().generatedChunk(); try { PrecisionStopwatch p = PrecisionStopwatch.start(); - Hunk blocks = vblocks.listen((xx, y, zz, t) -> catchBlockUpdates(x + xx, y + getMinHeight(), z + zz, t)); + Hunk blocks = vblocks.listen((xx, y, zz, t) -> catchBlockUpdates(x + xx, y, z + zz, t)); if (getDimension().isDebugChunkCrossSections() && ((x >> 4) % getDimension().getDebugCrossSectionsMod() == 0 || (z >> 4) % getDimension().getDebugCrossSectionsMod() == 0)) { for (int i = 0; i < 16; i++) { 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 9a87d26e9..010628b7d 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 @@ -78,7 +78,6 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; import java.awt.Color; -import java.util.Arrays; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -141,7 +140,9 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat return getTarget().getWorld().minHeight(); } - void setMinHeight(int min); + default void setMinHeight(int min) { + getTarget().getWorld().minHeight(min); + } @BlockCoordinates default void generate(int x, int z, TerrainChunk tc, boolean multicore) throws WrongEngineBroException { @@ -457,14 +458,11 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat } } - for (int i = 0; i < 4; i++) { - try { - Arrays.parallelSort(nitems, (a, b) -> rng.nextInt()); - break; - } catch (Throwable e) { - Iris.reportError(e); - - } + for (int i = nitems.length; i > 1; i--) { + int j = rng.nextInt(i); + ItemStack tmp = nitems[i - 1]; + nitems[i - 1] = nitems[j]; + nitems[j] = tmp; } inventory.setContents(nitems); diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleCarvingComponent.java b/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleCarvingComponent.java index 31762626f..8d067abfd 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleCarvingComponent.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/components/MantleCarvingComponent.java @@ -58,21 +58,21 @@ public class MantleCarvingComponent extends IrisMantleComponent { @ChunkCoordinates private void carve(IrisCarving carving, MantleWriter writer, RNG rng, int cx, int cz) { - carving.doCarving(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4); + carving.doCarving(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4, 0); } private int computeRadius() { var dimension = getDimension(); int max = 0; - max = Math.max(max, dimension.getCarving().getMaxRange(getData())); + max = Math.max(max, dimension.getCarving().getMaxRange(getData(), 0)); for (var i : dimension.getAllRegions(this::getData)) { - max = Math.max(max, i.getCarving().getMaxRange(getData())); + max = Math.max(max, i.getCarving().getMaxRange(getData(), 0)); } for (var i : dimension.getAllBiomes(this::getData)) { - max = Math.max(max, i.getCarving().getMaxRange(getData())); + max = Math.max(max, i.getCarving().getMaxRange(getData(), 0)); } return max; diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java b/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java index 65a9a59a8..f3f162a7d 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java @@ -19,6 +19,7 @@ package com.volmit.iris.engine.object; import com.volmit.iris.Iris; +import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.nms.INMS; @@ -34,8 +35,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; +import org.bukkit.Material; import org.bukkit.block.data.BlockData; -import org.bukkit.entity.EntityType; import java.util.Map; @@ -202,6 +203,14 @@ public class IrisBlockData extends IrisRegistrant { public TileData tryGetTile(IrisData data) { //TODO Do like a registry thing with the tile data registry. Also update the parsing of data to include **block** entities. var type = getBlockData(data).getMaterial(); + if (type == Material.SPAWNER && this.data.containsKey("entitySpawn")) { + String id = (String) this.data.get("entitySpawn"); + if (tileData == null) tileData = new KMap<>(); + KMap spawnData = (KMap) tileData.computeIfAbsent("SpawnData", k -> new KMap<>()); + KMap entity = (KMap) spawnData.computeIfAbsent("entity", k -> new KMap<>()); + entity.putIfAbsent("id", Identifier.fromString(id).toString()); + } + if (!INMS.get().hasTile(type) || tileData == null || tileData.isEmpty()) return null; return new TileData(type, this.tileData); diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCarving.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCarving.java index bf7efa6af..1da8b1a31 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCarving.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCarving.java @@ -61,21 +61,25 @@ public class IrisCarving { @BlockCoordinates - public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) { - doCarving(writer, rng, engine, x, y, z, -1); + public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int depth) { + doCarving(writer, rng, engine, x, y, z, depth, -1); } @BlockCoordinates - public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int waterHint) { + public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { + int nextRecursion = recursion + 1; + if (caves.isNotEmpty()) { for (IrisCavePlacer i : caves) { - i.generateCave(writer, rng, engine, x, y, z, waterHint); + if (recursion > i.getMaxRecursion()) continue; + i.generateCave(writer, rng, engine, x, y, z, nextRecursion, waterHint); } } if (ravines.isNotEmpty()) { for (IrisRavinePlacer i : ravines) { - i.generateRavine(writer, rng, engine, x, y, z, waterHint); + if (recursion > i.getMaxRecursion()) continue; + i.generateRavine(writer, rng, engine, x, y, z, nextRecursion, waterHint); } } @@ -104,15 +108,18 @@ public class IrisCarving { } } - public int getMaxRange(IrisData data) { + public int getMaxRange(IrisData data, int recursion) { int max = 0; + int nextRecursion = recursion + 1; for (IrisCavePlacer i : caves) { - max = Math.max(max, i.getSize(data)); + if (recursion > i.getMaxRecursion()) continue; + max = Math.max(max, i.getSize(data, nextRecursion)); } for (IrisRavinePlacer i : ravines) { - max = Math.max(max, i.getSize(data)); + if (recursion > i.getMaxRecursion()) continue; + max = Math.max(max, i.getSize(data, nextRecursion)); } if (elipsoids.isNotEmpty()) { diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java index 32ab22439..e0e818403 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCave.java @@ -66,10 +66,10 @@ public class IrisCave extends IrisRegistrant { } public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) { - generate(writer, rng, engine, x, y, z, -1); + generate(writer, rng, engine, x, y, z, 0, -1); } - public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int waterHint) { + public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { double girth = getWorm().getGirth().get(rng, x, z, engine.getData()); KList points = getWorm().generate(rng, engine.getData(), writer, verticalRange, x, y, z, (at) -> { @@ -92,7 +92,7 @@ public class IrisCave extends IrisRegistrant { int h = Math.min(Math.max(highestWater, waterHint), engine.getDimension().getFluidHeight()); for (IrisPosition i : points) { - fork.doCarving(writer, rng, engine, i.getX(), i.getY(), i.getZ(), h); + fork.doCarving(writer, rng, engine, i.getX(), i.getY(), i.getZ(), recursion, h); } MatterCavern c = new MatterCavern(true, customBiome, (byte) 0); @@ -108,7 +108,7 @@ public class IrisCave extends IrisRegistrant { } - public int getMaxSize(IrisData data) { - return getWorm().getMaxDistance() + fork.getMaxRange(data); + public int getMaxSize(IrisData data, int depth) { + return getWorm().getMaxDistance() + fork.getMaxRange(data, depth); } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCavePlacer.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCavePlacer.java index acaa55904..1a95493a1 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCavePlacer.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCavePlacer.java @@ -50,6 +50,10 @@ public class IrisCavePlacer implements IRare { @Desc("The cave to place") @RegistryListResource(IrisCave.class) private String cave; + @MinNumber(1) + @MaxNumber(256) + @Desc("The maximum recursion depth") + private int maxRecursion = 16; @Desc("If set to true, this cave is allowed to break the surface") private boolean breakSurface = true; @Desc("The height range this cave can spawn at. If breakSurface is false, the output of this range will be clamped by the current world height to prevent surface breaking.") @@ -60,10 +64,10 @@ public class IrisCavePlacer implements IRare { } public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z) { - generateCave(mantle, rng, engine, x, y, z, -1); + generateCave(mantle, rng, engine, x, y, z, 0, -1); } - public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z, int waterHint) { + public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { if (fail.get()) { return; } @@ -92,18 +96,18 @@ public class IrisCavePlacer implements IRare { } try { - cave.generate(mantle, rng, engine, x + rng.nextInt(15), y, z + rng.nextInt(15), waterHint); + cave.generate(mantle, rng, engine, x + rng.nextInt(15), y, z + rng.nextInt(15), recursion, waterHint); } catch (Throwable e) { e.printStackTrace(); fail.set(true); } } - public int getSize(IrisData data) { + public int getSize(IrisData data, int depth) { IrisCave cave = getRealCave(data); if (cave != null) { - return cave.getMaxSize(data); + return cave.getMaxSize(data, depth); } return 32; diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisRavine.java b/core/src/main/java/com/volmit/iris/engine/object/IrisRavine.java index ca6bb7bd4..e2d9a79e4 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisRavine.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisRavine.java @@ -93,10 +93,10 @@ public class IrisRavine extends IrisRegistrant { } public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) { - generate(writer, rng, engine, x, y, z, -1); + generate(writer, rng, engine, x, y, z, 0, -1); } - public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int waterHint) { + public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { KList pos = getWorm().generate(rng, engine.getData(), writer, null, x, y, z, (at) -> { }); CNG dg = depthStyle.getGenerator().createNoCache(rng, engine.getData()); @@ -135,7 +135,7 @@ public class IrisRavine extends IrisRegistrant { int width = (int) Math.round(bw.fitDouble(baseWidthStyle.getMin(), baseWidthStyle.getMax(), p.getX(), p.getZ())); int surface = (int) Math.round(rsurface - depth * 0.45); - fork.doCarving(writer, rng, engine, p.getX(), rng.i(surface - depth, surface), p.getZ(), Math.max(highestWater, waterHint)); + fork.doCarving(writer, rng, engine, p.getX(), rng.i(surface - depth, surface), p.getZ(), recursion, Math.max(highestWater, waterHint)); for (int i = surface + depth; i >= surface; i--) { if (i % ribThickness == 0) { @@ -184,7 +184,7 @@ public class IrisRavine extends IrisRegistrant { } - public int getMaxSize(IrisData data) { - return getWorm().getMaxDistance() + fork.getMaxRange(data); + public int getMaxSize(IrisData data, int depth) { + return getWorm().getMaxDistance() + fork.getMaxRange(data, depth); } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisRavinePlacer.java b/core/src/main/java/com/volmit/iris/engine/object/IrisRavinePlacer.java index 570859a63..fa65c5c79 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisRavinePlacer.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisRavinePlacer.java @@ -50,16 +50,20 @@ public class IrisRavinePlacer implements IRare { @Desc("The ravine to place") @RegistryListResource(IrisRavine.class) private String ravine; + @MinNumber(1) + @MaxNumber(256) + @Desc("The maximum recursion depth") + private int maxRecursion = 100; public IrisRavine getRealRavine(IrisData data) { return ravineCache.aquire(() -> data.getRavineLoader().load(getRavine())); } public void generateRavine(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z) { - generateRavine(mantle, rng, engine, x, y, z, -1); + generateRavine(mantle, rng, engine, x, y, z, 0, -1); } - public void generateRavine(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z, int waterHint) { + public void generateRavine(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) { if (fail.get()) { return; } @@ -80,14 +84,14 @@ public class IrisRavinePlacer implements IRare { try { int xx = x + rng.nextInt(15); int zz = z + rng.nextInt(15); - ravine.generate(mantle, rng, engine, xx, y, zz, waterHint); + ravine.generate(mantle, rng, engine, xx, y, zz, recursion, waterHint); } catch (Throwable e) { e.printStackTrace(); fail.set(true); } } - public int getSize(IrisData data) { - return getRealRavine(data).getMaxSize(data); + public int getSize(IrisData data, int depth) { + return getRealRavine(data).getMaxSize(data, depth); } } diff --git a/core/src/main/java/com/volmit/iris/util/context/IrisContext.java b/core/src/main/java/com/volmit/iris/util/context/IrisContext.java index 8b69eb867..73bae0e5e 100644 --- a/core/src/main/java/com/volmit/iris/util/context/IrisContext.java +++ b/core/src/main/java/com/volmit/iris/util/context/IrisContext.java @@ -87,4 +87,21 @@ public class IrisContext { public IrisComplex getComplex() { return engine.getComplex(); } + + public KMap asContext() { + var hash32 = engine.getHash32().getNow(null); + var dimension = engine.getDimension(); + var mantle = engine.getMantle(); + return new KMap() + .qput("studio", engine.isStudio()) + .qput("closed", engine.isClosed()) + .qput("pack", new KMap<>() + .qput("key", dimension == null ? "" : dimension.getLoadKey()) + .qput("version", dimension == null ? "" : dimension.getVersion()) + .qput("hash", hash32 == null ? "" : Long.toHexString(hash32))) + .qput("mantle", new KMap<>() + .qput("idle", mantle.getAdjustedIdleDuration()) + .qput("loaded", mantle.getLoadedRegionCount()) + .qput("queued", mantle.getUnloadRegionCount())); + } } diff --git a/core/src/main/java/com/volmit/iris/util/decree/DecreeSystem.java b/core/src/main/java/com/volmit/iris/util/decree/DecreeSystem.java index e76f62965..d22a8b822 100644 --- a/core/src/main/java/com/volmit/iris/util/decree/DecreeSystem.java +++ b/core/src/main/java/com/volmit/iris/util/decree/DecreeSystem.java @@ -160,7 +160,8 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter { } J.aBukkit(() -> { - if (!call(new VolmitSender(sender), args)) { + var volmit = new VolmitSender(sender); + if (!call(volmit, args)) { if (IrisSettings.get().getGeneral().isCommandSounds()) { if (sender instanceof Player) { @@ -169,7 +170,7 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter { } } - sender.sendMessage(C.RED + "Unknown Iris Command"); + volmit.sendMessage(C.RED + "Unknown Iris Command"); } else { if (IrisSettings.get().getGeneral().isCommandSounds()) { if (sender instanceof Player) { diff --git a/core/src/main/java/com/volmit/iris/util/format/C.java b/core/src/main/java/com/volmit/iris/util/format/C.java index de1893c8f..85deb3cac 100644 --- a/core/src/main/java/com/volmit/iris/util/format/C.java +++ b/core/src/main/java/com/volmit/iris/util/format/C.java @@ -376,6 +376,28 @@ public enum C { return "#" + Integer.toHexString(spin(color.awtColor(), h, s, b).getRGB()).substring(2); } + public static String mini(String s) { + String msg = compress(s); + StringBuilder b = new StringBuilder(); + boolean c = false; + + for (char i : msg.toCharArray()) { + if (!c) { + if (i == C.COLOR_CHAR) { + c = true; + continue; + } + b.append(i); + } else { + c = false; + C o = C.getByChar(i); + b.append(o.token); + } + } + + return b.toString(); + } + public static String aura(String s, int hrad, int srad, int vrad) { return aura(s, hrad, srad, vrad, 0.3D); } diff --git a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java index 9de145a3f..6e1e56e54 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java @@ -85,7 +85,6 @@ public class Mantle { this.worldHeight = worldHeight; this.ioTrim = new AtomicBoolean(false); this.ioTectonicUnload = new AtomicBoolean(false); - new File(dataFolder, ".tmp").mkdirs(); loadedRegions = new KMap<>(); lastUse = new KMap<>(); ioBurst = MultiBurst.burst; @@ -370,11 +369,10 @@ public class Mantle { */ public synchronized void close() { Iris.debug("Closing The Mantle " + C.DARK_AQUA + dataFolder.getAbsolutePath()); - if (closed.get()) { + if (closed.getAndSet(true)) { return; } - closed.set(true); hyperLock.disable(); BurstExecutor b = ioBurst.burst(toUnload.size()); loadedRegions.forEach((i, plate) -> b.queue(() -> { @@ -384,11 +382,11 @@ public class Mantle { oldFileForRegion(dataFolder, i).delete(); } catch (Throwable e) { Iris.error("Failed to write Tectonic Plate " + C.DARK_GREEN + Cache.keyX(i) + " " + Cache.keyZ(i)); + Iris.reportError(e); e.printStackTrace(); } })); loadedRegions.clear(); - IO.delete(new File(dataFolder, ".tmp")); try { b.complete(); @@ -396,6 +394,7 @@ public class Mantle { Iris.reportError(e); } + IO.delete(new File(dataFolder, ".tmp")); Iris.debug("The Mantle has Closed " + C.DARK_AQUA + dataFolder.getAbsolutePath()); } diff --git a/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java b/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java index 009993321..101019023 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java @@ -27,6 +27,7 @@ import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; import com.volmit.iris.util.io.CountingDataInputStream; +import com.volmit.iris.util.io.IO; import com.volmit.iris.util.scheduling.PrecisionStopwatch; import lombok.Getter; import net.jpountz.lz4.LZ4BlockInputStream; @@ -222,16 +223,8 @@ public class TectonicPlate { */ public void write(File file) throws IOException { PrecisionStopwatch p = PrecisionStopwatch.start(); - File temp = File.createTempFile("iris-tectonic-plate", ".bin", new File(file.getParentFile(), ".tmp")); - try { - try (DataOutputStream dos = new DataOutputStream(new LZ4BlockOutputStream(new FileOutputStream(temp)))) { - write(dos); - } - Files.move(temp.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING); - Iris.debug("Saved Tectonic Plate " + C.DARK_GREEN + file.getName() + C.RED + " in " + Form.duration(p.getMilliseconds(), 2)); - } finally { - temp.delete(); - } + IO.write(file, out -> new DataOutputStream(new LZ4BlockOutputStream(out)), this::write); + Iris.debug("Saved Tectonic Plate " + C.DARK_GREEN + file.getName() + C.RED + " in " + Form.duration(p.getMilliseconds(), 2)); } /** diff --git a/core/src/main/java/com/volmit/iris/util/particle/FastParticle.java b/core/src/main/java/com/volmit/iris/util/particle/FastParticle.java deleted file mode 100644 index 4052dbdd2..000000000 --- a/core/src/main/java/com/volmit/iris/util/particle/FastParticle.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.volmit.iris.util.particle; - -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.Player; - -/** - * Simple Bukkit Particles API with 1.7 to 1.13.2 support ! - *

- * You can find the project on GitHub - * - * @author MrMicky - */ -public final class FastParticle { - - private static final ParticleSender PARTICLE_SENDER; - - static { - if (FastReflection.optionalClass("org.bukkit.Particle$DustOptions").isPresent()) { - PARTICLE_SENDER = new ParticleSender.ParticleSender1_13(); - } else if (FastReflection.optionalClass("org.bukkit.Particle").isPresent()) { - PARTICLE_SENDER = new ParticleSender.ParticleSenderImpl(); - } else { - PARTICLE_SENDER = new ParticleSenderLegacy(); - } - } - - private FastParticle() { - throw new UnsupportedOperationException(); - } - - /* - * Worlds methods - */ - public static void spawnParticle(World world, ParticleType particle, Location location, int count) { - spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count); - } - - public static void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count) { - spawnParticle(world, particle, x, y, z, count, null); - } - - public static void spawnParticle(World world, ParticleType particle, Location location, int count, T data) { - spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, data); - } - - public static void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count, - T data) { - spawnParticle(world, particle, x, y, z, count, 0.0D, 0.0D, 0.0D, data); - } - - public static void spawnParticle(World world, ParticleType particle, Location location, int count, double offsetX, - double offsetY, double offsetZ) { - spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ); - } - - public static void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count, - double offsetX, double offsetY, double offsetZ) { - spawnParticle(world, particle, x, y, z, count, offsetX, offsetY, offsetZ, null); - } - - public static void spawnParticle(World world, ParticleType particle, Location location, int count, - double offsetX, double offsetY, double offsetZ, T data) { - spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, - offsetZ, data); - } - - public static void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count, - double offsetX, double offsetY, double offsetZ, T data) { - spawnParticle(world, particle, x, y, z, count, offsetX, offsetY, offsetZ, 1.0D, data); - } - - public static void spawnParticle(World world, ParticleType particle, Location location, int count, double offsetX, - double offsetY, double offsetZ, double extra) { - spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, extra); - } - - public static void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count, - double offsetX, double offsetY, double offsetZ, double extra) { - spawnParticle(world, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, null); - } - - public static void spawnParticle(World world, ParticleType particle, Location location, int count, - double offsetX, double offsetY, double offsetZ, double extra, T data) { - spawnParticle(world, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, extra, data); - } - - public static void spawnParticle(World world, ParticleType particle, double x, double y, double z, int count, - double offsetX, double offsetY, double offsetZ, double extra, T data) { - sendParticle(world, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data); - } - - /* - * Player methods - */ - public static void spawnParticle(Player player, ParticleType particle, Location location, int count) { - spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count); - } - - public static void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count) { - spawnParticle(player, particle, x, y, z, count, null); - } - - public static void spawnParticle(Player player, ParticleType particle, Location location, int count, T data) { - spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, data); - } - - public static void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count, - T data) { - spawnParticle(player, particle, x, y, z, count, 0.0D, 0.0D, 0.0D, data); - } - - public static void spawnParticle(Player player, ParticleType particle, Location location, int count, double offsetX, - double offsetY, double offsetZ) { - spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ); - } - - public static void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count, - double offsetX, double offsetY, double offsetZ) { - spawnParticle(player, particle, x, y, z, count, offsetX, offsetY, offsetZ, null); - } - - public static void spawnParticle(Player player, ParticleType particle, Location location, int count, - double offsetX, double offsetY, double offsetZ, T data) { - spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, data); - } - - public static void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count, - double offsetX, double offsetY, double offsetZ, T data) { - spawnParticle(player, particle, x, y, z, count, offsetX, offsetY, offsetZ, 1.0D, data); - } - - public static void spawnParticle(Player player, ParticleType particle, Location location, int count, double offsetX, - double offsetY, double offsetZ, double extra) { - spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, extra); - } - - public static void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count, - double offsetX, double offsetY, double offsetZ, double extra) { - spawnParticle(player, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, null); - } - - public static void spawnParticle(Player player, ParticleType particle, Location location, int count, - double offsetX, double offsetY, double offsetZ, double extra, T data) { - spawnParticle(player, particle, location.getX(), location.getY(), location.getZ(), count, offsetX, offsetY, offsetZ, extra, data); - } - - public static void spawnParticle(Player player, ParticleType particle, double x, double y, double z, int count, - double offsetX, double offsetY, double offsetZ, double extra, T data) { - sendParticle(player, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data); - } - - private static void sendParticle(Object receiver, ParticleType particle, double x, double y, double z, int count, - double offsetX, double offsetY, double offsetZ, double extra, Object data) { - if (!particle.isSupported()) { - throw new IllegalArgumentException("The particle '" + particle + "' is not compatible with your server version"); - } - - PARTICLE_SENDER.spawnParticle(receiver, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data); - } -} diff --git a/core/src/main/java/com/volmit/iris/util/particle/FastReflection.java b/core/src/main/java/com/volmit/iris/util/particle/FastReflection.java deleted file mode 100644 index ee5994fb6..000000000 --- a/core/src/main/java/com/volmit/iris/util/particle/FastReflection.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.volmit.iris.util.particle; - -import com.volmit.iris.Iris; -import org.bukkit.Bukkit; - -import java.util.Optional; - -/** - * Small reflection class to use CraftBukkit and NMS - * - * @author MrMicky - */ -public final class FastReflection { - - public static final String OBC_PACKAGE = "org.bukkit.craftbukkit"; - public static final String NMS_PACKAGE = "net.minecraft.server"; - - public static final String VERSION = Bukkit.getServer().getClass().getPackage().getName().substring(OBC_PACKAGE.length() + 1); - - private FastReflection() { - throw new UnsupportedOperationException(); - } - - public static String nmsClassName(String className) { - return NMS_PACKAGE + '.' + VERSION + '.' + className; - } - - public static Class nmsClass(String className) throws ClassNotFoundException { - return Class.forName(nmsClassName(className)); - } - - public static Optional> nmsOptionalClass(String className) { - return optionalClass(nmsClassName(className)); - } - - public static String obcClassName(String className) { - return OBC_PACKAGE + '.' + VERSION + '.' + className; - } - - public static Class obcClass(String className) throws ClassNotFoundException { - return Class.forName(obcClassName(className)); - } - - public static Optional> obcOptionalClass(String className) { - return optionalClass(obcClassName(className)); - } - - public static Optional> optionalClass(String className) { - try { - return Optional.of(Class.forName(className)); - } catch (ClassNotFoundException e) { - Iris.reportError(e); - return Optional.empty(); - } - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - public static Object enumValueOf(Class enumClass, String enumName) { - return Enum.valueOf((Class) enumClass, enumName.toUpperCase()); - } -} \ No newline at end of file diff --git a/core/src/main/java/com/volmit/iris/util/particle/ParticleSender.java b/core/src/main/java/com/volmit/iris/util/particle/ParticleSender.java deleted file mode 100644 index d9ac0a401..000000000 --- a/core/src/main/java/com/volmit/iris/util/particle/ParticleSender.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.volmit.iris.util.particle; - -import com.volmit.iris.Iris; -import org.bukkit.Bukkit; -import org.bukkit.Color; -import org.bukkit.Particle; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.entity.Player; -import org.bukkit.material.MaterialData; - -/** - * Particle sender using the Bukkit particles API for 1.9+ servers - * - * @author MrMicky - */ -@SuppressWarnings("deprecation") -interface ParticleSender { - - void spawnParticle(Object receiver, ParticleType particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, Object data); - - Object getParticle(ParticleType particle); - - boolean isValidData(Object particle, Object data); - - default double color(double color) { - return color / 255.0; - } - - class ParticleSenderImpl implements ParticleSender { - - @Override - public void spawnParticle(Object receiver, ParticleType particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, Object data) { - Particle bukkitParticle = Particle.valueOf(particle.toString()); - - if (data instanceof Color) { - if (particle.getDataType() == Color.class) { - Color color = (Color) data; - count = 0; - offsetX = color(color.getRed()); - offsetY = color(color.getGreen()); - offsetZ = color(color.getBlue()); - extra = 1.0; - } - data = null; - } - - if (receiver instanceof World) { - ((World) receiver).spawnParticle(bukkitParticle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data); - } else if (receiver instanceof Player) { - ((Player) receiver).spawnParticle(bukkitParticle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data); - } - } - - @Override - public Particle getParticle(ParticleType particle) { - try { - return Particle.valueOf(particle.toString()); - } catch (IllegalArgumentException e) { - Iris.reportError(e); - return null; - } - } - - @Override - public boolean isValidData(Object particle, Object data) { - return isValidDataBukkit((Particle) particle, data); - } - - public boolean isValidDataBukkit(Particle particle, Object data) { - return particle.getDataType() == Void.class || particle.getDataType().isInstance(data); - } - } - - class ParticleSender1_13 extends ParticleSenderImpl { - @Override - public void spawnParticle(Object receiver, ParticleType particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, Object data) { - Particle bukkitParticle = Particle.valueOf(particle.toString()); - - if (bukkitParticle.getDataType() == Particle.DustOptions.class) { - if (data instanceof Color) { - data = new Particle.DustOptions((Color) data, 1); - } else if (data == null) { - data = new Particle.DustOptions(Color.RED, 1); - } - } else if (bukkitParticle.getDataType() == BlockData.class && data instanceof MaterialData) { - data = Bukkit.createBlockData(((MaterialData) data).getItemType()); - } - - super.spawnParticle(receiver, particle, x, y, z, count, offsetX, offsetY, offsetZ, extra, data); - } - - @Override - public boolean isValidDataBukkit(Particle particle, Object data) { - if (particle.getDataType() == Particle.DustOptions.class && data instanceof Color) { - return true; - } - - if (particle.getDataType() == BlockData.class && data instanceof MaterialData) { - return true; - } - - return super.isValidDataBukkit(particle, data); - } - } -} diff --git a/core/src/main/java/com/volmit/iris/util/particle/ParticleSenderLegacy.java b/core/src/main/java/com/volmit/iris/util/particle/ParticleSenderLegacy.java deleted file mode 100644 index 1668de313..000000000 --- a/core/src/main/java/com/volmit/iris/util/particle/ParticleSenderLegacy.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.volmit.iris.util.particle; - -import com.volmit.iris.Iris; -import org.bukkit.Color; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.material.MaterialData; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -/** - * Legacy particle sender with NMS for 1.7/1.8 servers - * - * @author MrMicky - */ -@SuppressWarnings({"deprecation", "JavaReflectionInvocation"}) -class ParticleSenderLegacy implements ParticleSender { - - private static final boolean SERVER_IS_1_8; - - private static final Constructor PACKET_PARTICLE; - private static final Class ENUM_PARTICLE; - - private static final Method WORLD_GET_HANDLE; - private static final Method WORLD_SEND_PARTICLE; - - private static final Method PLAYER_GET_HANDLE; - private static final Field PLAYER_CONNECTION; - private static final Method SEND_PACKET; - private static final int[] EMPTY = new int[0]; - - static { - ENUM_PARTICLE = FastReflection.nmsOptionalClass("EnumParticle").orElse(null); - SERVER_IS_1_8 = ENUM_PARTICLE != null; - - try { - Class packetParticleClass = FastReflection.nmsClass("PacketPlayOutWorldParticles"); - Class playerClass = FastReflection.nmsClass("EntityPlayer"); - Class playerConnectionClass = FastReflection.nmsClass("PlayerConnection"); - Class worldClass = FastReflection.nmsClass("WorldServer"); - Class entityPlayerClass = FastReflection.nmsClass("EntityPlayer"); - - Class craftPlayerClass = FastReflection.obcClass("entity.CraftPlayer"); - Class craftWorldClass = FastReflection.obcClass("CraftWorld"); - - if (SERVER_IS_1_8) { - PACKET_PARTICLE = packetParticleClass.getConstructor(ENUM_PARTICLE, boolean.class, float.class, - float.class, float.class, float.class, float.class, float.class, float.class, int.class, - int[].class); - WORLD_SEND_PARTICLE = worldClass.getDeclaredMethod("sendParticles", entityPlayerClass, ENUM_PARTICLE, - boolean.class, double.class, double.class, double.class, int.class, double.class, double.class, - double.class, double.class, int[].class); - } else { - PACKET_PARTICLE = packetParticleClass.getConstructor(String.class, float.class, float.class, float.class, - float.class, float.class, float.class, float.class, int.class); - WORLD_SEND_PARTICLE = worldClass.getDeclaredMethod("a", String.class, double.class, double.class, - double.class, int.class, double.class, double.class, double.class, double.class); - } - - WORLD_GET_HANDLE = craftWorldClass.getDeclaredMethod("getHandle"); - PLAYER_GET_HANDLE = craftPlayerClass.getDeclaredMethod("getHandle"); - PLAYER_CONNECTION = playerClass.getField("playerConnection"); - SEND_PACKET = playerConnectionClass.getMethod("sendPacket", FastReflection.nmsClass("Packet")); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - } - - @Override - public void spawnParticle(Object receiver, ParticleType particle, double x, double y, double z, int count, double offsetX, double offsetY, - double offsetZ, double extra, Object data) { - try { - int[] datas = toData(particle, data); - - if (data instanceof Color) { - if (particle.getDataType() == Color.class) { - Color color = (Color) data; - count = 0; - offsetX = color(color.getRed()); - offsetY = color(color.getGreen()); - offsetZ = color(color.getBlue()); - extra = 1.0; - } - } - - if (receiver instanceof World) { - Object worldServer = WORLD_GET_HANDLE.invoke(receiver); - - if (SERVER_IS_1_8) { - WORLD_SEND_PARTICLE.invoke(worldServer, null, getEnumParticle(particle), true, x, y, z, count, offsetX, offsetY, offsetZ, extra, datas); - } else { - String particleName = particle.getLegacyName() + (datas.length != 2 ? "" : "_" + datas[0] + "_" + datas[1]); - WORLD_SEND_PARTICLE.invoke(worldServer, particleName, x, y, z, count, offsetX, offsetY, offsetZ, extra); - } - } else if (receiver instanceof Player) { - Object packet; - - if (SERVER_IS_1_8) { - packet = PACKET_PARTICLE.newInstance(getEnumParticle(particle), true, (float) x, (float) y, - (float) z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count, datas); - } else { - String particleName = particle.getLegacyName() + (datas.length != 2 ? "" : "_" + datas[0] + "_" + datas[1]); - packet = PACKET_PARTICLE.newInstance(particleName, (float) x, (float) y, (float) z, - (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count); - } - - Object entityPlayer = PLAYER_GET_HANDLE.invoke(receiver); - Object playerConnection = PLAYER_CONNECTION.get(entityPlayer); - SEND_PACKET.invoke(playerConnection, packet); - } - } catch (ReflectiveOperationException e) { - Iris.reportError(e); - throw new RuntimeException(e); - } - } - - @Override - public boolean isValidData(Object particle, Object data) { - return true; - } - - @Override - public Object getParticle(ParticleType particle) { - if (!SERVER_IS_1_8) { - return particle.getLegacyName(); - } - - try { - return getEnumParticle(particle); - } catch (IllegalArgumentException e) { - Iris.reportError(e); - return null; - } - } - - private Object getEnumParticle(ParticleType particleType) { - return FastReflection.enumValueOf(ENUM_PARTICLE, particleType.toString()); - } - - private int[] toData(ParticleType particle, Object data) { - Class dataType = particle.getDataType(); - if (dataType == ItemStack.class) { - if (!(data instanceof ItemStack itemStack)) { - return SERVER_IS_1_8 ? new int[2] : new int[]{1, 0}; - } - - return new int[]{itemStack.getType().getId(), itemStack.getDurability()}; - } - - if (dataType == MaterialData.class) { - if (!(data instanceof MaterialData materialData)) { - return SERVER_IS_1_8 ? new int[1] : new int[]{1, 0}; - } - - if (SERVER_IS_1_8) { - return new int[]{materialData.getItemType().getId() + (materialData.getData() << 12)}; - } else { - return new int[]{materialData.getItemType().getId(), materialData.getData()}; - } - } - - return EMPTY; - } -} diff --git a/core/src/main/java/com/volmit/iris/util/particle/ParticleType.java b/core/src/main/java/com/volmit/iris/util/particle/ParticleType.java deleted file mode 100644 index 25da1bd75..000000000 --- a/core/src/main/java/com/volmit/iris/util/particle/ParticleType.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.volmit.iris.util.particle; - -import com.volmit.iris.Iris; -import org.bukkit.Color; -import org.bukkit.inventory.ItemStack; -import org.bukkit.material.MaterialData; - -/** - * @author MrMicky - */ -@SuppressWarnings("deprecation") -public enum ParticleType { - - // 1.7+ - EXPLOSION_NORMAL("explode", "poof"), - EXPLOSION_LARGE("largeexplode", "explosion"), - EXPLOSION_HUGE("hugeexplosion", "explosion_emitter"), - FIREWORKS_SPARK("fireworksSpark", "firework"), - WATER_BUBBLE("bubble", "bubble"), - WATER_SPLASH("splash", "splash"), - WATER_WAKE("wake", "fishing"), - SUSPENDED("suspended", "underwater"), - SUSPENDED_DEPTH("depthsuspend", "underwater"), - CRIT("crit", "crit"), - CRIT_MAGIC("magicCrit", "enchanted_hit"), - SMOKE_NORMAL("smoke", "smoke"), - SMOKE_LARGE("largesmoke", "large_smoke"), - SPELL("spell", "effect"), - SPELL_INSTANT("instantSpell", "instant_effect"), - SPELL_MOB("mobSpell", "entity_effect"), - SPELL_MOB_AMBIENT("mobSpellAmbient", "ambient_entity_effect"), - SPELL_WITCH("witchMagic", "witch"), - DRIP_WATER("dripWater", "dripping_water"), - DRIP_LAVA("dripLava", "dripping_lava"), - VILLAGER_ANGRY("angryVillager", "angry_villager"), - VILLAGER_HAPPY("happyVillager", "happy_villager"), - TOWN_AURA("townaura", "mycelium"), - NOTE("note", "note"), - PORTAL("portal", "portal"), - ENCHANTMENT_TABLE("enchantmenttable", "enchant"), - FLAME("flame", "flame"), - LAVA("lava", "lava"), - // FOOTSTEP("footstep", null), - CLOUD("cloud", "cloud"), - REDSTONE("reddust", "dust"), - SNOWBALL("snowballpoof", "item_snowball"), - SNOW_SHOVEL("snowshovel", "item_snowball"), - SLIME("slime", "item_slime"), - HEART("heart", "heart"), - ITEM_CRACK("iconcrack", "item"), - BLOCK_CRACK("blockcrack", "block"), - BLOCK_DUST("blockdust", "block"), - - // 1.8+ - BARRIER("barrier", "barrier", 8), - WATER_DROP("droplet", "rain", 8), - MOB_APPEARANCE("mobappearance", "elder_guardian", 8), - // ITEM_TAKE("take", null, 8), - - // 1.9+ - DRAGON_BREATH("dragonbreath", "dragon_breath", 9), - END_ROD("endRod", "end_rod", 9), - DAMAGE_INDICATOR("damageIndicator", "damage_indicator", 9), - SWEEP_ATTACK("sweepAttack", "sweep_attack", 9), - - // 1.10+ - FALLING_DUST("fallingdust", "falling_dust", 10), - - // 1.11+ - TOTEM("totem", "totem_of_undying", 11), - SPIT("spit", "spit", 11), - - // 1.13+ - SQUID_INK(13), - BUBBLE_POP(13), - CURRENT_DOWN(13), - BUBBLE_COLUMN_UP(13), - NAUTILUS(13), - DOLPHIN(13), - - // 1.14+ - SNEEZE(14), - CAMPFIRE_COSY_SMOKE(14), - CAMPFIRE_SIGNAL_SMOKE(14), - COMPOSTER(14), - FLASH(14), - FALLING_LAVA(14), - LANDING_LAVA(14), - FALLING_WATER(14), - - // 1.15+ - DRIPPING_HONEY(15), - FALLING_HONEY(15), - LANDING_HONEY(15), - FALLING_NECTAR(15); - - private static final int SERVER_VERSION_ID; - - static { - String ver = FastReflection.VERSION; - SERVER_VERSION_ID = ver.charAt(4) == '_' ? Character.getNumericValue(ver.charAt(3)) : Integer.parseInt(ver.substring(3, 5)); - } - - private final String legacyName; - private final String name; - private final int minimumVersion; - - // 1.7 particles - ParticleType(String legacyName, String name) { - this(legacyName, name, -1); - } - - // 1.13+ particles - ParticleType(int minimumVersion) { - this.legacyName = null; - this.name = name().toLowerCase(); - this.minimumVersion = minimumVersion; - } - - // 1.8-1.12 particles - ParticleType(String legacyName, String name, int minimumVersion) { - this.legacyName = legacyName; - this.name = name; - this.minimumVersion = minimumVersion; - } - - public static ParticleType getParticle(String particleName) { - try { - return ParticleType.valueOf(particleName.toUpperCase()); - } catch (IllegalArgumentException e) { - Iris.reportError(e); - for (ParticleType particle : values()) { - if (particle.getName().equalsIgnoreCase(particleName)) { - return particle; - } - - if (particle.hasLegacyName() && particle.getLegacyName().equalsIgnoreCase(particleName)) { - return particle; - } - } - } - return null; - } - - public boolean hasLegacyName() { - return legacyName != null; - } - - public String getLegacyName() { - if (!hasLegacyName()) { - throw new IllegalStateException("Particle " + name() + " don't have legacy name"); - } - return legacyName; - } - - public String getName() { - return name; - } - - public boolean isSupported() { - return minimumVersion <= 0 || SERVER_VERSION_ID >= minimumVersion; - } - - public Class getDataType() { - return switch (this) { - case ITEM_CRACK -> ItemStack.class; - case BLOCK_CRACK, BLOCK_DUST, FALLING_DUST -> - //noinspection deprecation - MaterialData.class; - case REDSTONE -> Color.class; - default -> Void.class; - }; - } -} diff --git a/core/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java b/core/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java index 217b44054..dccb95ce7 100644 --- a/core/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java +++ b/core/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java @@ -264,7 +264,7 @@ public class VolmitSender implements CommandSender { private Component createNoPrefixComponent(String message) { if (!IrisSettings.get().getGeneral().canUseCustomColors(this)) { String t = C.translateAlternateColorCodes('&', MiniMessage.miniMessage().stripTags(message)); - return MiniMessage.miniMessage().deserialize(t); + return MiniMessage.miniMessage().deserialize(C.mini(t)); } String t = C.translateAlternateColorCodes('&', message); @@ -273,13 +273,13 @@ public class VolmitSender implements CommandSender { } private Component createNoPrefixComponentNoProcessing(String message) { - return MiniMessage.builder().postProcessor(c -> c).build().deserialize(message); + return MiniMessage.builder().postProcessor(c -> c).build().deserialize(C.mini(message)); } private Component createComponent(String message) { if (!IrisSettings.get().getGeneral().canUseCustomColors(this)) { String t = C.translateAlternateColorCodes('&', MiniMessage.miniMessage().stripTags(getTag() + message)); - return MiniMessage.miniMessage().deserialize(t); + return MiniMessage.miniMessage().deserialize(C.mini(t)); } String t = C.translateAlternateColorCodes('&', getTag() + message); @@ -290,11 +290,11 @@ public class VolmitSender implements CommandSender { private Component createComponentRaw(String message) { if (!IrisSettings.get().getGeneral().canUseCustomColors(this)) { String t = C.translateAlternateColorCodes('&', MiniMessage.miniMessage().stripTags(getTag() + message)); - return MiniMessage.miniMessage().deserialize(t); + return MiniMessage.miniMessage().deserialize(C.mini(t)); } String t = C.translateAlternateColorCodes('&', getTag() + message); - return MiniMessage.miniMessage().deserialize(t); + return MiniMessage.miniMessage().deserialize(C.mini(t)); } public void showWaiting(String passive, CompletableFuture f) { diff --git a/core/src/main/java/com/volmit/iris/util/sentry/ServerID.java b/core/src/main/java/com/volmit/iris/util/sentry/ServerID.java new file mode 100644 index 000000000..da766574e --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/sentry/ServerID.java @@ -0,0 +1,59 @@ +package com.volmit.iris.util.sentry; + +import com.volmit.iris.util.io.IO; +import io.sentry.protocol.User; +import lombok.SneakyThrows; +import org.bukkit.Bukkit; +import oshi.SystemInfo; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class ServerID { + public static final String ID = calculate(); + + public static User asUser() { + User u = new User(); + u.setId(ID); + return u; + } + + @SneakyThrows + private static String calculate() { + Digest md = new Digest(); + md.update(System.getProperty("java.vm.name")); + md.update(System.getProperty("java.vm.version")); + md.update(new SystemInfo().getHardware().getProcessor().toString()); + md.update(Runtime.getRuntime().maxMemory()); + for (var p : Bukkit.getPluginManager().getPlugins()) { + md.update(p.getName()); + } + + return IO.bytesToHex(md.digest()); + } + + private static final class Digest { + private final MessageDigest md = MessageDigest.getInstance("SHA-256"); + private final byte[] buffer = new byte[8]; + private final ByteBuffer wrapped = ByteBuffer.wrap(buffer); + + private Digest() throws NoSuchAlgorithmException { + } + + public void update(String string) { + if (string == null) return; + md.update(string.getBytes(StandardCharsets.UTF_8)); + } + + public void update(long Long) { + wrapped.putLong(0, Long); + md.update(buffer, 0, 8); + } + + public byte[] digest() { + return md.digest(); + } + } +} diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml index 7ff73ff7e..0a58f5d00 100644 --- a/core/src/main/resources/plugin.yml +++ b/core/src/main/resources/plugin.yml @@ -23,5 +23,5 @@ libraries: commands: iris: aliases: [ ir, irs ] -api-version: '${apiversion}' +api-version: '${apiVersion}' hotload-dependencies: false \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f2..e6441136f 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 48c0a02ca..ff23a68d7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c78733..1aa94a426 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ @@ -205,6 +214,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index ac1b06f93..7101f8e46 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +41,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/settings.gradle b/settings.gradle.kts similarity index 74% rename from settings.gradle rename to settings.gradle.kts index 9315a1131..c45462895 100644 --- a/settings.gradle +++ b/settings.gradle.kts @@ -23,19 +23,19 @@ pluginManagement { } } plugins { - id "org.gradle.toolchains.foojay-resolver-convention" version "0.8.0" + id ("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } -rootProject.name = 'Iris' +rootProject.name = "Iris" -include(':core') +include(":core") include( - ':nms:v1_21_R4', - ':nms:v1_21_R3', - ':nms:v1_21_R2', - ':nms:v1_21_R1', - ':nms:v1_20_R4', - ':nms:v1_20_R3', - ':nms:v1_20_R2', - ':nms:v1_20_R1', + ":nms:v1_21_R4", + ":nms:v1_21_R3", + ":nms:v1_21_R2", + ":nms:v1_21_R1", + ":nms:v1_20_R4", + ":nms:v1_20_R3", + ":nms:v1_20_R2", + ":nms:v1_20_R1", ) \ No newline at end of file