9
0
mirror of https://github.com/VolmitSoftware/Iris.git synced 2025-12-21 07:59:30 +00:00

Compare commits

..

19 Commits

Author SHA1 Message Date
Julian Krings
eff598d005 update headless dev command 2025-04-02 16:42:39 +02:00
Julian Krings
d86ec7b1cd Merge remote-tracking branch 'origin/dev' into feat/headless
# Conflicts:
#	core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java
#	core/src/main/java/com/volmit/iris/core/commands/CommandIris.java
#	core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java
#	core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java
#	nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java
#	nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java
#	nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java
#	nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java
#	nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java
#	nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java
#	nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java
2025-04-02 16:33:51 +02:00
Julian Krings
0d9a45dfd9 disable headless pregen on world creation for benchmark worlds 2025-03-18 16:12:09 +01:00
Julian Krings
8a55bbfd20 Merge branch 'dev' into feat/headless
# Conflicts:
#	core/src/main/java/com/volmit/iris/core/commands/CommandIris.java
2025-03-07 16:17:23 +01:00
Julian Krings
5934c43b70 Merge branch 'dev' into feat/headless 2025-02-18 17:10:23 +01:00
Julian Krings
11567b13d3 potentially fix chunk position bug 2025-02-18 17:08:08 +01:00
Julian Krings
2087ba88b1 fix adding chunks to region while being saved 2025-02-09 12:33:20 +01:00
Julian Krings
e9d1b9f18e prevent Biome.CUSTOM from being resolved on <1.21.3 2025-02-08 21:45:51 +01:00
Julian Krings
6e84d38680 set chunk status to full AFTER generation 2025-02-08 20:59:20 +01:00
Julian Krings
22622f6e8a set chunk status to full on creation 2025-02-08 20:22:18 +01:00
Julian Krings
735203aa95 exclude asm from shadowJar 2025-02-08 12:20:27 +01:00
Julian Krings
013bc365a9 implement headless on all supported versions 2025-02-08 12:07:13 +01:00
Julian Krings
c2dfbac641 refactor headless to decrease duplicate code in nms bindings 2025-02-07 21:51:23 +01:00
Julian Krings
7d472c0b13 Merge branch 'dev' into feat/headless
# Conflicts:
#	core/src/main/java/com/volmit/iris/core/commands/CommandIris.java
2025-02-06 23:29:22 +01:00
Julian Krings
5b4ab0a3c1 add headless pregen dev command 2025-02-04 10:55:39 +01:00
Julian Krings
e8dd81b014 add headless to world creation 2025-01-29 16:36:04 +01:00
Julian Krings
d32cc281e3 fix compile after merge 2025-01-29 14:32:04 +01:00
Julian Krings
2ff6b59271 Merge branch 'dev' into feat/headless 2025-01-29 14:30:17 +01:00
Julian Krings
3ff87566f5 implement headless for 1.21.4 2025-01-26 14:28:59 +01:00
355 changed files with 14719 additions and 20511 deletions

259
build.gradle Normal file
View File

@@ -0,0 +1,259 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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"
}
version '3.6.5-1.20.1-1.21.4'
// 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 NMS_BINDINGS = Map.of(
"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.each { nms ->
project(":nms:${nms.key}") {
apply plugin: 'java'
apply plugin: 'com.volmit.nmstools'
nmsTools {
it.jvm = JVM_VERSION.getOrDefault(nms.key, 21)
it.version = nms.value
}
dependencies {
implementation project(":core")
}
}
}
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'
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'
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/snapshots/" }
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
}
}
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)

View File

@@ -1,283 +0,0 @@
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 <https://www.gnu.org/licenses/>.
*/
buildscript {
repositories.maven("https://jitpack.io")
dependencies.classpath("com.github.VolmitSoftware:NMSTools:c88961416f")
}
plugins {
java
`java-library`
alias(libs.plugins.download)
alias(libs.plugins.runPaper)
}
group = "com.volmit"
version = "3.8.0-1.20.1-1.21.10"
apply<ApiGenerator>()
// 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 = "10G"
val serverMaxHeap = "10G"
val additionalFlags = "-XX:+AlwaysPreTouch"
//Valid values are: none, truecolor, indexed256, indexed16, indexed8
val color = "truecolor"
val errorReporting = "true" == findProperty("errorReporting")
val nmsBindings = mapOf(
"v1_21_R6" to "1.21.10-R0.1-SNAPSHOT",
"v1_21_R5" to "1.21.8-R0.1-SNAPSHOT",
"v1_21_R4" to "1.21.5-R0.1-SNAPSHOT",
"v1_21_R3" to "1.21.4-R0.1-SNAPSHOT",
"v1_21_R2" to "1.21.3-R0.1-SNAPSHOT",
"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<String, Int>()
nmsBindings.forEach { (key, value) ->
project(":nms:$key") {
apply<JavaPlugin>()
nmsBinding {
jvm = jvmVersion.getOrDefault(key, 21)
version = value
type = NMSBinding.Type.DIRECT
}
dependencies {
compileOnly(project(":core"))
compileOnly(rootProject.libs.annotations)
compileOnly(rootProject.libs.byteBuddy.core)
}
}
tasks.register<RunServer>("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", "true")
systemProperty("net.kyori.ansi.colorLevel", color)
systemProperty("com.mojang.eula.agree", true)
systemProperty("iris.suppressReporting", !errorReporting)
jvmArgs("-javaagent:${project(":core:agent").tasks.jar.flatMap { it.archiveFile }.get().asFile.absolutePath}")
jvmArgs(additionalFlags.split(' '))
}
}
val included: Configuration by configurations.creating
val jarJar: Configuration by configurations.creating
dependencies {
for (key in nmsBindings.keys) {
included(project(":nms:$key", "reobf"))
}
included(project(":core", "shadow"))
jarJar(project(":core:agent"))
}
tasks {
jar {
inputs.files(included)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from(jarJar, provider { included.resolve().map(::zipTree) })
archiveFileName.set("Iris-${project.version}.jar")
}
register<Copy>("iris") {
group = "iris"
dependsOn("jar")
from(layout.buildDirectory.file("libs/Iris-${project.version}.jar"))
into(layout.buildDirectory)
}
register<Copy>("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<Download>("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 url = "http://sentry.volmit.com:8080"
val authToken = project.findProperty("sentry.auth.token") ?: System.getenv("SENTRY_AUTH_TOKEN")
val org = "sentry"
val projectName = "iris"
exec(cli, "--url", url , "--auth-token", authToken, "releases", "new", "-o", org, "-p", projectName, version)
exec(cli, "--url", url , "--auth-token", authToken, "releases", "set-commits", "-o", org, "-p", projectName, version, "--auto", "--ignore-missing")
//exec(cli, "--url", url, "--auth-token", authToken, "releases", "finalize", "-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()
}
configurations.configureEach {
resolutionStrategy.cacheChangingModulesFor(60, "minutes")
resolutionStrategy.cacheDynamicVersionsFor(60, "minutes")
}
allprojects {
apply<JavaPlugin>()
repositories {
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.codemc.org/repository/maven-public/")
maven("https://jitpack.io") // EcoItems, score
maven("https://repo.nexomc.com/releases/") // nexo
maven("https://maven.devs.beer/") // itemsadder
maven("https://repo.extendedclip.com/releases/") // placeholderapi
maven("https://mvn.lumine.io/repository/maven-public/") // mythic
maven("https://nexus.phoenixdevt.fr/repository/maven-public/") //MMOItems
maven("https://repo.onarandombox.com/content/groups/public/") //Multiverse Core
}
dependencies {
// Provided or Classpath
compileOnly(rootProject.libs.lombok)
annotationProcessor(rootProject.libs.lombok)
}
/**
* 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<Jar>("sourcesJar") {
archiveClassifier.set("sources")
from(sourceSets.main.map { it.allSource })
}
register<Jar>("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<Copy>("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<Copy>("build$name") {
group = "development"
outputs.upToDateWhen { false }
dependsOn("iris")
from(layout.buildDirectory.file("Iris-${project.version}.jar"))
into(file(path))
rename { "Iris.jar" }
}
}

View File

@@ -1,16 +0,0 @@
plugins {
kotlin("jvm") version embeddedKotlinVersion
}
repositories {
mavenCentral()
gradlePluginPortal()
maven("https://jitpack.io")
}
dependencies {
implementation("org.ow2.asm:asm:9.8")
implementation("com.github.VolmitSoftware:NMSTools:c88961416f")
implementation("io.papermc.paperweight:paperweight-userdev:2.0.0-beta.18")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
}

View File

@@ -1,121 +0,0 @@
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.jvm.tasks.Jar
import org.objectweb.asm.*
import java.io.File
import java.util.jar.JarFile
import java.util.jar.JarOutputStream
class ApiGenerator : Plugin<Project> {
override fun apply(target: Project): Unit = with(target) {
plugins.apply("maven-publish")
val task = tasks.register("irisApi", GenerateApiTask::class.java)
extensions.findByType(PublishingExtension::class.java)!!.apply {
repositories.maven {
it.name = "deployDir"
it.url = targetDirectory.toURI()
}
publications.create("maven", MavenPublication::class.java) {
it.groupId = name
it.version = version.toString()
it.artifact(task)
}
}
}
}
abstract class GenerateApiTask : DefaultTask() {
init {
group = "iris"
dependsOn("jar")
finalizedBy("publishMavenPublicationToDeployDirRepository")
doLast {
logger.lifecycle("The API is located at ${outputFile.absolutePath}")
}
}
@InputFile
val inputFile: File = project.tasks
.named("jar", Jar::class.java)
.get()
.archiveFile
.get()
.asFile
@OutputFile
val outputFile: File = project.targetDirectory.resolve(inputFile.name)
@TaskAction
fun generate() {
JarFile(inputFile).use { jar ->
JarOutputStream(outputFile.apply { parentFile?.mkdirs() }.outputStream()).use { out ->
jar.stream()
.parallel()
.filter { !it.isDirectory }
.filter { it.name.endsWith(".class") }
.forEach {
val bytes = jar.getInputStream(it).use { input ->
val writer = ClassWriter(ClassWriter.COMPUTE_MAXS)
val visitor = MethodClearingVisitor(writer)
ClassReader(input).accept(visitor, 0)
writer.toByteArray()
}
synchronized(out) {
out.putNextEntry(it)
out.write(bytes)
out.closeEntry()
}
}
}
}
}
}
val Project.targetDirectory: File get() {
val dir = System.getenv("DEPLOY_DIR") ?: return project.layout.buildDirectory.dir("api").get().asFile
return File(dir)
}
private class MethodClearingVisitor(
cv: ClassVisitor
) : ClassVisitor(Opcodes.ASM9, cv) {
override fun visitMethod(
access: Int,
name: String?,
descriptor: String?,
signature: String?,
exceptions: Array<out String>?
) = ExceptionThrowingMethodVisitor(super.visitMethod(access, name, descriptor, signature, exceptions))
}
private class ExceptionThrowingMethodVisitor(
mv: MethodVisitor
) : MethodVisitor(Opcodes.ASM9, mv) {
override fun visitCode() {
if (mv == null) return
mv.visitCode()
mv.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException")
mv.visitInsn(Opcodes.DUP)
mv.visitLdcInsn("Only API")
mv.visitMethodInsn(
Opcodes.INVOKESPECIAL,
"java/lang/IllegalStateException",
"<init>", "(Ljava/lang/String;)V", false
)
mv.visitInsn(Opcodes.ATHROW)
mv.visitMaxs(0, 0)
mv.visitEnd()
}
}

View File

@@ -1,182 +0,0 @@
import NMSBinding.Type
import com.volmit.nmstools.NMSToolsExtension
import com.volmit.nmstools.NMSToolsPlugin
import io.papermc.paperweight.userdev.PaperweightUser
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
import io.papermc.paperweight.userdev.PaperweightUserExtension
import io.papermc.paperweight.userdev.attribute.Obfuscation
import io.papermc.paperweight.util.constants.REOBF_CONFIG
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.gradle.api.*
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.LibraryElements
import org.gradle.api.attributes.Usage
import org.gradle.api.model.ObjectFactory
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.tasks.TaskAction
import org.gradle.internal.extensions.core.extra
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.jvm.toolchain.JavaToolchainService
import org.gradle.work.DisableCachingByDefault
import java.io.RandomAccessFile
import javax.inject.Inject
class NMSBinding : Plugin<Project> {
override fun apply(target: Project): Unit = with(target) {
val config = extra["nms"] as? Config ?: throw GradleException("No NMS binding configuration found")
val jvm = config.jvm
val type = config.type
if (type == Type.USER_DEV) {
plugins.apply(PaperweightUser::class.java)
dependencies.extensions.findByType(PaperweightUserDependenciesExtension::class.java)
?.paperDevBundle(config.version)
val java = extensions.findByType(JavaPluginExtension::class.java) ?: throw GradleException("Java plugin not found")
java.toolchain.languageVersion.set(JavaLanguageVersion.of(jvm))
val javaToolchains = project.extensions.getByType(JavaToolchainService::class.java) ?: throw GradleException("Java toolchain service not found")
extensions.configure(PaperweightUserExtension::class.java) {
it.javaLauncher.set(javaToolchains.launcherFor(java.toolchain))
}
} else {
extra["nmsTools.useBuildTools"] = type == Type.BUILD_TOOLS
plugins.apply(NMSToolsPlugin::class.java)
extensions.configure(NMSToolsExtension::class.java) {
it.jvm.set(jvm)
it.version.set(config.version)
}
configurations.register(REOBF_CONFIG) { conf ->
conf.isCanBeConsumed = true
conf.isCanBeResolved = false
conf.attributes {
it.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
it.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
it.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR))
it.attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL))
it.attribute(Obfuscation.OBFUSCATION_ATTRIBUTE, objects.named(Obfuscation.OBFUSCATED))
}
conf.outgoing.artifact(tasks.named("remap"))
}
}
val (major, minor) = config.version.parseVersion()
if (major <= 20 && minor <= 4) return@with
tasks.register("convert", ConversionTask::class.java, type)
tasks.named("compileJava") { it.dependsOn("convert") }
rootProject.tasks.named("prepareKotlinBuildScriptModel") { it.dependsOn("$path:convert") }
}
@DisableCachingByDefault
abstract class ConversionTask @Inject constructor(type: Type) : DefaultTask() {
private val pattern: Regex
private val replacement: String
init {
group = "nms"
inputs.property("type", type)
val java = project.extensions.findByType(JavaPluginExtension::class.java) ?: throw GradleException("Java plugin not found")
val source = java.sourceSets.named("main").map { it.allJava }
inputs.files(source)
outputs.files(source)
if (type == Type.USER_DEV) {
pattern = "org\\.bukkit\\.craftbukkit\\.${project.name}".toRegex()
replacement = "org.bukkit.craftbukkit"
} else {
pattern = "org\\.bukkit\\.craftbukkit\\.(?!${project.name})".toRegex()
replacement = "org.bukkit.craftbukkit.${project.name}."
}
}
@TaskAction
fun process() {
val dispatcher = Dispatchers.IO.limitedParallelism(16)
runBlocking {
for (file in inputs.files) {
if (file.extension !in listOf("java"))
continue
launch(dispatcher) {
val output = ArrayList<String>()
var changed = false
file.bufferedReader().use {
for (line in it.lines()) {
if (line.startsWith("package") || line.isBlank()) {
output += line
continue
}
if (!line.startsWith("import")) {
if (!changed) return@launch
else {
output += line
continue
}
}
if (!line.contains(pattern)) {
output += line
continue
}
output += line.replace(pattern, replacement)
changed = true
}
}
if (changed) {
RandomAccessFile(file, "r").use { raf ->
val bytes = ByteArray(NEW_LINE_BYTES.size)
raf.seek(raf.length() - bytes.size)
raf.readFully(bytes)
if (bytes.contentEquals(NEW_LINE_BYTES))
output += ""
}
file.writer().use {
val iterator = output.iterator()
while (iterator.hasNext()) {
it.append(iterator.next())
if (iterator.hasNext())
it.append(NEW_LINE)
}
}
}
}
}
}
}
}
enum class Type {
USER_DEV,
BUILD_TOOLS,
DIRECT,
}
}
private val NEW_LINE = System.lineSeparator()
private val NEW_LINE_BYTES = NEW_LINE.encodeToByteArray()
private fun String.parseVersion() = substringBefore('-').split(".").let {
it[1].toInt() to it[2].toInt()
}
class Config(
var jvm: Int = 21,
var type: Type = Type.DIRECT
) {
lateinit var version: String
}
fun Project.nmsBinding(action: Config.() -> Unit) {
extra["nms"] = Config().apply(action)
plugins.apply(NMSBinding::class.java)
}
private inline fun <reified T : Named> ObjectFactory.named(name: String): T = named(T::class.java, name)

View File

@@ -1,12 +0,0 @@
plugins {
java
}
tasks.jar {
manifest.attributes(
"Agent-Class" to "com.volmit.iris.util.agent.Installer",
"Premain-Class" to "com.volmit.iris.util.agent.Installer",
"Can-Redefine-Classes" to true,
"Can-Retransform-Classes" to true
)
}

View File

@@ -1,29 +0,0 @@
package com.volmit.iris.util.agent;
import java.lang.instrument.Instrumentation;
public class Installer {
private static volatile Instrumentation instrumentation;
public static Instrumentation getInstrumentation() {
Instrumentation instrumentation = Installer.instrumentation;
if (instrumentation == null) {
throw new IllegalStateException("The agent is not loaded or this method is not called via the system class loader");
}
return instrumentation;
}
public static void premain(String arguments, Instrumentation instrumentation) {
doMain(instrumentation);
}
public static void agentmain(String arguments, Instrumentation instrumentation) {
doMain(instrumentation);
}
private static synchronized void doMain(Instrumentation instrumentation) {
if (Installer.instrumentation != null)
return;
Installer.instrumentation = instrumentation;
}
}

95
core/build.gradle Normal file
View File

@@ -0,0 +1,95 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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.0.0-dev.38'
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()
)
}
}

View File

@@ -1,215 +0,0 @@
import io.github.slimjar.func.slimjarHelper
import io.github.slimjar.resolver.data.Mirror
import org.ajoberstar.grgit.Grgit
import java.net.URI
/*
* 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 <https://www.gnu.org/licenses/>.
*/
plugins {
java
`java-library`
alias(libs.plugins.shadow)
alias(libs.plugins.sentry)
alias(libs.plugins.slimjar)
alias(libs.plugins.grgit)
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.lombok)
}
val apiVersion = "1.19"
val main = "com.volmit.iris.Iris"
val lib = "com.volmit.iris.util"
/**
* 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(libs.spigot)
compileOnly(libs.log4j.api)
compileOnly(libs.log4j.core)
// Third Party Integrations
compileOnly(libs.nexo)
compileOnly(libs.itemsadder)
compileOnly(libs.placeholderApi)
compileOnly(libs.score)
compileOnly(libs.mmoitems)
compileOnly(libs.ecoitems)
compileOnly(libs.mythic)
compileOnly(libs.mythicChrucible)
compileOnly(libs.kgenerators) {
isTransitive = false
}
compileOnly(libs.multiverseCore)
// Shaded
implementation(slimjarHelper("spigot"))
// Dynamically Loaded
slim(libs.paralithic)
slim(libs.paperlib)
slim(libs.adventure.api)
slim(libs.adventure.minimessage)
slim(libs.adventure.platform)
slim(libs.bstats)
slim(libs.sentry)
slim(libs.commons.io)
slim(libs.commons.lang)
slim(libs.commons.lang3)
slim(libs.commons.math3)
slim(libs.oshi)
slim(libs.lz4)
slim(libs.fastutil)
slim(libs.lru)
slim(libs.zip)
slim(libs.gson)
slim(libs.asm)
slim(libs.caffeine)
slim(libs.byteBuddy.core)
slim(libs.byteBuddy.agent)
slim(libs.dom4j)
slim(libs.jaxen)
// Script Engine
slim(libs.kotlin.stdlib)
slim(libs.kotlin.coroutines)
slim(libs.kotlin.scripting.common)
slim(libs.kotlin.scripting.jvm)
slim(libs.kotlin.scripting.jvm.host)
slim(libs.kotlin.scripting.dependencies.maven) {
constraints {
slim(libs.mavenCore)
}
}
}
java {
disableAutoTargetJvm()
}
sentry {
url = "http://sentry.volmit.com:8080"
autoInstallation.enabled = false
includeSourceContext = true
org = "sentry"
projectName = "iris"
authToken = findProperty("sentry.auth.token") as String? ?: System.getenv("SENTRY_AUTH_TOKEN")
}
slimJar {
mirrors = listOf(Mirror(
URI.create("https://maven-central.storage-download.googleapis.com/maven2").toURL(),
URI.create("https://repo.maven.apache.org/maven2/").toURL()
))
relocate("com.dfsek.paralithic", "$lib.paralithic")
relocate("io.papermc.lib", "$lib.paper")
relocate("net.kyori", "$lib.kyori")
relocate("org.bstats", "$lib.metrics")
relocate("io.sentry", "$lib.sentry")
relocate("org.apache.maven", "$lib.maven")
relocate("org.codehaus.plexus", "$lib.plexus")
relocate("org.eclipse.sisu", "$lib.sisu")
relocate("org.eclipse.aether", "$lib.aether")
relocate("com.google.inject", "$lib.guice")
relocate("org.dom4j", "$lib.dom4j")
relocate("org.jaxen", "$lib.jaxen")
relocate("com.github.benmanes.caffeine", "$lib.caffeine")
}
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()
//minimize()
relocate("io.github.slimjar", "$lib.slimjar")
exclude("modules/loader-agent.isolated-jar")
}
sentryCollectSourcesJava {
dependsOn(generateTemplates)
}
}
val templateSource = file("src/main/templates")
val templateDest = layout.buildDirectory.dir("generated/sources/templates")
val generateTemplates = tasks.register<Copy>("generateTemplates") {
inputs.properties(
"environment" to if (project.hasProperty("release")) "production" else "development",
"commit" to provider {
val res = runCatching { project.extensions.getByType<Grgit>().head().id }
res.getOrDefault("")
.takeIf { it.length == 40 } ?: run {
this.logger.error("Git commit hash not found", res.exceptionOrNull())
"unknown"
}
},
)
from(templateSource)
into(templateDest)
rename { "com/volmit/iris/$it" }
expand(inputs.properties)
}
tasks.generateSentryBundleIdJava {
dependsOn(generateTemplates)
}
rootProject.tasks.named("prepareKotlinBuildScriptModel") {
dependsOn(generateTemplates)
}
sourceSets.main {
java.srcDir(generateTemplates.map { it.outputs })
}

File diff suppressed because it is too large Load Diff

View File

@@ -23,8 +23,8 @@ import com.volmit.iris.Iris;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONException;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.misc.getHardware;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.ChronoLatch;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -45,14 +45,13 @@ public class IrisSettings {
private IrisSettingsStudio studio = new IrisSettingsStudio();
private IrisSettingsPerformance performance = new IrisSettingsPerformance();
private IrisSettingsUpdater updater = new IrisSettingsUpdater();
private IrisSettingsPregen pregen = new IrisSettingsPregen();
private IrisSettingsSentry sentry = new IrisSettingsSentry();
public static int getThreadCount(int c) {
return Math.max(switch (c) {
return switch (c) {
case -1, -2, -4 -> Runtime.getRuntime().availableProcessors() / -c;
case 0, 1, 2 -> 1;
default -> Math.max(c, 2);
}, 1);
};
}
public static IrisSettings get() {
@@ -131,63 +130,30 @@ public class IrisSettings {
public boolean markerEntitySpawningSystem = true;
public boolean effectSystem = true;
public boolean worldEditWandCUI = true;
public boolean globalPregenCache = false;
}
@Data
public static class IrisSettingsConcurrency {
public int parallelism = -1;
public int ioParallelism = -2;
public int worldGenParallelism = -1;
public int getWorldGenThreads() {
return getThreadCount(worldGenParallelism);
}
}
@Data
public static class IrisSettingsPregen {
public boolean useCacheByDefault = true;
public boolean useHighPriority = false;
public boolean useVirtualThreads = false;
public boolean useTicketQueue = true;
public int maxConcurrency = 256;
}
@Data
public static class IrisSettingsPerformance {
private IrisSettingsEngineSVC engineSVC = new IrisSettingsEngineSVC();
public boolean trimMantleInStudio = false;
public int mantleKeepAlive = 30;
public int noiseCacheSize = 1_024;
public int cacheSize = 4_096;
public int resourceLoaderCacheSize = 1_024;
public int objectLoaderCacheSize = 4_096;
public int scriptLoaderCacheSize = 512;
public int tectonicPlateSize = -1;
public int mantleCleanupDelay = 200;
public int getTectonicPlateSize() {
if (tectonicPlateSize > 0)
return tectonicPlateSize;
return (int) (getHardware.getProcessMemory() / 200L);
}
}
@Data
public static class IrisSettingsUpdater {
public int maxConcurrency = 256;
public boolean nativeThreads = false;
public double threadMultiplier = 2;
public double chunkLoadSensitivity = 0.7;
public MsRange emptyMsRange = new MsRange(80, 100);
public MsRange defaultMsRange = new MsRange(20, 40);
public int getMaxConcurrency() {
return Math.max(Math.abs(maxConcurrency), 1);
}
public double getThreadMultiplier() {
return Math.min(Math.abs(threadMultiplier), 0.1);
}
@@ -210,7 +176,6 @@ public class IrisSettings {
public boolean DoomsdayAnnihilationSelfDestructMode = false;
public boolean commandSounds = true;
public boolean debug = false;
public boolean dumpMantleOnError = false;
public boolean disableNMS = false;
public boolean pluginMetrics = true;
public boolean splashLogoStartup = true;
@@ -230,13 +195,6 @@ public class IrisSettings {
}
}
@Data
public static class IrisSettingsSentry {
public boolean includeServerId = true;
public boolean disableAutoReporting = false;
public boolean debug = false;
}
@Data
public static class IrisSettingsGUI {
public boolean useServerLaunchedGuis = true;
@@ -249,10 +207,6 @@ public class IrisSettings {
public String defaultWorldType = "overworld";
public int maxBiomeChildDepth = 4;
public boolean preventLeafDecay = true;
public boolean useMulticore = false;
public boolean useMulticoreMantle = false;
public boolean offsetNoiseTypes = false;
public boolean earlyCustomBlocks = false;
}
@Data
@@ -262,15 +216,4 @@ public class IrisSettings {
public boolean disableTimeAndWeather = true;
public boolean autoStartDefaultStudio = false;
}
@Data
public static class IrisSettingsEngineSVC {
public boolean useVirtualThreads = true;
public boolean forceMulticoreWrite = false;
public int priority = Thread.NORM_PRIORITY;
public int getPriority() {
return Math.max(Math.min(priority, Thread.MAX_PRIORITY), Thread.MIN_PRIORITY);
}
}
}

View File

@@ -1,126 +0,0 @@
package com.volmit.iris.core;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.misc.ServerProperties;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Type;
import java.util.Objects;
import java.util.stream.Stream;
public class IrisWorlds {
private static final AtomicCache<IrisWorlds> cache = new AtomicCache<>();
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final Type TYPE = TypeToken.getParameterized(KMap.class, String.class, String.class).getType();
private final KMap<String, String> worlds;
private volatile boolean dirty = false;
private IrisWorlds(KMap<String, String> worlds) {
this.worlds = worlds;
readBukkitWorlds().forEach(this::put0);
save();
}
public static IrisWorlds get() {
return cache.aquire(() -> {
File file = Iris.instance.getDataFile("worlds.json");
if (!file.exists()) {
return new IrisWorlds(new KMap<>());
}
try {
String json = IO.readAll(file);
KMap<String, String> worlds = GSON.fromJson(json, TYPE);
return new IrisWorlds(Objects.requireNonNullElseGet(worlds, KMap::new));
} catch (Throwable e) {
Iris.error("Failed to load worlds.json!");
e.printStackTrace();
Iris.reportError(e);
}
return new IrisWorlds(new KMap<>());
});
}
public void put(String name, String type) {
put0(name, type);
save();
}
private void put0(String name, String type) {
String old = worlds.put(name, type);
if (!type.equals(old))
dirty = true;
}
public KMap<String, String> getWorlds() {
clean();
return readBukkitWorlds().put(worlds);
}
public Stream<IrisData> getPacks() {
return getDimensions()
.map(IrisDimension::getLoader)
.filter(Objects::nonNull);
}
public Stream<IrisDimension> getDimensions() {
return getWorlds()
.entrySet()
.stream()
.map(entry -> Iris.loadDimension(entry.getKey(), entry.getValue()))
.filter(Objects::nonNull);
}
public void clean() {
dirty = worlds.entrySet().removeIf(entry -> !new File(Bukkit.getWorldContainer(), entry.getKey() + "/iris/pack/dimensions/" + entry.getValue() + ".json").exists());
}
public synchronized void save() {
clean();
if (!dirty) return;
try {
IO.write(Iris.instance.getDataFile("worlds.json"), OutputStreamWriter::new, writer -> GSON.toJson(worlds, TYPE, writer));
dirty = false;
} catch (IOException e) {
Iris.error("Failed to save worlds.json!");
e.printStackTrace();
Iris.reportError(e);
}
}
public static KMap<String, String> readBukkitWorlds() {
var bukkit = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML);
var worlds = bukkit.getConfigurationSection("worlds");
if (worlds == null) return new KMap<>();
var result = new KMap<String, String>();
for (String world : worlds.getKeys(false)) {
var gen = worlds.getString(world + ".generator");
if (gen == null) continue;
String loadKey;
if (gen.equalsIgnoreCase("iris")) {
loadKey = IrisSettings.get().getGenerator().getDefaultWorldType();
} else if (gen.startsWith("Iris:")) {
loadKey = gen.substring(5);
} else continue;
result.put(world, loadKey);
}
return result;
}
}

View File

@@ -23,7 +23,10 @@ import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.core.nms.datapack.IDataFixer;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisRange;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
@@ -31,8 +34,8 @@ import com.volmit.iris.util.format.C;
import com.volmit.iris.util.misc.ServerProperties;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import lombok.Data;
import lombok.NonNull;
import lombok.SneakyThrows;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
@@ -42,13 +45,12 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.stream.Stream;
import static com.volmit.iris.core.nms.datapack.IDataFixer.Dimension.*;
public class ServerConfigurator {
public static void configure() {
IrisSettings.IrisSettingsAutoconfiguration s = IrisSettings.get().getAutoConfiguration();
@@ -69,12 +71,10 @@ public class ServerConfigurator {
f.load(spigotConfig);
long tt = f.getLong("settings.timeout-time");
long spigotTimeout = TimeUnit.MINUTES.toSeconds(5);
if (tt < spigotTimeout) {
Iris.warn("Updating spigot.yml timeout-time: " + tt + " -> " + spigotTimeout + " (5 minutes)");
if (tt < TimeUnit.MINUTES.toSeconds(5)) {
Iris.warn("Updating spigot.yml timeout-time: " + tt + " -> " + TimeUnit.MINUTES.toSeconds(20) + " (5 minutes)");
Iris.warn("You can disable this change (autoconfigureServer) in Iris settings, then change back the value.");
f.set("settings.timeout-time", spigotTimeout);
f.set("settings.timeout-time", TimeUnit.MINUTES.toSeconds(5));
f.save(spigotConfig);
}
}
@@ -84,11 +84,10 @@ public class ServerConfigurator {
f.load(spigotConfig);
long tt = f.getLong("watchdog.early-warning-delay");
long watchdog = TimeUnit.MINUTES.toMillis(3);
if (tt < watchdog) {
Iris.warn("Updating paper.yml watchdog early-warning-delay: " + tt + " -> " + watchdog + " (3 minutes)");
if (tt < TimeUnit.MINUTES.toMillis(3)) {
Iris.warn("Updating paper.yml watchdog early-warning-delay: " + tt + " -> " + TimeUnit.MINUTES.toMillis(15) + " (3 minutes)");
Iris.warn("You can disable this change (autoconfigureServer) in Iris settings, then change back the value.");
f.set("watchdog.early-warning-delay", watchdog);
f.set("watchdog.early-warning-delay", TimeUnit.MINUTES.toMillis(3));
f.save(spigotConfig);
}
}
@@ -103,52 +102,44 @@ public class ServerConfigurator {
return worlds;
}
public static boolean installDataPacks(boolean fullInstall) {
return installDataPacks(DataVersion.getDefault(), fullInstall);
public static void installDataPacks(boolean fullInstall) {
installDataPacks(DataVersion.getDefault(), fullInstall);
}
public static boolean installDataPacks(IDataFixer fixer, boolean fullInstall) {
if (fixer == null) {
Iris.error("Unable to install datapacks, fixer is null!");
return false;
}
public static void installDataPacks(IDataFixer fixer, boolean fullInstall) {
Iris.info("Checking Data Packs...");
DimensionHeight height = new DimensionHeight(fixer);
KList<File> folders = getDatapacksFolder();
KMap<String, KSet<String>> biomes = new KMap<>();
try (Stream<IrisData> stream = allPacks()) {
stream.flatMap(height::merge)
.parallel()
.forEach(dim -> {
Iris.verbose(" Checking Dimension " + dim.getLoadFile().getPath());
dim.installBiomes(fixer, dim::getLoader, folders, biomes.computeIfAbsent(dim.getLoadKey(), k -> new KSet<>()));
dim.installDimensionType(fixer, folders);
});
}
allPacks().flatMap(height::merge)
.parallel()
.forEach(dim -> {
Iris.verbose(" Checking Dimension " + dim.getLoadFile().getPath());
dim.installBiomes(fixer, dim::getLoader, folders, biomes.computeIfAbsent(dim.getLoadKey(), k -> new KSet<>()));
});
IrisDimension.writeShared(folders, height);
Iris.info("Data Packs Setup!");
return fullInstall && verifyDataPacksPost(IrisSettings.get().getAutoConfiguration().isAutoRestartOnCustomBiomeInstall());
if (fullInstall)
verifyDataPacksPost(IrisSettings.get().getAutoConfiguration().isAutoRestartOnCustomBiomeInstall());
}
private static boolean verifyDataPacksPost(boolean allowRestarting) {
try (Stream<IrisData> stream = allPacks()) {
boolean bad = stream
.map(data -> {
Iris.verbose("Checking Pack: " + data.getDataFolder().getPath());
var loader = data.getDimensionLoader();
return loader.loadAll(loader.getPossibleKeys())
.stream()
.filter(Objects::nonNull)
.map(ServerConfigurator::verifyDataPackInstalled)
.toList()
.contains(false);
})
.toList()
.contains(true);
if (!bad) return false;
}
private static void verifyDataPacksPost(boolean allowRestarting) {
boolean bad = allPacks()
.map(data -> {
Iris.verbose("Checking Pack: " + data.getDataFolder().getPath());
var loader = data.getDimensionLoader();
return loader.loadAll(loader.getPossibleKeys())
.stream()
.map(ServerConfigurator::verifyDataPackInstalled)
.toList()
.contains(false);
})
.toList()
.contains(true);
if (!bad) return;
if (allowRestarting) {
@@ -171,7 +162,6 @@ public class ServerConfigurator {
J.sleep(3000);
}
return true;
}
public static void restart() {
@@ -223,11 +213,6 @@ public class ServerConfigurator {
}
}
if (INMS.get().missingDimensionTypes(dimension.getDimensionTypeKey())) {
Iris.warn("The Dimension Type for " + dimension.getLoadFile() + " is not registered on the server.");
warn = true;
}
if (warn) {
Iris.error("The Pack " + key + " is INCAPABLE of generating custom biomes");
Iris.error("If not done automatically, restart your server before generating with this pack!");
@@ -237,13 +222,10 @@ public class ServerConfigurator {
}
public static Stream<IrisData> allPacks() {
return Stream.concat(listFiles(Iris.instance.getDataFolder("packs"))
return Stream.concat(listFiles(new File("plugins/Iris/packs")),
listFiles(Bukkit.getWorldContainer()).map(w -> new File(w, "iris/pack")))
.filter(File::isDirectory)
.filter( base -> {
var content = new File(base, "dimensions").listFiles();
return content != null && content.length > 0;
})
.map(IrisData::get), IrisWorlds.get().getPacks());
.map(IrisData::get);
}
@Nullable
@@ -257,58 +239,49 @@ public class ServerConfigurator {
return path.substring(worldContainer.length(), path.length() - l);
}
@SneakyThrows
private static Stream<File> listFiles(File parent) {
if (!parent.isDirectory()) return Stream.empty();
return Files.walk(parent.toPath()).map(Path::toFile);
var files = parent.listFiles();
return files == null ? Stream.empty() : Arrays.stream(files);
}
@Data
public static class DimensionHeight {
private final IDataFixer fixer;
private final AtomicIntegerArray[] dimensions = new AtomicIntegerArray[3];
public DimensionHeight(IDataFixer fixer) {
this.fixer = fixer;
for (int i = 0; i < 3; i++) {
dimensions[i] = new AtomicIntegerArray(new int[]{
Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE
});
}
}
private IrisRange overworld = new IrisRange();
private IrisRange nether = new IrisRange();
private IrisRange end = new IrisRange();
private int logicalOverworld = 0;
private int logicalNether = 0;
private int logicalEnd = 0;
public Stream<IrisDimension> merge(IrisData data) {
Iris.verbose("Checking Pack: " + data.getDataFolder().getPath());
var loader = data.getDimensionLoader();
return loader.loadAll(loader.getPossibleKeys())
.stream()
.filter(Objects::nonNull)
.peek(this::merge);
}
public void merge(IrisDimension dimension) {
AtomicIntegerArray array = dimensions[dimension.getBaseDimension().ordinal()];
array.updateAndGet(0, min -> Math.min(min, dimension.getMinHeight()));
array.updateAndGet(1, max -> Math.max(max, dimension.getMaxHeight()));
array.updateAndGet(2, logical -> Math.max(logical, dimension.getLogicalHeight()));
overworld.merge(dimension.getDimensionHeight());
nether.merge(dimension.getDimensionHeight());
end.merge(dimension.getDimensionHeight());
logicalOverworld = Math.max(logicalOverworld, dimension.getLogicalHeight());
logicalNether = Math.max(logicalNether, dimension.getLogicalHeightNether());
logicalEnd = Math.max(logicalEnd, dimension.getLogicalHeightEnd());
}
public String[] jsonStrings() {
var dims = IDataFixer.Dimension.values();
var arr = new String[3];
for (int i = 0; i < 3; i++) {
arr[i] = jsonString(dims[i]);
}
return arr;
public String overworldType() {
return fixer.createDimension(OVERRWORLD, overworld, logicalOverworld).toString(4);
}
public String jsonString(IDataFixer.Dimension dimension) {
var data = dimensions[dimension.ordinal()];
int minY = data.get(0);
int maxY = data.get(1);
int logicalHeight = data.get(2);
if (minY == Integer.MAX_VALUE || maxY == Integer.MIN_VALUE || Integer.MIN_VALUE == logicalHeight)
return null;
return fixer.createDimension(dimension, minY, maxY - minY, logicalHeight, null).toString(4);
public String netherType() {
return fixer.createDimension(NETHER, nether, logicalNether).toString(4);
}
public String endType() {
return fixer.createDimension(THE_END, end, logicalEnd).toString(4);
}
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.pregenerator.DeepSearchPregenerator;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.TurboPregenerator;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.data.Dimension;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.Position2;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.util.Vector;
import java.io.File;
import java.io.IOException;
@Decree(name = "DeepSearch", aliases = "search", description = "Pregenerate your Iris worlds!")
public class CommandDeepSearch implements DecreeExecutor {
public String worldName;
@Decree(description = "DeepSearch a world")
public void start(
@Param(description = "The radius of the pregen in blocks", aliases = "size")
int radius,
@Param(description = "The world to pregen", contextual = true)
World world,
@Param(aliases = "middle", description = "The center location of the pregen. Use \"me\" for your current location", defaultValue = "0,0")
Vector center
) {
worldName = world.getName();
File worldDirectory = new File(Bukkit.getWorldContainer(), world.getName());
File TurboFile = new File(worldDirectory, "DeepSearch.json");
if (TurboFile.exists()) {
if (DeepSearchPregenerator.getInstance() != null) {
sender().sendMessage(C.BLUE + "DeepSearch is already in progress");
Iris.info(C.YELLOW + "DeepSearch is already in progress");
return;
} else {
try {
TurboFile.delete();
} catch (Exception e){
Iris.error("Failed to delete the old instance file of DeepSearch!");
return;
}
}
}
try {
if (sender().isPlayer() && access() == null) {
sender().sendMessage(C.RED + "The engine access for this world is null!");
sender().sendMessage(C.RED + "Please make sure the world is loaded & the engine is initialized. Generate a new chunk, for example.");
}
DeepSearchPregenerator.DeepSearchJob DeepSearchJob = DeepSearchPregenerator.DeepSearchJob.builder()
.world(world)
.radiusBlocks(radius)
.position(0)
.build();
File SearchGenFile = new File(worldDirectory, "DeepSearch.json");
DeepSearchPregenerator pregenerator = new DeepSearchPregenerator(DeepSearchJob, SearchGenFile);
pregenerator.start();
String msg = C.GREEN + "DeepSearch started in " + C.GOLD + worldName + C.GREEN + " of " + C.GOLD + (radius * 2) + C.GREEN + " by " + C.GOLD + (radius * 2) + C.GREEN + " blocks from " + C.GOLD + center.getX() + "," + center.getZ();
sender().sendMessage(msg);
Iris.info(msg);
} catch (Throwable e) {
sender().sendMessage(C.RED + "Epic fail. See console.");
Iris.reportError(e);
e.printStackTrace();
}
}
@Decree(description = "Stop the active DeepSearch task", aliases = "x")
public void stop(@Param(aliases = "world", description = "The world to pause") World world) throws IOException {
DeepSearchPregenerator DeepSearchInstance = DeepSearchPregenerator.getInstance();
File worldDirectory = new File(Bukkit.getWorldContainer(), world.getName());
File turboFile = new File(worldDirectory, "DeepSearch.json");
if (DeepSearchInstance != null) {
DeepSearchInstance.shutdownInstance(world);
sender().sendMessage(C.LIGHT_PURPLE + "Closed Turbogen instance for " + world.getName());
} else if (turboFile.exists() && turboFile.delete()) {
sender().sendMessage(C.LIGHT_PURPLE + "Closed Turbogen instance for " + world.getName());
} else if (turboFile.exists()) {
Iris.error("Failed to delete the old instance file of Turbo Pregen!");
} else {
sender().sendMessage(C.YELLOW + "No active pregeneration tasks to stop");
}
}
@Decree(description = "Pause / continue the active pregeneration task", aliases = {"t", "resume", "unpause"})
public void pause(
@Param(aliases = "world", description = "The world to pause")
World world
) {
if (TurboPregenerator.getInstance() != null) {
TurboPregenerator.setPausedTurbo(world);
sender().sendMessage(C.GREEN + "Paused/unpaused Turbo Pregen, now: " + (TurboPregenerator.isPausedTurbo(world) ? "Paused" : "Running") + ".");
} else {
File worldDirectory = new File(Bukkit.getWorldContainer(), world.getName());
File TurboFile = new File(worldDirectory, "DeepSearch.json");
if (TurboFile.exists()){
TurboPregenerator.loadTurboGenerator(world.getName());
sender().sendMessage(C.YELLOW + "Started DeepSearch back up!");
} else {
sender().sendMessage(C.YELLOW + "No active DeepSearch tasks to pause/unpause.");
}
}
}
}

View File

@@ -18,44 +18,32 @@
package com.volmit.iris.core.commands;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.volmit.iris.Iris;
import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.methods.HeadlessPregenMethod;
import com.volmit.iris.core.service.IrisEngineSVC;
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.engine.object.IrisPosition;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.decree.specialhandlers.NullableDimensionHandler;
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.mantle.TectonicPlate;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.matter.Matter;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.nbt.mca.MCAFile;
import com.volmit.iris.util.nbt.mca.MCAUtil;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.jobs.Job;
import lombok.SneakyThrows;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import net.jpountz.lz4.LZ4FrameInputStream;
@@ -64,352 +52,109 @@ import org.apache.commons.lang.RandomStringUtils;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.util.Vector;
import java.io.*;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@Decree(name = "Developer", origin = DecreeOrigin.BOTH, description = "Iris World Manager", aliases = {"dev"})
public class CommandDeveloper implements DecreeExecutor {
private CommandTurboPregen turboPregen;
private CommandLazyPregen lazyPregen;
private CommandUpdater updater;
@Decree(description = "Get Loaded TectonicPlates Count", origin = DecreeOrigin.BOTH, sync = true)
public void EngineStatus() {
Iris.service(IrisEngineSVC.class)
.engineStatus(sender());
}
List<World> IrisWorlds = new ArrayList<>();
int TotalLoadedChunks = 0;
int TotalQueuedTectonicPlates = 0;
int TotalNotQueuedTectonicPlates = 0;
int TotalTectonicPlates = 0;
@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"));
}
long lowestUnloadDuration = 0;
long highestUnloadDuration = 0;
@Decree(description = "Dev cmd to fix all the broken objects caused by faulty shrinkwarp")
public void fixObjects(
@Param(aliases = "dimension", description = "The dimension type to create the world with")
IrisDimension type
) {
if (type == null) {
sender().sendMessage("Type cant be null?");
return;
for (World world : Bukkit.getWorlds()) {
try {
if (IrisToolbelt.access(world).getEngine() != null) {
IrisWorlds.add(world);
}
} catch (Exception e) {
// no
}
}
IrisData dm = IrisData.get(Iris.instance.getDataFolder("packs", type.getLoadKey()));
var loader = dm.getObjectLoader();
var processed = new KMap<String, IrisPosition>();
var objects = loader.getPossibleKeys();
var pieces = dm.getJigsawPieceLoader().getPossibleKeys();
var sender = sender();
sender.sendMessage(C.IRIS + "Found " + objects.length + " objects in " + type.getLoadKey());
sender.sendMessage(C.IRIS + "Found " + pieces.length + " jigsaw pieces in " + type.getLoadKey());
final int total = objects.length;
final AtomicInteger completed = new AtomicInteger();
final AtomicInteger changed = new AtomicInteger();
new Job() {
@Override
public String getName() {
return "Fixing Objects";
for (World world : IrisWorlds) {
Engine engine = IrisToolbelt.access(world).getEngine();
TotalQueuedTectonicPlates += (int) engine.getMantle().getToUnload();
TotalNotQueuedTectonicPlates += (int) engine.getMantle().getNotQueuedLoadedRegions();
TotalTectonicPlates += engine.getMantle().getLoadedRegionCount();
if (highestUnloadDuration <= (long) engine.getMantle().getTectonicDuration()) {
highestUnloadDuration = (long) engine.getMantle().getTectonicDuration();
}
@Override
public void execute() {
Arrays.stream(pieces).parallel()
.map(dm.getJigsawPieceLoader()::load)
.filter(Objects::nonNull)
.forEach(piece -> {
var offset = processed.compute(piece.getObject(), (key, o) -> {
if (o != null) return o;
var obj = loader.load(key);
if (obj == null) return new IrisPosition();
obj.shrinkwrap();
try {
if (!obj.getShrinkOffset().isZero()) {
changed.incrementAndGet();
obj.write(obj.getLoadFile());
}
completeWork();
} catch (IOException e) {
Iris.error("Failed to write object " + obj.getLoadKey());
e.printStackTrace();
return new IrisPosition();
}
return new IrisPosition(obj.getShrinkOffset());
});
if (offset.getX() == 0 && offset.getY() == 0 && offset.getZ() == 0)
return;
piece.getConnectors().forEach(connector -> connector.setPosition(connector.getPosition().add(offset)));
try {
IO.writeAll(piece.getLoadFile(), dm.getGson().toJson(piece));
} catch (IOException e) {
Iris.error("Failed to write jigsaw piece " + piece.getLoadKey());
e.printStackTrace();
}
});
Arrays.stream(loader.getPossibleKeys()).parallel()
.filter(key -> !processed.containsKey(key))
.map(loader::load)
.forEach(obj -> {
if (obj == null) {
completeWork();
return;
}
obj.shrinkwrap();
if (obj.getShrinkOffset().isZero()) {
completeWork();
return;
}
try {
obj.write(obj.getLoadFile());
completeWork();
changed.incrementAndGet();
} catch (IOException e) {
Iris.error("Failed to write object " + obj.getLoadKey());
e.printStackTrace();
}
});
if (lowestUnloadDuration >= (long) engine.getMantle().getTectonicDuration()) {
lowestUnloadDuration = (long) engine.getMantle().getTectonicDuration();
}
@Override
public void completeWork() {
completed.incrementAndGet();
for (Chunk chunk : world.getLoadedChunks()) {
if (chunk.isLoaded()) {
TotalLoadedChunks++;
}
}
@Override
public int getTotalWork() {
return total;
}
@Override
public int getWorkCompleted() {
return completed.get();
}
}.execute(sender, () -> {
var failed = total - completed.get();
if (failed != 0) sender.sendMessage(C.IRIS + "" + failed + " objects failed!");
if (changed.get() != 0) sender.sendMessage(C.IRIS + "" + changed.get() + " objects had their offsets changed!");
else sender.sendMessage(C.IRIS + "No objects had their offsets changed!");
});
}
Iris.info("-------------------------");
Iris.info(C.DARK_PURPLE + "Engine Status");
Iris.info(C.DARK_PURPLE + "Total Loaded Chunks: " + C.LIGHT_PURPLE + TotalLoadedChunks);
Iris.info(C.DARK_PURPLE + "Tectonic Limit: " + C.LIGHT_PURPLE + IrisEngineSVC.getTectonicLimit());
Iris.info(C.DARK_PURPLE + "Tectonic Total Plates: " + C.LIGHT_PURPLE + TotalTectonicPlates);
Iris.info(C.DARK_PURPLE + "Tectonic Active Plates: " + C.LIGHT_PURPLE + TotalNotQueuedTectonicPlates);
Iris.info(C.DARK_PURPLE + "Tectonic ToUnload: " + C.LIGHT_PURPLE + TotalQueuedTectonicPlates);
Iris.info(C.DARK_PURPLE + "Lowest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(lowestUnloadDuration));
Iris.info(C.DARK_PURPLE + "Highest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(highestUnloadDuration));
Iris.info(C.DARK_PURPLE + "Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize()));
Iris.info("-------------------------");
}
@Decree(description = "Test")
public void mantle(@Param(defaultValue = "false") boolean plate, @Param(defaultValue = "21474836474") String name) throws Throwable {
var base = Iris.instance.getDataFile("dump", "pv." + name + ".ttp.lz4b.bin");
var section = Iris.instance.getDataFile("dump", "pv." + name + ".section.bin");
public void benchmarkMantle(
@Param(description = "The world to bench", aliases = {"world"})
World world
) throws IOException, ClassNotFoundException {
Engine engine = IrisToolbelt.access(world).getEngine();
int maxHeight = engine.getTarget().getHeight();
File folder = new File(Bukkit.getWorldContainer(), world.getName());
int c = 0;
//MCAUtil.read()
//extractSection(base, section, 5604930, 4397);
File tectonicplates = new File(folder, "mantle");
for (File i : Objects.requireNonNull(tectonicplates.listFiles())) {
TectonicPlate.read(maxHeight, i);
c++;
Iris.info("Loaded count: " + c );
if (plate) {
try (var in = CountingDataInputStream.wrap(new BufferedInputStream(new FileInputStream(base)))) {
new TectonicPlate(1088, in, true);
} catch (Throwable e) {
e.printStackTrace();
}
} else Matter.read(section);
if (!TectonicPlate.hasError())
Iris.info("Read " + (plate ? base : section).length() + " bytes from " + (plate ? base : section).getAbsolutePath());
}
private void extractSection(File source, File target, long offset, int length) throws IOException {
var raf = new RandomAccessFile(source, "r");
var bytes = new byte[length];
raf.seek(offset);
raf.readFully(bytes);
raf.close();
Files.write(target.toPath(), bytes);
}
@Decree(description = "Test")
public void dumpThreads() {
try {
File fi = Iris.instance.getDataFile("dump", "td-" + new java.sql.Date(M.ms()) + ".txt");
FileOutputStream fos = new FileOutputStream(fi);
Map<Thread, StackTraceElement[]> f = Thread.getAllStackTraces();
PrintWriter pw = new PrintWriter(fos);
pw.println(Thread.activeCount() + "/" + f.size());
var run = Runtime.getRuntime();
pw.println("Memory:");
pw.println("\tMax: " + run.maxMemory());
pw.println("\tTotal: " + run.totalMemory());
pw.println("\tFree: " + run.freeMemory());
pw.println("\tUsed: " + (run.totalMemory() - run.freeMemory()));
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();
}
}
@SneakyThrows
@Decree(description = "Generate Iris structures for all loaded datapack structures")
public void generateStructures(
@Param(description = "The pack to add the generated structures to", aliases = "pack", defaultValue = "null", customHandler = NullableDimensionHandler.class)
IrisDimension dimension,
@Param(description = "Ignore existing structures", defaultValue = "false")
boolean force
) {
var map = INMS.get().collectStructures();
if (map.isEmpty()) {
sender().sendMessage(C.IRIS + "No structures found");
return;
}
sender().sendMessage(C.IRIS + "Found " + map.size() + " structures");
final File dataDir;
final IrisData data;
final Set<String> existingStructures;
final Map<String, Set<String>> snippets;
final File dimensionFile;
final File structuresFolder;
final File snippetsFolder;
var dimensionObj = new JsonObject();
if (dimension == null) {
dataDir = Iris.instance.getDataFolder("structures");
IO.delete(dataDir);
data = IrisData.get(dataDir);
existingStructures = Set.of();
snippets = Map.of();
dimensionFile = new File(dataDir, "structures.json");
} else {
data = dimension.getLoader();
dataDir = data.getDataFolder();
existingStructures = new KSet<>(data.getJigsawStructureLoader().getPossibleKeys());
dimensionObj = data.getGson().fromJson(IO.readAll(dimension.getLoadFile()), JsonObject.class);
snippets = Optional.ofNullable(dimensionObj.getAsJsonArray("jigsawStructures"))
.map(array -> array.asList()
.stream()
.filter(JsonElement::isJsonPrimitive)
.collect(Collectors.toMap(element -> data.getGson()
.fromJson(element, IrisJigsawStructurePlacement.class)
.getStructure(),
element -> Set.of(element.getAsString()),
KSet::merge)))
.orElse(Map.of());
dimensionFile = dimension.getLoadFile();
}
structuresFolder = new File(dataDir, "jigsaw-structures");
snippetsFolder = new File(dataDir, "snippet" + "/" + IrisJigsawStructurePlacement.class.getAnnotation(Snippet.class).value());
var gson = data.getGson();
var jigsawStructures = Optional.ofNullable(dimensionObj.getAsJsonArray("jigsawStructures"))
.orElse(new JsonArray(map.size()));
map.forEach((key, placement) -> {
String loadKey = "datapack/" + key.namespace() + "/" + key.key();
if (existingStructures.contains(loadKey) && !force)
return;
var structures = placement.structures();
var obj = placement.toJson(loadKey);
if (obj == null || structures.isEmpty()) {
sender().sendMessage(C.RED + "Failed to generate hook for " + key);
return;
}
File snippetFile = new File(snippetsFolder, loadKey + ".json");
try {
IO.writeAll(snippetFile, gson.toJson(obj));
} catch (IOException e) {
sender().sendMessage(C.RED + "Failed to generate snippet for " + key);
e.printStackTrace();
return;
}
Set<String> loadKeys = snippets.getOrDefault(loadKey, Set.of(loadKey));
jigsawStructures.asList().removeIf(e -> loadKeys.contains((e.isJsonObject() ? e.getAsJsonObject().get("structure") : e).getAsString()));
jigsawStructures.add("snippet/" + loadKey);
String structureKey;
if (structures.size() > 1) {
KList<String> common = new KList<>();
for (int i = 0; i < structures.size(); i++) {
var tags = structures.get(i).tags();
if (i == 0) common.addAll(tags);
else common.removeIf(tag -> !tags.contains(tag));
}
structureKey = common.isNotEmpty() ? "#" + common.getFirst() : structures.getFirst().key();
} else structureKey = structures.getFirst().key();
JsonArray array = new JsonArray();
if (structures.size() > 1) {
structures.stream()
.flatMap(structure -> {
String[] arr = new String[structure.weight()];
Arrays.fill(arr, structure.key());
return Arrays.stream(arr);
})
.forEach(array::add);
} else array.add(structureKey);
obj = new JsonObject();
obj.addProperty("structureKey", structureKey);
obj.add("datapackStructures", array);
File out = new File(structuresFolder, loadKey + ".json");
out.getParentFile().mkdirs();
try {
IO.writeAll(out, gson.toJson(obj));
} catch (IOException e) {
e.printStackTrace();
}
});
dimensionObj.add("jigsawStructures", jigsawStructures);
IO.writeAll(dimensionFile, gson.toJson(dimensionObj));
data.hotloaded();
}
@Decree(description = "Test")
public void packBenchmark(
@Param(description = "The pack to bench", aliases = {"pack"}, defaultValue = "overworld")
IrisDimension dimension,
@Param(description = "Radius in regions", defaultValue = "2048")
int radius,
@Param(description = "Diameter in regions", defaultValue = "2048")
int diameter,
@Param(description = "Headless", defaultValue = "true")
boolean headless,
@Param(description = "Open GUI while benchmarking", defaultValue = "false")
boolean gui
) {
new IrisPackBenchmarking(dimension, radius, gui);
int rb = diameter << 9;
Iris.info("Benchmarking pack " + dimension.getName() + " with diameter: " + rb + "(" + diameter + ")");
new IrisPackBenchmarking(dimension, diameter, headless, gui);
}
@Decree(description = "Upgrade to another Minecraft version")
@@ -477,6 +222,42 @@ public class CommandDeveloper implements DecreeExecutor {
sender.sendMessage(C.RED + "Failed to load " + failed.get() + " of " + keys.length + " objects");
}
@Decree(description = "Pregenerate a world")
public void headless(
@Param(description = "The radius of the pregen in blocks", aliases = "size")
int radius,
@Param(description = "The world to pregen", contextual = true)
World world,
@Param(aliases = "middle", description = "The center location of the pregen. Use \"me\" for your current location", defaultValue = "0,0")
Vector center
) {
try {
var engine = Optional.ofNullable(IrisToolbelt.access(world))
.map(PlatformChunkGenerator::getEngine)
.orElse(null);
if (engine == null) {
sender().sendMessage(C.RED + "The engine access for this world is null!");
sender().sendMessage(C.RED + "Please make sure the world is loaded & the engine is initialized. Generate a new chunk, for example.");
}
radius = Math.max(radius, 1024);
IrisToolbelt.pregenerate(PregenTask
.builder()
.center(new Position2(center.getBlockX(), center.getBlockZ()))
.gui(true)
.radiusX(radius)
.radiusZ(radius)
.build(), new HeadlessPregenMethod(engine), engine);
String msg = C.GREEN + "Headless Pregen started in " + C.GOLD + world.getName() + C.GREEN + " of " + C.GOLD + (radius * 2) + C.GREEN + " by " + C.GOLD + (radius * 2) + C.GREEN + " blocks from " + C.GOLD + center.getX() + "," + center.getZ();
sender().sendMessage(msg);
Iris.info(msg);
} catch (Throwable e) {
sender().sendMessage(C.RED + "Epic fail. See console.");
Iris.reportError(e);
e.printStackTrace();
}
}
@Decree(description = "Test", aliases = {"ip"})
public void network() {
try {
@@ -498,8 +279,7 @@ public class CommandDeveloper implements DecreeExecutor {
@Param(description = "base IrisWorld") World world,
@Param(description = "raw TectonicPlate File") String path,
@Param(description = "Algorithm to Test") String algorithm,
@Param(description = "Amount of Tests") int amount,
@Param(description = "Is versioned", defaultValue = "false") boolean versioned) {
@Param(description = "Amount of Tests") int amount) {
if (!IrisToolbelt.isIrisWorld(world)) {
sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", Bukkit.getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList()));
return;
@@ -516,7 +296,7 @@ public class CommandDeveloper implements DecreeExecutor {
service.submit(() -> {
try {
CountingDataInputStream raw = CountingDataInputStream.wrap(new FileInputStream(file));
TectonicPlate plate = new TectonicPlate(height, raw, versioned);
TectonicPlate plate = new TectonicPlate(height, raw);
raw.close();
double d1 = 0;
@@ -535,7 +315,7 @@ public class CommandDeveloper implements DecreeExecutor {
size = tmp.length();
start = System.currentTimeMillis();
CountingDataInputStream din = createInput(tmp, algorithm);
new TectonicPlate(height, din, true);
new TectonicPlate(height, din);
din.close();
d2 += System.currentTimeMillis() - start;
tmp.delete();

View File

@@ -20,11 +20,18 @@ package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.pregenerator.ChunkUpdater;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.tools.IrisBenchmarking;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.core.safeguard.UtilsSFG;
import com.volmit.iris.engine.object.IrisWorld;
import com.volmit.iris.engine.platform.BukkitChunkGenerator;
import com.volmit.iris.engine.platform.DummyChunkGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
@@ -32,40 +39,45 @@ import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.decree.specialhandlers.NullablePlayerHandler;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.misc.ServerProperties;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import lombok.SneakyThrows;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.*;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import static com.volmit.iris.Iris.service;
import static com.volmit.iris.core.service.EditSVC.deletingWorld;
import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML;
import static com.volmit.iris.core.tools.IrisBenchmarking.inProgress;
import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode;
import static com.volmit.iris.core.safeguard.ServerBootSFG.incompatibilities;
import static org.bukkit.Bukkit.getServer;
@Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command")
public class CommandIris implements DecreeExecutor {
private CommandUpdater updater;
private CommandStudio studio;
private CommandPregen pregen;
private CommandLazyPregen lazyPregen;
private CommandSettings settings;
private CommandObject object;
private CommandJigsaw jigsaw;
private CommandWhat what;
private CommandEdit edit;
private CommandFind find;
private CommandSupport support;
private CommandDeveloper developer;
public static boolean worldCreation = false;
private static final AtomicReference<Thread> mainWorld = new AtomicReference<>();
String WorldEngine;
String worldNameToCheck = "YourWorldName";
VolmitSender sender = Iris.getSender();
@@ -76,22 +88,39 @@ public class CommandIris implements DecreeExecutor {
String name,
@Param(aliases = "dimension", description = "The dimension type to create the world with", defaultValue = "default")
IrisDimension type,
@Param(description = "The radius of chunks to generate in headless mode (-1 to disable)", defaultValue = "10", aliases = "radius")
int headlessRadius,
@Param(description = "The seed to generate the world with", defaultValue = "1337")
long seed,
@Param(aliases = "main-world", description = "Whether or not to automatically use this world as the main world", defaultValue = "false")
boolean main
long seed
) {
if (name.equalsIgnoreCase("iris")) {
sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds.");
sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?");
return;
}
if (name.equalsIgnoreCase("benchmark")) {
sender().sendMessage(C.RED + "You cannot use the world name \"benchmark\" for creating worlds as Iris uses this directory for Benchmarking Packs.");
sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?");
return;
if(sender() instanceof Player) {
if (incompatibilities.get("Multiverse-Core")) {
sender().sendMessage(C.RED + "Your server has an incompatibility that may corrupt all worlds on the server if not handled properly.");
sender().sendMessage(C.RED + "it is strongly advised for you to take action. see log for full detail");
sender().sendMessage(C.RED + "----------------------------------------------------------------");
sender().sendMessage(C.RED + "Command ran: /iris create");
sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings());
sender().sendMessage(C.RED + "----------------------------------------------------------------");
}
if (unstablemode && !incompatibilities.get("Multiverse-Core")) {
sender().sendMessage(C.RED + "Your server is experiencing an incompatibility with the Iris plugin.");
sender().sendMessage(C.RED + "Please rectify this problem to avoid further complications.");
sender().sendMessage(C.RED + "----------------------------------------------------------------");
sender().sendMessage(C.RED + "Command ran: /iris create");
sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings());
sender().sendMessage(C.RED + "----------------------------------------------------------------");
}
}
if (name.equals("iris")) {
sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds.");
sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?");
return;
}
if (name.equals("Benchmark")) {
sender().sendMessage(C.RED + "You cannot use the world name \"Benchmark\" for creating worlds as Iris uses this directory for Benchmarking Packs.");
sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?");
return;
}
if (new File(Bukkit.getWorldContainer(), name).exists()) {
sender().sendMessage(C.RED + "That folder already exists!");
@@ -106,13 +135,8 @@ public class CommandIris implements DecreeExecutor {
.seed(seed)
.sender(sender())
.studio(false)
.headlessRadius(headlessRadius)
.create();
if (main) {
Runtime.getRuntime().addShutdownHook(mainWorld.updateAndGet(old -> {
if (old != null) Runtime.getRuntime().removeShutdownHook(old);
return new Thread(() -> updateMainWorld(name));
}));
}
} catch (Throwable e) {
sender().sendMessage(C.RED + "Exception raised during creation. See the console for more details.");
Iris.error("Exception raised during world creation: " + e.getMessage());
@@ -122,24 +146,6 @@ public class CommandIris implements DecreeExecutor {
}
worldCreation = false;
sender().sendMessage(C.GREEN + "Successfully created your world!");
if (main) sender().sendMessage(C.GREEN + "Your world will automatically be set as the main world when the server restarts.");
}
@SneakyThrows
private void updateMainWorld(String newName) {
File worlds = Bukkit.getWorldContainer();
var data = ServerProperties.DATA;
try (var in = new FileInputStream(ServerProperties.SERVER_PROPERTIES)) {
data.load(in);
}
for (String sub : List.of("datapacks", "playerdata", "advancements", "stats")) {
IO.copyDirectory(new File(worlds, ServerProperties.LEVEL_NAME + "/" + sub).toPath(), new File(worlds, newName + "/" + sub).toPath());
}
data.setProperty("level-name", newName);
try (var out = new FileOutputStream(ServerProperties.SERVER_PROPERTIES)) {
data.store(out, null);
}
}
@Decree(description = "Teleport to another world", aliases = {"tp"}, sync = true)
@@ -172,6 +178,16 @@ public class CommandIris implements DecreeExecutor {
sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software");
}
//todo Move to React
@Decree(description = "Benchmark your server", origin = DecreeOrigin.CONSOLE)
public void serverbenchmark() throws InterruptedException {
if(!inProgress) {
IrisBenchmarking.runBenchmark();
} else {
Iris.info(C.RED + "Benchmark already is in progress.");
}
}
/*
/todo
@Decree(description = "Benchmark a pack", origin = DecreeOrigin.CONSOLE)
@@ -317,6 +333,24 @@ public class CommandIris implements DecreeExecutor {
return dir.delete();
}
@Decree(description = "Updates all chunk in the specified world")
public void updater(
@Param(description = "World to update chunks at")
World world
) {
if (!IrisToolbelt.isIrisWorld(world)) {
sender().sendMessage(C.GOLD + "This is not an Iris world");
return;
}
ChunkUpdater updater = new ChunkUpdater(world);
if (sender().isPlayer()) {
sender().sendMessage(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks()));
} else {
Iris.info(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks()));
}
updater.start();
}
@Decree(description = "Set aura spins")
public void aura(
@Param(description = "The h color value", defaultValue = "-20")
@@ -369,19 +403,17 @@ public class CommandIris implements DecreeExecutor {
sender().sendMessage(C.GREEN + "Set debug to: " + to);
}
//TODO fix pack trimming
@Decree(description = "Download a project.", aliases = "dl")
public void download(
@Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project")
String pack,
@Param(name = "branch", description = "The branch to download from", defaultValue = "main")
String branch,
//@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false")
//boolean trim,
@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false")
boolean trim,
@Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false")
boolean overwrite
) {
boolean trim = false;
sender().sendMessage(C.GREEN + "Downloading pack: " + pack + "/" + branch + (trim ? " trimmed" : "") + (overwrite ? " overwriting" : ""));
if (pack.equals("overworld")) {
String url = "https://github.com/IrisDimensions/overworld/releases/download/" + INMS.OVERWORLD_TAG + "/overworld.zip";
@@ -479,6 +511,7 @@ public class CommandIris implements DecreeExecutor {
return;
}
File BUKKIT_YML = new File("bukkit.yml");
String pathtodim = world + File.separator +"iris"+File.separator +"pack"+File.separator +"dimensions"+File.separator;
File directory = new File(Bukkit.getWorldContainer(), pathtodim);
@@ -516,7 +549,7 @@ public class CommandIris implements DecreeExecutor {
return;
}
}
Iris.instance.checkForBukkitWorlds(world::equals);
checkForBukkitWorlds(world);
sender().sendMessage(C.GREEN + world + " loaded successfully.");
}
@Decree(description = "Evacuate an iris world", origin = DecreeOrigin.PLAYER, sync = true)
@@ -537,4 +570,96 @@ public class CommandIris implements DecreeExecutor {
File worldDirectory = new File(worldContainer, worldName);
return worldDirectory.exists() && worldDirectory.isDirectory();
}
private void checkForBukkitWorlds(String world) {
FileConfiguration fc = new YamlConfiguration();
try {
fc.load(new File("bukkit.yml"));
ConfigurationSection section = fc.getConfigurationSection("worlds");
if (section == null) {
return;
}
List<String> worldsToLoad = Collections.singletonList(world);
for (String s : section.getKeys(false)) {
if (!worldsToLoad.contains(s)) {
continue;
}
ConfigurationSection entry = section.getConfigurationSection(s);
if (!entry.contains("generator", true)) {
continue;
}
String generator = entry.getString("generator");
if (generator.startsWith("Iris:")) {
generator = generator.split("\\Q:\\E")[1];
} else if (generator.equalsIgnoreCase("Iris")) {
generator = IrisSettings.get().getGenerator().getDefaultWorldType();
} else {
continue;
}
Iris.info("2 World: %s | Generator: %s", s, generator);
if (Bukkit.getWorlds().stream().anyMatch(w -> w.getName().equals(s))) {
continue;
}
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
WorldCreator c = new WorldCreator(s)
.generator(getDefaultWorldGenerator(s, generator))
.environment(IrisData.loadAnyDimension(generator).getEnvironment());
INMS.get().createWorld(c);
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
}
} catch (Throwable e) {
e.printStackTrace();
}
}
public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {
Iris.debug("Default World Generator Called for " + worldName + " using ID: " + id);
if (worldName.equals("test")) {
try {
throw new RuntimeException();
} catch (Throwable e) {
Iris.info(e.getStackTrace()[1].getClassName());
if (e.getStackTrace()[1].getClassName().contains("com.onarandombox.MultiverseCore")) {
Iris.debug("MVC Test detected, Quick! Send them the dummy!");
return new DummyChunkGenerator();
}
}
}
IrisDimension dim;
if (id == null || id.isEmpty()) {
dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType());
} else {
dim = IrisData.loadAnyDimension(id);
}
Iris.debug("Generator ID: " + id + " requested by bukkit/plugin");
if (dim == null) {
Iris.warn("Unable to find dimension type " + id + " Looking for online packs...");
service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, true);
dim = IrisData.loadAnyDimension(id);
if (dim == null) {
throw new RuntimeException("Can't find dimension " + id + "!");
} else {
Iris.info("Resolved missing dimension, proceeding with generation.");
}
}
Iris.debug("Assuming IrisDimension: " + dim.getName());
IrisWorld w = IrisWorld.builder()
.name(worldName)
.seed(1337)
.environment(dim.getEnvironment())
.worldFolder(new File(Bukkit.getWorldContainer(), worldName))
.minHeight(dim.getMinHeight())
.maxHeight(dim.getMaxHeight())
.build();
Iris.debug("Generator Config: " + w.toString());
File ff = new File(w.worldFolder(), "iris/pack");
if (!ff.exists() || ff.listFiles().length == 0) {
ff.mkdirs();
service(StudioSVC.class).installIntoWorld(sender, dim.getLoadKey(), ff.getParentFile());
}
return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey());
}
}

View File

@@ -48,7 +48,7 @@ public class CommandJigsaw implements DecreeExecutor {
IrisJigsawPiece piece
) {
File dest = piece.getLoadFile();
new JigsawEditor(player(), piece, IrisData.loadAnyObject(piece.getObject(), data()), dest);
new JigsawEditor(player(), piece, IrisData.loadAnyObject(piece.getObject()), dest);
}
@Decree(description = "Place a jigsaw structure")
@@ -78,7 +78,7 @@ public class CommandJigsaw implements DecreeExecutor {
@Param(description = "The object to use for this piece", customHandler = ObjectHandler.class)
String object
) {
IrisObject o = IrisData.loadAnyObject(object, data());
IrisObject o = IrisData.loadAnyObject(object);
if (object == null) {
sender().sendMessage(C.RED + "Failed to find existing object");

View File

@@ -38,6 +38,7 @@ import com.volmit.iris.util.decree.specialhandlers.ObjectHandler;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.Direction;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.Queue;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
@@ -78,9 +79,9 @@ public class CommandObject implements DecreeExecutor {
futureBlockChanges.put(block, block.getBlockData());
if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase(), false);
block.setBlockData(data.getBase());
Iris.warn("Tried to place custom block at " + x + ", " + y + ", " + z + " which is not supported!");
} else block.setBlockData(d, false);
} else block.setBlockData(d);
}
@Override
@@ -123,16 +124,6 @@ public class CommandObject implements DecreeExecutor {
tile.toBukkitTry(world.getBlockAt(xx, yy, zz));
}
@Override
public <T> void setData(int xx, int yy, int zz, T data) {
}
@Override
public <T> T getData(int xx, int yy, int zz, Class<T> t) {
return null;
}
@Override
public Engine getEngine() {
return null;
@@ -145,11 +136,11 @@ public class CommandObject implements DecreeExecutor {
@Param(description = "The object to analyze", customHandler = ObjectHandler.class)
String object
) {
IrisObject o = IrisData.loadAnyObject(object, data());
IrisObject o = IrisData.loadAnyObject(object);
sender().sendMessage("Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD() + "");
sender().sendMessage("Blocks Used: " + NumberFormat.getIntegerInstance().format(o.getBlocks().size()));
var queue = o.getBlocks().values();
Queue<BlockData> queue = o.getBlocks().enqueueValues();
Map<Material, Set<BlockData>> unsorted = new HashMap<>();
Map<BlockData, Integer> amounts = new HashMap<>();
Map<Material, Integer> materials = new HashMap<>();
@@ -210,7 +201,7 @@ public class CommandObject implements DecreeExecutor {
@Decree(description = "Shrink an object to its minimum size")
public void shrink(@Param(description = "The object to shrink", customHandler = ObjectHandler.class) String object) {
IrisObject o = IrisData.loadAnyObject(object, data());
IrisObject o = IrisData.loadAnyObject(object);
sender().sendMessage("Current Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD());
o.shrinkwrap();
sender().sendMessage("New Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD());
@@ -250,8 +241,7 @@ public class CommandObject implements DecreeExecutor {
Location[] b = WandSVC.getCuboid(player());
if (b == null || b[0] == null || b[1] == null) {
sender().sendMessage("No area selected.");
if (b == null) {
return;
}
Location a1 = b[0].clone();
@@ -334,7 +324,7 @@ public class CommandObject implements DecreeExecutor {
// @Param(description = "The scale interpolator to use", defaultValue = "none")
// IrisObjectPlacementScaleInterpolator interpolator
) {
IrisObject o = IrisData.loadAnyObject(object, data());
IrisObject o = IrisData.loadAnyObject(object);
double maxScale = Double.max(10 - o.getBlocks().size() / 10000d, 1);
if (scale > maxScale) {
sender().sendMessage(C.YELLOW + "Indicated scale exceeds maximum. Downscaled to maximum: " + maxScale);
@@ -427,10 +417,6 @@ 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();
@@ -491,10 +477,6 @@ 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();
@@ -542,10 +524,6 @@ 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();

View File

@@ -39,9 +39,7 @@ public class CommandPregen implements DecreeExecutor {
@Param(description = "The world to pregen", contextual = true)
World world,
@Param(aliases = "middle", description = "The center location of the pregen. Use \"me\" for your current location", defaultValue = "0,0")
Vector center,
@Param(description = "Open the Iris pregen gui", defaultValue = "true")
boolean gui
Vector center
) {
try {
if (sender().isPlayer() && access() == null) {
@@ -52,7 +50,7 @@ public class CommandPregen implements DecreeExecutor {
IrisToolbelt.pregenerate(PregenTask
.builder()
.center(new Position2(center.getBlockX(), center.getBlockZ()))
.gui(gui)
.gui(true)
.radiusX(radius)
.radiusZ(radius)
.build(), world);

View File

@@ -46,19 +46,18 @@ import com.volmit.iris.util.interpolation.InterpolationMethod;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.parallel.SyncExecutor;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.O;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.scheduling.jobs.ParallelRadiusJob;
import com.volmit.iris.util.scheduling.jobs.QueueJob;
import io.papermc.lib.PaperLib;
import org.bukkit.*;
import org.bukkit.event.inventory.InventoryType;
@@ -77,8 +76,8 @@ import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
@@ -92,19 +91,18 @@ public class CommandStudio implements DecreeExecutor {
return duration.toString().substring(2).replaceAll("(\\d[HMS])(?!$)", "$1 ").toLowerCase();
}
//TODO fix pack trimming
@Decree(description = "Download a project.", aliases = "dl")
public void download(
@Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project")
String pack,
@Param(name = "branch", description = "The branch to download from", defaultValue = "master")
String branch,
//@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false")
//boolean trim,
@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false")
boolean trim,
@Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false")
boolean overwrite
) {
new CommandIris().download(pack, branch, overwrite);
new CommandIris().download(pack, branch, trim, overwrite);
}
@Decree(description = "Open a new studio world", aliases = "o", sync = true)
@@ -163,74 +161,70 @@ public class CommandStudio implements DecreeExecutor {
@Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5")
int radius
) {
World world = player().getWorld();
if (!IrisToolbelt.isIrisWorld(world)) {
if (IrisToolbelt.isIrisWorld(player().getWorld())) {
VolmitSender sender = sender();
J.a(() -> {
DecreeContext.touch(sender);
PlatformChunkGenerator plat = IrisToolbelt.access(player().getWorld());
Engine engine = plat.getEngine();
try {
Chunk cx = player().getLocation().getChunk();
KList<Runnable> js = new KList<>();
BurstExecutor b = MultiBurst.burst.burst();
b.setMulticore(false);
int rad = engine.getMantle().getRadius();
for (int i = -(radius + rad); i <= radius + rad; i++) {
for (int j = -(radius + rad); j <= radius + rad; j++) {
engine.getMantle().getMantle().deleteChunk(i + cx.getX(), j + cx.getZ());
}
}
for (int i = -radius; i <= radius; i++) {
for (int j = -radius; j <= radius; j++) {
int finalJ = j;
int finalI = i;
b.queue(() -> plat.injectChunkReplacement(player().getWorld(), finalI + cx.getX(), finalJ + cx.getZ(), (f) -> {
synchronized (js) {
js.add(f);
}
}));
}
}
b.complete();
sender().sendMessage(C.GREEN + "Regenerating " + Form.f(js.size()) + " Sections");
QueueJob<Runnable> r = new QueueJob<>() {
final KList<Future<?>> futures = new KList<>();
@Override
public void execute(Runnable runnable) {
futures.add(J.sfut(runnable));
if (futures.size() > 64) {
while (futures.isNotEmpty()) {
try {
futures.remove(0).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
@Override
public String getName() {
return "Regenerating";
}
};
r.queue(js);
r.execute(sender());
} catch (Throwable e) {
sender().sendMessage("Unable to parse view-distance");
}
});
} else {
sender().sendMessage(C.RED + "You must be in an Iris World to use regen!");
}
VolmitSender sender = sender();
var loc = player().getLocation().clone();
J.a(() -> {
PlatformChunkGenerator plat = IrisToolbelt.access(world);
Engine engine = plat.getEngine();
DecreeContext.touch(sender);
try (SyncExecutor executor = new SyncExecutor(20);
var service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())
) {
int x = loc.getBlockX() >> 4;
int z = loc.getBlockZ() >> 4;
int rad = engine.getMantle().getRadius();
var mantle = engine.getMantle().getMantle();
var chunkMap = new KMap<Position2, MantleChunk>();
ParallelRadiusJob prep = new ParallelRadiusJob(Integer.MAX_VALUE, service) {
@Override
protected void execute(int rX, int rZ) {
if (Math.abs(rX) <= radius && Math.abs(rZ) <= radius) {
mantle.deleteChunk(rX + x, rZ + z);
return;
}
rX += x;
rZ += z;
chunkMap.put(new Position2(rX, rZ), mantle.getChunk(rX, rZ));
mantle.deleteChunk(rX, rZ);
}
@Override
public String getName() {
return "Preparing Mantle";
}
}.retarget(radius + rad, 0, 0);
CountDownLatch pLatch = new CountDownLatch(1);
prep.execute(sender(), pLatch::countDown);
pLatch.await();
ParallelRadiusJob job = new ParallelRadiusJob(Integer.MAX_VALUE, service) {
@Override
protected void execute(int x, int z) {
plat.injectChunkReplacement(world, x, z, executor);
}
@Override
public String getName() {
return "Regenerating";
}
}.retarget(radius, x, z);
CountDownLatch latch = new CountDownLatch(1);
job.execute(sender(), latch::countDown);
latch.await();
chunkMap.forEach((pos, chunk) ->
mantle.getChunk(pos.getX(), pos.getZ()).copyFrom(chunk));
} catch (Throwable e) {
sender().sendMessage("Error while regenerating chunks");
e.printStackTrace();
} finally {
DecreeContext.remove();
}
});
}
@Decree(description = "Convert objects in the \"convert\" folder")
@@ -319,15 +313,11 @@ public class CommandStudio implements DecreeExecutor {
O<Integer> ta = new O<>();
ta.set(-1);
var sender = sender();
var player = player();
var engine = engine();
ta.set(Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () ->
{
if (!player.getOpenInventory().getType().equals(InventoryType.CHEST)) {
if (!player().getOpenInventory().getType().equals(InventoryType.CHEST)) {
Bukkit.getScheduler().cancelTask(ta.get());
sender.sendMessage(C.GREEN + "Opened inventory!");
sender().sendMessage(C.GREEN + "Opened inventory!");
return;
}
@@ -335,49 +325,13 @@ public class CommandStudio implements DecreeExecutor {
inv.clear();
}
engine.addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player.getWorld(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ(), 1);
engine().addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player().getWorld(), player().getLocation().getBlockX(), player().getLocation().getBlockY(), player().getLocation().getBlockZ(), 1);
}, 0, fast ? 5 : 35));
sender().sendMessage(C.GREEN + "Opening inventory now!");
player().openInventory(inv);
}
@Decree(description = "Calculate the chance for each region to generate", origin = DecreeOrigin.PLAYER)
public void regions(@Param(description = "The radius in chunks", defaultValue = "500") int radius) {
var engine = engine();
if (engine == null) {
sender().sendMessage(C.RED + "Only works in an Iris world!");
return;
}
var sender = sender();
var player = player();
Thread.ofVirtual()
.start(() -> {
int d = radius * 2;
KMap<String, AtomicInteger> data = new KMap<>();
engine.getDimension().getRegions().forEach(key -> data.put(key, new AtomicInteger(0)));
var multiBurst = new MultiBurst("Region Sampler");
var executor = multiBurst.burst(radius * radius);
sender.sendMessage(C.GRAY + "Generating data...");
var loc = player.getLocation();
int totalTasks = d * d;
AtomicInteger completedTasks = new AtomicInteger(0);
int c = J.ar(() -> sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding regions"), 0);
new Spiraler(d, d, (x, z) -> executor.queue(() -> {
var region = engine.getRegion((x << 4) + 8, (z << 4) + 8);
data.computeIfAbsent(region.getLoadKey(), (k) -> new AtomicInteger(0))
.incrementAndGet();
completedTasks.incrementAndGet();
})).setOffset(loc.getBlockX(), loc.getBlockZ()).drain();
executor.complete();
multiBurst.close();
J.car(c);
sender.sendMessage(C.GREEN + "Done!");
var loader = engine.getData().getRegionLoader();
data.forEach((k, v) -> sender.sendMessage(C.GREEN + k + ": " + loader.load(k).getRarity() + " / " + Form.f((double) v.get() / totalTasks * 100, 2) + "%"));
});
}
@Decree(description = "Get all structures in a radius of chunks", aliases = "dist", origin = DecreeOrigin.PLAYER)
public void distances(@Param(description = "The radius in chunks") int radius) {
@@ -389,7 +343,7 @@ public class CommandStudio implements DecreeExecutor {
var sender = sender();
int d = radius * 2;
KMap<String, KList<Position2>> data = new KMap<>();
var multiBurst = new MultiBurst("Distance Sampler");
var multiBurst = new MultiBurst("Distance Sampler", Thread.MIN_PRIORITY);
var executor = multiBurst.burst(radius * radius);
sender.sendMessage(C.GRAY + "Generating data...");
@@ -688,14 +642,8 @@ public class CommandStudio implements DecreeExecutor {
}
sender().sendMessage(C.GREEN + "Sending you to the studio world!");
var player = player();
PaperLib.teleportAsync(player(), Iris.service(StudioSVC.class)
.getActiveProject()
.getActiveProvider()
.getTarget()
.getWorld()
.spawnLocation()
).thenRun(() -> player.setGameMode(GameMode.SPECTATOR));
player().teleport(Iris.service(StudioSVC.class).getActiveProject().getActiveProvider().getTarget().getWorld().spawnLocation());
player().setGameMode(GameMode.SPECTATOR);
}
@Decree(description = "Update your dimension projects VSCode workspace")

View File

@@ -0,0 +1,82 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.pregenerator.ChunkUpdater;
import com.volmit.iris.core.service.IrisEngineSVC;
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.collection.KList;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.mantle.TectonicPlate;
import com.volmit.iris.util.misc.Hastebin;
import com.volmit.iris.util.misc.Platform;
import com.volmit.iris.util.misc.getHardware;
import com.volmit.iris.util.nbt.mca.MCAFile;
import com.volmit.iris.util.nbt.mca.MCAUtil;
import com.volmit.iris.util.plugin.VolmitSender;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import net.jpountz.lz4.LZ4FrameInputStream;
import net.jpountz.lz4.LZ4FrameOutputStream;
import org.apache.commons.lang.RandomStringUtils;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import oshi.SystemInfo;
import java.io.*;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@Decree(name = "Support", origin = DecreeOrigin.BOTH, description = "Iris World Manager", aliases = {"support"})
public class CommandSupport implements DecreeExecutor {
@Decree(description = "report")
public void report() {
try {
if (sender().isPlayer()) sender().sendMessage(C.GOLD + "Creating report..");
if (!sender().isPlayer()) Iris.info(C.GOLD + "Creating report..");
Hastebin.enviornment(sender());
} catch (Exception e) {
Iris.info(C.RED + "Something went wrong: ");
e.printStackTrace();
}
}
}

View File

@@ -18,7 +18,6 @@
package com.volmit.iris.core.commands;
import lombok.Synchronized;
import org.bukkit.World;
import com.volmit.iris.Iris;
@@ -33,8 +32,7 @@ import com.volmit.iris.util.format.Form;
@Decree(name = "updater", origin = DecreeOrigin.BOTH, description = "Iris World Updater")
public class CommandUpdater implements DecreeExecutor {
private final Object lock = new Object();
private transient ChunkUpdater chunkUpdater;
private ChunkUpdater chunkUpdater;
@Decree(description = "Updates all chunk in the specified world")
public void start(
@@ -45,22 +43,19 @@ public class CommandUpdater implements DecreeExecutor {
sender().sendMessage(C.GOLD + "This is not an Iris world");
return;
}
synchronized (lock) {
if (chunkUpdater != null) {
chunkUpdater.stop();
}
chunkUpdater = new ChunkUpdater(world);
if (sender().isPlayer()) {
sender().sendMessage(C.GREEN + "Updating " + world.getName() + C.GRAY + " Total chunks: " + Form.f(chunkUpdater.getChunks()));
} else {
Iris.info(C.GREEN + "Updating " + world.getName() + C.GRAY + " Total chunks: " + Form.f(chunkUpdater.getChunks()));
}
chunkUpdater.start();
if (chunkUpdater != null) {
chunkUpdater.stop();
}
chunkUpdater = new ChunkUpdater(world);
if (sender().isPlayer()) {
sender().sendMessage(C.GREEN + "Updating " + world.getName() + C.GRAY + " Total chunks: " + Form.f(chunkUpdater.getChunks()));
} else {
Iris.info(C.GREEN + "Updating " + world.getName() + C.GRAY + " Total chunks: " + Form.f(chunkUpdater.getChunks()));
}
chunkUpdater.start();
}
@Synchronized("lock")
@Decree(description = "Pause the updater")
public void pause( ) {
if (chunkUpdater == null) {
@@ -83,7 +78,6 @@ public class CommandUpdater implements DecreeExecutor {
}
}
@Synchronized("lock")
@Decree(description = "Stops the updater")
public void stop() {
if (chunkUpdater == null) {

View File

@@ -61,14 +61,14 @@ public class JigsawEditor implements Listener {
private Location target;
public JigsawEditor(Player player, IrisJigsawPiece piece, IrisObject object, File saveLocation) {
if (object == null) throw new RuntimeException("Object is null! " + piece.getObject());
editors.compute(player, ($, current) -> {
if (current != null) {
current.exit();
}
return this;
});
if (editors.containsKey(player)) {
editors.get(player).close();
}
editors.put(player, this);
if (object == null) {
throw new RuntimeException("Object is null! " + piece.getObject());
}
this.object = object;
this.player = player;
origin = player.getLocation().clone().add(0, 7, 0);

View File

@@ -40,10 +40,7 @@ import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
@@ -56,7 +53,7 @@ public class PregeneratorJob implements PregenListener {
private static final Color COLOR_NETWORK_GENERATING = parseColor("#836b8c");
private static final Color COLOR_GENERATED = parseColor("#65c295");
private static final Color COLOR_CLEANED = parseColor("#34eb93");
private static final AtomicReference<PregeneratorJob> instance = new AtomicReference<>();
public static PregeneratorJob instance;
private final MemoryMonitor monitor;
private final PregenTask task;
private final boolean saving;
@@ -67,21 +64,14 @@ public class PregeneratorJob implements PregenListener {
private final Position2 max;
private final ChronoLatch cl = new ChronoLatch(TimeUnit.MINUTES.toMillis(1));
private final Engine engine;
private final ExecutorService service;
private JFrame frame;
private PregenRenderer renderer;
private int rgc = 0;
private String[] info;
public PregeneratorJob(PregenTask task, PregeneratorMethod method, Engine engine) {
instance.updateAndGet(old -> {
if (old != null) {
old.pregenerator.close();
old.close();
}
return this;
});
this.engine = engine;
instance = this;
monitor = new MemoryMonitor(50);
saving = false;
info = new String[]{"Initializing..."};
@@ -106,44 +96,40 @@ public class PregeneratorJob implements PregenListener {
}, "Iris Pregenerator");
t.setPriority(Thread.MIN_PRIORITY);
t.start();
service = Executors.newVirtualThreadPerTaskExecutor();
}
public static boolean shutdownInstance() {
PregeneratorJob inst = instance.get();
if (inst == null) {
if (instance == null) {
return false;
}
J.a(inst.pregenerator::close);
J.a(() -> instance.pregenerator.close());
return true;
}
public static PregeneratorJob getInstance() {
return instance.get();
return instance;
}
public static boolean pauseResume() {
PregeneratorJob inst = instance.get();
if (inst == null) {
if (instance == null) {
return false;
}
if (isPaused()) {
inst.pregenerator.resume();
instance.pregenerator.resume();
} else {
inst.pregenerator.pause();
instance.pregenerator.pause();
}
return true;
}
public static boolean isPaused() {
PregeneratorJob inst = instance.get();
if (inst == null) {
if (instance == null) {
return true;
}
return inst.paused();
return instance.paused();
}
private static Color parseColor(String c) {
@@ -193,7 +179,7 @@ public class PregeneratorJob implements PregenListener {
J.a(() -> {
pregenerator.close();
close();
instance.compareAndSet(this, null);
instance = null;
});
}
@@ -233,10 +219,10 @@ public class PregeneratorJob implements PregenListener {
}
@Override
public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, long generated, long totalChunks, long chunksRemaining, long eta, long elapsed, String method, boolean cached) {
public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method) {
info = new String[]{
(paused() ? "PAUSED" : (saving ? "Saving... " : "Generating")) + " " + Form.f(generated) + " of " + Form.f(totalChunks) + " (" + Form.pc(percent, 0) + " Complete)",
"Speed: " + (cached ? "Cached " : "") + Form.f(chunksPerSecond, 0) + " Chunks/s, " + Form.f(regionsPerMinute, 1) + " Regions/m, " + Form.f(chunksPerMinute, 0) + " Chunks/m",
"Speed: " + Form.f(chunksPerSecond, 0) + " Chunks/s, " + Form.f(regionsPerMinute, 1) + " Regions/m, " + Form.f(chunksPerMinute, 0) + " Chunks/m",
Form.duration(eta, 2) + " Remaining " + " (" + Form.duration(elapsed, 2) + " Elapsed)",
"Generation Method: " + method,
"Memory: " + Form.memSize(monitor.getUsedBytes(), 2) + " (" + Form.pc(monitor.getUsagePercent(), 0) + ") Pressure: " + Form.memSize(monitor.getPressure(), 0) + "/s",
@@ -254,16 +240,13 @@ public class PregeneratorJob implements PregenListener {
}
@Override
public void onChunkGenerated(int x, int z, boolean cached) {
if (renderer == null || frame == null || !frame.isVisible()) return;
service.submit(() -> {
if (engine != null) {
draw(x, z, engine.draw((x << 4) + 8, (z << 4) + 8));
return;
}
public void onChunkGenerated(int x, int z) {
if (engine != null) {
draw(x, z, engine.draw((x << 4) + 8, (z << 4) + 8));
return;
}
draw(x, z, COLOR_GENERATED);
});
draw(x, z, COLOR_GENERATED);
}
@Override
@@ -321,9 +304,8 @@ public class PregeneratorJob implements PregenListener {
@Override
public void onClose() {
close();
instance.compareAndSet(this, null);
instance = null;
whenDone.forEach(Runnable::run);
service.shutdownNow();
}
@Override

View File

@@ -30,6 +30,7 @@ import com.volmit.iris.engine.object.IrisWorld;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.registry.Attributes;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.M;
@@ -39,6 +40,7 @@ import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.O;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.bukkit.Location;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@@ -413,7 +415,8 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
}
private double getWorldX(double screenX) {
return (mscale * screenX) + ((oxp / scale) * mscale);
//return (mscale * screenX) + ((oxp / scale) * mscale);
return (mscale * screenX) + ((oxp / scale));
}
private double getWorldZ(double screenZ) {
@@ -483,13 +486,6 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
hz += Math.abs(hz - lz) * 0.36;
}
if (Math.abs(lx - hx) < 0.5) {
hx = lx;
}
if (Math.abs(lz - hz) < 0.5) {
hz = lz;
}
if (centities.flip()) {
J.s(() -> {
synchronized (lastEntities) {
@@ -514,8 +510,8 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
int iscale = (int) scale;
g.setColor(Color.white);
g.clearRect(0, 0, w, h);
double offsetX = oxp / scale;
double offsetZ = ozp / scale;
int posX = (int) oxp;
int posZ = (int) ozp;
m.set(3);
for (int r = 0; r < Math.max(w, h); r += iscale) {
@@ -524,14 +520,10 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
int a = i - (w / 2);
int b = j - (h / 2);
if (a * a + b * b <= r * r) {
int tx = (int) (Math.floor((offsetX + i) / iscale) * iscale);
int tz = (int) (Math.floor((offsetZ + j) / iscale) * iscale);
BufferedImage t = getTile(gg, iscale, tx, tz, m);
BufferedImage t = getTile(gg, iscale, Math.floorDiv((posX / iscale) + i, iscale) * iscale, Math.floorDiv((posZ / iscale) + j, iscale) * iscale, m);
if (t != null) {
int rx = Math.floorMod((int) Math.floor(offsetX), iscale);
int rz = Math.floorMod((int) Math.floor(offsetZ), iscale);
g.drawImage(t, i - rx, j - rz, iscale, iscale, (img, infoflags, x, y, width, height) -> true);
g.drawImage(t, i - ((posX / iscale) % (iscale)), j - ((posZ / iscale) % (iscale)), iscale, iscale, (img, infoflags, x, y, width, height) -> true);
}
}
}
@@ -659,8 +651,8 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
private void animateTo(double wx, double wz) {
double cx = getWorldX(getWidth() / 2);
double cz = getWorldZ(getHeight() / 2);
ox += ((wx - cx) / mscale) * scale;
oz += ((wz - cz) / mscale) * scale;
ox += (wx - cx);
oz += (wz - cz);
}
private void renderPosition(Graphics2D g, double x, double z) {
@@ -815,28 +807,11 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
return;
}
double m0 = mscale;
double m1 = m0 + ((0.25 * m0) * notches);
m1 = Math.max(m1, 0.00001);
if (m1 == m0) {
return;
}
//Iris.info("Blocks/Pixel: " + (mscale) + ", Blocks Wide: " + (w * mscale));
positions.clear();
fastpositions.clear();
Point p = e.getPoint();
double sx = p.getX();
double sz = p.getY();
double newOxp = scale * ((m0 / m1) * (sx + (oxp / scale)) - sx);
double newOzp = scale * ((m0 / m1) * (sz + (ozp / scale)) - sz);
mscale = m1;
oxp = newOxp;
ozp = newOzp;
ox = oxp;
oz = ozp;
mscale = mscale + ((0.25 * mscale) * notches);
mscale = Math.max(mscale, 0.00001);
}
@Override

View File

@@ -1,18 +1,16 @@
package com.volmit.iris.core.link.data;
package com.volmit.iris.core.link;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.reflect.WrappedField;
import com.willfp.ecoitems.items.EcoItem;
import com.willfp.ecoitems.items.EcoItems;
import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
public class EcoItemsDataProvider extends ExternalDataProvider {
@@ -36,6 +34,12 @@ public class EcoItemsDataProvider extends ExternalDataProvider {
}
}
@NotNull
@Override
public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@NotNull
@Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
@@ -44,18 +48,30 @@ public class EcoItemsDataProvider extends ExternalDataProvider {
return itemStack.get(item).clone();
}
@NotNull
@Override
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
if (dataType != DataType.ITEM) return List.of();
return EcoItems.INSTANCE.values()
.stream()
.map(x -> Identifier.fromNamespacedKey(id.get(x)))
.filter(dataType.asPredicate(this))
.toList();
public Identifier[] getBlockTypes() {
return new Identifier[0];
}
@NotNull
@Override
public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>();
for (EcoItem item : EcoItems.INSTANCE.values()) {
try {
Identifier key = Identifier.fromNamespacedKey(id.get(item));
if (getItemStack(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new Identifier[0]);
}
@Override
public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
return id.namespace().equalsIgnoreCase("ecoitems") && dataType == DataType.ITEM;
public boolean isValidProvider(@NotNull Identifier id, boolean isItem) {
return id.namespace().equalsIgnoreCase("ecoitems") && isItem;
}
}

View File

@@ -1,15 +1,13 @@
package com.volmit.iris.core.link.data;
package com.volmit.iris.core.link;
import com.ssomar.score.api.executableitems.ExecutableItemsAPI;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
import java.util.Optional;
@@ -23,6 +21,12 @@ public class ExecutableItemsDataProvider extends ExternalDataProvider {
Iris.info("Setting up ExecutableItems Link...");
}
@NotNull
@Override
public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@NotNull
@Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
@@ -31,19 +35,30 @@ public class ExecutableItemsDataProvider extends ExternalDataProvider {
.orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()));
}
@NotNull
@Override
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
if (dataType != DataType.ITEM) return List.of();
return ExecutableItemsAPI.getExecutableItemsManager()
.getExecutableItemIdsList()
.stream()
.map(name -> new Identifier("executable_items", name))
.filter(dataType.asPredicate(this))
.toList();
public Identifier[] getBlockTypes() {
return new Identifier[0];
}
@NotNull
@Override
public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>();
for (String name : ExecutableItemsAPI.getExecutableItemsManager().getExecutableItemIdsList()) {
try {
Identifier key = new Identifier("executable_items", name);
if (getItemStack(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new Identifier[0]);
}
@Override
public boolean isValidProvider(@NotNull Identifier key, DataType dataType) {
return key.namespace().equalsIgnoreCase("executable_items") && dataType == DataType.ITEM;
public boolean isValidProvider(@NotNull Identifier key, boolean isItem) {
return key.namespace().equalsIgnoreCase("executable_items") && isItem;
}
}

View File

@@ -1,37 +1,24 @@
package com.volmit.iris.core.link;
import com.volmit.iris.core.link.data.DataType;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.math.RNG;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
@Getter
@RequiredArgsConstructor
public abstract class ExternalDataProvider implements Listener {
public abstract class ExternalDataProvider {
@NonNull
private final String pluginId;
@@ -66,21 +53,7 @@ public abstract class ExternalDataProvider implements Listener {
* @throws MissingResourceException when the blockId is invalid
*/
@NotNull
public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
/**
* Retrieves a list of all {@link BlockProperty} objects associated with the specified block identifier.
*
* @param blockId The identifier of the block whose properties are to be retrieved. Must not be null.
* @return A list of {@link BlockProperty} objects representing the properties of the block.
* @throws MissingResourceException If the specified block identifier is invalid or cannot be found.
*/
@NotNull
public List<BlockProperty> getBlockProperties(@NotNull Identifier blockId) throws MissingResourceException {
return List.of();
}
public abstract BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException;
/**
* @see ExternalDataProvider#getItemStack(Identifier)
@@ -100,9 +73,7 @@ public abstract class ExternalDataProvider implements Listener {
* @throws MissingResourceException when the itemId is invalid
*/
@NotNull
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
}
public abstract ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException;
/**
* This method is used for placing blocks that need to use the plugins api
@@ -114,57 +85,9 @@ public abstract class ExternalDataProvider implements Listener {
*/
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {}
/**
* Spawns a mob in the specified location using the given engine and entity identifier.
*
* @param location The location in the world where the mob should spawn. Must not be null.
* @param entityId The identifier of the mob entity to spawn. Must not be null.
* @return The spawned {@link Entity} if successful, or null if the mob could not be spawned.
*/
@Nullable
public Entity spawnMob(@NotNull Location location, @NotNull Identifier entityId) throws MissingResourceException {
throw new MissingResourceException("Failed to find Entity!", entityId.namespace(), entityId.key());
}
public abstract @NotNull Identifier[] getBlockTypes();
public abstract @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType);
public abstract @NotNull Identifier[] getItemTypes();
public abstract boolean isValidProvider(@NotNull Identifier id, DataType dataType);
protected static Pair<Float, BlockFace> parseYawAndFace(@NotNull Engine engine, @NotNull Block block, @NotNull KMap<@NotNull String, @NotNull String> state) {
float yaw = 0;
BlockFace face = BlockFace.NORTH;
long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY();
RNG rng = new RNG(seed);
if ("true".equals(state.get("randomYaw"))) {
yaw = rng.f(0, 360);
} else if (state.containsKey("yaw")) {
yaw = Float.parseFloat(state.get("yaw"));
}
if ("true".equals(state.get("randomFace"))) {
BlockFace[] faces = BlockFace.values();
face = faces[rng.i(0, faces.length - 1)];
} else if (state.containsKey("face")) {
face = BlockFace.valueOf(state.get("face").toUpperCase());
}
if (face == BlockFace.SELF) {
face = BlockFace.NORTH;
}
return new Pair<>(yaw, face);
}
protected static List<BlockProperty> YAW_FACE_BIOME_PROPERTIES = List.of(
BlockProperty.ofEnum(BiomeColor.class, "matchBiome", null),
BlockProperty.ofBoolean("randomYaw", false),
BlockProperty.ofFloat("yaw", 0, 0, 360f, false, true),
BlockProperty.ofBoolean("randomFace", true),
new BlockProperty(
"face",
BlockFace.class,
BlockFace.NORTH,
Arrays.asList(BlockFace.values()).subList(0, BlockFace.values().length - 1),
BlockFace::name
)
);
public abstract boolean isValidProvider(@NotNull Identifier id, boolean isItem);
}

View File

@@ -1,11 +1,10 @@
package com.volmit.iris.core.link.data;
package com.volmit.iris.core.link;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.reflect.WrappedField;
@@ -19,8 +18,6 @@ import org.bukkit.block.data.type.Leaves;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.function.Supplier;
@@ -67,7 +64,7 @@ public class HMCLeavesDataProvider extends ExternalDataProvider {
BlockData blockData = Bukkit.createBlockData(material);
if (IrisSettings.get().getGenerator().preventLeafDecay && blockData instanceof Leaves leaves)
leaves.setPersistent(true);
return IrisCustomData.of(blockData, ExternalDataSVC.buildState(blockId, state));
return new IrisCustomData(blockData, ExternalDataSVC.buildState(blockId, state));
}
@NotNull
@@ -92,20 +89,41 @@ public class HMCLeavesDataProvider extends ExternalDataProvider {
}
}
@NotNull
@Override
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
if (dataType == DataType.ENTITY) return List.of();
return (dataType == DataType.BLOCK ? blockDataMap.keySet() : itemDataField.keySet())
.stream()
.map(x -> new Identifier("hmcleaves", x))
.filter(dataType.asPredicate(this))
.toList();
public Identifier[] getBlockTypes() {
KList<Identifier> names = new KList<>();
for (String name : blockDataMap.keySet()) {
try {
Identifier key = new Identifier("hmcleaves", name);
if (getBlockData(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new Identifier[0]);
}
@NotNull
@Override
public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>();
for (String name : itemDataField.keySet()) {
try {
Identifier key = new Identifier("hmcleaves", name);
if (getItemStack(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new Identifier[0]);
}
@Override
public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
if (dataType == DataType.ENTITY) return false;
return (dataType == DataType.ITEM ? itemDataField.keySet() : blockDataMap.keySet()).contains(id.key());
public boolean isValidProvider(@NotNull Identifier id, boolean isItem) {
return (isItem ? itemDataField.keySet() : blockDataMap.keySet()).contains(id.key());
}
private <C, T> Map<String, T> getMap(C config, String name) {

View File

@@ -0,0 +1,76 @@
package com.volmit.iris.core.link;
import com.volmit.iris.Iris;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import dev.lone.itemsadder.api.CustomBlock;
import dev.lone.itemsadder.api.CustomStack;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.MissingResourceException;
public class ItemAdderDataProvider extends ExternalDataProvider {
private KList<String> itemNamespaces, blockNamespaces;
public ItemAdderDataProvider() {
super("ItemsAdder");
}
@Override
public void init() {
this.itemNamespaces = new KList<>();
this.blockNamespaces = new KList<>();
for (Identifier i : getItemTypes()) {
itemNamespaces.addIfMissing(i.namespace());
}
for (Identifier i : getBlockTypes()) {
blockNamespaces.addIfMissing(i.namespace());
Iris.info("Found ItemAdder Block: " + i);
}
}
@NotNull
@Override
public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
return CustomBlock.getBaseBlockData(blockId.toString());
}
@NotNull
@Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
CustomStack stack = CustomStack.getInstance(itemId.toString());
if (stack == null) {
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
}
return stack.getItemStack();
}
@NotNull
@Override
public Identifier[] getBlockTypes() {
KList<Identifier> keys = new KList<>();
for (String s : CustomBlock.getNamespacedIdsInRegistry()) {
keys.add(Identifier.fromString(s));
}
return keys.toArray(new Identifier[0]);
}
@NotNull
@Override
public Identifier[] getItemTypes() {
KList<Identifier> keys = new KList<>();
for (String s : CustomStack.getNamespacedIdsInRegistry()) {
keys.add(Identifier.fromString(s));
}
return keys.toArray(new Identifier[0]);
}
@Override
public boolean isValidProvider(@NotNull Identifier id, boolean isItem) {
return isItem ? this.itemNamespaces.contains(id.namespace()) : this.blockNamespaces.contains(id.namespace());
}
}

View File

@@ -1,24 +1,21 @@
package com.volmit.iris.core.link.data;
package com.volmit.iris.core.link;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.scheduling.J;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.ItemTier;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.block.CustomBlock;
import org.bukkit.Bukkit;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
public class MMOItemsDataProvider extends ExternalDataProvider {
@@ -88,35 +85,52 @@ public class MMOItemsDataProvider extends ExternalDataProvider {
return item;
}
@NotNull
@Override
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
return switch (dataType) {
case ENTITY -> List.of();
case BLOCK -> api().getCustomBlocks().getBlockIds().stream().map(id -> new Identifier("mmoitems", String.valueOf(id)))
.filter(dataType.asPredicate(this))
.toList();
case ITEM -> {
Supplier<Collection<Identifier>> supplier = () -> api().getTypes()
.getAll()
.stream()
.flatMap(type -> api()
.getTemplates()
.getTemplateNames(type)
.stream()
.map(name -> new Identifier("mmoitems_" + type.getId(), name)))
.filter(dataType.asPredicate(this))
.toList();
public Identifier[] getBlockTypes() {
KList<Identifier> names = new KList<>();
for (Integer id : api().getCustomBlocks().getBlockIds()) {
try {
Identifier key = new Identifier("mmoitems", String.valueOf(id));
if (getBlockData(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
return names.toArray(new Identifier[0]);
}
if (Bukkit.isPrimaryThread()) yield supplier.get();
else yield J.sfut(supplier).join();
@NotNull
@Override
public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>();
Runnable run = () -> {
for (Type type : api().getTypes().getAll()) {
for (String name : api().getTemplates().getTemplateNames(type)) {
try {
Identifier key = new Identifier("mmoitems_" + type.getId(), name);
if (getItemStack(key) != null)
names.add(key);
} catch (MissingResourceException ignored) {
}
}
}
};
if (Bukkit.isPrimaryThread()) run.run();
else {
try {
J.sfut(run).get();
} catch (InterruptedException | ExecutionException e) {
Iris.error("Failed getting MMOItems item types!");
Iris.reportError(e);
}
}
return names.toArray(new Identifier[0]);
}
@Override
public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
if (dataType == DataType.ENTITY) return false;
return dataType == DataType.ITEM ? id.namespace().split("_", 2).length == 2 : id.namespace().equals("mmoitems");
public boolean isValidProvider(@NotNull Identifier id, boolean isItem) {
return isItem ? id.namespace().split("_", 2).length == 2 : id.namespace().equals("mmoitems");
}
private MMOItems api() {

View File

@@ -18,60 +18,126 @@
package com.volmit.iris.core.link;
import lombok.SneakyThrows;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.collection.KMap;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.mvplugins.multiverse.core.MultiverseCoreApi;
import org.mvplugins.multiverse.core.world.MultiverseWorld;
import org.mvplugins.multiverse.core.world.WorldManager;
import org.mvplugins.multiverse.core.world.options.ImportWorldOptions;
import org.bukkit.WorldType;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
public class MultiverseCoreLink {
private final boolean active;
private final KMap<String, String> worldNameTypes = new KMap<>();
public MultiverseCoreLink() {
active = Bukkit.getPluginManager().getPlugin("Multiverse-Core") != null;
}
public boolean addWorld(String worldName, IrisDimension dim, String seed) {
if (!isSupported()) {
return false;
}
try {
Plugin p = getMultiverse();
Object mvWorldManager = p.getClass().getDeclaredMethod("getMVWorldManager").invoke(p);
Method m = mvWorldManager.getClass().getDeclaredMethod("addWorld",
String.class, World.Environment.class, String.class, WorldType.class, Boolean.class, String.class, boolean.class);
boolean b = (boolean) m.invoke(mvWorldManager, worldName, dim.getEnvironment(), seed, WorldType.NORMAL, false, "Iris", false);
saveConfig();
return b;
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
return false;
}
@SuppressWarnings("unchecked")
public Map<String, ?> getList() {
try {
Plugin p = getMultiverse();
Object mvWorldManager = p.getClass().getDeclaredMethod("getMVWorldManager").invoke(p);
Field f = mvWorldManager.getClass().getDeclaredField("worldsFromTheConfig");
f.setAccessible(true);
return (Map<String, ?>) f.get(mvWorldManager);
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
return null;
}
public void removeFromConfig(World world) {
removeFromConfig(world.getName());
if (!isSupported()) {
return;
}
getList().remove(world.getName());
saveConfig();
}
public void removeFromConfig(String world) {
if (!active) return;
var manager = worldManager();
manager.removeWorld(world).onSuccess(manager::saveWorldsConfig);
}
@SneakyThrows
public void updateWorld(World bukkitWorld, String pack) {
if (!active) return;
var generator = "Iris:" + pack;
var manager = worldManager();
var world = manager.getWorld(bukkitWorld).getOrElse(() -> {
var options = ImportWorldOptions.worldName(bukkitWorld.getName())
.generator(generator)
.environment(bukkitWorld.getEnvironment())
.useSpawnAdjust(false);
return manager.importWorld(options).get();
});
world.setAutoLoad(false);
if (!generator.equals(world.getGenerator())) {
var field = MultiverseWorld.class.getDeclaredField("worldConfig");
field.setAccessible(true);
var config = field.get(world);
config.getClass()
.getDeclaredMethod("setGenerator", String.class)
.invoke(config, generator);
if (!isSupported()) {
return;
}
manager.saveWorldsConfig();
getList().remove(world);
saveConfig();
}
private WorldManager worldManager() {
var api = MultiverseCoreApi.get();
return api.getWorldManager();
public void saveConfig() {
try {
Plugin p = getMultiverse();
Object mvWorldManager = p.getClass().getDeclaredMethod("getMVWorldManager").invoke(p);
mvWorldManager.getClass().getDeclaredMethod("saveWorldsConfig").invoke(mvWorldManager);
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
}
public void assignWorldType(String worldName, String type) {
worldNameTypes.put(worldName, type);
}
public String getWorldNameType(String worldName, String defaultType) {
try {
String t = worldNameTypes.get(worldName);
return t == null ? defaultType : t;
} catch (Throwable e) {
Iris.reportError(e);
return defaultType;
}
}
public boolean isSupported() {
return getMultiverse() != null;
}
public Plugin getMultiverse() {
return Bukkit.getPluginManager().getPlugin("Multiverse-Core");
}
public String envName(World.Environment environment) {
if (environment == null) {
return "normal";
}
return switch (environment) {
case NORMAL -> "normal";
case NETHER -> "nether";
case THE_END -> "end";
default -> environment.toString().toLowerCase();
};
}
}

View File

@@ -16,19 +16,19 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.link.data;
package com.volmit.iris.core.link;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.math.RNG;
import io.lumine.mythic.bukkit.BukkitAdapter;
import io.lumine.mythic.bukkit.utils.serialize.Chroma;
import io.lumine.mythiccrucible.MythicCrucible;
@@ -37,12 +37,11 @@ import io.lumine.mythiccrucible.items.ItemManager;
import io.lumine.mythiccrucible.items.blocks.CustomBlockItemContext;
import io.lumine.mythiccrucible.items.furniture.FurnitureItemContext;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
import java.util.Optional;
@@ -72,26 +71,13 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider {
CustomBlockItemContext blockItemContext = crucibleItem.getBlockData();
FurnitureItemContext furnitureItemContext = crucibleItem.getFurnitureData();
if (furnitureItemContext != null) {
return IrisCustomData.of(B.getAir(), ExternalDataSVC.buildState(blockId, state));
return new IrisCustomData(B.getAir(), ExternalDataSVC.buildState(blockId, state));
} else if (blockItemContext != null) {
return blockItemContext.getBlockData();
}
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@Override
public @NotNull List<BlockProperty> getBlockProperties(@NotNull Identifier blockId) throws MissingResourceException {
CrucibleItem crucibleItem = this.itemManager.getItem(blockId.key())
.orElseThrow(() -> new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()));
if (crucibleItem.getFurnitureData() != null) {
return YAW_FACE_BIOME_PROPERTIES;
} else if (crucibleItem.getBlockData() != null) {
return List.of();
}
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@NotNull
@Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
@@ -102,27 +88,69 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider {
.generateItemStack(1));
}
@NotNull
@Override
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
return itemManager.getItems()
.stream()
.map(i -> new Identifier("crucible", i.getInternalName()))
.filter(dataType.asPredicate(this))
.toList();
public Identifier[] getBlockTypes() {
KList<Identifier> names = new KList<>();
for (CrucibleItem item : this.itemManager.getItems()) {
if (item.getBlockData() == null) continue;
try {
Identifier key = new Identifier("crucible", item.getInternalName());
if (getBlockData(key) != null) {
Iris.info("getBlockTypes: Block loaded '" + item.getInternalName() + "'");
names.add(key);
}
} catch (MissingResourceException ignored) {}
}
return names.toArray(new Identifier[0]);
}
@NotNull
@Override
public Identifier[] getItemTypes() {
KList<Identifier> names = new KList<>();
for (CrucibleItem item : this.itemManager.getItems()) {
try {
Identifier key = new Identifier("crucible", item.getInternalName());
if (getItemStack(key) != null) {
Iris.info("getItemTypes: Item loaded '" + item.getInternalName() + "'");
names.add(key);
}
} catch (MissingResourceException ignored) {}
}
return names.toArray(new Identifier[0]);
}
@Override
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
var parsedState = ExternalDataSVC.parseState(blockId);
var state = parsedState.getB();
blockId = parsedState.getA();
var pair = ExternalDataSVC.parseState(blockId);
var state = pair.getB();
blockId = pair.getA();
Optional<CrucibleItem> item = itemManager.getItem(blockId.key());
if (item.isEmpty()) return;
FurnitureItemContext furniture = item.get().getFurnitureData();
if (furniture == null) return;
var pair = parseYawAndFace(engine, block, state);
float yaw = 0;
BlockFace face = BlockFace.NORTH;
long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY();
RNG rng = new RNG(seed);
if ("true".equals(state.get("randomYaw"))) {
yaw = rng.f(0, 360);
} else if (state.containsKey("yaw")) {
yaw = Float.parseFloat(state.get("yaw"));
}
if ("true".equals(state.get("randomFace"))) {
BlockFace[] faces = BlockFace.values();
face = faces[rng.i(0, faces.length - 1)];
} else if (state.containsKey("face")) {
face = BlockFace.valueOf(state.get("face").toUpperCase());
}
if (face == BlockFace.SELF) {
face = BlockFace.NORTH;
}
BiomeColor type = null;
Chroma color = null;
try {
@@ -133,12 +161,11 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider {
if (biomeColor == null) return;
color = Chroma.of(biomeColor.getRGB());
}
furniture.place(block, pair.getB(), pair.getA(), color);
furniture.place(block, face, yaw, color);
}
@Override
public boolean isValidProvider(@NotNull Identifier key, DataType dataType) {
if (dataType == DataType.ENTITY) return false;
public boolean isValidProvider(@NotNull Identifier key, boolean isItem) {
return key.namespace().equalsIgnoreCase("crucible");
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.link;
import io.lumine.mythic.bukkit.MythicBukkit;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.plugin.Plugin;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
public class MythicMobsLink {
public MythicMobsLink() {
}
public boolean isEnabled() {
return getPlugin() != null;
}
public Plugin getPlugin() {
return Bukkit.getPluginManager().getPlugin("MythicMobs");
}
/**
* Spawn a mythic mob at this location
*
* @param mob The mob
* @param location The location
* @return The mob, or null if it can't be spawned
*/
public @Nullable
Entity spawnMob(String mob, Location location) {
return isEnabled() ? MythicBukkit.inst().getMobManager().spawnMob(mob, location).getEntity().getBukkitEntity() : null;
}
public Collection<String> getMythicMobTypes() {
return isEnabled() ? MythicBukkit.inst().getMobManager().getMobNames() : List.of();
}
}

View File

@@ -1,34 +1,34 @@
package com.volmit.iris.core.link.data;
package com.volmit.iris.core.link;
import com.nexomc.nexo.api.NexoBlocks;
import com.nexomc.nexo.api.NexoFurniture;
import com.nexomc.nexo.api.NexoItems;
import com.nexomc.nexo.items.ItemBuilder;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.math.RNG;
import org.bukkit.Color;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.inventory.meta.MapMeta;
import org.bukkit.inventory.meta.PotionMeta;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.Arrays;
import java.util.MissingResourceException;
import java.util.concurrent.atomic.AtomicBoolean;
public class NexoDataProvider extends ExternalDataProvider {
private final AtomicBoolean failed = new AtomicBoolean(false);
public NexoDataProvider() {
super("Nexo");
}
@@ -49,23 +49,14 @@ public class NexoDataProvider extends ExternalDataProvider {
BlockData data = NexoBlocks.blockData(blockId.key());
if (data == null)
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
return IrisCustomData.of(data, blockState);
return new IrisCustomData(data, blockState);
} else if (NexoFurniture.isFurniture(blockId.key())) {
return IrisCustomData.of(B.getAir(), blockState);
return new IrisCustomData(B.getAir(), blockState);
}
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@Override
public @NotNull List<BlockProperty> getBlockProperties(@NotNull Identifier blockId) throws MissingResourceException {
if (!NexoItems.exists(blockId.key())) {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
return NexoFurniture.isFurniture(blockId.key()) ? YAW_FACE_BIOME_PROPERTIES : List.of();
}
@NotNull
@Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
@@ -73,19 +64,14 @@ public class NexoDataProvider extends ExternalDataProvider {
if (builder == null) {
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
}
try {
return builder.build();
} catch (Exception e) {
e.printStackTrace();
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
}
return builder.build();
}
@Override
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
var statePair = ExternalDataSVC.parseState(blockId);
var state = statePair.getB();
blockId = statePair.getA();
var pair = ExternalDataSVC.parseState(blockId);
var state = pair.getB();
blockId = pair.getA();
if (NexoBlocks.isCustomBlock(blockId.key())) {
NexoBlocks.place(blockId.key(), block.getLocation());
@@ -95,8 +81,26 @@ public class NexoDataProvider extends ExternalDataProvider {
if (!NexoFurniture.isFurniture(blockId.key()))
return;
var pair = parseYawAndFace(engine, block, state);
ItemDisplay display = NexoFurniture.place(blockId.key(), block.getLocation(), pair.getA(), pair.getB());
float yaw = 0;
BlockFace face = BlockFace.NORTH;
long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY();
RNG rng = new RNG(seed);
if ("true".equals(state.get("randomYaw"))) {
yaw = rng.f(0, 360);
} else if (state.containsKey("yaw")) {
yaw = Float.parseFloat(state.get("yaw"));
}
if ("true".equals(state.get("randomFace"))) {
BlockFace[] faces = BlockFace.values();
face = faces[rng.i(0, faces.length - 1)];
} else if (state.containsKey("face")) {
face = BlockFace.valueOf(state.get("face").toUpperCase());
}
if (face == BlockFace.SELF) {
face = BlockFace.NORTH;
}
ItemDisplay display = NexoFurniture.place(blockId.key(), block.getLocation(), yaw, face);
if (display == null) return;
ItemStack itemStack = display.getItemStack();
if (itemStack == null) return;
@@ -110,31 +114,51 @@ public class NexoDataProvider extends ExternalDataProvider {
var biomeColor = INMS.get().getBiomeColor(block.getLocation(), type);
if (biomeColor == null) return;
var potionColor = Color.fromARGB(biomeColor.getAlpha(), biomeColor.getRed(), biomeColor.getGreen(), biomeColor.getBlue());
var meta = itemStack.getItemMeta();
switch (meta) {
case LeatherArmorMeta armor -> armor.setColor(potionColor);
case PotionMeta potion -> potion.setColor(potionColor);
case MapMeta map -> map.setColor(potionColor);
case null, default -> {}
if (itemStack.getItemMeta() instanceof PotionMeta meta) {
meta.setColor(potionColor);
itemStack.setItemMeta(meta);
}
itemStack.setItemMeta(meta);
}
display.setItemStack(itemStack);
}
@NotNull
@Override
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
if (dataType == DataType.ENTITY) return List.of();
return NexoItems.itemNames()
.stream()
public Identifier[] getBlockTypes() {
return NexoItems.itemNames().stream()
.map(i -> new Identifier("nexo", i))
.filter(dataType.asPredicate(this))
.toList();
.filter(i -> {
try {
return getBlockData(i) != null;
} catch (MissingResourceException e) {
return false;
}
})
.toArray(Identifier[]::new);
}
@NotNull
@Override
public Identifier[] getItemTypes() {
return NexoItems.itemNames().stream()
.map(i -> new Identifier("nexo", i))
.filter(i -> {
try {
return getItemStack(i) != null;
} catch (MissingResourceException e) {
return false;
}
})
.toArray(Identifier[]::new);
}
@Override
public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
if (dataType == DataType.ENTITY) return false;
public boolean isValidProvider(@NotNull Identifier id, boolean isItem) {
return "nexo".equalsIgnoreCase(id.namespace());
}
@Override
public boolean isReady() {
return super.isReady() && !failed.get();
}
}

View File

@@ -47,7 +47,6 @@ public class WorldEditLink {
} catch (Throwable e) {
Iris.error("Could not get selection");
e.printStackTrace();
Iris.reportError(e);
active.reset();
active.aquire(() -> false);
}

View File

@@ -1,33 +0,0 @@
package com.volmit.iris.core.link.data;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import java.util.MissingResourceException;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
public enum DataType implements BiPredicate<ExternalDataProvider, Identifier> {
ITEM,
BLOCK,
ENTITY;
@Override
public boolean test(ExternalDataProvider dataProvider, Identifier identifier) {
if (!dataProvider.isValidProvider(identifier, this)) return false;
try {
switch (this) {
case ITEM -> dataProvider.getItemStack(identifier);
case BLOCK -> dataProvider.getBlockData(identifier);
case ENTITY -> {}
}
return true;
} catch (MissingResourceException e) {
return false;
}
}
public Predicate<Identifier> asPredicate(ExternalDataProvider dataProvider) {
return i -> test(dataProvider, i);
}
}

View File

@@ -1,107 +0,0 @@
package com.volmit.iris.core.link.data;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.IrisCustomData;
import dev.lone.itemsadder.api.CustomBlock;
import dev.lone.itemsadder.api.CustomStack;
import dev.lone.itemsadder.api.Events.ItemsAdderLoadDataEvent;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.event.EventHandler;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
import java.util.stream.Collectors;
public class ItemAdderDataProvider extends ExternalDataProvider {
private final KSet<String> itemNamespaces = new KSet<>();
private final KSet<String> blockNamespaces = new KSet<>();
public ItemAdderDataProvider() {
super("ItemsAdder");
}
@Override
public void init() {
updateNamespaces();
}
@EventHandler
public void onLoadData(ItemsAdderLoadDataEvent event) {
updateNamespaces();
}
@NotNull
@Override
public BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
CustomBlock block = CustomBlock.getInstance(blockId.toString());
if (block == null) {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
return IrisCustomData.of(block.getBaseBlockData(), blockId);
}
@NotNull
@Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
CustomStack stack = CustomStack.getInstance(itemId.toString());
if (stack == null) {
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
}
return stack.getItemStack();
}
@Override
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
CustomBlock custom;
if ((custom = CustomBlock.place(blockId.toString(), block.getLocation())) == null)
return;
block.setBlockData(custom.getBaseBlockData(), false);
}
@Override
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
return switch (dataType) {
case ENTITY -> List.of();
case ITEM -> CustomStack.getNamespacedIdsInRegistry()
.stream()
.map(Identifier::fromString)
.toList();
case BLOCK -> CustomBlock.getNamespacedIdsInRegistry()
.stream()
.map(Identifier::fromString)
.toList();
};
}
private void updateNamespaces() {
try {
updateNamespaces(DataType.ITEM);
updateNamespaces(DataType.BLOCK);
} catch (Throwable e) {
Iris.warn("Failed to update ItemAdder namespaces: " + e.getMessage());
}
}
private void updateNamespaces(DataType dataType) {
var namespaces = getTypes(dataType).stream().map(Identifier::namespace).collect(Collectors.toSet());
var currentNamespaces = dataType == DataType.ITEM ? itemNamespaces : blockNamespaces;
currentNamespaces.removeIf(n -> !namespaces.contains(n));
currentNamespaces.addAll(namespaces);
}
@Override
public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
if (dataType == DataType.ENTITY) return false;
return dataType == DataType.ITEM ? itemNamespaces.contains(id.namespace()) : blockNamespaces.contains(id.namespace());
}
}

View File

@@ -1,74 +0,0 @@
package com.volmit.iris.core.link.data;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisCustomData;
import me.kryniowesegryderiusz.kgenerators.Main;
import me.kryniowesegryderiusz.kgenerators.api.KGeneratorsAPI;
import me.kryniowesegryderiusz.kgenerators.generators.locations.objects.GeneratorLocation;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
public class KGeneratorsDataProvider extends ExternalDataProvider {
public KGeneratorsDataProvider() {
super("KGenerators");
}
@Override
public void init() {
}
@Override
public @NotNull BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
if (Main.getGenerators().get(blockId.key()) == null) throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
return IrisCustomData.of(Material.STRUCTURE_VOID.createBlockData(), ExternalDataSVC.buildState(blockId, state));
}
@Override
public @NotNull ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
var gen = Main.getGenerators().get(itemId.key());
if (gen == null) throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
return gen.getGeneratorItem();
}
@Override
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
if (block.getType() != Material.STRUCTURE_VOID) return;
var existing = KGeneratorsAPI.getLoadedGeneratorLocation(block.getLocation());
if (existing != null) return;
block.setBlockData(B.getAir(), false);
var gen = Main.getGenerators().get(blockId.key());
if (gen == null) return;
var loc = new GeneratorLocation(-1, gen, block.getLocation(), Main.getPlacedGenerators().getChunkInfo(block.getChunk()), null, null);
Main.getDatabases().getDb().saveGenerator(loc);
Main.getPlacedGenerators().addLoaded(loc);
Main.getSchedules().schedule(loc, true);
}
@Override
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
if (dataType == DataType.ENTITY) return List.of();
return Main.getGenerators().getAll().stream()
.map(gen -> new Identifier("kgenerators", gen.getId()))
.filter(dataType.asPredicate(this))
.toList();
}
@Override
public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
if (dataType == DataType.ENTITY) return false;
return "kgenerators".equalsIgnoreCase(id.namespace());
}
}

View File

@@ -1,130 +0,0 @@
package com.volmit.iris.core.link.data;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.tools.IrisToolbelt;
import io.lumine.mythic.api.adapters.AbstractLocation;
import io.lumine.mythic.api.config.MythicLineConfig;
import io.lumine.mythic.api.mobs.entities.SpawnReason;
import io.lumine.mythic.api.skills.conditions.ILocationCondition;
import io.lumine.mythic.bukkit.BukkitAdapter;
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.mobs.ActiveMob;
import io.lumine.mythic.core.mobs.MobStack;
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.Location;
import org.bukkit.entity.Entity;
import org.bukkit.event.EventHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
public class MythicMobsDataProvider extends ExternalDataProvider {
public MythicMobsDataProvider() {
super("MythicMobs");
}
@Override
public void init() {
}
@Override
public @Nullable Entity spawnMob(@NotNull Location location, @NotNull Identifier entityId) throws MissingResourceException {
var mm = spawnMob(BukkitAdapter.adapt(location), entityId);
return mm == null ? null : mm.getEntity().getBukkitEntity();
}
private ActiveMob spawnMob(AbstractLocation location, Identifier entityId) throws MissingResourceException {
var manager = MythicBukkit.inst().getMobManager();
var mm = manager.getMythicMob(entityId.key()).orElse(null);
if (mm == null) {
var stack = manager.getMythicMobStack(entityId.key());
if (stack == null) throw new MissingResourceException("Failed to find Mob!", entityId.namespace(), entityId.key());
return stack.spawn(location, 1d, SpawnReason.OTHER, null);
}
return mm.spawn(location, 1d, SpawnReason.OTHER, null, null);
}
@Override
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
if (dataType != DataType.ENTITY) return List.of();
var manager = MythicBukkit.inst().getMobManager();
return Stream.concat(manager.getMobNames().stream(),
manager.getMobStacks()
.stream()
.map(MobStack::getName)
)
.distinct()
.map(name -> new Identifier("mythicmobs", name))
.toList();
}
@Override
public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
return id.namespace().equalsIgnoreCase("mythicmobs") && dataType == DataType.ENTITY;
}
@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<String> biomes = ConcurrentHashMap.newKeySet();
@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 = "irisregion", description = "Tests if the target is within the given list of biomes")
public static class IrisRegionCondition extends SkillCondition implements ILocationCondition {
@MythicField(name = "region", aliases = {"r"}, description = "A list of regions to check")
private Set<String> regions = ConcurrentHashMap.newKeySet();
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());
}
}
}

View File

@@ -24,7 +24,6 @@ import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import com.volmit.iris.Iris;
import com.volmit.iris.core.scripting.environment.PackEnvironment;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.*;
@@ -34,23 +33,19 @@ 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.format.C;
import com.volmit.iris.util.mantle.flag.MantleFlagAdapter;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.reflect.KeyedType;
import com.volmit.iris.util.reflect.OldEnum;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import lombok.Data;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.Objects;
import java.util.function.Function;
@Data
public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
@@ -58,7 +53,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
private final File dataFolder;
private final int id;
private boolean closed = false;
private PackEnvironment environment;
private ResourceLoader<IrisBiome> biomeLoader;
private ResourceLoader<IrisLootTable> lootLoader;
private ResourceLoader<IrisRegion> regionLoader;
@@ -98,10 +92,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
return dataLoaders.computeIfAbsent(dataFolder, IrisData::new);
}
public static Optional<IrisData> getLoaded(File dataFolder) {
return Optional.ofNullable(dataLoaders.get(dataFolder));
}
public static void dereference() {
dataLoaders.v().forEach(IrisData::cleanupEngine);
}
@@ -121,100 +111,92 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
Iris.warn(" " + rl.getResourceTypeName() + " @ /" + rl.getFolderName() + ": Cache=" + rl.getLoadCache().getSize() + " Folders=" + rl.getFolders().size());
}
public static IrisObject loadAnyObject(String key, @Nullable IrisData nearest) {
return loadAny(IrisObject.class, key, nearest);
public static IrisObject loadAnyObject(String key) {
return loadAny(key, (dm) -> dm.getObjectLoader().load(key, false));
}
public static IrisMatterObject loadAnyMatter(String key, @Nullable IrisData nearest) {
return loadAny(IrisMatterObject.class, key, nearest);
public static IrisMatterObject loadAnyMatter(String key) {
return loadAny(key, (dm) -> dm.getMatterLoader().load(key, false));
}
public static IrisBiome loadAnyBiome(String key, @Nullable IrisData nearest) {
return loadAny(IrisBiome.class, key, nearest);
public static IrisBiome loadAnyBiome(String key) {
return loadAny(key, (dm) -> dm.getBiomeLoader().load(key, false));
}
public static IrisExpression loadAnyExpression(String key, @Nullable IrisData nearest) {
return loadAny(IrisExpression.class, key, nearest);
public static IrisExpression loadAnyExpression(String key) {
return loadAny(key, (dm) -> dm.getExpressionLoader().load(key, false));
}
public static IrisMod loadAnyMod(String key, @Nullable IrisData nearest) {
return loadAny(IrisMod.class, key, nearest);
public static IrisMod loadAnyMod(String key) {
return loadAny(key, (dm) -> dm.getModLoader().load(key, false));
}
public static IrisJigsawPiece loadAnyJigsawPiece(String key, @Nullable IrisData nearest) {
return loadAny(IrisJigsawPiece.class, key, nearest);
public static IrisJigsawPiece loadAnyJigsawPiece(String key) {
return loadAny(key, (dm) -> dm.getJigsawPieceLoader().load(key, false));
}
public static IrisJigsawPool loadAnyJigsawPool(String key, @Nullable IrisData nearest) {
return loadAny(IrisJigsawPool.class, key, nearest);
public static IrisJigsawPool loadAnyJigsawPool(String key) {
return loadAny(key, (dm) -> dm.getJigsawPoolLoader().load(key, false));
}
public static IrisEntity loadAnyEntity(String key, @Nullable IrisData nearest) {
return loadAny(IrisEntity.class, key, nearest);
public static IrisEntity loadAnyEntity(String key) {
return loadAny(key, (dm) -> dm.getEntityLoader().load(key, false));
}
public static IrisLootTable loadAnyLootTable(String key, @Nullable IrisData nearest) {
return loadAny(IrisLootTable.class, key, nearest);
public static IrisLootTable loadAnyLootTable(String key) {
return loadAny(key, (dm) -> dm.getLootLoader().load(key, false));
}
public static IrisBlockData loadAnyBlock(String key, @Nullable IrisData nearest) {
return loadAny(IrisBlockData.class, key, nearest);
public static IrisBlockData loadAnyBlock(String key) {
return loadAny(key, (dm) -> dm.getBlockLoader().load(key, false));
}
public static IrisSpawner loadAnySpaner(String key, @Nullable IrisData nearest) {
return loadAny(IrisSpawner.class, key, nearest);
public static IrisSpawner loadAnySpaner(String key) {
return loadAny(key, (dm) -> dm.getSpawnerLoader().load(key, false));
}
public static IrisScript loadAnyScript(String key, @Nullable IrisData nearest) {
return loadAny(IrisScript.class, key, nearest);
public static IrisScript loadAnyScript(String key) {
return loadAny(key, (dm) -> dm.getScriptLoader().load(key, false));
}
public static IrisRavine loadAnyRavine(String key, @Nullable IrisData nearest) {
return loadAny(IrisRavine.class, key, nearest);
public static IrisRavine loadAnyRavine(String key) {
return loadAny(key, (dm) -> dm.getRavineLoader().load(key, false));
}
public static IrisRegion loadAnyRegion(String key, @Nullable IrisData nearest) {
return loadAny(IrisRegion.class, key, nearest);
public static IrisRegion loadAnyRegion(String key) {
return loadAny(key, (dm) -> dm.getRegionLoader().load(key, false));
}
public static IrisMarker loadAnyMarker(String key, @Nullable IrisData nearest) {
return loadAny(IrisMarker.class, key, nearest);
public static IrisMarker loadAnyMarker(String key) {
return loadAny(key, (dm) -> dm.getMarkerLoader().load(key, false));
}
public static IrisCave loadAnyCave(String key, @Nullable IrisData nearest) {
return loadAny(IrisCave.class, key, nearest);
public static IrisCave loadAnyCave(String key) {
return loadAny(key, (dm) -> dm.getCaveLoader().load(key, false));
}
public static IrisImage loadAnyImage(String key, @Nullable IrisData nearest) {
return loadAny(IrisImage.class, key, nearest);
public static IrisImage loadAnyImage(String key) {
return loadAny(key, (dm) -> dm.getImageLoader().load(key, false));
}
public static IrisDimension loadAnyDimension(String key, @Nullable IrisData nearest) {
return loadAny(IrisDimension.class, key, nearest);
public static IrisDimension loadAnyDimension(String key) {
return loadAny(key, (dm) -> dm.getDimensionLoader().load(key, false));
}
public static IrisJigsawStructure loadAnyJigsawStructure(String key, @Nullable IrisData nearest) {
return loadAny(IrisJigsawStructure.class, key, nearest);
public static IrisJigsawStructure loadAnyJigsawStructure(String key) {
return loadAny(key, (dm) -> dm.getJigsawStructureLoader().load(key, false));
}
public static IrisGenerator loadAnyGenerator(String key, @Nullable IrisData nearest) {
return loadAny(IrisGenerator.class, key, nearest);
public static IrisGenerator loadAnyGenerator(String key) {
return loadAny(key, (dm) -> dm.getGeneratorLoader().load(key, false));
}
public static <T extends IrisRegistrant> T loadAny(Class<T> type, String key, @Nullable IrisData nearest) {
public static <T extends IrisRegistrant> T loadAny(String key, Function<IrisData, T> v) {
try {
if (nearest != null) {
T t = nearest.load(type, key, false);
if (t != null) {
return t;
}
}
for (File i : Objects.requireNonNull(Iris.instance.getDataFolder("packs").listFiles())) {
if (i.isDirectory()) {
IrisData dm = get(i);
if (dm == nearest) continue;
T t = dm.load(type, key, false);
T t = v.apply(dm);
if (t != null) {
return t;
@@ -229,17 +211,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
return null;
}
public <T extends IrisRegistrant> T load(Class<T> type, String key, boolean warn) {
var loader = getLoader(type);
if (loader == null) return null;
return loader.load(key, warn);
}
@SuppressWarnings("unchecked")
public <T extends IrisRegistrant> ResourceLoader<T> getLoader(Class<T> type) {
return (ResourceLoader<T>) loaders.get(type);
}
public ResourceLoader<?> getTypedLoaderFor(File f) {
String[] k = f.getPath().split("\\Q" + File.separator + "\\E");
@@ -279,20 +250,12 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
}
}
if (engine == null) return;
var global = engine.getDimension().getPreProcessors(t.getFolderName());
var local = t.getPreprocessors();
if ((global != null && global.isNotEmpty()) || local.isNotEmpty()) {
if (engine != null && t.getPreprocessors().isNotEmpty()) {
synchronized (this) {
if (global != null) {
for (String i : global) {
engine.getExecution().preprocessObject(i, t);
Iris.debug("Loader<" + C.GREEN + t.getTypeName() + C.LIGHT_PURPLE + "> iprocess " + C.YELLOW + t.getLoadKey() + C.LIGHT_PURPLE + " in <rainbow>" + i);
}
}
engine.getExecution().getAPI().setPreprocessorObject(t);
for (String i : local) {
engine.getExecution().preprocessObject(i, t);
for (String i : t.getPreprocessors()) {
engine.getExecution().execute(i);
Iris.debug("Loader<" + C.GREEN + t.getTypeName() + C.LIGHT_PURPLE + "> iprocess " + C.YELLOW + t.getLoadKey() + C.LIGHT_PURPLE + " in <rainbow>" + i);
}
}
@@ -306,7 +269,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
public void close() {
closed = true;
dump();
dataLoaders.remove(dataFolder);
}
public IrisData copy() {
@@ -338,7 +300,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
return r;
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
Iris.error("Failed to create loader! " + registrant.getCanonicalName());
}
@@ -347,14 +308,12 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
}
public synchronized void hotloaded() {
closed = false;
possibleSnippets = new KMap<>();
builder = new GsonBuilder()
.addDeserializationExclusionStrategy(this)
.addSerializationExclusionStrategy(this)
.setLenient()
.registerTypeAdapterFactory(this)
.registerTypeAdapter(MantleFlag.class, new MantleFlagAdapter())
.setPrettyPrinting();
loaders.clear();
File packs = dataFolder;
@@ -379,18 +338,16 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
this.imageLoader = registerLoader(IrisImage.class);
this.scriptLoader = registerLoader(IrisScript.class);
this.matterObjectLoader = registerLoader(IrisMatterObject.class);
this.environment = PackEnvironment.create(this);
builder.registerTypeAdapterFactory(KeyedType::createTypeAdapter);
if (OldEnum.exists()) {
builder.registerTypeAdapterFactory(new TypeAdapterFactory() {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
return (TypeAdapter<T>) OldEnum.create(type.getRawType());
}
});
}
gson = builder.create();
dimensionLoader.streamAll()
.map(IrisDimension::getDataScripts)
.flatMap(KList::stream)
.forEach(environment::execute);
if (engine != null) {
engine.hotload();
}
}
public void dump() {
@@ -403,34 +360,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
for (ResourceLoader<?> i : loaders.values()) {
i.clearList();
}
possibleSnippets.clear();
}
public Set<Class<?>> resolveSnippets() {
var result = new HashSet<Class<?>>();
var processed = new HashSet<Class<?>>();
var excluder = gson.excluder();
var queue = new LinkedList<Class<?>>(loaders.keySet());
while (!queue.isEmpty()) {
var type = queue.poll();
if (excluder.excludeClass(type, false) || !processed.add(type))
continue;
if (type.isAnnotationPresent(Snippet.class))
result.add(type);
try {
for (var field : type.getDeclaredFields()) {
if (excluder.excludeField(field, false))
continue;
queue.add(field.getType());
}
} catch (Throwable ignored) {
}
}
return result;
}
public String toLoadKey(File f) {
@@ -479,7 +408,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
}
String snippetType = typeToken.getRawType().getDeclaredAnnotation(Snippet.class).value();
String snippedBase = "snippet/" + snippetType + "/";
return new TypeAdapter<>() {
@Override
@@ -493,20 +421,20 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
if (reader.peek().equals(JsonToken.STRING)) {
String r = reader.nextString();
if (!r.startsWith("snippet/"))
return null;
if (!r.startsWith(snippedBase))
r = snippedBase + r.substring(8);
File f = new File(getDataFolder(), r + ".json");
if (f.exists()) {
try (JsonReader snippetReader = new JsonReader(new FileReader(f))){
return adapter.read(snippetReader);
} catch (Throwable e) {
Iris.error("Couldn't read snippet " + r + " in " + reader.getPath() + " (" + e.getMessage() + ")");
if (r.startsWith("snippet/" + snippetType + "/")) {
File f = new File(getDataFolder(), r + ".json");
if (f.exists()) {
try {
JsonReader snippetReader = new JsonReader(new FileReader(f));
return adapter.read(snippetReader);
} catch (Throwable e) {
Iris.error("Couldn't read snippet " + r + " in " + reader.getPath() + " (" + e.getMessage() + ")");
}
} else {
Iris.error("Couldn't find snippet " + r + " in " + reader.getPath());
}
} else {
Iris.error("Couldn't find snippet " + r + " in " + reader.getPath());
}
return null;
@@ -533,20 +461,11 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
KList<String> l = new KList<>();
File snippetFolder = new File(getDataFolder(), "snippet/" + f);
if (!snippetFolder.exists()) return l;
String absPath = snippetFolder.getAbsolutePath();
try (var stream = Files.walk(snippetFolder.toPath())) {
stream.filter(Files::isRegularFile)
.map(Path::toAbsolutePath)
.map(Path::toString)
.filter(s -> s.endsWith(".json"))
.map(s -> s.substring(absPath.length() + 1))
.map(s -> s.replace("\\", "/"))
.map(s -> s.split("\\Q.\\E")[0])
.forEach(s -> l.add("snippet/" + s));
} catch (Throwable e) {
e.printStackTrace();
if (snippetFolder.exists() && snippetFolder.isDirectory()) {
for (File i : snippetFolder.listFiles()) {
l.add("snippet/" + f + "/" + i.getName().split("\\Q.\\E")[0]);
}
}
return l;
@@ -558,7 +477,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
}
public void savePrefetch(Engine engine) {
BurstExecutor b = MultiBurst.ioBurst.burst(loaders.size());
BurstExecutor b = MultiBurst.burst.burst(loaders.size());
for (ResourceLoader<?> i : loaders.values()) {
b.queue(() -> {
@@ -575,7 +494,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
}
public void loadPrefetch(Engine engine) {
BurstExecutor b = MultiBurst.ioBurst.burst(loaders.size());
BurstExecutor b = MultiBurst.burst.burst(loaders.size());
for (ResourceLoader<?> i : loaders.values()) {
b.queue(() -> {

View File

@@ -28,19 +28,17 @@ import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.plugin.VolmitSender;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.awt.*;
import java.io.File;
@Data
public abstract class IrisRegistrant {
@Desc("Preprocess this object in-memory when it's loaded, run scripts using the variable 'object' and modify properties about this object before it's used.\nFile extension: .proc.kts")
@Desc("Preprocess this object in-memory when it's loaded, run scripts using the variable 'Iris.getPreprocessorObject()' and modify properties about this object before it's used.")
@RegistryListResource(IrisScript.class)
@ArrayType(min = 1, type = String.class)
private KList<String> preprocessors = new KList<>();
@EqualsAndHashCode.Exclude
private transient IrisData loader;
private transient String loadKey;

View File

@@ -23,7 +23,6 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.project.SchemaBuilder;
import com.volmit.iris.core.service.PreservationSVC;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.MeteredCache;
import com.volmit.iris.util.collection.KList;
@@ -45,10 +44,9 @@ import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -61,7 +59,7 @@ import java.util.zip.GZIPOutputStream;
public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
public static final AtomicDouble tlt = new AtomicDouble(0);
private static final int CACHE_SIZE = 100000;
protected final AtomicCache<KList<File>> folderCache;
protected final AtomicReference<KList<File>> folderCache;
protected KSet<String> firstAccess;
protected File root;
protected String folderName;
@@ -77,7 +75,7 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
public ResourceLoader(File root, IrisData manager, String folderName, String resourceTypeName, Class<? extends T> objectClass) {
this.manager = manager;
firstAccess = new KSet<>();
folderCache = new AtomicCache<>();
folderCache = new AtomicReference<>();
sec = new ChronoLatch(5000);
loads = new AtomicInteger();
this.objectClass = objectClass;
@@ -171,6 +169,7 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
return possibleKeys;
}
KSet<String> m = new KSet<>();
KList<File> files = getFolders();
if (files == null) {
@@ -178,7 +177,6 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
return possibleKeys;
}
HashSet<String> m = new HashSet<>();
for (File i : files) {
for (File j : matchAllFiles(i, (f) -> f.getName().endsWith(".json"))) {
m.add(i.toURI().relativize(j.toURI()).getPath().replaceAll("\\Q.json\\E", ""));
@@ -217,10 +215,6 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
return j;
}
public Stream<T> streamAll() {
return streamAll(Arrays.stream(getPossibleKeys()));
}
public Stream<T> streamAll(Stream<String> s) {
return s.map(this::load);
}
@@ -241,15 +235,13 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
public KList<T> loadAllParallel(KList<String> s) {
KList<T> m = new KList<>();
BurstExecutor burst = MultiBurst.ioBurst.burst(s.size());
BurstExecutor burst = MultiBurst.burst.burst(s.size());
for (String i : s) {
burst.queue(() -> {
T t = load(i);
if (t == null)
return;
synchronized (m) {
if (t != null) {
m.add(t);
}
});
@@ -320,8 +312,7 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
return null;
}
var set = firstAccess;
if (set != null) firstAccess.add(name);
firstAccess.add(name);
return loadCache.get(name);
}
@@ -344,24 +335,21 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
}
din.close();
file.deleteOnExit();
Iris.info("Loading " + s.size() + " prefetch " + getFolderName());
firstAccess = null;
loadAllParallel(s);
}
public void saveFirstAccess(Engine engine) throws IOException {
if (firstAccess == null) return;
String id = "DIM" + Math.abs(engine.getSeedManager().getSeed() + engine.getDimension().getVersion() + engine.getDimension().getLoadKey().hashCode());
File file = Iris.instance.getDataFile("prefetch/" + id + "/" + Math.abs(getFolderName().hashCode()) + ".ipfch");
file.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(file);
GZIPOutputStream gzo = new CustomOutputStream(fos, 9);
DataOutputStream dos = new DataOutputStream(gzo);
var set = firstAccess;
firstAccess = null;
dos.writeInt(set.size());
dos.writeInt(firstAccess.size());
for (String i : set) {
for (String i : firstAccess) {
dos.writeUTF(i);
}
@@ -370,24 +358,29 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
}
public KList<File> getFolders() {
return folderCache.aquire(() -> {
KList<File> fc = new KList<>();
synchronized (folderCache) {
if (folderCache.get() == null) {
KList<File> fc = new KList<>();
File[] files = root.listFiles();
if (files == null) {
throw new IllegalStateException("Failed to list files in " + root);
}
File[] files = root.listFiles();
if (files == null) {
throw new IllegalStateException("Failed to list files in " + root);
}
for (File i : files) {
if (i.isDirectory()) {
if (i.getName().equals(folderName)) {
fc.add(i);
break;
for (File i : files) {
if (i.isDirectory()) {
if (i.getName().equals(folderName)) {
fc.add(i);
break;
}
}
}
folderCache.set(fc);
}
return fc;
});
}
return folderCache.get();
}
public KList<File> getFolders(String rc) {
@@ -407,7 +400,7 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
public void clearCache() {
possibleKeys = null;
loadCache.invalidate();
folderCache.reset();
folderCache.set(null);
}
public File fileFor(T b) {
@@ -433,7 +426,7 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
}
public void clearList() {
folderCache.reset();
folderCache.set(null);
possibleKeys = null;
}

View File

@@ -82,8 +82,8 @@ public class ScriptResourceLoader extends ResourceLoader<IrisScript> {
private Set<String> getKeysInDirectory(File directory) {
Set<String> keys = new HashSet<>();
for (File file : directory.listFiles()) {
if (file.isFile() && file.getName().endsWith(".kts")) {
keys.add(file.getName().replaceAll("\\Q.kts\\E", ""));
if (file.isFile() && file.getName().endsWith(".js")) {
keys.add(file.getName().replaceAll("\\Q.js\\E", ""));
} else if (file.isDirectory()) {
keys.addAll(getKeysInDirectory(file));
}
@@ -127,12 +127,12 @@ public class ScriptResourceLoader extends ResourceLoader<IrisScript> {
public File findFile(String name) {
for (File i : getFolders(name)) {
for (File j : i.listFiles()) {
if (j.isFile() && j.getName().endsWith(".kts") && j.getName().split("\\Q.\\E")[0].equals(name)) {
if (j.isFile() && j.getName().endsWith(".js") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return j;
}
}
File file = new File(i, name + ".kts");
File file = new File(i, name + ".js");
if (file.exists()) {
return file;
@@ -147,12 +147,12 @@ public class ScriptResourceLoader extends ResourceLoader<IrisScript> {
private IrisScript loadRaw(String name) {
for (File i : getFolders(name)) {
for (File j : i.listFiles()) {
if (j.isFile() && j.getName().endsWith(".kts") && j.getName().split("\\Q.\\E")[0].equals(name)) {
if (j.isFile() && j.getName().endsWith(".js") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return loadFile(j, name);
}
}
File file = new File(i, name + ".kts");
File file = new File(i, name + ".js");
if (file.exists()) {
return loadFile(file, name);

View File

@@ -24,24 +24,19 @@ import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import org.bukkit.Bukkit;
import java.util.List;
import java.util.Map;
public class INMS {
private static final Version CURRENT = Boolean.getBoolean("iris.no-version-limit") ?
new Version(Integer.MAX_VALUE, Integer.MAX_VALUE, null) :
new Version(21, 10, null);
private static final List<Version> REVISION = List.of(
new Version(21, 9, "v1_21_R6"),
new Version(21, 6, "v1_21_R5"),
new Version(21, 5, "v1_21_R4"),
new Version(21, 4, "v1_21_R3"),
new Version(21, 2, "v1_21_R2"),
new Version(21, 0, "v1_21_R1"),
new Version(20, 5, "v1_20_R4")
private static final Map<String, String> REVISION = Map.of(
"1.20.5", "v1_20_R4",
"1.20.6", "v1_20_R4",
"1.21", "v1_21_R1",
"1.21.1", "v1_21_R1",
"1.21.2", "v1_21_R2",
"1.21.3", "v1_21_R2",
"1.21.4", "v1_21_R3"
);
private static final List<Version> PACKS = List.of(
new Version(21, 5, "31100"),
new Version(21, 4, "31020"),
new Version(21, 2, "31000"),
new Version(20, 1, "3910")
@@ -49,7 +44,7 @@ public class INMS {
//@done
private static final INMSBinding binding = bind();
public static final String OVERWORLD_TAG = getTag(PACKS, "3910");
public static final String OVERWORLD_TAG = getOverworldTag();
public static INMSBinding get() {
return binding;
@@ -63,7 +58,7 @@ public class INMS {
try {
String name = Bukkit.getServer().getClass().getCanonicalName();
if (name.equals("org.bukkit.craftbukkit.CraftServer")) {
return getTag(REVISION, "BUKKIT");
return REVISION.getOrDefault(Bukkit.getServer().getBukkitVersion().split("-")[0], "BUKKIT");
} else {
return name.split("\\Q.\\E")[3];
}
@@ -101,7 +96,7 @@ public class INMS {
return new NMSBinding1X();
}
private static String getTag(List<Version> versions, String def) {
private static String getOverworldTag() {
var version = Bukkit.getServer().getBukkitVersion().split("-")[0].split("\\.", 3);
int major = 0;
int minor = 0;
@@ -112,16 +107,13 @@ public class INMS {
} else if (version.length == 2) {
major = Integer.parseInt(version[1]);
}
if (CURRENT.major < major || CURRENT.minor < minor) {
return versions.getFirst().tag;
}
for (var p : versions) {
for (var p : PACKS) {
if (p.major > major || p.minor > minor)
continue;
return p.tag;
}
return def;
return "3910";
}
private record Version(int major, int minor, String tag) {}

View File

@@ -18,15 +18,12 @@
package com.volmit.iris.core.nms;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.container.AutoClosing;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.nms.container.StructurePlacement;
import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.core.nms.headless.IRegionStorage;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.mantle.Mantle;
@@ -43,7 +40,6 @@ import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack;
import java.awt.Color;
import java.util.List;
public interface INMSBinding {
boolean hasTile(Material material);
@@ -95,10 +91,12 @@ public interface INMSBinding {
MCABiomeContainer newBiomeContainer(int min, int max);
default World createWorld(WorldCreator c) {
if (c.generator() instanceof PlatformChunkGenerator gen
&& missingDimensionTypes(gen.getTarget().getDimension().getDimensionTypeKey()))
throw new IllegalStateException("Missing dimension types to create world");
return c.createWorld();
if (missingDimensionTypes(true, true, true))
throw new IllegalStateException("Missing dimenstion types to create world");
try (var ignored = injectLevelStems()) {
return c.createWorld();
}
}
int countCustomBiomes();
@@ -131,17 +129,13 @@ public interface INMSBinding {
return 441;
}
IRegionStorage createRegionStorage(Engine engine);
KList<String> getStructureKeys();
boolean missingDimensionTypes(String... keys);
AutoClosing injectLevelStems();
default boolean injectBukkit() {
return true;
}
Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end);
KMap<Material, List<BlockProperty>> getBlockProperties();
void placeStructures(Chunk chunk);
KMap<Identifier, StructurePlacement> collectStructures();
boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end);
}

View File

@@ -1,6 +1,5 @@
package com.volmit.iris.core.nms.container;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.function.NastyRunnable;
import lombok.AllArgsConstructor;
@@ -8,7 +7,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
@AllArgsConstructor
public class AutoClosing implements AutoCloseable {
private static final KMap<Thread, AutoClosing> CONTEXTS = new KMap<>();
private final AtomicBoolean closed = new AtomicBoolean();
private final NastyRunnable action;
@@ -16,24 +14,9 @@ public class AutoClosing implements AutoCloseable {
public void close() {
if (closed.getAndSet(true)) return;
try {
removeContext();
action.run();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
public void storeContext() {
CONTEXTS.put(Thread.currentThread(), this);
}
public void removeContext() {
CONTEXTS.values().removeIf(c -> c == this);
}
public static void closeContext() {
AutoClosing closing = CONTEXTS.remove(Thread.currentThread());
if (closing == null) return;
closing.close();
}
}

View File

@@ -1,154 +0,0 @@
package com.volmit.iris.core.nms.container;
import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.function.Function;
public class BlockProperty {
private static final Set<Class<?>> NATIVES = Set.of(Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Boolean.class, String.class);
private final String name;
private final Class<?> type;
private final Object defaultValue;
private final Set<Object> values;
private final Function<Object, String> nameFunction;
private final Function<Object, Object> jsonFunction;
public <T extends Comparable<T>> BlockProperty(
String name,
Class<T> type,
T defaultValue,
Collection<T> values,
Function<T, String> nameFunction
) {
this.name = name;
this.type = type;
this.defaultValue = defaultValue;
this.values = Collections.unmodifiableSet(new TreeSet<>(values));
this.nameFunction = (Function<Object, String>) (Object) nameFunction;
jsonFunction = NATIVES.contains(type) ? Function.identity() : this.nameFunction::apply;
}
public static <T extends Enum<T>> BlockProperty ofEnum(Class<T> type, String name, T defaultValue) {
return new BlockProperty(
name,
type,
defaultValue,
Arrays.asList(type.getEnumConstants()),
val -> val == null ? "null" : val.name()
);
}
public static BlockProperty ofFloat(String name, float defaultValue, float min, float max, boolean exclusiveMin, boolean exclusiveMax) {
return new BoundedDouble(
name,
defaultValue,
min,
max,
exclusiveMin,
exclusiveMax,
(f) -> String.format("%.2f", f)
);
}
public static BlockProperty ofBoolean(String name, boolean defaultValue) {
return new BlockProperty(
name,
Boolean.class,
defaultValue,
List.of(true, false),
(b) -> b ? "true" : "false"
);
}
@Override
public @NotNull String toString() {
return name + "=" + nameFunction.apply(defaultValue) + " [" + String.join(",", names()) + "]";
}
public String name() {
return name;
}
public String defaultValue() {
return nameFunction.apply(defaultValue);
}
public List<String> names() {
return values.stream().map(nameFunction).toList();
}
public Object defaultValueAsJson() {
return jsonFunction.apply(defaultValue);
}
public JSONArray valuesAsJson() {
return new JSONArray(values.stream().map(jsonFunction).toList());
}
public JSONObject buildJson() {
var json = new JSONObject();
json.put("type", jsonType());
json.put("default", defaultValueAsJson());
if (!values.isEmpty()) json.put("enum", valuesAsJson());
return json;
}
public String jsonType() {
if (type == Boolean.class)
return "boolean";
if (type == Byte.class || type == Short.class || type == Integer.class || type == Long.class)
return "integer";
if (type == Float.class || type == Double.class)
return "number";
return "string";
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (BlockProperty) obj;
return Objects.equals(this.name, that.name) &&
Objects.equals(this.values, that.values) &&
Objects.equals(this.type, that.type);
}
@Override
public int hashCode() {
return Objects.hash(name, values, type);
}
private static class BoundedDouble extends BlockProperty {
private final double min, max;
private final boolean exclusiveMin, exclusiveMax;
public BoundedDouble(
String name,
double defaultValue,
double min,
double max,
boolean exclusiveMin,
boolean exclusiveMax,
Function<Double, String> nameFunction
) {
super(name, Double.class, defaultValue, List.of(), nameFunction);
this.min = min;
this.max = max;
this.exclusiveMin = exclusiveMin;
this.exclusiveMax = exclusiveMax;
}
@Override
public JSONObject buildJson() {
return super.buildJson()
.put("minimum", min)
.put("maximum", max)
.put("exclusiveMinimum", exclusiveMin)
.put("exclusiveMaximum", exclusiveMax);
}
}
}

View File

@@ -1,77 +0,0 @@
package com.volmit.iris.core.nms.container;
import com.google.gson.JsonObject;
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement.SpreadType;
import lombok.*;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import org.apache.commons.math3.fraction.Fraction;
import java.util.List;
@Data
@SuperBuilder
@Accessors(fluent = true, chain = true)
public abstract class StructurePlacement {
private final int salt;
private final float frequency;
private final List<Structure> structures;
public abstract JsonObject toJson(String structure);
protected JsonObject createBase(String structure) {
JsonObject object = new JsonObject();
object.addProperty("structure", structure);
object.addProperty("salt", salt);
return object;
}
public int frequencyToSpacing() {
var frac = new Fraction(Math.max(Math.min(frequency, 1), 0.000000001f));
return (int) Math.round(Math.sqrt((double) frac.getDenominator() / frac.getNumerator()));
}
@Getter
@Accessors(chain = true, fluent = true)
@EqualsAndHashCode(callSuper = true)
@SuperBuilder
public static class RandomSpread extends StructurePlacement {
private final int spacing;
private final int separation;
private final SpreadType spreadType;
@Override
public JsonObject toJson(String structure) {
JsonObject object = createBase(structure);
object.addProperty("spacing", Math.max(spacing, frequencyToSpacing()));
object.addProperty("separation", separation);
object.addProperty("spreadType", spreadType.name());
return object;
}
}
@Getter
@EqualsAndHashCode(callSuper = true)
@SuperBuilder
public static class ConcentricRings extends StructurePlacement {
private final int distance;
private final int spread;
private final int count;
@Override
public JsonObject toJson(String structure) {
return null;
}
}
public record Structure(
int weight,
String key,
List<String> tags
) {
public boolean isValid() {
return weight > 0 && key != null;
}
}
}

View File

@@ -13,7 +13,6 @@ import java.util.function.Supplier;
//https://minecraft.wiki/w/Pack_format
@Getter
public enum DataVersion {
UNSUPPORTED("0.0.0", 0, () -> null),
V1192("1.19.2", 10, DataFixerV1192::new),
V1205("1.20.6", 41, DataFixerV1206::new),
V1213("1.21.3", 57, DataFixerV1213::new);

View File

@@ -1,31 +1,28 @@
package com.volmit.iris.core.nms.datapack;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimensionTypeOptions;
import com.volmit.iris.engine.object.IrisRange;
import com.volmit.iris.util.json.JSONObject;
import org.jetbrains.annotations.Nullable;
public interface IDataFixer {
default JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
return json;
}
JSONObject resolve(Dimension dimension, @Nullable IrisDimensionTypeOptions options);
JSONObject rawDimension(Dimension dimension);
void fixDimension(Dimension dimension, JSONObject json);
default JSONObject createDimension(Dimension base, int minY, int height, int logicalHeight, @Nullable IrisDimensionTypeOptions options) {
JSONObject obj = resolve(base, options);
obj.put("min_y", minY);
obj.put("height", height);
default JSONObject createDimension(Dimension dimension, IrisRange height, int logicalHeight) {
JSONObject obj = rawDimension(dimension);
obj.put("min_y", height.getMin());
obj.put("height", height.getMax() - height.getMin());
obj.put("logical_height", logicalHeight);
fixDimension(base, obj);
return obj;
}
enum Dimension {
OVERWORLD,
OVERRWORLD,
NETHER,
END
THE_END
}
}

View File

@@ -1,104 +1,81 @@
package com.volmit.iris.core.nms.datapack.v1192;
import com.volmit.iris.core.nms.datapack.IDataFixer;
import com.volmit.iris.engine.object.IrisDimensionTypeOptions;
import com.volmit.iris.util.json.JSONObject;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import static com.volmit.iris.engine.object.IrisDimensionTypeOptions.TriState.*;
public class DataFixerV1192 implements IDataFixer {
private static final Map<Dimension, IrisDimensionTypeOptions> OPTIONS = Map.of(
Dimension.OVERWORLD, new IrisDimensionTypeOptions(
FALSE,
TRUE,
FALSE,
FALSE,
TRUE,
TRUE,
TRUE,
FALSE,
1d,
0f,
null,
192,
0),
Dimension.NETHER, new IrisDimensionTypeOptions(
TRUE,
FALSE,
TRUE,
TRUE,
FALSE,
FALSE,
FALSE,
TRUE,
8d,
0.1f,
18000L,
null,
15),
Dimension.END, new IrisDimensionTypeOptions(
FALSE,
FALSE,
FALSE,
FALSE,
FALSE,
TRUE,
FALSE,
FALSE,
1d,
0f,
6000L,
null,
0)
);
private static final Map<Dimension, String> DIMENSIONS = Map.of(
Dimension.OVERWORLD, """
Dimension.OVERRWORLD, """
{
"ambient_light": 0.0,
"bed_works": true,
"coordinate_scale": 1.0,
"effects": "minecraft:overworld",
"has_ceiling": false,
"has_raids": true,
"has_skylight": true,
"infiniburn": "#minecraft:infiniburn_overworld",
"monster_spawn_block_light_limit": 0,
"monster_spawn_light_level": {
"type": "minecraft:uniform",
"value": {
"max_inclusive": 7,
"min_inclusive": 0
}
}
},
"natural": true,
"piglin_safe": false,
"respawn_anchor_works": false,
"ultrawarm": false
}""",
Dimension.NETHER, """
{
"ambient_light": 0.1,
"bed_works": false,
"coordinate_scale": 8.0,
"effects": "minecraft:the_nether",
"fixed_time": 18000,
"has_ceiling": true,
"has_raids": false,
"has_skylight": false,
"infiniburn": "#minecraft:infiniburn_nether",
"monster_spawn_block_light_limit": 15,
"monster_spawn_light_level": 7,
"natural": false,
"piglin_safe": true,
"respawn_anchor_works": true,
"ultrawarm": true
}""",
Dimension.END, """
Dimension.THE_END, """
{
"ambient_light": 0.0,
"bed_works": false,
"coordinate_scale": 1.0,
"effects": "minecraft:the_end",
"fixed_time": 6000,
"has_ceiling": false,
"has_raids": true,
"has_skylight": false,
"infiniburn": "#minecraft:infiniburn_end",
"monster_spawn_block_light_limit": 0,
"monster_spawn_light_level": {
"type": "minecraft:uniform",
"value": {
"max_inclusive": 7,
"min_inclusive": 0
}
}
},
"natural": false,
"piglin_safe": false,
"respawn_anchor_works": false,
"ultrawarm": false
}"""
);
@Override
public JSONObject resolve(Dimension dimension, @Nullable IrisDimensionTypeOptions options) {
return options == null ? OPTIONS.get(dimension).toJson() : options.resolve(OPTIONS.get(dimension)).toJson();
}
@Override
public void fixDimension(Dimension dimension, JSONObject json) {
var missing = new JSONObject(DIMENSIONS.get(dimension));
for (String key : missing.keySet()) {
if (json.has(key)) continue;
json.put(key, missing.get(key));
}
public JSONObject rawDimension(Dimension dimension) {
return new JSONObject(DIMENSIONS.get(dimension));
}
}

View File

@@ -45,12 +45,13 @@ public class DataFixerV1206 extends DataFixerV1192 {
}
@Override
public void fixDimension(Dimension dimension, JSONObject json) {
super.fixDimension(dimension, json);
public JSONObject rawDimension(Dimension dimension) {
JSONObject json = super.rawDimension(dimension);
if (!(json.get("monster_spawn_light_level") instanceof JSONObject lightLevel))
return;
return json;
var value = (JSONObject) lightLevel.remove("value");
lightLevel.put("max_inclusive", value.get("max_inclusive"));
lightLevel.put("min_inclusive", value.get("min_inclusive"));
return json;
}
}

View File

@@ -0,0 +1,17 @@
package com.volmit.iris.core.nms.headless;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import lombok.NonNull;
import java.io.IOException;
public interface IRegion extends AutoCloseable {
@ChunkCoordinates
boolean exists(int x, int z);
void write(@NonNull SerializableChunk chunk) throws IOException;
@Override
void close();
}

View File

@@ -0,0 +1,27 @@
package com.volmit.iris.core.nms.headless;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.documentation.RegionCoordinates;
import lombok.NonNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
public interface IRegionStorage {
@ChunkCoordinates
boolean exists(int x, int z);
@Nullable
@RegionCoordinates
IRegion getRegion(int x, int z, boolean existingOnly) throws IOException;
@NonNull
@ChunkCoordinates
SerializableChunk createChunk(int x, int z);
void fillBiomes(@NonNull SerializableChunk chunk, @Nullable ChunkContext ctx);
void close();
}

View File

@@ -0,0 +1,12 @@
package com.volmit.iris.core.nms.headless;
import com.volmit.iris.engine.data.chunk.TerrainChunk;
import com.volmit.iris.util.math.Position2;
public interface SerializableChunk extends TerrainChunk {
Position2 getPos();
Object serialize();
void mark();
}

View File

@@ -19,13 +19,11 @@
package com.volmit.iris.core.nms.v1X;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.INMSBinding;
import com.volmit.iris.core.nms.container.AutoClosing;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.core.nms.headless.IRegionStorage;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.nms.container.StructurePlacement;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
@@ -44,7 +42,6 @@ import org.bukkit.generator.structure.Structure;
import org.bukkit.inventory.ItemStack;
import java.awt.Color;
import java.util.List;
import java.util.stream.StreamSupport;
public class NMSBinding1X implements INMSBinding {
@@ -115,6 +112,11 @@ public class NMSBinding1X implements INMSBinding {
return Color.GREEN;
}
@Override
public IRegionStorage createRegionStorage(Engine engine) {
return null;
}
@Override
public KList<String> getStructureKeys() {
var list = StreamSupport.stream(Registry.STRUCTURE.spliterator(), false)
@@ -125,29 +127,20 @@ public class NMSBinding1X implements INMSBinding {
}
@Override
public boolean missingDimensionTypes(String... keys) {
public AutoClosing injectLevelStems() {
return new AutoClosing(() -> {});
}
@Override
public Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
return new Pair<>(0, new AutoClosing(() -> {}));
}
@Override
public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) {
return false;
}
@Override
public KMap<Material, List<BlockProperty>> getBlockProperties() {
KMap<Material, List<BlockProperty>> map = new KMap<>();
for (Material m : Material.values()) {
if (m.isBlock()) map.put(m, List.of());
}
return map;
}
@Override
public void placeStructures(Chunk chunk) {
}
@Override
public KMap<Identifier, StructurePlacement> collectStructures() {
return new KMap<>();
}
@Override
public CompoundTag serializeEntity(Entity location) {
return null;
@@ -232,11 +225,6 @@ public class NMSBinding1X implements INMSBinding {
return true;
}
@Override
public DataVersion getDataVersion() {
return DataVersion.UNSUPPORTED;
}
@Override
public int getBiomeId(Biome biome) {
return biome.ordinal();

View File

@@ -2,15 +2,16 @@ package com.volmit.iris.core.pregenerator;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.service.PreservationSVC;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.plugin.chunk.TicketHolder;
import com.volmit.iris.util.profile.LoadBalancer;
import com.volmit.iris.util.scheduling.J;
import io.papermc.lib.PaperLib;
@@ -20,16 +21,16 @@ import org.bukkit.World;
import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
public class ChunkUpdater {
private static final String REGION_PATH = "region" + File.separator + "r.";
private final AtomicBoolean paused = new AtomicBoolean();
private final AtomicBoolean cancelled = new AtomicBoolean();
private final TicketHolder holder;
private final KMap<Long, Pair<Long, AtomicInteger>> lastUse = new KMap<>();
private final RollingSequence chunksPerSecond = new RollingSequence(5);
private final AtomicInteger totalMaxChunks = new AtomicInteger();
private final AtomicInteger chunksProcessed = new AtomicInteger();
@@ -37,14 +38,14 @@ public class ChunkUpdater {
private final AtomicInteger chunksUpdated = new AtomicInteger();
private final AtomicBoolean serverEmpty = new AtomicBoolean(true);
private final AtomicLong lastCpsTime = new AtomicLong(M.ms());
private final int maxConcurrency = IrisSettings.get().getUpdater().getMaxConcurrency();
private final int coreLimit = (int) Math.max(Runtime.getRuntime().availableProcessors() * IrisSettings.get().getUpdater().getThreadMultiplier(), 1);
private final Semaphore semaphore = new Semaphore(maxConcurrency);
private final LoadBalancer loadBalancer = new LoadBalancer(semaphore, maxConcurrency, IrisSettings.get().getUpdater().emptyMsRange);
private final Semaphore semaphore = new Semaphore(256);
private final LoadBalancer loadBalancer = new LoadBalancer(semaphore, 256, IrisSettings.get().getUpdater().emptyMsRange);
private final AtomicLong startTime = new AtomicLong();
private final Dimensions dimensions;
private final PregenTask task;
private final ExecutorService chunkExecutor = IrisSettings.get().getUpdater().isNativeThreads() ? Executors.newFixedThreadPool(coreLimit) : Executors.newVirtualThreadPerTaskExecutor();
private final ExecutorService executor = Executors.newFixedThreadPool(coreLimit);
private final ExecutorService chunkExecutor = Executors.newFixedThreadPool(coreLimit);
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private final CountDownLatch latch;
private final Engine engine;
@@ -53,7 +54,6 @@ public class ChunkUpdater {
public ChunkUpdater(World world) {
this.engine = IrisToolbelt.access(world).getEngine();
this.world = world;
this.holder = Iris.tickets.getHolder(world);
this.dimensions = calculateWorldDimensions(new File(world.getWorldFolder(), "region"));
this.task = dimensions.task();
this.totalMaxChunks.set(dimensions.count * 1024);
@@ -108,10 +108,10 @@ public class ChunkUpdater {
}
}
} catch (Exception e) {
Iris.reportError(e);
e.printStackTrace();
}
}, 0, 3, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(this::unloadChunks, 0, 1, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(() -> {
boolean empty = Bukkit.getOnlinePlayers().isEmpty();
if (serverEmpty.getAndSet(empty) == empty)
@@ -126,7 +126,6 @@ public class ChunkUpdater {
t.setPriority(Thread.MAX_PRIORITY);
t.start();
Iris.service(PreservationSVC.class).register(t);
} catch (Exception e) {
e.printStackTrace();
}
@@ -137,6 +136,8 @@ public class ChunkUpdater {
loadBalancer.close();
semaphore.acquire(256);
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
chunkExecutor.shutdown();
chunkExecutor.awaitTermination(5, TimeUnit.SECONDS);
scheduler.shutdownNow();
@@ -161,12 +162,12 @@ public class ChunkUpdater {
J.sleep(50);
}
if (rX < dimensions.min.getX() ||
rX > dimensions.max.getX() ||
rZ < dimensions.min.getZ() ||
rZ > dimensions.max.getZ() ||
!new File(world.getWorldFolder(), REGION_PATH + rX + "." + rZ + ".mca").exists()
) return;
if (rX < dimensions.min.getX() || rX > dimensions.max.getX() || rZ < dimensions.min.getZ() || rZ > dimensions.max.getZ()) {
return;
}
if (!new File(world.getWorldFolder(), "region" + File.separator + rX + "." + rZ + ".mca").exists()) {
return;
}
task.iterateChunks(rX, rZ, (x, z) -> {
while (paused.get() && !cancelled.get()) {
@@ -197,16 +198,20 @@ public class ChunkUpdater {
return;
}
var mc = engine.getMantle().getMantle().getChunk(x, z).use();
try {
Chunk c = world.getChunkAt(x, z);
engine.getMantle().getMantle().getChunk(c);
engine.updateChunk(c);
removeTickets(x, z);
for (int xx = -1; xx <= 1; xx++) {
for (int zz = -1; zz <= 1; zz++) {
var counter = lastUse.get(Cache.key(x + xx, z + zz));
if (counter != null) counter.getB().decrementAndGet();
}
}
} finally {
chunksUpdated.incrementAndGet();
chunksProcessed.getAndIncrement();
mc.release();
}
}
@@ -228,16 +233,41 @@ public class ChunkUpdater {
for (int dz = -1; dz <= 1; dz++) {
int xx = x + dx;
int zz = z + dz;
PaperLib.getChunkAtAsync(world, xx, zz, false, true)
.thenAccept(chunk -> {
if (chunk == null || !chunk.isGenerated()) {
latch.countDown();
generated.set(false);
return;
}
holder.addTicket(chunk);
latch.countDown();
});
executor.submit(() -> {
try {
Chunk c;
try {
c = PaperLib.getChunkAtAsync(world, xx, zz, false, true)
.thenApply(chunk -> {
if (chunk != null)
chunk.addPluginChunkTicket(Iris.instance);
return chunk;
}).get();
} catch (InterruptedException | ExecutionException e) {
generated.set(false);
return;
}
if (c == null) {
generated.set(false);
return;
}
if (!c.isLoaded()) {
var future = J.sfut(() -> c.load(false));
if (future != null) future.join();
}
if (!PaperLib.isChunkGenerated(c.getWorld(), xx, zz))
generated.set(false);
var pair = lastUse.computeIfAbsent(Cache.key(c), k -> new Pair<>(0L, new AtomicInteger(-1)));
pair.setA(M.ms());
pair.getB().updateAndGet(i -> i == -1 ? 1 : ++i);
} finally {
latch.countDown();
}
});
}
}
@@ -246,16 +276,27 @@ public class ChunkUpdater {
} catch (InterruptedException e) {
Iris.info("Interrupted while waiting for chunks to load");
}
if (generated.get()) return true;
removeTickets(x, z);
return false;
return generated.get();
}
private void removeTickets(int x, int z) {
for (int xx = -1; xx <= 1; xx++) {
for (int zz = -1; zz <= 1; zz++) {
holder.removeTicket(x + xx, z + zz);
private synchronized void unloadChunks() {
for (var key : new ArrayList<>(lastUse.keySet())) {
if (key == null) continue;
var pair = lastUse.get(key);
if (pair == null) continue;
var lastUseTime = pair.getA();
var counter = pair.getB();
if (lastUseTime == null || counter == null)
continue;
if (M.ms() - lastUseTime >= 5000 && counter.get() == 0) {
int x = Cache.keyX(key);
int z = Cache.keyZ(key);
J.s(() -> {
world.removePluginChunkTicket(x, z, Iris.instance);
world.unloadChunk(x, z);
lastUse.remove(key);
});
}
}
}
@@ -268,10 +309,10 @@ public class ChunkUpdater {
return;
}
unloadChunks();
world.save();
}).get();
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
}

View File

@@ -0,0 +1,80 @@
package com.volmit.iris.core.pregenerator;
public class EmptyListener implements PregenListener {
public static PregenListener INSTANCE = new EmptyListener();
@Override
public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method) {
}
@Override
public void onChunkGenerating(int x, int z) {
}
@Override
public void onChunkGenerated(int x, int z) {
}
@Override
public void onRegionGenerated(int x, int z) {
}
@Override
public void onRegionGenerating(int x, int z) {
}
@Override
public void onChunkCleaned(int x, int z) {
}
@Override
public void onRegionSkipped(int x, int z) {
}
@Override
public void onNetworkStarted(int x, int z) {
}
@Override
public void onNetworkFailed(int x, int z) {
}
@Override
public void onNetworkReclaim(int revert) {
}
@Override
public void onNetworkGeneratedChunk(int x, int z) {
}
@Override
public void onNetworkDownloaded(int x, int z) {
}
@Override
public void onClose() {
}
@Override
public void onSaving() {
}
@Override
public void onChunkExistsInRegionGen(int x, int z) {
}
}

View File

@@ -31,33 +31,28 @@ import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Looper;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
public class IrisPregenerator {
private static final double INVALID = 9223372036854775807d;
private final PregenTask task;
private final PregeneratorMethod generator;
private final PregenListener listener;
private final Looper ticker;
private final AtomicBoolean paused;
private final AtomicBoolean shutdown;
private final RollingSequence cachedPerSecond;
private final RollingSequence chunksPerSecond;
private final RollingSequence chunksPerMinute;
private final RollingSequence regionsPerMinute;
private final KList<Integer> chunksPerSecondHistory;
private final AtomicLong generated;
private final AtomicLong generatedLast;
private final AtomicLong generatedLastMinute;
private final AtomicLong cached;
private final AtomicLong cachedLast;
private final AtomicLong cachedLastMinute;
private final AtomicLong totalChunks;
private static AtomicInteger generated;
private final AtomicInteger generatedLast;
private final AtomicInteger generatedLastMinute;
private static AtomicInteger totalChunks;
private final AtomicLong startTime;
private final ChronoLatch minuteLatch;
private final AtomicReference<String> currentGeneratorMethod;
@@ -66,10 +61,8 @@ public class IrisPregenerator {
private final KSet<Position2> net;
private final ChronoLatch cl;
private final ChronoLatch saveLatch = new ChronoLatch(30000);
private final IrisPackBenchmarking benchmarking;
public IrisPregenerator(PregenTask task, PregeneratorMethod generator, PregenListener listener) {
benchmarking = IrisPackBenchmarking.getInstance();
this.listener = listenify(listener);
cl = new ChronoLatch(5000);
generatedRegions = new KSet<>();
@@ -81,71 +74,46 @@ public class IrisPregenerator {
net = new KSet<>();
currentGeneratorMethod = new AtomicReference<>("Void");
minuteLatch = new ChronoLatch(60000, false);
cachedPerSecond = new RollingSequence(5);
chunksPerSecond = new RollingSequence(10);
chunksPerMinute = new RollingSequence(10);
regionsPerMinute = new RollingSequence(10);
chunksPerSecondHistory = new KList<>();
generated = new AtomicLong(0);
generatedLast = new AtomicLong(0);
generatedLastMinute = new AtomicLong(0);
cached = new AtomicLong();
cachedLast = new AtomicLong(0);
cachedLastMinute = new AtomicLong(0);
totalChunks = new AtomicLong(0);
generated = new AtomicInteger(0);
generatedLast = new AtomicInteger(0);
generatedLastMinute = new AtomicInteger(0);
totalChunks = new AtomicInteger(0);
task.iterateAllChunks((_a, _b) -> totalChunks.incrementAndGet());
startTime = new AtomicLong(M.ms());
ticker = new Looper() {
@Override
protected long loop() {
long eta = computeETA();
long secondCached = cached.get() - cachedLast.get();
cachedLast.set(cached.get());
cachedPerSecond.put(secondCached);
long secondGenerated = generated.get() - generatedLast.get() - secondCached;
int secondGenerated = generated.get() - generatedLast.get();
generatedLast.set(generated.get());
if (secondCached == 0 || secondGenerated != 0) {
chunksPerSecond.put(secondGenerated);
chunksPerSecondHistory.add((int) secondGenerated);
}
chunksPerSecond.put(secondGenerated);
chunksPerSecondHistory.add(secondGenerated);
if (minuteLatch.flip()) {
long minuteCached = cached.get() - cachedLastMinute.get();
cachedLastMinute.set(cached.get());
long minuteGenerated = generated.get() - generatedLastMinute.get() - minuteCached;
int minuteGenerated = generated.get() - generatedLastMinute.get();
generatedLastMinute.set(generated.get());
if (minuteCached == 0 || minuteGenerated != 0) {
chunksPerMinute.put(minuteGenerated);
regionsPerMinute.put((double) minuteGenerated / 1024D);
}
chunksPerMinute.put(minuteGenerated);
regionsPerMinute.put((double) minuteGenerated / 1024D);
}
boolean cached = cachedPerSecond.getAverage() != 0;
listener.onTick(
cached ? cachedPerSecond.getAverage() : chunksPerSecond.getAverage(),
chunksPerMinute.getAverage(),
listener.onTick(chunksPerSecond.getAverage(), chunksPerMinute.getAverage(),
regionsPerMinute.getAverage(),
(double) generated.get() / (double) totalChunks.get(), generated.get(),
totalChunks.get(),
totalChunks.get() - generated.get(), eta, M.ms() - startTime.get(), currentGeneratorMethod.get(),
cached);
(double) generated.get() / (double) totalChunks.get(),
generated.get(), totalChunks.get(),
totalChunks.get() - generated.get(),
eta, M.ms() - startTime.get(), currentGeneratorMethod.get());
if (cl.flip()) {
double percentage = ((double) generated.get() / (double) totalChunks.get()) * 100;
Iris.info("%s: %s of %s (%.0f%%), %s/s ETA: %s",
benchmarking != null ? "Benchmarking" : "Pregen",
Form.f(generated.get()),
Form.f(totalChunks.get()),
percentage,
cached ?
"Cached " + Form.f((int) cachedPerSecond.getAverage()) :
Form.f((int) chunksPerSecond.getAverage()),
Form.duration(eta, 2)
);
if (!IrisPackBenchmarking.benchmarkInProgress) {
Iris.info("Pregen: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (%.0f%%) " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration(eta, 2), percentage);
} else {
Iris.info("Benchmarking: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (%.0f%%) " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration(eta, 2), percentage);
}
}
return 1000;
}
@@ -153,12 +121,12 @@ public class IrisPregenerator {
}
private long computeETA() {
double d = (long) (generated.get() > 1024 ? // Generated chunks exceed 1/8th of total?
return (long) (totalChunks.get() > 1024 ? // Generated chunks exceed 1/8th of total?
// If yes, use smooth function (which gets more accurate over time since its less sensitive to outliers)
((totalChunks.get() - generated.get()) * ((double) (M.ms() - startTime.get()) / (double) generated.get())) :
// If no, use quick function (which is less accurate over time but responds better to the initial delay)
((totalChunks.get() - generated.get()) / chunksPerSecond.getAverage()) * 1000);
return Double.isFinite(d) && d != INVALID ? (long) d : 0;
((totalChunks.get() - generated.get()) / chunksPerSecond.getAverage()) * 1000
);
}
@@ -170,15 +138,13 @@ public class IrisPregenerator {
init();
ticker.start();
checkRegions();
var p = PrecisionStopwatch.start();
task.iterateRegions((x, z) -> visitRegion(x, z, true));
task.iterateRegions((x, z) -> visitRegion(x, z, false));
Iris.info("Pregen took " + Form.duration((long) p.getMilliseconds()));
shutdown();
if (benchmarking == null) {
if (!IrisPackBenchmarking.benchmarkInProgress) {
Iris.info(C.IRIS + "Pregen stopped.");
} else {
benchmarking.finishedBenchmark(chunksPerSecondHistory);
IrisPackBenchmarking.instance.finishedBenchmark(chunksPerSecondHistory);
}
}
@@ -268,8 +234,8 @@ public class IrisPregenerator {
private PregenListener listenify(PregenListener listener) {
return new PregenListener() {
@Override
public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, long generated, long totalChunks, long chunksRemaining, long eta, long elapsed, String method, boolean cached) {
listener.onTick(chunksPerSecond, chunksPerMinute, regionsPerMinute, percent, generated, totalChunks, chunksRemaining, eta, elapsed, method, cached);
public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method) {
listener.onTick(chunksPerSecond, chunksPerMinute, regionsPerMinute, percent, generated, totalChunks, chunksRemaining, eta, elapsed, method);
}
@Override
@@ -278,10 +244,9 @@ public class IrisPregenerator {
}
@Override
public void onChunkGenerated(int x, int z, boolean c) {
listener.onChunkGenerated(x, z, c);
public void onChunkGenerated(int x, int z) {
listener.onChunkGenerated(x, z);
generated.addAndGet(1);
if (c) cached.addAndGet(1);
}
@Override

View File

@@ -19,15 +19,11 @@
package com.volmit.iris.core.pregenerator;
public interface PregenListener {
void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, long generated, long totalChunks, long chunksRemaining, long eta, long elapsed, String method, boolean cached);
void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method);
void onChunkGenerating(int x, int z);
default void onChunkGenerated(int x, int z) {
onChunkGenerated(x, z, false);
}
void onChunkGenerated(int x, int z, boolean cached);
void onChunkGenerated(int x, int z);
void onRegionGenerated(int x, int z);

View File

@@ -1,69 +0,0 @@
package com.volmit.iris.core.pregenerator.cache;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.documentation.RegionCoordinates;
import java.io.File;
public interface PregenCache {
default boolean isThreadSafe() {
return false;
}
@ChunkCoordinates
boolean isChunkCached(int x, int z);
@RegionCoordinates
boolean isRegionCached(int x, int z);
@ChunkCoordinates
void cacheChunk(int x, int z);
@RegionCoordinates
void cacheRegion(int x, int z);
void write();
void trim(long unloadDuration);
static PregenCache create(File directory) {
if (directory == null) return EMPTY;
return new PregenCacheImpl(directory, 16);
}
default PregenCache sync() {
if (isThreadSafe()) return this;
return new SynchronizedCache(this);
}
PregenCache EMPTY = new PregenCache() {
@Override
public boolean isThreadSafe() {
return true;
}
@Override
public boolean isChunkCached(int x, int z) {
return false;
}
@Override
public boolean isRegionCached(int x, int z) {
return false;
}
@Override
public void cacheChunk(int x, int z) {}
@Override
public void cacheRegion(int x, int z) {}
@Override
public void write() {}
@Override
public void trim(long unloadDuration) {}
};
}

View File

@@ -1,50 +0,0 @@
package com.volmit.iris.core.pregenerator.cache;
record SynchronizedCache(PregenCache cache) implements PregenCache {
@Override
public boolean isThreadSafe() {
return true;
}
@Override
public boolean isChunkCached(int x, int z) {
synchronized (cache) {
return cache.isChunkCached(x, z);
}
}
@Override
public boolean isRegionCached(int x, int z) {
synchronized (cache) {
return cache.isRegionCached(x, z);
}
}
@Override
public void cacheChunk(int x, int z) {
synchronized (cache) {
cache.cacheChunk(x, z);
}
}
@Override
public void cacheRegion(int x, int z) {
synchronized (cache) {
cache.cacheRegion(x, z);
}
}
@Override
public void write() {
synchronized (cache) {
cache.write();
}
}
@Override
public void trim(long unloadDuration) {
synchronized (cache) {
cache.trim(unloadDuration);
}
}
}

View File

@@ -19,7 +19,6 @@
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.core.tools.IrisToolbelt;
@@ -32,32 +31,24 @@ import io.papermc.lib.PaperLib;
import org.bukkit.Chunk;
import org.bukkit.World;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
public class AsyncPregenMethod implements PregeneratorMethod {
private static final AtomicInteger THREAD_COUNT = new AtomicInteger();
private final World world;
private final Executor executor;
private final MultiBurst burst;
private final Semaphore semaphore;
private final int threads;
private final boolean urgent;
private final Map<Chunk, Long> lastUse;
public AsyncPregenMethod(World world, int unusedThreads) {
public AsyncPregenMethod(World world, int threads) {
if (!PaperLib.isPaper()) {
throw new UnsupportedOperationException("Cannot use PaperAsync on non paper!");
}
this.world = world;
this.executor = IrisSettings.get().getPregen().isUseTicketQueue() ? new TicketExecutor() : new ServiceExecutor();
this.threads = IrisSettings.get().getPregen().getMaxConcurrency();
this.semaphore = new Semaphore(this.threads, true);
this.urgent = IrisSettings.get().getPregen().useHighPriority;
burst = new MultiBurst("Iris Async Pregen", Thread.MIN_PRIORITY);
semaphore = new Semaphore(256);
this.lastUse = new KMap<>();
}
@@ -69,18 +60,13 @@ public class AsyncPregenMethod implements PregeneratorMethod {
return;
}
long minTime = M.ms() - 10_000;
lastUse.entrySet().removeIf(i -> {
final Chunk chunk = i.getKey();
final Long lastUseTime = i.getValue();
if (!chunk.isLoaded() || lastUseTime == null)
return true;
if (lastUseTime < minTime) {
chunk.unload();
return true;
for (Chunk i : new ArrayList<>(lastUse.keySet())) {
Long lastUseTime = lastUse.get(i);
if (!i.isLoaded() || (lastUseTime != null && M.ms() - lastUseTime >= 10000)) {
i.unload();
lastUse.remove(i);
}
return false;
});
}
world.save();
}).get();
} catch (Throwable e) {
@@ -88,10 +74,24 @@ public class AsyncPregenMethod implements PregeneratorMethod {
}
}
private void completeChunk(int x, int z, PregenListener listener) {
try {
PaperLib.getChunkAtAsync(world, x, z, true).thenAccept((i) -> {
lastUse.put(i, M.ms());
listener.onChunkGenerated(x, z);
listener.onChunkCleaned(x, z);
}).get();
} catch (InterruptedException ignored) {
} catch (Throwable e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
@Override
public void init() {
unloadAndSaveAllChunks();
increaseWorkerThreads();
}
@Override
@@ -101,10 +101,9 @@ public class AsyncPregenMethod implements PregeneratorMethod {
@Override
public void close() {
semaphore.acquireUninterruptibly(threads);
semaphore.acquireUninterruptibly(256);
unloadAndSaveAllChunks();
executor.shutdown();
resetWorkerThreads();
burst.close();
}
@Override
@@ -130,7 +129,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
} catch (InterruptedException e) {
return;
}
executor.generate(x, z, listener);
burst.complete(() -> completeChunk(x, z, listener));
}
@Override
@@ -141,100 +140,4 @@ public class AsyncPregenMethod implements PregeneratorMethod {
return null;
}
public static void increaseWorkerThreads() {
THREAD_COUNT.updateAndGet(i -> {
if (i > 0) return 1;
var adjusted = IrisSettings.get().getConcurrency().getWorldGenThreads();
try {
var field = Class.forName("ca.spottedleaf.moonrise.common.util.MoonriseCommon").getDeclaredField("WORKER_POOL");
var pool = field.get(null);
var threads = ((Thread[]) pool.getClass().getDeclaredMethod("getCoreThreads").invoke(pool)).length;
if (threads >= adjusted) return 0;
pool.getClass().getDeclaredMethod("adjustThreadCount", int.class).invoke(pool, adjusted);
return threads;
} catch (Throwable e) {
Iris.warn("Failed to increase worker threads, if you are on paper or a fork of it please increase it manually to " + adjusted);
Iris.warn("For more information see https://docs.papermc.io/paper/reference/global-configuration#chunk_system_worker_threads");
if (e instanceof InvocationTargetException) {
Iris.reportError(e);
e.printStackTrace();
}
}
return 0;
});
}
public static void resetWorkerThreads() {
THREAD_COUNT.updateAndGet(i -> {
if (i == 0) return 0;
try {
var field = Class.forName("ca.spottedleaf.moonrise.common.util.MoonriseCommon").getDeclaredField("WORKER_POOL");
var pool = field.get(null);
var method = pool.getClass().getDeclaredMethod("adjustThreadCount", int.class);
method.invoke(pool, i);
return 0;
} catch (Throwable e) {
Iris.reportError(e);
Iris.error("Failed to reset worker threads");
e.printStackTrace();
}
return i;
});
}
private interface Executor {
void generate(int x, int z, PregenListener listener);
default void shutdown() {}
}
private class ServiceExecutor implements Executor {
private final ExecutorService service = IrisSettings.get().getPregen().isUseVirtualThreads() ?
Executors.newVirtualThreadPerTaskExecutor() :
new MultiBurst("Iris Async Pregen");
public void generate(int x, int z, PregenListener listener) {
service.submit(() -> {
try {
PaperLib.getChunkAtAsync(world, x, z, true, urgent).thenAccept((i) -> {
listener.onChunkGenerated(x, z);
listener.onChunkCleaned(x, z);
if (i == null) return;
lastUse.put(i, M.ms());
}).get();
} catch (InterruptedException ignored) {
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
} finally {
semaphore.release();
}
});
}
@Override
public void shutdown() {
service.shutdown();
}
}
private class TicketExecutor implements Executor {
@Override
public void generate(int x, int z, PregenListener listener) {
PaperLib.getChunkAtAsync(world, x, z, true, urgent)
.exceptionally(e -> {
Iris.reportError(e);
e.printStackTrace();
return null;
})
.thenAccept(i -> {
semaphore.release();
listener.onChunkGenerated(x, z);
listener.onChunkCleaned(x, z);
if (i == null) return;
lastUse.put(i, M.ms());
});
}
}
}

View File

@@ -1,86 +0,0 @@
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.Iris;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.core.pregenerator.cache.PregenCache;
import com.volmit.iris.core.service.GlobalCacheSVC;
import com.volmit.iris.util.mantle.Mantle;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class CachedPregenMethod implements PregeneratorMethod {
private final PregeneratorMethod method;
private final PregenCache cache;
public CachedPregenMethod(PregeneratorMethod method, String worldName) {
this.method = method;
var cache = Iris.service(GlobalCacheSVC.class).get(worldName);
if (cache == null) {
Iris.debug("Could not find existing cache for " + worldName + " creating fallback");
cache = GlobalCacheSVC.createDefault(worldName);
}
this.cache = cache;
}
@Override
public void init() {
method.init();
}
@Override
public void close() {
method.close();
cache.write();
}
@Override
public void save() {
method.save();
cache.write();
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return cache.isRegionCached(x, z) || method.supportsRegions(x, z, listener);
}
@Override
public String getMethod(int x, int z) {
return method.getMethod(x, z);
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
if (cache.isRegionCached(x, z)) {
listener.onRegionGenerated(x, z);
int rX = x << 5, rZ = z << 5;
for (int cX = 0; cX < 32; cX++) {
for (int cZ = 0; cZ < 32; cZ++) {
listener.onChunkGenerated(rX + cX, rZ + cZ, true);
listener.onChunkCleaned(rX + cX, rZ + cZ);
}
}
return;
}
method.generateRegion(x, z, listener);
cache.cacheRegion(x, z);
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
if (cache.isChunkCached(x, z)) {
listener.onChunkGenerated(x, z, true);
listener.onChunkCleaned(x, z);
return;
}
method.generateChunk(x, z, listener);
cache.cacheChunk(x, z);
}
@Override
public Mantle getMantle() {
return method.getMantle();
}
}

View File

@@ -0,0 +1,112 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2024 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisHeadless;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.parallel.MultiBurst;
import java.io.IOException;
import java.util.concurrent.Semaphore;
public class HeadlessPregenMethod implements PregeneratorMethod {
private final Engine engine;
private final IrisHeadless headless;
private final Semaphore semaphore;
private final int max;
private final MultiBurst burst;
public HeadlessPregenMethod(Engine engine) {
this(engine, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism()));
}
public HeadlessPregenMethod(Engine engine, int threads) {
this.max = Math.max(threads, 4);
this.engine = engine;
this.headless = new IrisHeadless(engine);
burst = new MultiBurst("HeadlessPregen", 8);
this.semaphore = new Semaphore(max);
}
@Override
public void init() {
}
@Override
public void close() {
try {
semaphore.acquire(max);
} catch (InterruptedException ignored) {
}
try {
headless.close();
} catch (IOException e) {
Iris.error("Failed to close headless");
e.printStackTrace();
}
burst.close();
}
@Override
public void save() {
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public String getMethod(int x, int z) {
return "Headless";
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
try {
semaphore.acquire();
} catch (InterruptedException ignored) {
return;
}
burst.complete(() -> {
try {
listener.onChunkGenerating(x, z);
headless.generateChunk(x, z);
listener.onChunkGenerated(x, z);
} finally {
semaphore.release();
}
});
}
@Override
public Mantle getMantle() {
return engine.getMantle().getMantle();
}
}

View File

@@ -1,107 +0,0 @@
package com.volmit.iris.core.project;
import com.volmit.iris.Iris;
import com.volmit.iris.util.io.IO;
import org.zeroturnaround.zip.ZipUtil;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.*;
public class Gradle {
private static final boolean WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
private static final String[] ENVIRONMENT = createEnvironment();
private static final String VERSION = "8.14.2";
private static final String DISTRIBUTION_URL = "https://services.gradle.org/distributions/gradle-" + VERSION + "-bin.zip";
private static final String HASH = IO.hash(DISTRIBUTION_URL);
public static synchronized void wrapper(File projectDir) {
try {
File settings = new File(projectDir, "settings.gradle.kts");
if (!settings.exists()) settings.createNewFile();
runGradle(projectDir, "wrapper");
} catch (Throwable e) {
Iris.error("Failed to install gradle wrapper!");
e.printStackTrace();
Iris.reportError(e);
}
}
public static void runGradle(File projectDir, String... args) throws IOException, InterruptedException {
File gradle = downloadGradle(false);
String[] cmd = new String[args.length + 1];
cmd[0] = gradle.getAbsolutePath();
System.arraycopy(args, 0, cmd, 1, args.length);
var process = Runtime.getRuntime().exec(cmd, ENVIRONMENT, projectDir);
var lines = Collections.synchronizedList(new ArrayList<String>());
attach(process.getInputStream(), lines);
attach(process.getErrorStream(), lines);
var code = process.waitFor();
if (code == 0) {
lines.forEach(Iris::debug);
return;
}
lines.forEach(Iris::error);
throw new RuntimeException("Gradle exited with code " + code);
}
private static synchronized File downloadGradle(boolean force) {
var folder = Iris.instance.getDataFolder("cache", HASH.substring(0, 2), HASH);
if (force) {
IO.delete(folder);
folder.mkdirs();
}
var bin = new File(folder, "gradle-" + VERSION + "/bin/gradle" + (WINDOWS ? ".bat" : ""));
if (bin.exists()) {
bin.setExecutable(true);
return bin;
}
try (var input = new BufferedInputStream(URI.create(DISTRIBUTION_URL).toURL().openStream())) {
ZipUtil.unpack(input, folder);
} catch (Throwable e) {
throw new RuntimeException("Failed to download gradle", e);
}
bin.setExecutable(true);
return bin;
}
private static String[] createEnvironment() {
var env = new HashMap<>(System.getenv());
env.put("JAVA_HOME", findJavaHome());
return env.entrySet()
.stream()
.map(e -> e.getKey() + "=" + e.getValue())
.toArray(String[]::new);
}
private static String findJavaHome() {
String javaHome = System.getProperty("java.home");
if (javaHome != null && new File(javaHome + "/bin/java" + (WINDOWS ? ".exe" : "")).exists()) {
return javaHome;
}
return ProcessHandle.current()
.info()
.command()
.map(s -> new File(s).getAbsoluteFile().getParentFile().getParentFile())
.flatMap(f -> f.exists() ? Optional.of(f.getAbsolutePath()) : Optional.empty())
.orElseThrow(() -> new RuntimeException("Failed to find java home, please set java.home system property"));
}
private static void attach(InputStream stream, List<String> list) {
Thread.ofPlatform().start(() -> {
try (var in = new Scanner(stream)) {
while (in.hasNextLine()) {
String line = in.nextLine();
list.add(line);
}
}
});
}
}

View File

@@ -49,8 +49,6 @@ import lombok.Data;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.World;
import org.dom4j.Document;
import org.dom4j.Element;
import org.zeroturnaround.zip.ZipUtil;
import java.awt.*;
@@ -158,7 +156,7 @@ public class IrisProject {
public void openVSCode(VolmitSender sender) {
IrisDimension d = IrisData.loadAnyDimension(getName(), null);
IrisDimension d = IrisData.loadAnyDimension(getName());
J.attemptAsync(() ->
{
try {
@@ -219,15 +217,24 @@ public class IrisProject {
close();
}
J.a(() -> {
IrisDimension d = IrisData.loadAnyDimension(getName(), null);
if (d == null) {
sender.sendMessage("Can't find dimension: " + getName());
return;
} else if (sender.isPlayer()) {
J.s(() -> sender.player().setGameMode(GameMode.SPECTATOR));
}
boolean hasError = false;
if (hasError) {
return;
}
IrisDimension d = IrisData.loadAnyDimension(getName());
if (d == null) {
sender.sendMessage("Can't find dimension: " + getName());
return;
} else if (sender.isPlayer()) {
sender.player().setGameMode(GameMode.SPECTATOR);
}
openVSCode(sender);
J.a(() -> {
try {
activeProvider = (PlatformChunkGenerator) IrisToolbelt.createWorld()
.seed(seed)
@@ -240,8 +247,6 @@ public class IrisProject {
} catch (IrisException e) {
e.printStackTrace();
}
openVSCode(sender);
});
}
@@ -325,7 +330,7 @@ public class IrisProject {
}
}
for (Class<?> i : dm.resolveSnippets()) {
for (Class<?> i : Iris.getClasses("com.volmit.iris.engine.object.", Snippet.class)) {
try {
String snipType = i.getDeclaredAnnotation(Snippet.class).value();
JSONObject o = new JSONObject();
@@ -354,74 +359,6 @@ public class IrisProject {
settings.put("json.schemas", schemas);
ws.put("settings", settings);
dm.getEnvironment().configureProject();
File schemasFile = new File(path, ".idea" + File.separator + "jsonSchemas.xml");
Document doc = IO.read(schemasFile);
Element mappings = (Element) doc.selectSingleNode("//component[@name='JsonSchemaMappingsProjectConfiguration']");
if (mappings == null) {
mappings = doc.getRootElement()
.addElement("component")
.addAttribute("name", "JsonSchemaMappingsProjectConfiguration");
}
Element state = (Element) mappings.selectSingleNode("state");
if (state == null) state = mappings.addElement("state");
Element map = (Element) state.selectSingleNode("map");
if (map == null) map = state.addElement("map");
var schemaMap = new KMap<String, String>();
schemas.forEach(element -> {
if (!(element instanceof JSONObject obj))
return;
String url = obj.getString("url");
String dir = obj.getJSONArray("fileMatch").getString(0);
schemaMap.put(url, dir.substring(1, dir.indexOf("/*")));
});
map.selectNodes("entry/value/SchemaInfo/option[@name='relativePathToSchema']")
.stream()
.map(node -> node.valueOf("@value"))
.forEach(schemaMap::remove);
var ideaSchemas = map;
schemaMap.forEach((url, dir) -> {
var genName = UUID.randomUUID().toString();
var info = ideaSchemas.addElement("entry")
.addAttribute("key", genName)
.addElement("value")
.addElement("SchemaInfo");
info.addElement("option")
.addAttribute("name", "generatedName")
.addAttribute("value", genName);
info.addElement("option")
.addAttribute("name", "name")
.addAttribute("value", dir);
info.addElement("option")
.addAttribute("name", "relativePathToSchema")
.addAttribute("value", url);
var item = info.addElement("option")
.addAttribute("name", "patterns")
.addElement("list")
.addElement("Item");
item.addElement("option")
.addAttribute("name", "directory")
.addAttribute("value", "true");
item.addElement("option")
.addAttribute("name", "path")
.addAttribute("value", dir);
item.addElement("option")
.addAttribute("name", "mappingKind")
.addAttribute("value", "Directory");
});
if (!schemaMap.isEmpty()) {
IO.write(schemasFile, doc);
}
Gradle.wrapper(path);
return ws;
}
@@ -440,17 +377,17 @@ public class IrisProject {
KSet<IrisLootTable> loot = new KSet<>();
KSet<IrisBlockData> blocks = new KSet<>();
for (String i : dm.getBlockLoader().getPossibleKeys()) {
for (String i : dm.getDimensionLoader().getPossibleKeys()) {
blocks.add(dm.getBlockLoader().load(i));
}
dimension.getRegions().forEach((i) -> regions.add(dm.getRegionLoader().load(i)));
dimension.getLoot().getTables().forEach((i) -> loot.add(dm.getLootLoader().load(i)));
regions.forEach((i) -> biomes.addAll(i.getAllBiomes(() -> dm)));
regions.forEach((i) -> biomes.addAll(i.getAllBiomes(null)));
regions.forEach((r) -> r.getLoot().getTables().forEach((i) -> loot.add(dm.getLootLoader().load(i))));
regions.forEach((r) -> r.getEntitySpawners().forEach((sp) -> spawners.add(dm.getSpawnerLoader().load(sp))));
dimension.getEntitySpawners().forEach((sp) -> spawners.add(dm.getSpawnerLoader().load(sp)));
biomes.forEach((i) -> i.getGenerators().forEach((j) -> generators.add(j.getCachedGenerator(() -> dm))));
biomes.forEach((i) -> i.getGenerators().forEach((j) -> generators.add(j.getCachedGenerator(null))));
biomes.forEach((r) -> r.getLoot().getTables().forEach((i) -> loot.add(dm.getLootLoader().load(i))));
biomes.forEach((r) -> r.getEntitySpawners().forEach((sp) -> spawners.add(dm.getSpawnerLoader().load(sp))));
spawners.forEach((i) -> i.getSpawns().forEach((j) -> entities.add(dm.getEntityLoader().load(j.getEntity()))));

View File

@@ -19,30 +19,27 @@
package com.volmit.iris.core.project;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.link.data.DataType;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.reflect.KeyedType;
import com.volmit.iris.util.reflect.OldEnum;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.lang.reflect.Field;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public class SchemaBuilder {
private static final String SYMBOL_LIMIT__N = "*";
@@ -111,59 +108,62 @@ public class SchemaBuilder {
private JSONObject buildProperties(Class<?> c) {
JSONObject o = new JSONObject();
JSONObject properties = new JSONObject();
String desc = getDescription(c);
o.put("description", desc);
o.put("x-intellij-html-description", desc.replace("\n", "<br>"));
o.put("description", getDescription(c));
o.put("type", getType(c));
JSONArray required = new JSONArray();
JSONArray extended = new JSONArray();
var parent = c.getSuperclass();
while (parent != null && IrisRegistrant.class.isAssignableFrom(parent)) {
buildProperties(properties, required, extended, parent);
parent = parent.getSuperclass();
}
buildProperties(properties, required, extended, c);
if (required.length() > 0) {
o.put("required", required);
}
if (extended.length() > 0) {
o.put("allOf", extended);
}
o.put("properties", properties);
return buildSnippet(o, c);
}
private void buildProperties(JSONObject properties, JSONArray required, JSONArray extended, Class<?> c) {
for (Field k : c.getDeclaredFields()) {
if (Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
continue;
}
try {
if (c.isAssignableFrom(IrisRegistrant.class) || IrisRegistrant.class.isAssignableFrom(c)) {
for (Field k : IrisRegistrant.class.getDeclaredFields()) {
k.setAccessible(true);
} catch (InaccessibleObjectException e) {
if (Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
continue;
}
JSONObject property = buildProperty(k, c);
if (property.getBoolean("!required")) {
required.put(k.getName());
}
property.remove("!required");
properties.put(k.getName(), property);
}
}
for (Field k : c.getDeclaredFields()) {
k.setAccessible(true);
if (Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
continue;
}
JSONObject property = buildProperty(k, c);
if (Boolean.TRUE == property.remove("!top")) {
extended.put(property);
continue;
}
if (Boolean.TRUE == property.remove("!required")) {
required.put(k.getName());
}
property.remove("!required");
properties.put(k.getName(), property);
}
if (required.length() > 0) {
o.put("required", required);
}
o.put("properties", properties);
if (c.isAnnotationPresent(Snippet.class)) {
JSONObject anyOf = new JSONObject();
JSONArray arr = new JSONArray();
JSONObject str = new JSONObject();
str.put("type", "string");
arr.put(o);
arr.put(str);
anyOf.put("anyOf", arr);
return anyOf;
}
return o;
}
private JSONObject buildProperty(Field k, Class<?> cl) {
@@ -276,18 +276,16 @@ public class SchemaBuilder {
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
KList<String> list = Iris.service(ExternalDataSVC.class)
.getAllIdentifiers(DataType.ENTITY)
.stream()
.map(Identifier::toString)
.collect(KList.collector());
KList<String> list = new KList<>();
list.addAll(Iris.linkMythicMobs.getMythicMobTypes().stream().map(s -> "MythicMobs:" + s).collect(Collectors.toList()));
//TODO add Citizens stuff here too
j.put("enum", list.toJSONStringArray());
definitions.put(key, j);
}
fancyType = "Custom Mob Type";
fancyType = "Mythic Mob Type";
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Custom Mob Type (use ctrl+space for auto complete!)");
description.add(SYMBOL_TYPE__N + " Must be a valid Mythic Mob Type (use ctrl+space for auto complete!) Define mythic mobs with the mythic mobs plugin configuration files.");
} else if (k.isAnnotationPresent(RegistryListFont.class)) {
String key = "enum-font";
@@ -344,70 +342,20 @@ public class SchemaBuilder {
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)");
} else if (KeyedType.isKeyed(k.getType())) {
fancyType = addEnum(k.getType(), prop, description, KeyedType.values(k.getType()), Function.identity());
} else if (k.getType().isEnum()) {
fancyType = addEnum(k.getType(), prop, description, k.getType().getEnumConstants(), o -> ((Enum<?>) o).name());
} else if (OldEnum.isOldEnum(k.getType())) {
fancyType = addEnum(k.getType(), prop, description, OldEnum.values(k.getType()), OldEnum::name);
}
}
case "object" -> {
//TODO add back descriptions
if (k.isAnnotationPresent(RegistryMapBlockState.class)) {
String blockType = k.getDeclaredAnnotation(RegistryMapBlockState.class).value();
fancyType = "Block State";
prop.put("!top", true);
JSONArray any = new JSONArray();
prop.put("anyOf", any);
B.getBlockStates().forEach((blocks, properties) -> {
if (blocks.isEmpty()) return;
String raw = blocks.getFirst().replace(':', '_');
String enumKey = "enum-block-state-" + raw;
String propertiesKey = "obj-block-state-" + raw;
any.put(new JSONObject()
.put("if", new JSONObject()
.put("properties", new JSONObject()
.put(blockType, new JSONObject()
.put("type", "string")
.put("$ref", "#/definitions/" + enumKey))))
.put("then", new JSONObject()
.put("properties", new JSONObject()
.put(k.getName(), new JSONObject()
.put("type", "object")
.put("$ref", "#/definitions/" + propertiesKey))))
.put("else", false));
if (!definitions.containsKey(enumKey)) {
JSONArray filters = new JSONArray();
blocks.forEach(filters::put);
definitions.put(enumKey, new JSONObject()
.put("type", "string")
.put("enum", filters));
}
if (!definitions.containsKey(propertiesKey)) {
JSONObject props = new JSONObject();
properties.forEach(property -> {
props.put(property.name(), property.buildJson());
});
definitions.put(propertiesKey, new JSONObject()
.put("type", "object")
.put("properties", props));
}
});
} else {
fancyType = k.getType().getSimpleName().replaceAll("\\QIris\\E", "") + " (Object)";
String key = "obj-" + k.getType().getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase();
if (!definitions.containsKey(key)) {
definitions.put(key, new JSONObject());
definitions.put(key, buildProperties(k.getType()));
}
prop.put("$ref", "#/definitions/" + key);
fancyType = k.getType().getSimpleName().replaceAll("\\QIris\\E", "") + " (Object)";
String key = "obj-" + k.getType().getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase();
if (!definitions.containsKey(key)) {
definitions.put(key, new JSONObject());
definitions.put(key, buildProperties(k.getType()));
}
prop.put("$ref", "#/definitions/" + key);
}
case "array" -> {
fancyType = "List of Something...?";
@@ -528,26 +476,6 @@ public class SchemaBuilder {
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid Enchantment Type (use ctrl+space for auto complete!)");
} else if (k.isAnnotationPresent(RegistryListFunction.class)) {
var functionClass = k.getDeclaredAnnotation(RegistryListFunction.class).value();
try {
var instance = functionClass.getDeclaredConstructor().newInstance();
String key = instance.key();
fancyType = instance.fancyName();
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", instance.apply(data));
definitions.put(key, j);
}
JSONObject items = new JSONObject();
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid " + fancyType + " (use ctrl+space for auto complete!)");
} catch (Throwable e) {
Iris.error("Could not execute apply method in " + functionClass.getName());
}
} else if (t.type().equals(PotionEffectType.class)) {
fancyType = "List of Potion Effect Types";
String key = "enum-potion-effect-type";
@@ -562,10 +490,10 @@ public class SchemaBuilder {
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)");
} else if (KeyedType.isKeyed(t.type())) {
fancyType = addEnumList(prop, description, t, KeyedType.values(t.type()), Function.identity());
} else if (t.type().isEnum()) {
fancyType = addEnumList(prop, description, t, t.type().getEnumConstants(), o -> ((Enum<?>) o).name());
} else if (OldEnum.isOldEnum(t.type())) {
fancyType = addEnumList(prop, description, t, OldEnum.values(t.type()), OldEnum::name);
}
}
}
@@ -578,26 +506,16 @@ public class SchemaBuilder {
}
KList<String> d = new KList<>();
d.add("<h>" + k.getName() + "</h>");
d.add(getFieldDescription(k) + "<hr></hr>");
d.add("<h>" + fancyType + "</h>");
String typeDesc = getDescription(k.getType());
boolean present = !typeDesc.isBlank();
if (present) d.add(typeDesc);
d.add(k.getName());
d.add(getFieldDescription(k));
d.add(" ");
d.add(fancyType);
d.add(getDescription(k.getType()));
Snippet snippet = k.getType().getDeclaredAnnotation(Snippet.class);
if (snippet == null) {
ArrayType array = k.getType().getDeclaredAnnotation(ArrayType.class);
if (array != null) {
snippet = array.type().getDeclaredAnnotation(Snippet.class);
}
}
if (snippet != null) {
String sm = snippet.value();
if (present) d.add(" ");
if (k.getType().isAnnotationPresent(Snippet.class)) {
String sm = k.getType().getDeclaredAnnotation(Snippet.class).value();
d.add(" ");
d.add("You can instead specify \"snippet/" + sm + "/some-name.json\" to use a snippet file instead of specifying it here.");
present = false;
}
try {
@@ -605,13 +523,15 @@ public class SchemaBuilder {
Object value = k.get(cl.newInstance());
if (value != null) {
if (present) d.add(" ");
if (value instanceof List) {
d.add(SYMBOL_LIMIT__N + " Default Value is an empty list");
} else if (!k.getType().isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(value instanceof Enum<?>) && !KeyedType.isKeyed(k.getType())) {
d.add(SYMBOL_LIMIT__N + " Default Value is a default object (create this object to see default properties)");
d.add(" ");
d.add("* Default Value is an empty list");
} else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum()) && !OldEnum.isOldEnum(cl)) {
d.add(" ");
d.add("* Default Value is a default object (create this object to see default properties)");
} else {
d.add(SYMBOL_LIMIT__N + " Default Value is " + value);
d.add(" ");
d.add("* Default Value is " + value);
}
}
} catch (Throwable ignored) {
@@ -619,50 +539,41 @@ public class SchemaBuilder {
}
description.forEach((g) -> d.add(g.trim()));
String desc = d.toString("\n")
.replace("<hr></hr>", "\n")
.replace("<h>", "")
.replace("</h>", "");
String hDesc = d.toString("<br>");
prop.put("type", type);
prop.put("description", desc);
prop.put("x-intellij-html-description", hDesc);
return buildSnippet(prop, k.getType());
}
prop.put("description", d.toString("\n"));
private JSONObject buildSnippet(JSONObject prop, Class<?> type) {
Snippet snippet = type.getDeclaredAnnotation(Snippet.class);
if (snippet == null) return prop;
if (k.getType().isAnnotationPresent(Snippet.class)) {
JSONObject anyOf = new JSONObject();
JSONArray arr = new JSONArray();
JSONObject str = new JSONObject();
str.put("type", "string");
String key = "enum-snippet-" + k.getType().getDeclaredAnnotation(Snippet.class).value();
str.put("$ref", "#/definitions/" + key);
JSONObject anyOf = new JSONObject();
JSONArray arr = new JSONArray();
JSONObject str = new JSONObject();
str.put("type", "string");
String key = "enum-snippet-" + snippet.value();
str.put("$ref", "#/definitions/" + key);
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
JSONArray snl = new JSONArray();
data.getPossibleSnippets(k.getType().getDeclaredAnnotation(Snippet.class).value()).forEach(snl::put);
j.put("enum", snl);
definitions.put(key, j);
}
if (!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
JSONArray snl = new JSONArray();
data.getPossibleSnippets(snippet.value()).forEach(snl::put);
j.put("enum", snl);
definitions.put(key, j);
arr.put(prop);
arr.put(str);
prop.put("description", d.toString("\n"));
str.put("description", d.toString("\n"));
anyOf.put("anyOf", arr);
anyOf.put("description", d.toString("\n"));
anyOf.put("!required", k.isAnnotationPresent(Required.class));
return anyOf;
}
arr.put(prop);
arr.put(str);
str.put("description", prop.getString("description"));
str.put("x-intellij-html-description", prop.getString("x-intellij-html-description"));
anyOf.put("anyOf", arr);
anyOf.put("description", prop.getString("description"));
anyOf.put("x-intellij-html-description", prop.getString("x-intellij-html-description"));
anyOf.put("!required", type.isAnnotationPresent(Required.class));
return anyOf;
return prop;
}
@NotNull
private <T> String addEnumList(JSONObject prop, KList<String> description, ArrayType t, T[] values, Function<T, String> function) {
private String addEnumList(JSONObject prop, KList<String> description, ArrayType t, Object[] values, Function<Object, String> function) {
JSONObject items = new JSONObject();
var s = addEnum(t.type(), items, description, values, function);
prop.put("items", items);
@@ -671,19 +582,17 @@ public class SchemaBuilder {
}
@NotNull
private <T> String addEnum(Class<?> type, JSONObject prop, KList<String> description, T[] values, Function<T, String> function) {
private String addEnum(Class<?> type, JSONObject prop, KList<String> description, Object[] values, Function<Object, String> function) {
JSONArray a = new JSONArray();
boolean advanced = type.isAnnotationPresent(Desc.class);
for (T gg : values) {
for (Object gg : values) {
if (advanced) {
try {
JSONObject j = new JSONObject();
String name = function.apply(gg);
j.put("const", name);
Desc dd = type.getField(name).getAnnotation(Desc.class);
String desc = dd == null ? ("No Description for " + name) : dd.value();
j.put("description", desc);
j.put("x-intellij-html-description", desc.replace("\n", "<br>"));
j.put("description", dd == null ? ("No Description for " + name) : dd.value());
a.put(j);
} catch (Throwable e) {
Iris.reportError(e);
@@ -720,7 +629,7 @@ public class SchemaBuilder {
return "boolean";
}
if (c.equals(String.class) || c.isEnum() || KeyedType.isKeyed(c)) {
if (c.equals(String.class) || c.isEnum() || OldEnum.isOldEnum(c) || c.equals(Enchantment.class) || c.equals(PotionEffectType.class)) {
return "string";
}

View File

@@ -0,0 +1,24 @@
package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
public class IrisSafeguard {
public static boolean unstablemode = false;
public static boolean warningmode = false;
public static boolean stablemode = false;
public static void IrisSafeguardSystem() {
Iris.info("Enabled Iris SafeGuard");
ServerBootSFG.BootCheck();
}
public static void earlySplash() {
if (ServerBootSFG.safeguardPassed || IrisSettings.get().getGeneral().DoomsdayAnnihilationSelfDestructMode)
return;
Iris.instance.splash();
UtilsSFG.splash();
}
}

View File

@@ -0,0 +1,80 @@
package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.util.format.C;
public class ModesSFG {
public static void selectMode() {
if (IrisSafeguard.unstablemode) {
Iris.safeguard(C.DARK_RED + "Iris is running in Unstable Mode");
unstable();
}
if (IrisSafeguard.warningmode) {
Iris.safeguard(C.GOLD + "Iris is running in Warning Mode");
warning();
}
if (IrisSafeguard.stablemode) {
stable();
}
}
public static void stable() {
Iris.safeguard(C.BLUE + "Iris is running Stable");
}
public static void unstable() {
UtilsSFG.printIncompatibleWarnings();
if (IrisSafeguard.unstablemode) {
Iris.info("");
Iris.info(C.DARK_GRAY + "--==<" + C.RED + " IMPORTANT " + C.DARK_GRAY + ">==--");
Iris.info(C.RED + "Iris is running in unstable mode which may cause the following issues:");
Iris.info(C.DARK_RED + "Server Issues");
Iris.info(C.RED + "- Server won't boot");
Iris.info(C.RED + "- Data Loss");
Iris.info(C.RED + "- Unexpected behavior.");
Iris.info(C.RED + "- And More...");
Iris.info(C.DARK_RED + "World Issues");
Iris.info(C.RED + "- Worlds can't load due to corruption.");
Iris.info(C.RED + "- Worlds may slowly corrupt until they can't load.");
Iris.info(C.RED + "- World data loss.");
Iris.info(C.RED + "- And More...");
Iris.info(C.DARK_RED + "ATTENTION: " + C.RED + "While running Iris in unstable mode, you won't be eligible for support.");
Iris.info(C.DARK_RED + "CAUSE: " + C.RED + UtilsSFG.MSGIncompatibleWarnings());
if (IrisSettings.get().getGeneral().DoomsdayAnnihilationSelfDestructMode) {
Iris.info(C.DARK_RED + "Boot Unstable is set to true, continuing with the startup process.");
} else {
Iris.info(C.DARK_RED + "Go to plugins/iris/settings.json and set DoomsdayAnnihilationSelfDestructMode to true if you wish to proceed.");
while (true) {
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
// no
}
}
}
Iris.info("");
}
}
public static void warning() {
UtilsSFG.printIncompatibleWarnings();
if (IrisSafeguard.warningmode) {
Iris.info("");
Iris.info(C.DARK_GRAY + "--==<" + C.GOLD + " IMPORTANT " + C.DARK_GRAY + ">==--");
Iris.info(C.GOLD + "Iris is running in warning mode which may cause the following issues:");
Iris.info(C.YELLOW + "- Data Loss");
Iris.info(C.YELLOW + "- Errors");
Iris.info(C.YELLOW + "- Broken worlds");
Iris.info(C.YELLOW + "- Unexpected behavior.");
Iris.info(C.YELLOW + "- And perhaps further complications.");
Iris.info(C.GOLD + "CAUSE: " + C.YELLOW + UtilsSFG.MSGIncompatibleWarnings());
Iris.info("");
}
}
}

View File

@@ -0,0 +1,8 @@
package com.volmit.iris.core.safeguard;
public class PerformanceSFG {
public static void calculatePerformance() {
}
}

View File

@@ -0,0 +1,176 @@
package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import com.volmit.iris.engine.object.IrisContextInjector;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import static com.volmit.iris.Iris.getJavaVersion;
import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
public class ServerBootSFG {
public static final Map<String, Boolean> incompatibilities = new HashMap<>();
public static boolean isCorrectJDK = true;
public static boolean hasEnoughDiskSpace = true;
public static boolean isJRE = false;
public static boolean hasPrivileges = true;
public static boolean unsuportedversion = false;
public static boolean missingDimensionTypes = false;
protected static boolean safeguardPassed;
public static boolean passedserversoftware = true;
protected static int count;
protected static byte severityLow;
protected static byte severityMedium;
protected static byte severityHigh;
public static String allIncompatibilities;
public static void BootCheck() {
Iris.info("Checking for possible conflicts..");
PluginManager pluginManager = Bukkit.getPluginManager();
Plugin[] plugins = pluginManager.getPlugins();
incompatibilities.clear();
incompatibilities.put("Multiverse-Core", false);
incompatibilities.put("dynmap", false);
incompatibilities.put("TerraformGenerator", false);
incompatibilities.put("Stratos", false);
String pluginName;
for (Plugin plugin : plugins) {
pluginName = plugin.getName();
Boolean flag = incompatibilities.get(pluginName);
if (flag != null && !flag) {
severityHigh++;
incompatibilities.put(pluginName, true);
}
}
StringJoiner joiner = new StringJoiner(", ");
for (Map.Entry<String, Boolean> entry : incompatibilities.entrySet()) {
if (entry.getValue()) {
joiner.add(entry.getKey());
}
}
// Legacy ServerInfo
String distro = Bukkit.getName().toLowerCase();
if (
!distro.contains("purpur") &&
!distro.contains("paper") &&
!distro.contains("spigot") &&
!distro.contains("pufferfish") &&
!distro.contains("bukkit")) {
passedserversoftware = false;
joiner.add("Server Software");
severityMedium++;
}
if (INMS.get() instanceof NMSBinding1X) {
unsuportedversion = true;
joiner.add("Unsupported Minecraft Version");
severityHigh++;
}
if (!List.of(21).contains(getJavaVersion())) {
isCorrectJDK = false;
joiner.add("Unsupported Java version");
severityMedium++;
}
if (!isJDK()) {
isJRE = true;
joiner.add("Unsupported JDK");
severityMedium++;
}
// if (!hasPrivileges()){
// hasPrivileges = false;
// joiner.add("Insufficient Privileges");
// severityMedium++;
// } Some servers dont like this
if (!enoughDiskSpace()){
hasEnoughDiskSpace = false;
joiner.add("Insufficient Disk Space");
severityMedium++;
}
if (IrisContextInjector.isMissingDimensionTypes()) {
missingDimensionTypes = true;
joiner.add("Missing Dimension Types");
severityHigh++;
}
allIncompatibilities = joiner.toString();
safeguardPassed = (severityHigh == 0 && severityMedium == 0 && severityLow == 0);
count = severityHigh + severityMedium + severityLow;
if (safeguardPassed) {
stablemode = true;
Iris.safeguard("Stable mode has been activated.");
}
if (!safeguardPassed) {
if (severityMedium >= 1 && severityHigh == 0) {
warningmode = true;
Iris.safeguard("Warning mode has been activated.");
}
if (severityHigh >= 1) {
unstablemode = true;
Iris.safeguard("Unstable mode has been activated.");
}
}
}
public static boolean isJDK() {
try {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// If the compiler is null, it means this is a JRE environment, not a JDK.
return compiler != null;
} catch (Exception ignored) {}
return false;
}
public static boolean hasPrivileges() {
Path pv = Paths.get(Bukkit.getWorldContainer() + "iristest.json");
try (FileChannel fc = FileChannel.open(pv, StandardOpenOption.CREATE, StandardOpenOption.DELETE_ON_CLOSE, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
if (Files.isReadable(pv) && Files.isWritable(pv)) {
return true;
}
} catch (Exception e) {
return false;
}
return false;
}
public static boolean enoughDiskSpace() {
File freeSpace = new File(Bukkit.getWorldContainer() + ".");
double gigabytes = freeSpace.getFreeSpace() / (1024.0 * 1024.0 * 1024.0);
if (gigabytes > 3){
return true;
} else {
return false;
}
}
private static boolean checkJavac(String path) {
return !path.isEmpty() && (new File(path, "javac").exists() || new File(path, "javac.exe").exists());
}
}

View File

@@ -0,0 +1,73 @@
package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris;
import com.volmit.iris.util.format.C;
public class UtilsSFG {
public static void splash() {
ModesSFG.selectMode();
}
public static void printIncompatibleWarnings() {
// String SupportedIrisVersion = getDescription().getVersion(); //todo Automatic version
if (ServerBootSFG.safeguardPassed) {
Iris.safeguard(C.BLUE + "0 Conflicts found");
} else {
if (IrisSafeguard.unstablemode) {
Iris.safeguard(C.DARK_RED + "" + ServerBootSFG.count + " Conflicts found");
}
if (IrisSafeguard.warningmode) {
Iris.safeguard(C.YELLOW + "" + ServerBootSFG.count + " Conflicts found");
}
if (ServerBootSFG.incompatibilities.get("Multiverse-Core")) {
Iris.safeguard(C.RED + "Multiverse");
Iris.safeguard(C.RED + "- The plugin Multiverse is not compatible with the server.");
Iris.safeguard(C.RED + "- If you want to have a world manager, consider using PhantomWorlds or MyWorlds instead.");
}
if (ServerBootSFG.incompatibilities.get("dynmap")) {
Iris.safeguard(C.RED + "Dynmap");
Iris.safeguard(C.RED + "- The plugin Dynmap is not compatible with the server.");
Iris.safeguard(C.RED + "- If you want to have a map plugin like Dynmap, consider Bluemap.");
}
if (ServerBootSFG.incompatibilities.get("TerraformGenerator") || ServerBootSFG.incompatibilities.get("Stratos")) {
Iris.safeguard(C.YELLOW + "Terraform Generator / Stratos");
Iris.safeguard(C.YELLOW + "- Iris is not compatible with other worldgen plugins.");
}
if (ServerBootSFG.unsuportedversion) {
Iris.safeguard(C.RED + "Server Version");
Iris.safeguard(C.RED + "- Iris only supports 1.20.1 > 1.21.4");
}
if (ServerBootSFG.missingDimensionTypes) {
Iris.safeguard(C.RED + "Dimension Types");
Iris.safeguard(C.RED + "- Required Iris dimension types were not loaded.");
Iris.safeguard(C.RED + "- If this still happens after a restart please contact support.");
}
if (!ServerBootSFG.passedserversoftware) {
Iris.safeguard(C.YELLOW + "Unsupported Server Software");
Iris.safeguard(C.YELLOW + "- Please consider using Paper or Purpur instead.");
}
if (!ServerBootSFG.hasPrivileges) {
Iris.safeguard(C.YELLOW + "Insufficient Privileges");
Iris.safeguard(C.YELLOW + "- The server has insufficient Privileges to run iris. Please contact support.");
}
if (!ServerBootSFG.hasEnoughDiskSpace) {
Iris.safeguard(C.YELLOW + "Insufficient Disk Space");
Iris.safeguard(C.YELLOW + "- The server has insufficient Free DiskSpace to run iris required 3GB+.");
}
if (!ServerBootSFG.isCorrectJDK) {
Iris.safeguard(C.YELLOW + "Unsupported java version");
Iris.safeguard(C.YELLOW + "- Please consider using JDK 21 Instead of JDK " + Iris.getJavaVersion());
}
if (ServerBootSFG.isJRE) {
Iris.safeguard(C.YELLOW + "Unsupported Server JDK");
Iris.safeguard(C.YELLOW + "- Please consider using JDK 21 Instead of JRE " + Iris.getJavaVersion());
}
}
}
public static String MSGIncompatibleWarnings() {
return ServerBootSFG.allIncompatibilities;
}
}

View File

@@ -1,30 +0,0 @@
package com.volmit.iris.core.scripting.environment;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.scripting.func.UpdateExecutor;
import com.volmit.iris.core.scripting.kotlin.environment.IrisExecutionEnvironment;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.mantle.MantleChunk;
import lombok.NonNull;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.Nullable;
public interface EngineEnvironment extends PackEnvironment {
static EngineEnvironment create(@NonNull Engine engine) {
return new IrisExecutionEnvironment(engine);
}
@NonNull
Engine getEngine();
@Nullable
Object spawnMob(@NonNull String script, @NonNull Location location);
void postSpawnMob(@NonNull String script, @NonNull Location location, @NonNull Entity mob);
void preprocessObject(@NonNull String script, @NonNull IrisRegistrant object);
void updateChunk(@NonNull String script, @NonNull MantleChunk mantleChunk, @NonNull Chunk chunk, @NonNull UpdateExecutor executor);
}

View File

@@ -1,22 +0,0 @@
package com.volmit.iris.core.scripting.environment;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.scripting.kotlin.environment.IrisPackExecutionEnvironment;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.math.RNG;
import lombok.NonNull;
import org.jetbrains.annotations.Nullable;
public interface PackEnvironment extends SimpleEnvironment {
static PackEnvironment create(@NonNull IrisData data) {
return new IrisPackExecutionEnvironment(data);
}
@NonNull
IrisData getData();
@Nullable
Object createNoise(@NonNull String script, @NonNull RNG rng);
EngineEnvironment with(@NonNull Engine engine);
}

View File

@@ -1,30 +0,0 @@
package com.volmit.iris.core.scripting.environment;
import com.volmit.iris.core.scripting.kotlin.environment.IrisSimpleExecutionEnvironment;
import lombok.NonNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Map;
public interface SimpleEnvironment {
static SimpleEnvironment create() {
return new IrisSimpleExecutionEnvironment();
}
static SimpleEnvironment create(@NonNull File projectDir) {
return new IrisSimpleExecutionEnvironment(projectDir);
}
void configureProject();
void execute(@NonNull String script);
void execute(@NonNull String script, @NonNull Class<?> type, @Nullable Map<@NonNull String, Object> vars);
@Nullable
Object evaluate(@NonNull String script);
@Nullable
Object evaluate(@NonNull String script, @NonNull Class<?> type, @Nullable Map<@NonNull String, Object> vars);
}

View File

@@ -1,10 +0,0 @@
package com.volmit.iris.core.scripting.func;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.documentation.BlockCoordinates;
@FunctionalInterface
public interface BiomeLookup {
@BlockCoordinates
IrisBiome at(int x, int z);
}

View File

@@ -1,22 +0,0 @@
package com.volmit.iris.core.scripting.func;
import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface UpdateExecutor {
@NotNull Runnable wrap(int delay, @NotNull Runnable runnable);
@NotNull
default Runnable wrap(@NotNull Runnable runnable) {
return wrap(1, runnable);
}
default void execute(@NotNull Runnable runnable) {
execute(1, runnable);
}
default void execute(int delay, @NotNull Runnable runnable) {
wrap(delay, runnable).run();
}
}

View File

@@ -22,39 +22,33 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.board.BoardManager;
import com.volmit.iris.util.board.BoardProvider;
import com.volmit.iris.util.board.BoardSettings;
import com.volmit.iris.util.board.ScoreDirection;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.J;
import lombok.Data;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.CopyOnWriteArrayList;
public class BoardSVC implements IrisService, BoardProvider {
private final KMap<Player, PlayerBoard> boards = new KMap<>();
private ScheduledExecutorService executor;
private BoardManager manager;
private com.volmit.iris.util.board.BoardManager manager;
@Override
public void onEnable() {
executor = Executors.newScheduledThreadPool(0, Thread.ofVirtual().factory());
J.ar(this::tick, 20);
manager = new BoardManager(Iris.instance, BoardSettings.builder()
.boardProvider(this)
.scoreDirection(ScoreDirection.DOWN)
@@ -63,7 +57,6 @@ public class BoardSVC implements IrisService, BoardProvider {
@Override
public void onDisable() {
executor.shutdownNow();
manager.onDisable();
boards.clear();
}
@@ -78,22 +71,14 @@ public class BoardSVC implements IrisService, BoardProvider {
J.s(() -> updatePlayer(e.getPlayer()));
}
@EventHandler
public void on(PlayerQuitEvent e) {
remove(e.getPlayer());
}
public void updatePlayer(Player p) {
if (IrisToolbelt.isIrisStudioWorld(p.getWorld())) {
manager.remove(p);
manager.setup(p);
} else remove(p);
}
private void remove(Player player) {
manager.remove(player);
var board = boards.remove(player);
if (board != null) board.task.cancel(true);
} else {
manager.remove(p);
boards.remove(p);
}
}
@Override
@@ -101,63 +86,73 @@ public class BoardSVC implements IrisService, BoardProvider {
return C.GREEN + "Iris";
}
public void tick() {
if (!Iris.service(StudioSVC.class).isProjectOpen()) {
return;
}
boards.forEach((k, v) -> v.update());
}
@Override
public List<String> getLines(Player player) {
return boards.computeIfAbsent(player, PlayerBoard::new).lines;
PlayerBoard pb = boards.computeIfAbsent(player, PlayerBoard::new);
synchronized (pb.lines) {
return pb.lines;
}
}
@Data
public class PlayerBoard {
public static class PlayerBoard {
private final Player player;
private final ScheduledFuture<?> task;
private volatile List<String> lines;
private final CopyOnWriteArrayList<String> lines;
public PlayerBoard(Player player) {
this.player = player;
this.lines = new ArrayList<>();
this.task = executor.scheduleAtFixedRate(this::tick, 0, 1, TimeUnit.SECONDS);
}
private void tick() {
if (!Iris.service(StudioSVC.class).isProjectOpen()) {
return;
}
this.lines = new CopyOnWriteArrayList<>();
update();
}
public void update() {
final World world = player.getWorld();
final Location loc = player.getLocation();
synchronized (lines) {
lines.clear();
final var access = IrisToolbelt.access(world);
if (access == null) return;
if (!IrisToolbelt.isIrisStudioWorld(player.getWorld())) {
return;
}
final var engine = access.getEngine();
if (engine == null) return;
Engine engine = IrisToolbelt.access(player.getWorld()).getEngine();
int x = player.getLocation().getBlockX();
int y = player.getLocation().getBlockY() - player.getWorld().getMinHeight();
int z = player.getLocation().getBlockZ();
int x = loc.getBlockX();
int y = loc.getBlockY() - world.getMinHeight();
int z = loc.getBlockZ();
List<String> lines = new ArrayList<>(this.lines.size());
lines.add("&7&m ");
lines.add(C.GREEN + "Speed" + C.GRAY + ": " + Form.f(engine.getGeneratedPerSecond(), 0) + "/s " + Form.duration(1000D / engine.getGeneratedPerSecond(), 0));
lines.add(C.AQUA + "Cache" + C.GRAY + ": " + Form.f(IrisData.cacheSize()));
lines.add(C.AQUA + "Mantle" + C.GRAY + ": " + engine.getMantle().getLoadedRegionCount());
if (IrisSettings.get().getGeneral().debug) {
lines.add(C.LIGHT_PURPLE + "Carving" + C.GRAY + ": " + engine.getMantle().isCarved(x,y,z));
if(IrisSettings.get().getGeneral().debug){
lines.add("&7&m ");
lines.add(C.GREEN + "Speed" + C.GRAY + ": " + Form.f(engine.getGeneratedPerSecond(), 0) + "/s " + Form.duration(1000D / engine.getGeneratedPerSecond(), 0));
lines.add(C.AQUA + "Cache" + C.GRAY + ": " + Form.f(IrisData.cacheSize()));
lines.add(C.AQUA + "Mantle" + C.GRAY + ": " + engine.getMantle().getLoadedRegionCount());
lines.add(C.LIGHT_PURPLE + "Carving" + C.GRAY + ": " + engine.getMantle().isCarved(x,y,z));
lines.add("&7&m ");
lines.add(C.AQUA + "Region" + C.GRAY + ": " + engine.getRegion(x, z).getName());
lines.add(C.AQUA + "Biome" + C.GRAY + ": " + engine.getBiomeOrMantle(x, y, z).getName());
lines.add(C.AQUA + "Height" + C.GRAY + ": " + Math.round(engine.getHeight(x, z)));
lines.add(C.AQUA + "Slope" + C.GRAY + ": " + Form.f(engine.getComplex().getSlopeStream().get(x, z), 2));
lines.add(C.AQUA + "BUD/s" + C.GRAY + ": " + Form.f(engine.getBlockUpdatesPerSecond()));
lines.add("&7&m ");
} else {
lines.add("&7&m ");
lines.add(C.GREEN + "Speed" + C.GRAY + ": " + Form.f(engine.getGeneratedPerSecond(), 0) + "/s " + Form.duration(1000D / engine.getGeneratedPerSecond(), 0));
lines.add(C.AQUA + "Cache" + C.GRAY + ": " + Form.f(IrisData.cacheSize()));
lines.add(C.AQUA + "Mantle" + C.GRAY + ": " + engine.getMantle().getLoadedRegionCount());
lines.add("&7&m ");
lines.add(C.AQUA + "Region" + C.GRAY + ": " + engine.getRegion(x, z).getName());
lines.add(C.AQUA + "Biome" + C.GRAY + ": " + engine.getBiomeOrMantle(x, y, z).getName());
lines.add(C.AQUA + "Height" + C.GRAY + ": " + Math.round(engine.getHeight(x, z)));
lines.add(C.AQUA + "Slope" + C.GRAY + ": " + Form.f(engine.getComplex().getSlopeStream().get(x, z), 2));
lines.add(C.AQUA + "BUD/s" + C.GRAY + ": " + Form.f(engine.getBlockUpdatesPerSecond()));
lines.add("&7&m ");
}
}
lines.add("&7&m ");
lines.add(C.AQUA + "Region" + C.GRAY + ": " + engine.getRegion(x, z).getName());
lines.add(C.AQUA + "Biome" + C.GRAY + ": " + engine.getBiomeOrMantle(x, y, z).getName());
lines.add(C.AQUA + "Height" + C.GRAY + ": " + Math.round(engine.getHeight(x, z)));
lines.add(C.AQUA + "Slope" + C.GRAY + ": " + Form.f(engine.getComplex().getSlopeStream().get(x, z), 2));
lines.add(C.AQUA + "BUD/s" + C.GRAY + ": " + Form.f(engine.getBlockUpdatesPerSecond()));
lines.add("&7&m ");
this.lines = lines;
}
}
}

View File

@@ -23,7 +23,6 @@ import com.volmit.iris.core.commands.CommandIris;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeContext;
import com.volmit.iris.util.decree.DecreeSystem;
import com.volmit.iris.util.decree.virtual.VirtualDecreeCommand;
import com.volmit.iris.util.format.C;
@@ -45,14 +44,7 @@ public class CommandSVC implements IrisService, DecreeSystem {
@Override
public void onEnable() {
Iris.instance.getCommand("iris").setExecutor(this);
J.a(() -> {
DecreeContext.touch(Iris.getSender());
try {
getRoot().cacheAll();
} finally {
DecreeContext.remove();
}
});
J.a(() -> getRoot().cacheAll());
}
@Override

View File

@@ -20,22 +20,16 @@ package com.volmit.iris.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.*;
import com.volmit.iris.core.link.data.DataType;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.io.JarScanner;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.J;
import lombok.Data;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.inventory.ItemStack;
@@ -53,12 +47,39 @@ public class ExternalDataSVC implements IrisService {
Iris.info("Loading ExternalDataProvider...");
Bukkit.getPluginManager().registerEvents(this, Iris.instance);
providers.addAll(createProviders());
providers.add(new NexoDataProvider());
if (Bukkit.getPluginManager().getPlugin("Nexo") != null) {
Iris.info("Nexo found, loading NexoDataProvider...");
}
providers.add(new MythicCrucibleDataProvider());
if (Bukkit.getPluginManager().getPlugin("MythicCrucible") != null) {
Iris.info("MythicCrucible found, loading MythicCrucibleDataProvider...");
}
providers.add(new ItemAdderDataProvider());
if (Bukkit.getPluginManager().getPlugin("ItemAdder") != null) {
Iris.info("ItemAdder found, loading ItemAdderDataProvider...");
}
providers.add(new ExecutableItemsDataProvider());
if (Bukkit.getPluginManager().getPlugin("ExecutableItems") != null) {
Iris.info("ExecutableItems found, loading ExecutableItemsDataProvider...");
}
providers.add(new HMCLeavesDataProvider());
if (Bukkit.getPluginManager().getPlugin("HMCLeaves") != null) {
Iris.info("BlockAdder found, loading HMCLeavesDataProvider...");
}
providers.add(new MMOItemsDataProvider());
if (Bukkit.getPluginManager().getPlugin("MMOItems") != null) {
Iris.info("MMOItems found, loading MMOItemsDataProvider...");
}
providers.add(new EcoItemsDataProvider());
if (Bukkit.getPluginManager().getPlugin("EcoItems") != null) {
Iris.info("EcoItems found, loading EcoItemsDataProvider...");
}
for (ExternalDataProvider p : providers) {
if (p.isReady()) {
activeProviders.add(p);
p.init();
Iris.instance.registerListener(p);
Iris.info("Enabled ExternalDataProvider for %s.", p.getPluginId());
}
}
@@ -70,11 +91,10 @@ public class ExternalDataSVC implements IrisService {
@EventHandler
public void onPluginEnable(PluginEnableEvent e) {
if (activeProviders.stream().noneMatch(p -> e.getPlugin().equals(p.getPlugin()))) {
providers.stream().filter(p -> p.isReady() && e.getPlugin().equals(p.getPlugin())).findFirst().ifPresent(edp -> {
if (activeProviders.stream().noneMatch(p -> p.getPlugin().equals(e.getPlugin()))) {
providers.stream().filter(p -> p.isReady() && p.getPlugin().equals(e.getPlugin())).findFirst().ifPresent(edp -> {
activeProviders.add(edp);
edp.init();
Iris.instance.registerListener(edp);
Iris.info("Enabled ExternalDataProvider for %s.", edp.getPluginId());
});
}
@@ -89,7 +109,6 @@ public class ExternalDataSVC implements IrisService {
if (provider.isReady()) {
activeProviders.add(provider);
provider.init();
Iris.instance.registerListener(provider);
}
}
@@ -97,7 +116,7 @@ public class ExternalDataSVC implements IrisService {
var pair = parseState(key);
Identifier mod = pair.getA();
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(mod, DataType.BLOCK)).findFirst();
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(mod, false)).findFirst();
if (provider.isEmpty())
return Optional.empty();
try {
@@ -108,20 +127,8 @@ public class ExternalDataSVC implements IrisService {
}
}
public Optional<List<BlockProperty>> getBlockProperties(final Identifier key) {
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(key, DataType.BLOCK)).findFirst();
if (provider.isEmpty())
return Optional.empty();
try {
return Optional.of(provider.get().getBlockProperties(key));
} catch (MissingResourceException e) {
Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]");
return Optional.empty();
}
}
public Optional<ItemStack> getItemStack(Identifier key, KMap<String, Object> customNbt) {
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(key, DataType.ITEM)).findFirst();
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(key, true)).findFirst();
if (provider.isEmpty()) {
Iris.warn("No matching Provider found for modded material \"%s\"!", key);
return Optional.empty();
@@ -135,7 +142,7 @@ public class ExternalDataSVC implements IrisService {
}
public void processUpdate(Engine engine, Block block, Identifier blockId) {
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(blockId, DataType.BLOCK)).findFirst();
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(blockId, false)).findFirst();
if (provider.isEmpty()) {
Iris.warn("No matching Provider found for modded material \"%s\"!", blockId);
return;
@@ -143,32 +150,16 @@ public class ExternalDataSVC implements IrisService {
provider.get().processUpdate(engine, block, blockId);
}
public Entity spawnMob(Location location, Identifier mobId) {
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(mobId, DataType.ENTITY)).findFirst();
if (provider.isEmpty()) {
Iris.warn("No matching Provider found for modded mob \"%s\"!", mobId);
return null;
}
try {
return provider.get().spawnMob(location, mobId);
} catch (MissingResourceException e) {
Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]");
return null;
}
public Identifier[] getAllBlockIdentifiers() {
KList<Identifier> names = new KList<>();
activeProviders.forEach(p -> names.add(p.getBlockTypes()));
return names.toArray(new Identifier[0]);
}
public Collection<Identifier> getAllIdentifiers(DataType dataType) {
return activeProviders.stream()
.flatMap(p -> p.getTypes(dataType).stream())
.toList();
}
public Collection<Pair<Identifier, List<BlockProperty>>> getAllBlockProperties() {
return activeProviders.stream()
.flatMap(p -> p.getTypes(DataType.BLOCK)
.stream()
.map(id -> new Pair<>(id, p.getBlockProperties(id))))
.toList();
public Identifier[] getAllItemIdentifiers() {
KList<Identifier> names = new KList<>();
activeProviders.forEach(p -> names.add(p.getItemTypes()));
return names.toArray(new Identifier[0]);
}
public static Pair<Identifier, KMap<String, String>> parseState(Identifier key) {
@@ -193,21 +184,4 @@ public class ExternalDataSVC implements IrisService {
.collect(Collectors.joining(",", key.key() + "[", "]"));
return new Identifier(key.namespace(), path);
}
private static KList<ExternalDataProvider> createProviders() {
JarScanner jar = new JarScanner(Iris.instance.getJarFile(), "com.volmit.iris.core.link.data", false);
J.attempt(jar::scan);
KList<ExternalDataProvider> providers = new KList<>();
for (Class<?> c : jar.getClasses()) {
if (ExternalDataProvider.class.isAssignableFrom(c)) {
try {
ExternalDataProvider p = (ExternalDataProvider) c.getDeclaredConstructor().newInstance();
if (p.getPlugin() != null) Iris.info(p.getPluginId() + " found, loading " + c.getSimpleName() + "...");
providers.add(p);
} catch (Throwable ignored) {}
}
}
return providers;
}
}

View File

@@ -1,136 +0,0 @@
package com.volmit.iris.core.service;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.cache.PregenCache;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.Looper;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.function.Function;
public class GlobalCacheSVC implements IrisService {
private static final KMap<String, Reference<PregenCache>> REFERENCE_CACHE = new KMap<>();
private final KMap<String, PregenCache> globalCache = new KMap<>();
private transient boolean lastState;
private static boolean disabled = true;
private Looper trimmer;
@Override
public void onEnable() {
disabled = false;
trimmer = new Looper() {
@Override
protected long loop() {
var it = REFERENCE_CACHE.values().iterator();
while (it.hasNext()) {
var cache = it.next().get();
if (cache == null) it.remove();
else cache.trim(10_000);
}
return disabled ? -1 : 2_000;
}
};
trimmer.start();
lastState = !IrisSettings.get().getWorld().isGlobalPregenCache();
if (lastState) return;
Bukkit.getWorlds().forEach(this::createCache);
}
@Override
public void onDisable() {
disabled = true;
try {
trimmer.join();
} catch (InterruptedException ignored) {}
globalCache.qclear((world, cache) -> cache.write());
}
@Nullable
public PregenCache get(@NonNull World world) {
return globalCache.get(world.getName());
}
@Nullable
public PregenCache get(@NonNull String world) {
return globalCache.get(world);
}
@EventHandler(priority = EventPriority.MONITOR)
public void on(WorldInitEvent event) {
if (isDisabled()) return;
createCache(event.getWorld());
}
@EventHandler(priority = EventPriority.MONITOR)
public void on(WorldUnloadEvent event) {
var cache = globalCache.remove(event.getWorld().getName());
if (cache == null) return;
cache.write();
}
@EventHandler(priority = EventPriority.MONITOR)
public void on(ChunkLoadEvent event) {
var cache = get(event.getWorld());
if (cache == null) return;
cache.cacheChunk(event.getChunk().getX(), event.getChunk().getZ());
}
private void createCache(World world) {
if (!IrisToolbelt.isIrisWorld(world)) return;
globalCache.computeIfAbsent(world.getName(), GlobalCacheSVC::createDefault);
}
private boolean isDisabled() {
boolean conf = IrisSettings.get().getWorld().isGlobalPregenCache();
if (lastState != conf)
return lastState;
if (conf) {
Bukkit.getWorlds().forEach(this::createCache);
} else {
globalCache.values().removeIf(cache -> {
cache.write();
return true;
});
}
return lastState = !conf;
}
@NonNull
public static PregenCache createCache(@NonNull String worldName, @NonNull Function<String, PregenCache> provider) {
PregenCache[] holder = new PregenCache[1];
REFERENCE_CACHE.compute(worldName, (name, ref) -> {
if (ref != null) {
if ((holder[0] = ref.get()) != null)
return ref;
}
return new WeakReference<>(holder[0] = provider.apply(worldName));
});
return holder[0];
}
@NonNull
public static PregenCache createDefault(@NonNull String worldName) {
return createCache(worldName, GlobalCacheSVC::createDefault0);
}
private static PregenCache createDefault0(String worldName) {
if (disabled) return PregenCache.EMPTY;
return PregenCache.create(new File(Bukkit.getWorldContainer(), String.join(File.separator, worldName, "iris", "pregen"))).sync();
}
}

View File

@@ -1,277 +1,317 @@
package com.volmit.iris.core.service;
import com.google.common.util.concurrent.AtomicDouble;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.mantle.TectonicPlate;
import com.volmit.iris.util.misc.getHardware;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.Looper;
import com.volmit.iris.util.stream.utility.CachedStream2D;
import com.volmit.iris.util.stream.utility.CachedStream3D;
import lombok.Synchronized;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.ServerLoadEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.jetbrains.annotations.Nullable;
import org.checkerframework.checker.units.qual.A;
import java.util.concurrent.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
public class IrisEngineSVC implements IrisService {
private static final int TRIM_PERIOD = 2_000;
private final AtomicInteger tectonicLimit = new AtomicInteger(30);
private final AtomicInteger tectonicPlates = new AtomicInteger();
private final AtomicInteger queuedTectonicPlates = new AtomicInteger();
private final AtomicInteger trimmerAlive = new AtomicInteger();
private final AtomicInteger unloaderAlive = new AtomicInteger();
private final AtomicInteger totalWorlds = new AtomicInteger();
private final AtomicDouble maxIdleDuration = new AtomicDouble();
private final AtomicDouble minIdleDuration = new AtomicDouble();
private final AtomicLong loadedChunks = new AtomicLong();
private final KMap<World, Registered> worlds = new KMap<>();
private ScheduledExecutorService service;
public static IrisEngineSVC instance;
public boolean isServerShuttingDown = false;
public boolean isServerLoaded = false;
private static final AtomicInteger tectonicLimit = new AtomicInteger(30);
private ReentrantLock lastUseLock;
private KMap<World, Long> lastUse;
private List<World> IrisWorlds;
private Looper cacheTicker;
private Looper trimTicker;
private Looper unloadTicker;
private Looper updateTicker;
private PrecisionStopwatch trimAlive;
private PrecisionStopwatch unloadAlive;
public PrecisionStopwatch trimActiveAlive;
public PrecisionStopwatch unloadActiveAlive;
private AtomicInteger TotalTectonicPlates;
private AtomicInteger TotalQueuedTectonicPlates;
private AtomicInteger TotalNotQueuedTectonicPlates;
private AtomicBoolean IsUnloadAlive;
private AtomicBoolean IsTrimAlive;
ChronoLatch cl;
public List<World> corruptedIrisWorlds = new ArrayList<>();
@Override
public void onEnable() {
var settings = IrisSettings.get().getPerformance();
var engine = settings.getEngineSVC();
service = Executors.newScheduledThreadPool(0,
(engine.isUseVirtualThreads()
? Thread.ofVirtual()
: Thread.ofPlatform().priority(engine.getPriority()))
.name("Iris EngineSVC-", 0)
.factory());
tectonicLimit.set(settings.getTectonicPlateSize());
Bukkit.getWorlds().forEach(this::add);
setup();
}
@Override
public void onDisable() {
service.shutdown();
updateTicker.interrupt();
worlds.keySet().forEach(this::remove);
worlds.clear();
}
public void engineStatus(VolmitSender sender) {
long[] sizes = new long[4];
long[] count = new long[4];
for (var cache : Iris.service(PreservationSVC.class).getCaches()) {
var type = switch (cache) {
case ResourceLoader<?> ignored -> 0;
case CachedStream2D<?> ignored -> 1;
case CachedStream3D<?> ignored -> 2;
default -> 3;
};
sizes[type] += cache.getSize();
count[type]++;
this.cl = new ChronoLatch(5000);
lastUse = new KMap<>();
lastUseLock = new ReentrantLock();
IrisWorlds = new ArrayList<>();
IsUnloadAlive = new AtomicBoolean(true);
IsTrimAlive = new AtomicBoolean(true);
trimActiveAlive = new PrecisionStopwatch();
unloadActiveAlive = new PrecisionStopwatch();
trimAlive = new PrecisionStopwatch();
unloadAlive = new PrecisionStopwatch();
TotalTectonicPlates = new AtomicInteger();
TotalQueuedTectonicPlates = new AtomicInteger();
TotalNotQueuedTectonicPlates = new AtomicInteger();
tectonicLimit.set(2);
long t = getHardware.getProcessMemory();
while (t > 200) {
tectonicLimit.getAndAdd(1);
t = t - 200;
}
this.setup();
this.TrimLogic();
this.UnloadLogic();
sender.sendMessage(C.DARK_PURPLE + "-------------------------");
sender.sendMessage(C.DARK_PURPLE + "Status:");
sender.sendMessage(C.DARK_PURPLE + "- Service: " + C.LIGHT_PURPLE + (service.isShutdown() ? "Shutdown" : "Running"));
sender.sendMessage(C.DARK_PURPLE + "- Updater: " + C.LIGHT_PURPLE + (updateTicker.isAlive() ? "Running" : "Stopped"));
sender.sendMessage(C.DARK_PURPLE + "- Period: " + C.LIGHT_PURPLE + Form.duration(TRIM_PERIOD));
sender.sendMessage(C.DARK_PURPLE + "- Trimmers: " + C.LIGHT_PURPLE + trimmerAlive.get());
sender.sendMessage(C.DARK_PURPLE + "- Unloaders: " + C.LIGHT_PURPLE + unloaderAlive.get());
sender.sendMessage(C.DARK_PURPLE + "Tectonic Plates:");
sender.sendMessage(C.DARK_PURPLE + "- Limit: " + C.LIGHT_PURPLE + tectonicLimit.get());
sender.sendMessage(C.DARK_PURPLE + "- Total: " + C.LIGHT_PURPLE + tectonicPlates.get());
sender.sendMessage(C.DARK_PURPLE + "- Queued: " + C.LIGHT_PURPLE + queuedTectonicPlates.get());
sender.sendMessage(C.DARK_PURPLE + "- Max Idle Duration: " + C.LIGHT_PURPLE + Form.duration(maxIdleDuration.get(), 2));
sender.sendMessage(C.DARK_PURPLE + "- Min Idle Duration: " + C.LIGHT_PURPLE + Form.duration(minIdleDuration.get(), 2));
sender.sendMessage(C.DARK_PURPLE + "Caches:");
sender.sendMessage(C.DARK_PURPLE + "- Resource: " + C.LIGHT_PURPLE + sizes[0] + " (" + count[0] + ")");
sender.sendMessage(C.DARK_PURPLE + "- 2D Stream: " + C.LIGHT_PURPLE + sizes[1] + " (" + count[1] + ")");
sender.sendMessage(C.DARK_PURPLE + "- 3D Stream: " + C.LIGHT_PURPLE + sizes[2] + " (" + count[2] + ")");
sender.sendMessage(C.DARK_PURPLE + "- Other: " + C.LIGHT_PURPLE + sizes[3] + " (" + count[3] + ")");
sender.sendMessage(C.DARK_PURPLE + "Other:");
sender.sendMessage(C.DARK_PURPLE + "- Iris Worlds: " + C.LIGHT_PURPLE + totalWorlds.get());
sender.sendMessage(C.DARK_PURPLE + "- Loaded Chunks: " + C.LIGHT_PURPLE + loadedChunks.get());
sender.sendMessage(C.DARK_PURPLE + "-------------------------");
trimAlive.begin();
unloadAlive.begin();
trimActiveAlive.begin();
unloadActiveAlive.begin();
updateTicker.start();
cacheTicker.start();
//trimTicker.start();
//unloadTicker.start();
instance = this;
}
public void engineStatus() {
boolean trimAlive = trimTicker.isAlive();
boolean unloadAlive = unloadTicker.isAlive();
Iris.info("Status:");
Iris.info("- Trim: " + trimAlive);
Iris.info("- Unload: " + unloadAlive);
}
public static int getTectonicLimit() {
return tectonicLimit.get();
}
@EventHandler
public void onWorldUnload(WorldUnloadEvent event) {
remove(event.getWorld());
updateWorlds();
}
@EventHandler
public void onWorldLoad(WorldLoadEvent event) {
add(event.getWorld());
updateWorlds();
}
private void remove(World world) {
var entry = worlds.remove(world);
if (entry == null) return;
entry.close();
@EventHandler
public void onServerBoot(ServerLoadEvent event) {
isServerLoaded = true;
}
private void add(World world) {
var access = IrisToolbelt.access(world);
if (access == null) return;
worlds.put(world, new Registered(world.getName(), access));
@EventHandler
public void onPluginDisable(PluginDisableEvent event) {
if (event.getPlugin().equals(Iris.instance)) {
isServerShuttingDown = true;
}
}
private synchronized void setup() {
if (updateTicker != null && updateTicker.isAlive())
return;
public void updateWorlds() {
for (World world : Bukkit.getWorlds()) {
try {
if (IrisToolbelt.access(world).getEngine() != null) {
IrisWorlds.add(world);
}
} catch (Exception e) {
// no
}
}
}
private void setup() {
cacheTicker = new Looper() {
@Override
protected long loop() {
long now = System.currentTimeMillis();
lastUseLock.lock();
try {
for (World key : new ArrayList<>(lastUse.keySet())) {
Long last = lastUse.get(key);
if (last == null)
continue;
if (now - last > 60000) {
lastUse.remove(key);
}
}
} finally {
lastUseLock.unlock();
}
return 1000;
}
};
updateTicker = new Looper() {
@Override
protected long loop() {
try {
int queuedPlates = 0;
int totalPlates = 0;
long chunks = 0;
int unloaders = 0;
int trimmers = 0;
int iris = 0;
TotalQueuedTectonicPlates.set(0);
TotalNotQueuedTectonicPlates.set(0);
TotalTectonicPlates.set(0);
for (World world : IrisWorlds) {
Engine engine = Objects.requireNonNull(IrisToolbelt.access(world)).getEngine();
TotalQueuedTectonicPlates.addAndGet((int) engine.getMantle().getToUnload());
TotalNotQueuedTectonicPlates.addAndGet((int) engine.getMantle().getNotQueuedLoadedRegions());
TotalTectonicPlates.addAndGet(engine.getMantle().getLoadedRegionCount());
}
if (!isServerShuttingDown && isServerLoaded) {
if (!trimTicker.isAlive()) {
Iris.info(C.RED + "TrimTicker found dead! Booting it up!");
try {
TrimLogic();
} catch (Exception e) {
Iris.error("What happened?");
e.printStackTrace();
}
}
double maxDuration = Long.MIN_VALUE;
double minDuration = Long.MAX_VALUE;
for (var entry : worlds.entrySet()) {
var registered = entry.getValue();
if (registered.closed) continue;
iris++;
if (registered.unloaderAlive()) unloaders++;
if (registered.trimmerAlive()) trimmers++;
var engine = registered.getEngine();
if (engine == null) continue;
queuedPlates += engine.getMantle().getUnloadRegionCount();
totalPlates += engine.getMantle().getLoadedRegionCount();
chunks += entry.getKey().getLoadedChunks().length;
double duration = engine.getMantle().getAdjustedIdleDuration();
if (duration > maxDuration) maxDuration = duration;
if (duration < minDuration) minDuration = duration;
if (!unloadTicker.isAlive()) {
Iris.info(C.RED + "UnloadTicker found dead! Booting it up!");
try {
UnloadLogic();
} catch (Exception e) {
Iris.error("What happened?");
e.printStackTrace();
}
}
}
trimmerAlive.set(trimmers);
unloaderAlive.set(unloaders);
tectonicPlates.set(totalPlates);
queuedTectonicPlates.set(queuedPlates);
maxIdleDuration.set(maxDuration);
minIdleDuration.set(minDuration);
loadedChunks.set(chunks);
totalWorlds.set(iris);
worlds.values().forEach(Registered::update);
} catch (Throwable e) {
e.printStackTrace();
} catch (Exception e) {
return -1;
}
return 1000;
}
};
updateTicker.start();
}
public void TrimLogic() {
if (trimTicker == null || !trimTicker.isAlive()) {
trimTicker = new Looper() {
private final Supplier<Engine> supplier = createSupplier();
private final class Registered {
private final String name;
private final PlatformChunkGenerator access;
private final int offset = RNG.r.nextInt(TRIM_PERIOD);
private transient ScheduledFuture<?> trimmer;
private transient ScheduledFuture<?> unloader;
private transient boolean closed;
private Registered(String name, PlatformChunkGenerator access) {
this.name = name;
this.access = access;
update();
}
private boolean unloaderAlive() {
return unloader != null && !unloader.isDone() && !unloader.isCancelled();
}
private boolean trimmerAlive() {
return trimmer != null && !trimmer.isDone() && !trimmer.isCancelled();
}
@Synchronized
private void update() {
if (closed || service == null || service.isShutdown())
return;
if (trimmer == null || trimmer.isDone() || trimmer.isCancelled()) {
trimmer = service.scheduleAtFixedRate(() -> {
Engine engine = getEngine();
if (engine == null || !engine.getMantle().getMantle().shouldReduce(engine))
return;
@Override
protected long loop() {
long start = System.currentTimeMillis();
trimAlive.reset();
try {
engine.getMantle().trim(tectonicLimit());
} catch (Throwable e) {
Iris.reportError(e);
Iris.error("EngineSVC: Failed to trim for " + name);
e.printStackTrace();
}
}, offset, TRIM_PERIOD, TimeUnit.MILLISECONDS);
}
if (unloader == null || unloader.isDone() || unloader.isCancelled()) {
unloader = service.scheduleAtFixedRate(() -> {
Engine engine = getEngine();
if (engine == null || !engine.getMantle().getMantle().shouldReduce(engine))
return;
try {
long unloadStart = System.currentTimeMillis();
int count = engine.getMantle().unloadTectonicPlate(IrisSettings.get().getPerformance().getEngineSVC().forceMulticoreWrite ? 0 : tectonicLimit());
if (count > 0) {
Iris.debug(C.GOLD + "Unloaded " + C.YELLOW + count + " TectonicPlates in " + C.RED + Form.duration(System.currentTimeMillis() - unloadStart, 2));
Engine engine = supplier.get();
if (engine != null) {
engine.getMantle().trim(tectonicLimit.get() / lastUse.size());
}
} catch (Throwable e) {
Iris.reportError(e);
Iris.error("EngineSVC: Failed to unload for " + name);
Iris.info(C.RED + "EngineSVC: Failed to trim.");
e.printStackTrace();
return -1;
}
}, offset + TRIM_PERIOD / 2, TRIM_PERIOD, TimeUnit.MILLISECONDS);
}
}
private int tectonicLimit() {
return tectonicLimit.get() / Math.max(worlds.size(), 1);
}
@Synchronized
private void close() {
if (closed) return;
closed = true;
if (trimmer != null) {
trimmer.cancel(false);
trimmer = null;
}
if (unloader != null) {
unloader.cancel(false);
unloader = null;
}
}
@Nullable
private Engine getEngine() {
if (closed) return null;
return access.getEngine();
int size = lastUse.size();
long time = (size > 0 ? 1000 / size : 1000) - (System.currentTimeMillis() - start);
if (time <= 0)
return 0;
return time;
}
};
trimTicker.start();
}
}
public void UnloadLogic() {
if (unloadTicker == null || !unloadTicker.isAlive()) {
unloadTicker = new Looper() {
private final Supplier<Engine> supplier = createSupplier();
@Override
protected long loop() {
long start = System.currentTimeMillis();
unloadAlive.reset();
try {
Engine engine = supplier.get();
if (engine != null) {
long unloadStart = System.currentTimeMillis();
int count = engine.getMantle().unloadTectonicPlate(tectonicLimit.get() / lastUse.size());
if (count > 0) {
Iris.debug(C.GOLD + "Unloaded " + C.YELLOW + count + " TectonicPlates in " + C.RED + Form.duration(System.currentTimeMillis() - unloadStart, 2));
}
}
} catch (Throwable e) {
Iris.reportError(e);
Iris.info(C.RED + "EngineSVC: Failed to unload.");
e.printStackTrace();
return -1;
}
int size = lastUse.size();
long time = (size > 0 ? 1000 / size : 1000) - (System.currentTimeMillis() - start);
if (time <= 0)
return 0;
return time;
}
};
unloadTicker.start();
}
}
private Supplier<Engine> createSupplier() {
AtomicInteger i = new AtomicInteger();
return () -> {
List<World> worlds = Bukkit.getWorlds();
if (i.get() >= worlds.size()) {
i.set(0);
}
try {
for (int j = 0; j < worlds.size(); j++) {
World world = worlds.get(i.getAndIncrement());
PlatformChunkGenerator generator = IrisToolbelt.access(world);
if (i.get() >= worlds.size()) {
i.set(0);
}
if (generator != null) {
Engine engine = generator.getEngine();
boolean closed = engine.getMantle().getData().isClosed();
if (engine != null && !engine.isStudio() && !closed) {
lastUseLock.lock();
lastUse.put(world, System.currentTimeMillis());
lastUseLock.unlock();
return engine;
}
}
}
} catch (Throwable e) {
Iris.info(C.RED + "EngineSVC: Failed to create supplier.");
e.printStackTrace();
Iris.reportError(e);
}
return null;
};
}
@Override
public void onDisable() {
cacheTicker.interrupt();
trimTicker.interrupt();
unloadTicker.interrupt();
lastUse.clear();
}
}

View File

@@ -24,45 +24,50 @@ import com.volmit.iris.engine.framework.MeteredCache;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.KCache;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.Looper;
import org.jetbrains.annotations.Unmodifiable;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class PreservationSVC implements IrisService {
private final List<Thread> threads = new CopyOnWriteArrayList<>();
private final List<ExecutorService> services = new CopyOnWriteArrayList<>();
private final List<WeakReference<MeteredCache>> caches = new CopyOnWriteArrayList<>();
private final List<MeteredCache> caches = new CopyOnWriteArrayList<>();
private Looper dereferencer;
public void register(Thread t) {
threads.add(t);
}
public void register(MultiBurst burst) {
}
public void register(ExecutorService service) {
services.add(service);
}
public void printCaches() {
var c = getCaches();
long s = 0;
long m = 0;
long s = caches.stream().filter(i -> !i.isClosed()).mapToLong(MeteredCache::getSize).sum();
long m = caches.stream().filter(i -> !i.isClosed()).mapToLong(MeteredCache::getMaxSize).sum();
double p = 0;
double mf = Math.max(c.size(), 1);
double mf = 0;
for (MeteredCache i : c) {
s += i.getSize();
m += i.getMaxSize();
for (MeteredCache i : caches) {
if (i.isClosed()) {
continue;
}
mf++;
p += i.getUsage();
}
mf = mf == 0 ? 1 : mf;
Iris.info("Cached " + Form.f(s) + " / " + Form.f(m) + " (" + Form.pc(p / mf) + ") from " + caches.size() + " Caches");
}
@@ -118,29 +123,14 @@ public class PreservationSVC implements IrisService {
}
public void updateCaches() {
caches.removeIf(ref -> {
var c = ref.get();
return c == null || c.isClosed();
});
caches.removeIf(MeteredCache::isClosed);
}
public void registerCache(MeteredCache cache) {
caches.add(new WeakReference<>(cache));
caches.add(cache);
}
public List<KCache<?, ?>> caches() {
return cacheStream().map(MeteredCache::getRawCache).collect(Collectors.toList());
}
@Unmodifiable
public List<MeteredCache> getCaches() {
return cacheStream().toList();
}
private Stream<MeteredCache> cacheStream() {
return caches.stream()
.map(WeakReference::get)
.filter(Objects::nonNull)
.filter(cache -> !cache.isClosed());
return caches.stream().map(MeteredCache::getRawCache).collect(Collectors.toList());
}
}

View File

@@ -18,6 +18,7 @@
package com.volmit.iris.core.service;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
@@ -88,18 +89,16 @@ public class StudioSVC implements IrisService {
}
public IrisDimension installIntoWorld(VolmitSender sender, String type, File folder) {
return installInto(sender, type, new File(folder, "iris/pack"));
}
public IrisDimension installInto(VolmitSender sender, String type, File folder) {
sender.sendMessage("Looking for Package: " + type);
IrisDimension dim = IrisData.loadAnyDimension(type, null);
File iris = new File(folder, "iris");
File irispack = new File(folder, "iris/pack");
IrisDimension dim = IrisData.loadAnyDimension(type);
if (dim == null) {
for (File i : getWorkspaceFolder().listFiles()) {
if (i.isFile() && i.getName().equals(type + ".iris")) {
sender.sendMessage("Found " + type + ".iris in " + WORKSPACE_NAME + " folder");
ZipUtil.unpack(i, folder);
ZipUtil.unpack(i, irispack);
break;
}
}
@@ -108,29 +107,29 @@ public class StudioSVC implements IrisService {
File f = new IrisProject(new File(getWorkspaceFolder(), type)).getPath();
try {
FileUtils.copyDirectory(f, folder);
FileUtils.copyDirectory(f, irispack);
} catch (IOException e) {
Iris.reportError(e);
}
}
File dimensionFile = new File(folder, "dimensions/" + type + ".json");
File dimf = new File(irispack, "dimensions/" + type + ".json");
if (!dimensionFile.exists() || !dimensionFile.isFile()) {
if (!dimf.exists() || !dimf.isFile()) {
downloadSearch(sender, type, false);
File downloaded = getWorkspaceFolder(type);
for (File i : downloaded.listFiles()) {
if (i.isFile()) {
try {
FileUtils.copyFile(i, new File(folder, i.getName()));
FileUtils.copyFile(i, new File(irispack, i.getName()));
} catch (IOException e) {
e.printStackTrace();
Iris.reportError(e);
}
} else {
try {
FileUtils.copyDirectory(i, new File(folder, i.getName()));
FileUtils.copyDirectory(i, new File(irispack, i.getName()));
} catch (IOException e) {
e.printStackTrace();
Iris.reportError(e);
@@ -141,13 +140,12 @@ public class StudioSVC implements IrisService {
IO.delete(downloaded);
}
if (!dimensionFile.exists() || !dimensionFile.isFile()) {
sender.sendMessage("Can't find the " + dimensionFile.getName() + " in the dimensions folder of this pack! Failed!");
if (!dimf.exists() || !dimf.isFile()) {
sender.sendMessage("Can't find the " + dimf.getName() + " in the dimensions folder of this pack! Failed!");
return null;
}
IrisData dm = IrisData.get(folder);
dm.hotloaded();
IrisData dm = IrisData.get(irispack);
dim = dm.getDimensionLoader().load(type);
if (dim == null) {
@@ -252,26 +250,30 @@ public class StudioSVC implements IrisService {
return;
}
IrisData data = IrisData.get(dir);
String[] dimensions = data.getDimensionLoader().getPossibleKeys();
File dimensions = new File(dir, "dimensions");
if (dimensions == null || dimensions.length == 0) {
if (!(dimensions.exists() && dimensions.isDirectory())) {
sender.sendMessage("Invalid Format. Missing dimensions folder");
return;
}
if (dimensions.listFiles() == null) {
sender.sendMessage("No dimension file found in the extracted zip file.");
sender.sendMessage("Check it is there on GitHub and report this to staff!");
} else if (dimensions.length != 1) {
} else if (dimensions.listFiles().length != 1) {
sender.sendMessage("Dimensions folder must have 1 file in it");
return;
}
IrisDimension d = data.getDimensionLoader().load(dimensions[0]);
data.close();
File dim = dimensions.listFiles()[0];
if (d == null) {
if (!dim.isFile()) {
sender.sendMessage("Invalid dimension (folder) in dimensions folder");
return;
}
String key = d.getLoadKey();
String key = dim.getName().split("\\Q.\\E")[0];
IrisDimension d = new Gson().fromJson(IO.readAll(dim), IrisDimension.class);
sender.sendMessage("Importing " + d.getName() + " (" + key + ")");
File packEntry = new File(packs, key);
@@ -279,7 +281,7 @@ public class StudioSVC implements IrisService {
IO.delete(packEntry);
}
if (IrisData.loadAnyDimension(key, null) != null) {
if (IrisData.loadAnyDimension(key) != null) {
sender.sendMessage("Another dimension in the packs folder is already using the key " + key + " IMPORT FAILED!");
return;
}
@@ -298,8 +300,6 @@ public class StudioSVC implements IrisService {
packEntry.mkdirs();
ZipUtil.unpack(cp, packEntry);
}
IrisData.getLoaded(packEntry)
.ifPresent(IrisData::hotloaded);
sender.sendMessage("Successfully Aquired " + d.getName());
ServerConfigurator.installDataPacks(true);

View File

@@ -189,16 +189,6 @@ public class TreeSVC implements IrisService {
}
@Override
public <T> void setData(int xx, int yy, int zz, T data) {
}
@Override
public <T> T getData(int xx, int yy, int zz, Class<T> t) {
return null;
}
@Override
public Engine getEngine() {
return engine;
@@ -235,7 +225,7 @@ public class TreeSVC implements IrisService {
if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase(), false);
Iris.service(ExternalDataSVC.class).processUpdate(engine, block, data.getCustom());
} else block.setBlockData(d, false);
} else block.setBlockData(d);
}
}
});

View File

@@ -51,7 +51,6 @@ 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;
@@ -81,8 +80,6 @@ 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());
@@ -90,7 +87,6 @@ public class WandSVC implements IrisService {
int total = c.getSizeX() * c.getSizeY() * c.getSizeZ();
var latch = new CountDownLatch(1);
var holder = Iris.tickets.getHolder(p.getWorld());
new Job() {
private int i;
private Chunk chunk;
@@ -109,7 +105,7 @@ public class WandSVC implements IrisService {
while (time > M.ms()) {
if (!it.hasNext()) {
if (chunk != null) {
holder.removeTicket(chunk);
chunk.removePluginChunkTicket(Iris.instance);
chunk = null;
}
@@ -123,10 +119,9 @@ public class WandSVC implements IrisService {
var bChunk = b.getChunk();
if (chunk == null) {
chunk = bChunk;
holder.addTicket(chunk);
chunk.addPluginChunkTicket(Iris.instance);
} else if (chunk != bChunk) {
holder.removeTicket(chunk);
holder.addTicket(bChunk);
chunk.removePluginChunkTicket(Iris.instance);
chunk = bChunk;
}
@@ -203,9 +198,7 @@ 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);
@@ -364,7 +357,6 @@ 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) {

View File

@@ -0,0 +1,625 @@
package com.volmit.iris.core.tools;
import com.volmit.iris.Iris;
import com.volmit.iris.util.format.C;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HWDiskStore;
import oshi.software.os.OperatingSystem;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.IntStream;
import java.util.zip.Deflater;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import static com.google.common.math.LongMath.isPrime;
import static com.volmit.iris.util.misc.getHardware.getCPUModel;
public class IrisBenchmarking {
static String ServerOS;
static String filePath = "benchmark.dat";
static double avgWriteSpeedMBps;
static double avgReadSpeedMBps;
static double highestWriteSpeedMBps;
static double highestReadSpeedMBps;
static double lowestWriteSpeedMBps;
static double lowestReadSpeedMBps;
static double calculateIntegerMath;
static double calculateFloatingPoint;
static double calculatePrimeNumbers;
static double calculateStringSorting;
static double calculateDataEncryption;
static double calculateDataCompression;
static String currentRunning = "None";
static int BenchmarksCompleted = 0;
static int BenchmarksTotal = 7;
static int totalTasks = 10;
static int currentTasks = 0;
static double WindowsCPUCompression;
static double WindowsCPUEncryption;
static double WindowsCPUCSHA1;
static double elapsedTimeNs;
static boolean Winsat = false;
static boolean WindowsDiskSpeed = false;
public static boolean inProgress = false;
static double startTime;
// Good enough for now. . .
public static void runBenchmark() throws InterruptedException {
inProgress = true;
getServerOS();
deleteTestFile(filePath);
AtomicReference<Double> doneCalculateDiskSpeed = new AtomicReference<>((double) 0);
startBenchmarkTimer();
Iris.info("Benchmark Started!");
Iris.warn("Although it may seem momentarily paused, it's actively processing.");
BenchmarksCompleted = 0;
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
currentRunning = "calculateDiskSpeed";
progressBar();
if (ServerOS.contains("Windows") && isRunningAsAdmin()) {
WindowsDiskSpeed = true;
WindowsDiskSpeedTest();
} else {
warningFallback();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
doneCalculateDiskSpeed.set(roundToTwoDecimalPlaces(calculateDiskSpeed()));
BenchmarksCompleted++;
}
}).thenRun(() -> {
currentRunning = "WindowsCpuSpeedTest";
progressBar();
if (ServerOS.contains("Windows") && isRunningAsAdmin()) {
Winsat = true;
WindowsCpuSpeedTest();
} else {
Iris.info("Skipping:" + C.BLUE + " Windows System Assessment Tool Benchmarks");
if (!ServerOS.contains("Windows")) {
Iris.info("Required Software:" + C.BLUE + " Windows");
BenchmarksTotal = 6;
}
if (!isRunningAsAdmin()) {
Iris.info(C.RED + "ERROR: " + C.DARK_RED + "Elevated privileges missing");
BenchmarksTotal = 6;
}
}
}).thenRun(() -> {
currentRunning = "calculateIntegerMath";
progressBar();
calculateIntegerMath = roundToTwoDecimalPlaces(calculateIntegerMath());
BenchmarksCompleted++;
}).thenRun(() -> {
currentRunning = "calculateFloatingPoint";
progressBar();
calculateFloatingPoint = roundToTwoDecimalPlaces(calculateFloatingPoint());
BenchmarksCompleted++;
}).thenRun(() -> {
currentRunning = "calculateStringSorting";
progressBar();
calculateStringSorting = roundToTwoDecimalPlaces(calculateStringSorting());
BenchmarksCompleted++;
}).thenRun(() -> {
currentRunning = "calculatePrimeNumbers";
progressBar();
calculatePrimeNumbers = roundToTwoDecimalPlaces(calculatePrimeNumbers());
BenchmarksCompleted++;
}).thenRun(() -> {
currentRunning = "calculateDataEncryption";
progressBar();
calculateDataEncryption = roundToTwoDecimalPlaces(calculateDataEncryption());
BenchmarksCompleted++;
}).thenRun(() -> {
currentRunning = "calculateDataCompression";
progressBar();
calculateDataCompression = roundToTwoDecimalPlaces(calculateDataCompression());
BenchmarksCompleted++;
}).thenRun(() -> {
elapsedTimeNs = stopBenchmarkTimer();
results();
inProgress = false;
});
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
public static void progressBar() {
Iris.info("-----------------------------------------------------");
Iris.info("Currently Running: " + C.BLUE + currentRunning);
// Iris.info("Tasks: " + "Current Tasks: " + C.BLUE + currentTasks + C.WHITE + " / " + "Total Tasks: " + C.BLUE + totalTasks);
Iris.info("Benchmarks Completed: " + C.BLUE + BenchmarksCompleted + C.WHITE + " / " + "Total: " + C.BLUE + BenchmarksTotal);
Iris.info("-----------------------------------------------------");
}
public static void results() {
SystemInfo systemInfo = new SystemInfo();
GlobalMemory globalMemory = systemInfo.getHardware().getMemory();
long totalMemoryMB = globalMemory.getTotal() / (1024 * 1024);
long availableMemoryMB = globalMemory.getAvailable() / (1024 * 1024);
long totalPageSize = globalMemory.getPageSize() / (1024 * 1024);
long usedMemoryMB = totalMemoryMB - availableMemoryMB;
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
Iris.info("OS: " + ServerOS);
if (!isRunningAsAdmin() || !ServerOS.contains("Windows")) {
Iris.info(C.GOLD + "For the full results use Windows + Admin Rights..");
}
Iris.info("CPU Model: " + getCPUModel());
Iris.info("CPU Score: " + "WIP");
Iris.info("- Integer Math: " + calculateIntegerMath + " MOps/Sec");
Iris.info("- Floating Point Math: " + calculateFloatingPoint + " MOps/Sec");
Iris.info("- Find Prime Numbers: " + calculatePrimeNumbers + " Primes/Sec");
Iris.info("- Random String Sorting: " + calculateStringSorting + " Thousand Strings/Sec");
Iris.info("- Data Encryption: " + formatDouble(calculateDataEncryption) + " MBytes/Sec");
Iris.info("- Data Compression: " + formatDouble(calculateDataCompression) + " MBytes/Sec");
if (WindowsDiskSpeed) {
//Iris.info("Disk Model: " + getDiskModel());
Iris.info(C.BLUE + "- Running with Windows System Assessment Tool");
Iris.info("- Sequential 64.0 Write: " + C.BLUE + formatDouble(avgWriteSpeedMBps) + " Mbps");
Iris.info("- Sequential 64.0 Read: " + C.BLUE + formatDouble(avgReadSpeedMBps) + " Mbps");
} else {
// Iris.info("Disk Model: " + getDiskModel());
Iris.info(C.GREEN + "- Running in Native Mode");
Iris.info("- Average Write Speed: " + C.GREEN + formatDouble(avgWriteSpeedMBps) + " Mbps");
Iris.info("- Average Read Speed: " + C.GREEN + formatDouble(avgReadSpeedMBps) + " Mbps");
Iris.info("- Highest Write Speed: " + formatDouble(highestWriteSpeedMBps) + " Mbps");
Iris.info("- Highest Read Speed: " + formatDouble(highestReadSpeedMBps) + " Mbps");
Iris.info("- Lowest Write Speed: " + formatDouble(lowestWriteSpeedMBps) + " Mbps");
Iris.info("- Lowest Read Speed: " + formatDouble(lowestReadSpeedMBps) + " Mbps");
}
Iris.info("Ram Usage: ");
Iris.info("- Total Ram: " + totalMemoryMB + " MB");
Iris.info("- Used Ram: " + usedMemoryMB + " MB");
Iris.info("- Total Process Ram: " + C.BLUE + getMaxMemoryUsage() + " MB");
Iris.info("- Total Paging Size: " + totalPageSize + " MB");
if (Winsat) {
Iris.info(C.BLUE + "Windows System Assessment Tool: ");
Iris.info("- CPU LZW Compression:" + C.BLUE + formatDouble(WindowsCPUCompression) + " MB/s");
Iris.info("- CPU AES256 Encryption: " + C.BLUE + formatDouble(WindowsCPUEncryption) + " MB/s");
Iris.info("- CPU SHA1 Hash: " + C.BLUE + formatDouble(WindowsCPUCSHA1) + " MB/s");
Iris.info("Duration: " + roundToTwoDecimalPlaces(elapsedTimeNs) + " Seconds");
}
}
public static long getMaxMemoryUsage() {
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage();
MemoryUsage nonHeapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage();
long maxHeapMemory = heapMemoryUsage.getMax();
long maxNonHeapMemory = nonHeapMemoryUsage.getMax();
long maxMemoryUsageMB = (maxHeapMemory + maxNonHeapMemory) / (1024 * 1024);
return maxMemoryUsageMB;
}
public static void getServerOS() {
SystemInfo systemInfo = new SystemInfo();
OperatingSystem os = systemInfo.getOperatingSystem();
ServerOS = os.toString();
}
public static boolean isRunningAsAdmin() {
if (ServerOS.contains("Windows")) {
try {
Process process = Runtime.getRuntime().exec("winsat disk");
process.waitFor();
return process.exitValue() == 0;
} catch (IOException | InterruptedException e) {
// Hmm
}
}
return false;
}
public static void warningFallback() {
Iris.info(C.RED + "Using the " + C.DARK_RED + "FALLBACK" + C.RED + " method due to compatibility issues. ");
Iris.info(C.RED + "Please note that this may result in less accurate results.");
}
private static String formatDouble(double value) {
return String.format("%.2f", value);
}
private static void startBenchmarkTimer() {
startTime = System.nanoTime();
}
private static double stopBenchmarkTimer() {
long endTime = System.nanoTime();
return (endTime - startTime) / 1_000_000_000.0;
}
private static double calculateIntegerMath() {
final int numIterations = 1_000_000_000;
final int numRuns = 30;
double totalMopsPerSec = 0;
for (int run = 0; run < numRuns; run++) {
long startTime = System.nanoTime();
int result = 0;
for (int i = 0; i < numIterations; i++) {
result += i * 2;
result -= i / 2;
result ^= i;
result <<= 1;
result >>= 1;
}
long endTime = System.nanoTime();
double elapsedSeconds = (endTime - startTime) / 1_000_000_000.0;
double mopsPerSec = (numIterations / elapsedSeconds) / 1_000_000.0;
totalMopsPerSec += mopsPerSec;
}
double averageMopsPerSec = totalMopsPerSec / numRuns;
return averageMopsPerSec;
}
private static double calculateFloatingPoint() {
long numIterations = 85_000_000;
int numRuns = 30;
double totalMopsPerSec = 0;
for (int run = 0; run < numRuns; run++) {
double result = 0;
long startTime = System.nanoTime();
for (int i = 0; i < numIterations; i++) {
result += Math.sqrt(i) * Math.sin(i) / (i + 1);
}
long endTime = System.nanoTime();
double elapsedSeconds = (endTime - startTime) / 1_000_000_000.0;
double mopsPerSec = (numIterations / elapsedSeconds) / 1_000_000.0;
totalMopsPerSec += mopsPerSec;
}
double averageMopsPerSec = totalMopsPerSec / numRuns;
return averageMopsPerSec;
}
private static double calculatePrimeNumbers() {
int primeCount;
long numIterations = 1_000_000;
int numRuns = 30;
double totalMopsPerSec = 0;
for (int run = 0; run < numRuns; run++) {
primeCount = 0;
long startTime = System.nanoTime();
for (int num = 2; primeCount < numIterations; num++) {
if (isPrime(num)) {
primeCount++;
}
}
long endTime = System.nanoTime();
double elapsedSeconds = (endTime - startTime) / 1_000_000_000.0;
double mopsPerSec = (primeCount / elapsedSeconds) / 1_000_000.0;
totalMopsPerSec += mopsPerSec;
}
double averageMopsPerSec = totalMopsPerSec / numRuns;
return averageMopsPerSec;
}
private static double calculateStringSorting() {
int stringCount = 1_000_000;
int stringLength = 100;
int numRuns = 30;
double totalMopsPerSec = 0;
for (int run = 0; run < numRuns; run++) {
List<String> randomStrings = generateRandomStrings(stringCount, stringLength);
long startTime = System.nanoTime();
randomStrings.sort(String::compareTo);
long endTime = System.nanoTime();
double elapsedSeconds = (endTime - startTime) / 1_000_000_000.0;
double mopsPerSec = (stringCount / elapsedSeconds) / 1_000.0;
totalMopsPerSec += mopsPerSec;
}
double averageMopsPerSec = totalMopsPerSec / numRuns;
return averageMopsPerSec;
}
public static double calculateDataEncryption() {
int dataSizeMB = 100;
byte[] dataToEncrypt = generateRandomData(dataSizeMB * 1024 * 1024);
int numRuns = 20;
double totalMBytesPerSec = 0;
for (int run = 0; run < numRuns; run++) {
long startTime = System.nanoTime();
byte[] encryptedData = performEncryption(dataToEncrypt, 1);
long endTime = System.nanoTime();
double elapsedSeconds = (endTime - startTime) / 1_000_000_000.0;
double mbytesPerSec = (dataToEncrypt.length / (1024 * 1024.0)) / elapsedSeconds;
totalMBytesPerSec += mbytesPerSec;
}
double averageMBytesPerSec = totalMBytesPerSec / numRuns;
return averageMBytesPerSec;
}
private static byte[] performEncryption(byte[] data, int numRuns) {
byte[] key = "MyEncryptionKey".getBytes();
byte[] result = Arrays.copyOf(data, data.length);
for (int run = 0; run < numRuns; run++) {
for (int i = 0; i < result.length; i++) {
result[i] ^= key[i % key.length];
}
}
return result;
}
public static double calculateDataCompression() {
int dataSizeMB = 500;
byte[] dataToCompress = generateRandomData(dataSizeMB * 1024 * 1024);
long startTime = System.nanoTime();
byte[] compressedData = performCompression(dataToCompress);
long endTime = System.nanoTime();
double elapsedSeconds = (endTime - startTime) / 1e9;
double mbytesPerSec = (compressedData.length / (1024.0 * 1024.0)) / elapsedSeconds;
return mbytesPerSec;
}
private static byte[] performCompression(byte[] data) {
Deflater deflater = new Deflater();
deflater.setInput(data);
deflater.finish();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
byte[] buffer = new byte[1024];
while (!deflater.finished()) {
int count = deflater.deflate(buffer);
outputStream.write(buffer, 0, count);
}
deflater.end();
return outputStream.toByteArray();
}
private static List<String> generateRandomStrings(int count, int length) {
SecureRandom random = new SecureRandom();
List<String> randomStrings = new ArrayList<>();
IntStream.range(0, count).forEach(i -> {
byte[] bytes = new byte[length];
random.nextBytes(bytes);
randomStrings.add(Base64.getEncoder().encodeToString(bytes));
});
return randomStrings;
}
private static byte[] generateRandomData(int size) {
SecureRandom random = new SecureRandom();
byte[] data = new byte[size];
random.nextBytes(data);
return data;
}
private static double roundToTwoDecimalPlaces(double value) {
return Double.parseDouble(String.format("%.2f", value));
}
private static double calculateCPUScore(long elapsedTimeNs) {
return 1.0 / (elapsedTimeNs / 1_000_000.0);
}
public static double calculateDiskSpeed() {
int numRuns = 10;
int fileSizeMB = 1000;
double[] writeSpeeds = new double[numRuns];
double[] readSpeeds = new double[numRuns];
for (int run = 0; run < numRuns; run++) {
long writeStartTime = System.nanoTime();
deleteTestFile(filePath);
createTestFile(filePath, fileSizeMB);
long writeEndTime = System.nanoTime();
long readStartTime = System.nanoTime();
readTestFile(filePath);
long readEndTime = System.nanoTime();
double writeSpeed = calculateDiskSpeedMBps(fileSizeMB, writeStartTime, writeEndTime);
double readSpeed = calculateDiskSpeedMBps(fileSizeMB, readStartTime, readEndTime);
writeSpeeds[run] = writeSpeed;
readSpeeds[run] = readSpeed;
if (run == 0) {
lowestWriteSpeedMBps = writeSpeed;
highestWriteSpeedMBps = writeSpeed;
lowestReadSpeedMBps = readSpeed;
highestReadSpeedMBps = readSpeed;
} else {
if (writeSpeed < lowestWriteSpeedMBps) {
lowestWriteSpeedMBps = writeSpeed;
}
if (writeSpeed > highestWriteSpeedMBps) {
highestWriteSpeedMBps = writeSpeed;
}
if (readSpeed < lowestReadSpeedMBps) {
lowestReadSpeedMBps = readSpeed;
}
if (readSpeed > highestReadSpeedMBps) {
highestReadSpeedMBps = readSpeed;
}
}
}
avgWriteSpeedMBps = calculateAverage(writeSpeeds);
avgReadSpeedMBps = calculateAverage(readSpeeds);
return 2;
}
public static void createTestFile(String filePath, int fileSizeMB) {
try {
File file = new File(filePath);
byte[] data = new byte[1024 * 1024];
Arrays.fill(data, (byte) 0);
FileOutputStream fos = new FileOutputStream(file);
for (int i = 0; i < fileSizeMB; i++) {
fos.write(data);
}
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void readTestFile(String filePath) {
try {
File file = new File(filePath);
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[1024];
while (fis.read(buffer) != -1) {
}
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void deleteTestFile(String filePath) {
File file = new File(filePath);
file.delete();
}
public static double calculateDiskSpeedMBps(int fileSizeMB, long startTime, long endTime) {
double elapsedSeconds = (endTime - startTime) / 1_000_000_000.0;
double writeSpeed = (fileSizeMB / elapsedSeconds);
return writeSpeed;
}
public static double calculateAverage(double[] values) {
double sum = 0;
for (double value : values) {
sum += value;
}
return sum / values.length;
}
public static void WindowsDiskSpeedTest() {
try {
String command = "winsat disk";
Process process = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
Iris.debug(line);
if (line.contains("Disk Sequential 64.0 Read")) {
avgReadSpeedMBps = extractSpeed(line);
} else if (line.contains("Disk Sequential 64.0 Write")) {
avgWriteSpeedMBps = extractSpeed(line);
}
}
process.waitFor();
process.destroy();
Iris.debug("Sequential Read Speed: " + avgReadSpeedMBps + " MB/s");
Iris.debug("Sequential Write Speed: " + avgWriteSpeedMBps + " MB/s");
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
private static double extractSpeed(String line) {
String[] tokens = line.split("\\s+");
for (int i = 0; i < tokens.length; i++) {
if (tokens[i].endsWith("MB/s") && i > 0) {
try {
return Double.parseDouble(tokens[i - 1]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
}
return 0.0;
}
public static void WindowsCpuSpeedTest() {
try {
String command = "winsat cpuformal";
Process process = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
Iris.debug(line);
if (line.contains("CPU AES256 Encryption")) {
WindowsCPUEncryption = extractCpuInfo(line);
}
if (line.contains("CPU LZW Compression")) {
WindowsCPUCompression = extractCpuInfo(line);
}
if (line.contains("CPU SHA1 Hash")) {
WindowsCPUCSHA1 = extractCpuInfo(line);
}
}
process.waitFor();
process.destroy();
Iris.debug("Winsat Encryption: " + WindowsCPUEncryption + " MB/s");
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
private static double extractCpuInfo(String line) {
String[] tokens = line.split("\\s+");
for (int i = 0; i < tokens.length; i++) {
if (tokens[i].endsWith("MB/s") && i > 0) {
try {
return Double.parseDouble(tokens[i - 1]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
}
return 0.0;
}
}

View File

@@ -2,21 +2,29 @@ package com.volmit.iris.core.tools;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.util.data.Varint;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.nbt.io.NBTUtil;
import com.volmit.iris.util.nbt.io.NamedTag;
import com.volmit.iris.util.nbt.tag.*;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.reflect.V;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import org.apache.commons.io.FileUtils;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.util.FileUtil;
import org.bukkit.util.Vector;
import java.io.*;
import java.util.*;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
@@ -31,17 +39,13 @@ public class IrisConverter {
sender.sendMessage("No schematic files to convert found in " + folder.getAbsolutePath());
return;
}
AtomicInteger counter = new AtomicInteger(0);
var stopwatch = PrecisionStopwatch.start();
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.submit(() -> {
for (File schem : fileList) {
try {
for (File schem : fileList) {
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
IrisObject object;
boolean largeObject = false;
NamedTag tag;
NamedTag tag = null;
try {
tag = NBTUtil.read(schem);
} catch (IOException e) {
@@ -49,20 +53,17 @@ public class IrisConverter {
throw new RuntimeException(e);
}
CompoundTag compound = (CompoundTag) tag.getTag();
int version = resolveVersion(compound);
if (!(version == 2 || version == 3))
throw new RuntimeException(C.RED + "Unsupported schematic version: " + version);
compound = version == 3 ? (CompoundTag) compound.get("Schematic") : compound;
if (compound.containsKey("Palette") && compound.containsKey("Width") && compound.containsKey("Height") && compound.containsKey("Length")) {
int objW = ((ShortTag) compound.get("Width")).getValue();
int objH = ((ShortTag) compound.get("Height")).getValue();
int objD = ((ShortTag) compound.get("Length")).getValue();
int i = -1;
int mv = objW * objH * objD;
AtomicInteger v = new AtomicInteger(0);
if (mv > 2_000_000) {
if (mv > 500_000) {
largeObject = true;
Iris.info(C.GRAY + "Converting.. " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
Iris.info(C.GRAY + "Converting.. "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
Iris.info(C.GRAY + "- It may take a while");
if (sender.isPlayer()) {
i = J.ar(() -> {
@@ -71,7 +72,6 @@ public class IrisConverter {
}
}
compound = version == 3 ? (CompoundTag) compound.get("Blocks") : compound;
CompoundTag paletteTag = (CompoundTag) compound.get("Palette");
Map<Integer, BlockData> blockmap = new HashMap<>(paletteTag.size(), 0.9f);
for (Map.Entry<String, Tag<?>> entry : paletteTag.getValue().entrySet()) {
@@ -82,16 +82,14 @@ public class IrisConverter {
blockmap.put(blockId, bd);
}
boolean isBytes = version == 3 ? compound.getByteArrayTag("Data").length() < 128 : ((IntTag) compound.get("PaletteMax")).getValue() < 128;
ByteArrayTag byteArray = version == 3 ? (ByteArrayTag) compound.get("Data") : (ByteArrayTag) compound.get("BlockData");
ByteArrayTag byteArray = (ByteArrayTag) compound.get("BlockData");
byte[] originalBlockArray = byteArray.getValue();
var din = new DataInputStream(new ByteArrayInputStream(originalBlockArray));
object = new IrisObject(objW, objH, objD);
IrisObject object = new IrisObject(objW, objH, objD);
for (int h = 0; h < objH; h++) {
for (int d = 0; d < objD; d++) {
for (int w = 0; w < objW; w++) {
int blockIndex = isBytes ? din.read() & 0xFF : Varint.readUnsignedVarInt(din);
BlockData bd = blockmap.get(blockIndex);
BlockData bd = blockmap.get((int) originalBlockArray[v.get()]);
if (!bd.getMaterial().isAir()) {
object.setUnsigned(w, h, d, bd);
}
@@ -99,59 +97,42 @@ public class IrisConverter {
}
}
}
if (i != -1) J.car(i);
try {
object.shrinkwrap();
object.write(new File(folder, schem.getName().replace(".schem", ".iob")));
counter.incrementAndGet();
if (sender.isPlayer()) {
if (largeObject) {
sender.sendMessage(C.IRIS + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis()));
} else {
sender.sendMessage(C.IRIS + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
}
}
if (largeObject) {
Iris.info(C.GRAY + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis()));
} else {
Iris.info(C.GRAY + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
}
FileUtils.delete(schem);
} catch (IOException e) {
sender.sendMessage(C.RED + "Failed to save: " + schem.getName());
throw new IOException(e);
Iris.info(C.RED + "Failed to save: " + schem.getName());
throw new RuntimeException(e);
}
} catch (Exception e) {
sender.sendMessage(C.RED + "Failed to convert: " + schem.getName());
e.printStackTrace();
if (sender.isPlayer()) {
if (largeObject) {
sender.sendMessage(C.IRIS + "Converted "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis()));
} else {
sender.sendMessage(C.IRIS + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
}
}
if (largeObject) {
Iris.info(C.GRAY + "Converted "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis()));
} else {
Iris.info(C.GRAY + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
}
FileUtils.delete(schem);
}
} catch (Exception e) {
Iris.info(C.RED + "Failed to convert: " + schem.getName());
if (sender.isPlayer()) {
sender.sendMessage(C.RED + "Failed to convert: " + schem.getName());
}
e.printStackTrace();
Iris.reportError(e);
}
stopwatch.end();
if (counter.get() != 0) {
sender.sendMessage(C.GRAY + "Converted: " + counter.get() + " in " + Form.duration(stopwatch.getMillis()));
}
if (counter.get() < fileList.length) {
sender.sendMessage(C.RED + "Some schematics failed to convert. Check the console for details.");
}
}
sender.sendMessage(C.GRAY + "converted: " + fileList.length);
});
}
private static int resolveVersion(CompoundTag compound) throws Exception {
try {
IntTag root = compound.getIntTag("Version");
if (root != null) {
return root.getValue();
}
CompoundTag schematic = (CompoundTag) compound.get("Schematic");
return schematic.getIntTag("Version").getValue();
} catch (NullPointerException e) {
throw new Exception("Cannot resolve schematic version", e);
}
}
}

View File

@@ -43,9 +43,8 @@ import java.io.File;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.IntSupplier;
import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
/**
* Makes it a lot easier to setup an engine, world, studio or whatever
@@ -53,6 +52,7 @@ import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML;
@Data
@Accessors(fluent = true, chain = true)
public class IrisCreator {
private static final File BUKKIT_YML = new File("bukkit.yml");
/**
* Specify an area to pregenerate during creation
*/
@@ -84,6 +84,11 @@ public class IrisCreator {
* Benchmark mode
*/
private boolean benchmark = false;
/**
* Radius of chunks to pregenerate in the headless mode
* if set to -1, headless mode is disabled
*/
private int headlessRadius = 10;
public static boolean removeFromBukkitYml(String name) throws IOException {
YamlConfiguration yml = YamlConfiguration.loadConfiguration(BUKKIT_YML);
@@ -127,6 +132,7 @@ public class IrisCreator {
Iris.service(StudioSVC.class).installIntoWorld(sender, d.getLoadKey(), new File(Bukkit.getWorldContainer(), name()));
}
AtomicReference<World> world = new AtomicReference<>();
AtomicDouble pp = new AtomicDouble(0);
O<Boolean> done = new O<>();
done.set(false);
@@ -136,64 +142,95 @@ public class IrisCreator {
.seed(seed)
.studio(studio)
.create();
if (ServerConfigurator.installDataPacks(true)) {
throw new IrisException("Datapacks were missing!");
}
ServerConfigurator.installDataPacks(false);
PlatformChunkGenerator access = (PlatformChunkGenerator) wc.generator();
if (access == null) throw new IrisException("Access is null. Something bad happened.");
if (access == null) {
throw new IrisException("Access is null. Something bad happened.");
}
if (headlessRadius > 0 && !benchmark) {
AtomicBoolean failed = new AtomicBoolean(false);
J.a(() -> {
int generated = access.getGenerated();
double total = Math.pow(headlessRadius * 2 + 1, 2);
while (generated < total) {
if (failed.get()) return;
double v = (double) generated / total;
if (sender.isPlayer()) {
sender.sendProgress(v, "Generating headless chunks");
J.sleep(16);
} else {
sender.sendMessage(C.WHITE + "Generating headless chunks " + Form.pc(v) + ((C.GRAY + " (" + ((int) total - generated) + " Left)")));
J.sleep(1000);
}
generated = access.getGenerated();
}
});
try {
access.prepareSpawnChunks(seed, headlessRadius);
} catch (Throwable e) {
Iris.error("Failed to prepare spawn chunks for " + name);
e.printStackTrace();
failed.set(true);
}
}
J.a(() -> {
IntSupplier g = () -> {
if (access.getEngine() == null) {
return 0;
}
return access.getEngine().getGenerated();
};
if(!benchmark) {
int req = access.getSpawnChunks().join();
for (int c = 0; c < req && !done.get(); c = g.getAsInt()) {
double v = (double) c / req;
int generated = access.getGenerated();
while (generated < req) {
double v = (double) generated / (double) req;
if (sender.isPlayer()) {
sender.sendProgress(v, "Generating");
J.sleep(16);
} else {
sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - c) + " Left)")));
sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - generated) + " Left)")));
J.sleep(1000);
}
generated = access.getGenerated();
}
}
});
World world;
try {
world = J.sfut(() -> INMS.get().createWorld(wc)).get();
J.sfut(() -> {
world.set(INMS.get().createWorld(wc));
}).get();
} catch (Throwable e) {
done.set(true);
throw new IrisException("Failed to create world!", e);
e.printStackTrace();
}
if (access == null) {
throw new IrisException("Access is null. Something bad happened.");
}
done.set(true);
if (sender.isPlayer() && !benchmark) {
J.s(() -> sender.player().teleport(new Location(world, 0, world.getHighestBlockYAt(0, 0) + 1, 0)));
J.s(() -> {
sender.player().teleport(new Location(world.get(), 0, world.get().getHighestBlockYAt(0, 0), 0));
});
}
if (studio || benchmark) {
J.s(() -> {
Iris.linkMultiverseCore.removeFromConfig(world);
Iris.linkMultiverseCore.removeFromConfig(world.get());
if (IrisSettings.get().getStudio().isDisableTimeAndWeather()) {
world.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
world.setTime(6000);
world.get().setGameRule(GameRule.DO_WEATHER_CYCLE, false);
world.get().setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
world.get().setTime(6000);
}
});
} else {
} else
addToBukkitYml();
J.s(() -> Iris.linkMultiverseCore.updateWorld(world, dimension));
}
if (pregen != null) {
CompletableFuture<Boolean> ff = new CompletableFuture<>();
@@ -223,7 +260,7 @@ public class IrisCreator {
e.printStackTrace();
}
}
return world;
return world.get();
}
private void addToBukkitYml() {

View File

@@ -2,9 +2,17 @@ package com.volmit.iris.core.tools;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.methods.HeadlessPregenMethod;
import com.volmit.iris.core.pregenerator.methods.HybridPregenMethod;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.IrisEngine;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineTarget;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisWorld;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.exceptions.IrisException;
@@ -12,6 +20,7 @@ import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Getter;
import org.bukkit.Bukkit;
import java.io.File;
@@ -23,31 +32,34 @@ import java.util.Collections;
public class IrisPackBenchmarking {
private static final ThreadLocal<IrisPackBenchmarking> instance = new ThreadLocal<>();
@Getter
public static IrisPackBenchmarking instance;
public static boolean benchmarkInProgress = false;
private final PrecisionStopwatch stopwatch = new PrecisionStopwatch();
private final IrisDimension dimension;
private final int radius;
private final int diameter;
private final boolean gui;
private final boolean headless;
private transient Engine engine;
public IrisPackBenchmarking(IrisDimension dimension, int radius, boolean gui) {
public IrisPackBenchmarking(IrisDimension dimension, int diameter, boolean headless, boolean gui) {
instance = this;
this.dimension = dimension;
this.radius = radius;
this.diameter = diameter;
this.headless = headless;
this.gui = gui;
runBenchmark();
}
public static IrisPackBenchmarking getInstance() {
return instance.get();
}
private void runBenchmark() {
Thread.ofVirtual()
.name("PackBenchmarking")
.start(() -> {
Iris.info("Setting up benchmark environment ");
benchmarkInProgress = true;
IO.delete(new File(Bukkit.getWorldContainer(), "benchmark"));
createBenchmark();
while (!IrisToolbelt.isIrisWorld(Bukkit.getWorld("benchmark"))) {
while (!headless && !IrisToolbelt.isIrisWorld(Bukkit.getWorld("benchmark"))) {
J.sleep(1000);
Iris.debug("Iris PackBenchmark: Waiting...");
}
@@ -58,10 +70,13 @@ public class IrisPackBenchmarking {
}
public boolean getBenchmarkInProgress() {
return benchmarkInProgress;
}
public void finishedBenchmark(KList<Integer> cps) {
try {
String time = Form.duration((long) stopwatch.getMilliseconds());
Engine engine = IrisToolbelt.access(Bukkit.getWorld("benchmark")).getEngine();
String time = Form.duration(stopwatch.getMillis());
Iris.info("-----------------");
Iris.info("Results:");
Iris.info("- Total time: " + time);
@@ -71,7 +86,11 @@ public class IrisPackBenchmarking {
Iris.info(" - Lowest CPS: " + findLowest(cps));
Iris.info("-----------------");
Iris.info("Creating a report..");
File results = Iris.instance.getDataFile("packbenchmarks", dimension.getName() + " " + LocalDateTime.now(Clock.systemDefaultZone()).toString().replace(':', '-') + ".txt");
File profilers = new File("plugins" + File.separator + "Iris" + File.separator + "packbenchmarks");
profilers.mkdir();
File results = new File(profilers, dimension.getName() + " " + LocalDateTime.now(Clock.systemDefaultZone()).toString().replace(':', '-') + ".txt");
results.getParentFile().mkdirs();
KMap<String, Double> metrics = engine.getMetrics().pull();
try (FileWriter writer = new FileWriter(results)) {
writer.write("-----------------\n");
@@ -98,12 +117,16 @@ public class IrisPackBenchmarking {
e.printStackTrace();
}
J.s(() -> {
var world = Bukkit.getWorld("benchmark");
if (world == null) return;
IrisToolbelt.evacuate(world);
Bukkit.unloadWorld(world, true);
});
if (headless) {
engine.close();
} else {
J.s(() -> {
var world = Bukkit.getWorld("benchmark");
if (world == null) return;
IrisToolbelt.evacuate(world);
Bukkit.unloadWorld(world, true);
});
}
stopwatch.end();
} catch (Exception e) {
@@ -114,31 +137,53 @@ public class IrisPackBenchmarking {
private void createBenchmark() {
try {
IrisToolbelt.createWorld()
if (headless) {
Iris.info("Using headless benchmark!");
IrisWorld world = IrisWorld.builder()
.name("benchmark")
.minHeight(dimension.getMinHeight())
.maxHeight(dimension.getMaxHeight())
.seed(1337)
.worldFolder(new File(Bukkit.getWorldContainer(), "benchmark"))
.environment(dimension.getEnvironment())
.build();
Iris.service(StudioSVC.class).installIntoWorld(
Iris.getSender(),
dimension.getLoadKey(),
world.worldFolder());
var data = IrisData.get(new File(world.worldFolder(), "iris/pack"));
var dim = data.getDimensionLoader().load(dimension.getLoadKey());
engine = new IrisEngine(new EngineTarget(world, dim, data), false);
return;
}
engine = IrisToolbelt.access(IrisToolbelt.createWorld()
.dimension(dimension.getLoadKey())
.name("benchmark")
.seed(1337)
.studio(false)
.benchmark(true)
.create();
.create())
.getEngine();
} catch (IrisException e) {
throw new RuntimeException(e);
}
}
private void startBenchmark() {
try {
instance.set(this);
IrisToolbelt.pregenerate(PregenTask
.builder()
.gui(gui)
.radiusX(radius)
.radiusZ(radius)
.build(), Bukkit.getWorld("benchmark")
);
} finally {
instance.remove();
}
IrisToolbelt.pregenerate(PregenTask
.builder()
.gui(gui)
.radiusX(diameter)
.radiusZ(diameter)
.build(), headless ?
new HeadlessPregenMethod(engine) :
new HybridPregenMethod(
engine.getWorld().realWorld(),
IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())
),
engine
);
}
private double calculateAverage(KList<Integer> list) {

View File

@@ -24,7 +24,6 @@ import com.volmit.iris.core.gui.PregeneratorJob;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.core.pregenerator.methods.CachedPregenMethod;
import com.volmit.iris.core.pregenerator.methods.HybridPregenMethod;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.framework.Engine;
@@ -34,7 +33,6 @@ import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import java.io.File;
import java.io.IOException;
@@ -46,7 +44,6 @@ import java.util.Map;
* Hope you packed snacks & road sodas.
*/
public class IrisToolbelt {
@ApiStatus.Internal
public static Map<String, Boolean> toolbeltConfiguration = new HashMap<>();
/**
@@ -144,18 +141,7 @@ public class IrisToolbelt {
* @return the pregenerator job (already started)
*/
public static PregeneratorJob pregenerate(PregenTask task, PregeneratorMethod method, Engine engine) {
return pregenerate(task, method, engine, IrisSettings.get().getPregen().useCacheByDefault);
}
/**
* Start a pregenerator task
*
* @param task the scheduled task
* @param method the method to execute the task
* @return the pregenerator job (already started)
*/
public static PregeneratorJob pregenerate(PregenTask task, PregeneratorMethod method, Engine engine, boolean cached) {
return new PregeneratorJob(task, cached && engine != null ? new CachedPregenMethod(method, engine.getWorld().name()) : method, engine);
return new PregeneratorJob(task, method, engine);
}
/**
@@ -234,11 +220,7 @@ public class IrisToolbelt {
}
public static void retainMantleDataForSlice(String className) {
toolbeltConfiguration.put("retain.mantle." + className, Boolean.TRUE);
}
public static boolean isRetainingMantleDataForSlice(String className) {
return !toolbeltConfiguration.isEmpty() && toolbeltConfiguration.get("retain.mantle." + className) == Boolean.TRUE;
toolbeltConfiguration.put("retain.mantle." + className, true);
}
public static <T> T getMantleData(World world, int x, int y, int z, Class<T> of) {

View File

@@ -21,10 +21,13 @@ package com.volmit.iris.core.tools;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.platform.BukkitChunkGenerator;
import com.volmit.iris.util.reflect.WrappedField;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.WorldType;
import org.bukkit.generator.ChunkGenerator;
import sun.misc.Unsafe;
import java.io.File;
@@ -64,7 +67,7 @@ public class IrisWorldCreator {
}
public WorldCreator create() {
IrisDimension dim = IrisData.loadAnyDimension(dimensionName, null);
IrisDimension dim = IrisData.loadAnyDimension(dimensionName);
IrisWorld w = IrisWorld.builder()
.name(name)
@@ -80,13 +83,13 @@ public class IrisWorldCreator {
return new WorldCreator(name)
.environment(w.environment())
.environment(findEnvironment())
.generateStructures(true)
.generator(g).seed(seed);
}
private World.Environment findEnvironment() {
IrisDimension dim = IrisData.loadAnyDimension(dimensionName, null);
IrisDimension dim = IrisData.loadAnyDimension(dimensionName);
if (dim == null || dim.getEnvironment() == null) {
return World.Environment.NORMAL;
} else {

View File

@@ -25,6 +25,8 @@ import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.interpolation.IrisInterpolation.NoiseKey;
@@ -40,8 +42,7 @@ import org.bukkit.Material;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import java.io.File;
import java.util.*;
import java.util.UUID;
@Data
@EqualsAndHashCode(exclude = "data")
@@ -51,7 +52,7 @@ public class IrisComplex implements DataProvider {
private RNG rng;
private double fluidHeight;
private IrisData data;
private Map<IrisInterpolator, Set<IrisGenerator>> generators;
private KMap<IrisInterpolator, KSet<IrisGenerator>> generators;
private ProceduralStream<IrisRegion> regionStream;
private ProceduralStream<Double> regionStyleStream;
private ProceduralStream<Double> regionIdentityStream;
@@ -89,17 +90,17 @@ public class IrisComplex implements DataProvider {
}
public IrisComplex(Engine engine, boolean simple) {
int cacheSize = IrisSettings.get().getPerformance().getNoiseCacheSize();
int cacheSize = IrisSettings.get().getPerformance().getCacheSize();
IrisBiome emptyBiome = new IrisBiome();
UUID focusUUID = UUID.nameUUIDFromBytes("focus".getBytes());
this.rng = new RNG(engine.getSeedManager().getComplex());
this.data = engine.getData();
double height = engine.getMaxHeight();
fluidHeight = engine.getDimension().getFluidHeight();
generators = new HashMap<>();
generators = new KMap<>();
focusBiome = engine.getFocus();
focusRegion = engine.getFocusRegion();
Map<InferredType, ProceduralStream<IrisBiome>> inferredStreams = new HashMap<>();
KMap<InferredType, ProceduralStream<IrisBiome>> inferredStreams = new KMap<>();
if (focusBiome != null) {
focusBiome.setInferredType(InferredType.LAND);
@@ -107,16 +108,10 @@ public class IrisComplex implements DataProvider {
}
//@builder
if (focusRegion != null) {
focusRegion.getAllBiomes(this).forEach(this::registerGenerators);
} else {
engine.getDimension()
.getRegions()
.forEach(i -> data.getRegionLoader().load(i)
.getAllBiomes(this)
.forEach(this::registerGenerators));
}
boolean legacy = engine.getDimension().isLegacyRarity();
engine.getDimension().getRegions().forEach((i) -> data.getRegionLoader().load(i)
.getAllBiomes(this).forEach((b) -> b
.getGenerators()
.forEach((c) -> registerGenerator(c.getCachedGenerator(this)))));
overlayStream = ProceduralStream.ofDouble((x, z) -> 0.0D).waste("Overlay Stream");
engine.getDimension().getOverlayNoise().forEach(i -> overlayStream = overlayStream.add((x, z) -> i.get(rng, getData(), x, z)));
rockStream = engine.getDimension().getRockPalette().getLayerGenerator(rng.nextParallelRNG(45), data).stream()
@@ -130,7 +125,7 @@ public class IrisComplex implements DataProvider {
ProceduralStream.of((x, z) -> focusRegion,
Interpolated.of(a -> 0D, a -> focusRegion))
: regionStyleStream
.selectRarity(data.getRegionLoader().loadAll(engine.getDimension().getRegions()), legacy)
.selectRarity(data.getRegionLoader().loadAll(engine.getDimension().getRegions()))
.cache2D("regionStream", engine, cacheSize).waste("Region Stream");
regionIDStream = regionIdentityStream.convertCached((i) -> new UUID(Double.doubleToLongBits(i),
String.valueOf(i * 38445).hashCode() * 3245556666L)).waste("Region ID Stream");
@@ -139,7 +134,7 @@ public class IrisComplex implements DataProvider {
-> engine.getDimension().getCaveBiomeStyle().create(rng.nextParallelRNG(InferredType.CAVE.ordinal()), getData()).stream()
.zoom(engine.getDimension().getBiomeZoom())
.zoom(r.getCaveBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getCaveBiomes()), legacy)
.selectRarity(data.getBiomeLoader().loadAll(r.getCaveBiomes()))
.onNull(emptyBiome)
).convertAware2D(ProceduralStream::get).cache2D("caveBiomeStream", engine, cacheSize).waste("Cave Biome Stream");
inferredStreams.put(InferredType.CAVE, caveBiomeStream);
@@ -149,7 +144,7 @@ public class IrisComplex implements DataProvider {
.zoom(engine.getDimension().getBiomeZoom())
.zoom(engine.getDimension().getLandZoom())
.zoom(r.getLandBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getLandBiomes(), (t) -> t.setInferredType(InferredType.LAND)), legacy)
.selectRarity(data.getBiomeLoader().loadAll(r.getLandBiomes(), (t) -> t.setInferredType(InferredType.LAND)))
).convertAware2D(ProceduralStream::get)
.cache2D("landBiomeStream", engine, cacheSize).waste("Land Biome Stream");
inferredStreams.put(InferredType.LAND, landBiomeStream);
@@ -159,7 +154,7 @@ public class IrisComplex implements DataProvider {
.zoom(engine.getDimension().getBiomeZoom())
.zoom(engine.getDimension().getSeaZoom())
.zoom(r.getSeaBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getSeaBiomes(), (t) -> t.setInferredType(InferredType.SEA)), legacy)
.selectRarity(data.getBiomeLoader().loadAll(r.getSeaBiomes(), (t) -> t.setInferredType(InferredType.SEA)))
).convertAware2D(ProceduralStream::get)
.cache2D("seaBiomeStream", engine, cacheSize).waste("Sea Biome Stream");
inferredStreams.put(InferredType.SEA, seaBiomeStream);
@@ -168,7 +163,7 @@ public class IrisComplex implements DataProvider {
-> engine.getDimension().getShoreBiomeStyle().create(rng.nextParallelRNG(InferredType.SHORE.ordinal()), getData()).stream()
.zoom(engine.getDimension().getBiomeZoom())
.zoom(r.getShoreBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getShoreBiomes(), (t) -> t.setInferredType(InferredType.SHORE)), legacy)
.selectRarity(data.getBiomeLoader().loadAll(r.getShoreBiomes(), (t) -> t.setInferredType(InferredType.SHORE)))
).convertAware2D(ProceduralStream::get).cache2D("shoreBiomeStream", engine, cacheSize).waste("Shore Biome Stream");
inferredStreams.put(InferredType.SHORE, shoreBiomeStream);
bridgeStream = focusBiome != null ? ProceduralStream.of((x, z) -> focusBiome.getInferredType(),
@@ -250,15 +245,7 @@ public class IrisComplex implements DataProvider {
}
}
String key = UUID.randomUUID().toString();
IrisRegion region = new IrisRegion();
region.getLandBiomes().add(focus.getLoadKey());
region.getSeaBiomes().add(focus.getLoadKey());
region.getShoreBiomes().add(focus.getLoadKey());
region.setLoadKey(key);
region.setLoader(data);
region.setLoadFile(new File(data.getDataFolder(), data.getRegionLoader().getFolderName() + "/" + key + ".json"));
return region;
return null;
}
private IrisDecorator decorateFor(IrisBiome b, double x, double z, IrisDecorationPart part) {
@@ -301,12 +288,12 @@ public class IrisComplex implements DataProvider {
return biome;
}
private double interpolateGenerators(Engine engine, IrisInterpolator interpolator, Set<IrisGenerator> generators, double x, double z, long seed) {
private double interpolateGenerators(Engine engine, IrisInterpolator interpolator, KSet<IrisGenerator> generators, double x, double z, long seed) {
if (generators.isEmpty()) {
return 0;
}
HashMap<NoiseKey, IrisBiome> cache = new HashMap<>(64);
KMap<NoiseKey, IrisBiome> cache = new KMap<>();
double hi = interpolator.interpolate(x, z, (xx, zz) -> {
try {
IrisBiome bx = baseBiomeStream.get(xx, zz);
@@ -373,12 +360,8 @@ public class IrisComplex implements DataProvider {
return Math.max(Math.min(getInterpolatedHeight(engine, x, z, seed) + fluidHeight + overlayStream.get(x, z), engine.getHeight()), 0);
}
private void registerGenerators(IrisBiome biome) {
biome.getGenerators().forEach(c -> registerGenerator(c.getCachedGenerator(this)));
}
private void registerGenerator(IrisGenerator cachedGenerator) {
generators.computeIfAbsent(cachedGenerator.getInterpolator(), (k) -> new HashSet<>()).add(cachedGenerator);
generators.computeIfAbsent(cachedGenerator.getInterpolator(), (k) -> new KSet<>()).add(cachedGenerator);
}
private IrisBiome implode(IrisBiome b, Double x, Double z) {

File diff suppressed because it is too large Load Diff

View File

@@ -30,14 +30,10 @@ import com.volmit.iris.engine.mantle.components.MantleObjectComponent;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import lombok.*;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Data
@EqualsAndHashCode(exclude = "engine")
@@ -47,9 +43,8 @@ public class IrisEngineMantle implements EngineMantle {
private final Mantle mantle;
@Getter(AccessLevel.NONE)
private final KMap<Integer, KList<MantleComponent>> components;
private final KMap<MantleFlag, MantleComponent> registeredComponents = new KMap<>();
private final AtomicCache<List<Pair<List<MantleComponent>, Integer>>> componentsCache = new AtomicCache<>();
private final AtomicCache<Set<MantleFlag>> disabledFlags = new AtomicCache<>();
private final AtomicCache<KList<Pair<KList<MantleComponent>, Integer>>> componentsCache = new AtomicCache<>();
private final AtomicCache<Integer> radCache = new AtomicCache<>();
private final MantleObjectComponent object;
private final MantleJigsawComponent jigsaw;
@@ -78,7 +73,7 @@ public class IrisEngineMantle implements EngineMantle {
}
@Override
public List<Pair<List<MantleComponent>, Integer>> getComponents() {
public KList<Pair<KList<MantleComponent>, Integer>> getComponents() {
return componentsCache.aquire(() -> {
var list = components.keySet()
.stream()
@@ -86,14 +81,13 @@ public class IrisEngineMantle implements EngineMantle {
.map(components::get)
.map(components -> {
int radius = components.stream()
.filter(MantleComponent::isEnabled)
.mapToInt(MantleComponent::getRadius)
.max()
.orElse(0);
return new Pair<>(List.copyOf(components), radius);
return new Pair<>(components, radius);
})
.filter(pair -> !pair.getA().isEmpty())
.toList();
.collect(Collectors.toCollection(KList::new));
int radius = 0;
for (var pair : list.reversed()) {
@@ -106,36 +100,9 @@ public class IrisEngineMantle implements EngineMantle {
}
@Override
public Map<MantleFlag, MantleComponent> getRegisteredComponents() {
return Collections.unmodifiableMap(registeredComponents);
}
@Override
public boolean registerComponent(MantleComponent c) {
if (registeredComponents.putIfAbsent(c.getFlag(), c) != null) return false;
c.setEnabled(!getDisabledFlags().contains(c.getFlag()));
public void registerComponent(MantleComponent c) {
components.computeIfAbsent(c.getPriority(), k -> new KList<>()).add(c);
componentsCache.reset();
return true;
}
@Override
public KList<MantleFlag> getComponentFlags() {
return new KList<>(registeredComponents.keySet());
}
@Override
public void hotload() {
disabledFlags.reset();
for (var component : registeredComponents.values()) {
component.hotload();
component.setEnabled(!getDisabledFlags().contains(component.getFlag()));
}
componentsCache.reset();
}
private Set<MantleFlag> getDisabledFlags() {
return disabledFlags.aquire(() -> Set.copyOf(getDimension().getDisabledComponents()));
}
@Override

View File

@@ -0,0 +1,84 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisScript;
import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
import com.volmit.iris.engine.scripting.IrisScriptingAPI;
import com.volmit.iris.util.format.C;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.apache.bsf.BSFException;
import org.apache.bsf.BSFManager;
import org.apache.bsf.engines.javascript.JavaScriptEngine;
@Data
@EqualsAndHashCode(exclude = "engine")
@ToString(exclude = "engine")
public class IrisExecutionEnvironment implements EngineExecutionEnvironment {
private final BSFManager manager;
private final Engine engine;
private final IrisScriptingAPI api;
private JavaScriptEngine javaScriptEngine;
public IrisExecutionEnvironment(Engine engine) {
this.engine = engine;
this.api = new IrisScriptingAPI(engine);
this.manager = new BSFManager();
this.manager.setClassLoader(Iris.class.getClassLoader());
try {
this.manager.declareBean("Iris", api, api.getClass());
this.javaScriptEngine = (JavaScriptEngine) this.manager.loadScriptingEngine("javascript");
} catch (Throwable e) {
e.printStackTrace();
}
}
@Override
public IrisScriptingAPI getAPI() {
return api;
}
public void execute(String script) {
execute(getEngine().getData().getScriptLoader().load(script));
}
public void execute(IrisScript script) {
Iris.debug("Execute Script (void) " + C.DARK_GREEN + script.getLoadKey());
try {
javaScriptEngine.exec("", 0, 0, script);
} catch (BSFException e) {
e.printStackTrace();
}
}
public Object evaluate(String script) {
Iris.debug("Execute Script (for result) " + C.DARK_GREEN + script);
try {
return javaScriptEngine.eval("", 0, 0, getEngine().getData().getScriptLoader().load(script));
} catch (BSFException e) {
e.printStackTrace();
}
return null;
}
}

View File

@@ -20,9 +20,7 @@ package com.volmit.iris.engine;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineAssignedWorldManager;
import com.volmit.iris.engine.object.*;
@@ -31,7 +29,7 @@ import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG;
@@ -57,7 +55,6 @@ import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.inventory.ItemStack;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -370,7 +367,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
private void spawn(IrisPosition pos, IrisEntitySpawn i) {
IrisSpawner ref = i.getReferenceSpawner();
if (!ref.canSpawn(getEngine(), pos.getX() >> 4, pos.getZ() >> 4))
if (!ref.canSpawn(getEngine(), pos.getX() >> 4, pos.getZ()))
return;
int s = i.spawn(getEngine(), pos, RNG.r);
@@ -425,36 +422,12 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
return;
}
var ref = new WeakReference<>(e.getWorld());
int cX = e.getX(), cZ = e.getZ();
J.s(() -> {
World world = ref.get();
if (world == null || !world.isChunkLoaded(cX, cZ))
return;
energy += 0.3;
fixEnergy();
getEngine().cleanupMantleChunk(cX, cZ);
}, IrisSettings.get().getPerformance().mantleCleanupDelay);
energy += 0.3;
fixEnergy();
getEngine().cleanupMantleChunk(e.getX(), e.getZ());
if (generated) {
//INMS.get().injectBiomesFromMantle(e, getMantle());
if (!IrisSettings.get().getGenerator().earlyCustomBlocks) return;
Iris.tickets.addTicket(e);
J.s(() -> {
var chunk = getMantle().getChunk(e).use();
int minY = getTarget().getWorld().minHeight();
try {
chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, () -> {
chunk.iterate(Identifier.class, (x, y, z, v) -> {
Iris.service(ExternalDataSVC.class).processUpdate(getEngine(), e.getBlock(x & 15, y + minY, z & 15), v);
});
});
} finally {
chunk.release();
Iris.tickets.removeTicket(e);
}
}, RNG.r.i(20, 60));
}
}

View File

@@ -106,14 +106,6 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<BlockData>
}
}
BlockData ore = biome.generateOres(realX, i, realZ, rng, getData(), true);
ore = ore == null ? region.generateOres(realX, i, realZ, rng, getData(), true) : ore;
ore = ore == null ? getDimension().generateOres(realX, i, realZ, rng, getData(), true) : ore;
if (ore != null) {
h.set(xf, i, zf, ore);
continue;
}
if (i > he && i <= hf) {
fdepth = hf - i;
@@ -146,9 +138,9 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<BlockData>
continue;
}
ore = biome.generateOres(realX, i, realZ, rng, getData(), false);
ore = ore == null ? region.generateOres(realX, i, realZ, rng, getData(), false) : ore;
ore = ore == null ? getDimension().generateOres(realX, i, realZ, rng, getData(), false) : ore;
BlockData ore = biome.generateOres(realX, i, realZ, rng, getData());
ore = ore == null ? region.generateOres(realX, i, realZ, rng, getData()) : ore;
ore = ore == null ? getDimension().generateOres(realX, i, realZ, rng, getData()) : ore;
if (ore != null) {
h.set(xf, i, zf, ore);

Some files were not shown because too many files have changed in this diff Show More