Compare commits

..

3 Commits

Author SHA1 Message Date
Julian Krings
3a74164627 implement priority to static placement component 2025-01-08 13:53:33 +01:00
Julian Krings
894de013dd Merge branch 'dev' into feat/static_placements
# Conflicts:
#	core/src/main/java/com/volmit/iris/engine/IrisEngineMantle.java
2025-01-08 13:03:30 +01:00
Julian Krings
9a81905fdd implement static placements for structures and objects 2025-01-06 01:48:11 +01:00
177 changed files with 6761 additions and 6652 deletions

View File

@@ -15,17 +15,17 @@ Consider supporting our development by buying Iris on spigot! We work hard to ma
### Command Line Builds
1. Install [Java JDK 21](https://www.oracle.com/java/technologies/javase/jdk21-archive-downloads.html)
1. Install [Java JDK 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
2. Set the JDK installation path to `JAVA_HOME` as an environment variable.
* Windows
1. Start > Type `env` and press Enter
2. Advanced > Environment Variables
3. Under System Variables, click `New...`
4. Variable Name: `JAVA_HOME`
5. Variable Value: `C:\Program Files\Java\jdk-21.0.1` (verify this exists after installing java don't just copy
5. Variable Value: `C:\Program Files\Java\jdk-17.0.1` (verify this exists after installing java don't just copy
the example text)
* MacOS
1. Run `/usr/libexec/java_home -V` and look for Java 21
1. Run `/usr/libexec/java_home -V` and look for Java 17
2. Run `sudo nano ~/.zshenv`
3. Add `export JAVA_HOME=$(/usr/libexec/java_home)` as a new line
4. Use `CTRL + X`, then Press `Y`, Then `ENTER`
@@ -35,7 +35,7 @@ Consider supporting our development by buying Iris on spigot! We work hard to ma
### IDE Builds (for development)
* Configure ITJ Gradle to use JDK 21 (in settings, search for gradle)
* Configure ITJ Gradle to use JDK 17 (in settings, search for gradle)
* Add a build line in the build.gradle for your own build task to directly compile Iris into your plugins folder if you
prefer.
* Resync the project & run your newly created task (under the development folder in gradle tasks!)

255
build.gradle Normal file
View File

@@ -0,0 +1,255 @@
/*
* 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.5.2-1.19.2-1.21.3'
// 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_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",
"v1_19_R3", "1.19.4-R0.1-SNAPSHOT",
"v1_19_R2", "1.19.3-R0.1-SNAPSHOT",
"v1_19_R1", "1.19.2-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 {
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.4.0'
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,278 +0,0 @@
import com.volmit.nmstools.NMSToolsExtension
import com.volmit.nmstools.NMSToolsPlugin
import de.undercouch.gradle.tasks.download.Download
import xyz.jpenilla.runpaper.task.RunServer
import kotlin.system.exitProcess
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2021 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
buildscript {
repositories.maven("https://jitpack.io")
dependencies.classpath("com.github.VolmitSoftware:NMSTools:c5cbc46ce6")
}
plugins {
java
`java-library`
id("com.gradleup.shadow") version "8.3.6"
id("de.undercouch.download") version "5.0.1"
id("xyz.jpenilla.run-paper") version "2.3.1"
id("io.sentry.jvm.gradle") version "5.7.0"
}
version = "3.6.10-1.20.1-1.21.5"
// ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED
// ======================== WINDOWS =============================
registerCustomOutputTask("Cyberpwn", "C://Users/cyberpwn/Documents/development/server/plugins")
registerCustomOutputTask("Psycho", "C://Dan/MinecraftDevelopment/Server/plugins")
registerCustomOutputTask("ArcaneArts", "C://Users/arcane/Documents/development/server/plugins")
registerCustomOutputTask("Coco", "D://mcsm/plugins")
registerCustomOutputTask("Strange", "D://Servers/1.17 Test Server/plugins")
registerCustomOutputTask("Vatuu", "D://Minecraft/Servers/1.19.4/plugins")
registerCustomOutputTask("CrazyDev22", "C://Users/Julian/Desktop/server/plugins")
registerCustomOutputTask("PixelFury", "C://Users/repix/workplace/Iris/1.21.3 - Development-Public-v3/plugins")
registerCustomOutputTask("PixelFuryDev", "C://Users/repix/workplace/Iris/1.21 - Development-v3/plugins")
// ========================== UNIX ==============================
registerCustomOutputTaskUnix("CyberpwnLT", "/Users/danielmills/development/server/plugins")
registerCustomOutputTaskUnix("PsychoLT", "/Users/brianfopiano/Developer/RemoteGit/Server/plugins")
registerCustomOutputTaskUnix("PixelMac", "/Users/test/Desktop/mcserver/plugins")
registerCustomOutputTaskUnix("CrazyDev22LT", "/home/julian/Desktop/server/plugins")
// ==============================================================
val serverMinHeap = "2G"
val serverMaxHeap = "8G"
//Valid values are: none, truecolor, indexed256, indexed16, indexed8
val color = "truecolor"
val errorReporting = false
val nmsBindings = mapOf(
"v1_21_R4" to "1.21.5-R0.1-SNAPSHOT",
"v1_21_R3" to "1.21.4-R0.1-SNAPSHOT",
"v1_21_R2" to "1.21.3-R0.1-SNAPSHOT",
"v1_21_R1" to "1.21.1-R0.1-SNAPSHOT",
"v1_20_R4" to "1.20.6-R0.1-SNAPSHOT",
"v1_20_R3" to "1.20.4-R0.1-SNAPSHOT",
"v1_20_R2" to "1.20.2-R0.1-SNAPSHOT",
"v1_20_R1" to "1.20.1-R0.1-SNAPSHOT",
)
val jvmVersion = mapOf<String, Int>()
nmsBindings.forEach { key, value ->
project(":nms:$key") {
apply<JavaPlugin>()
apply<NMSToolsPlugin>()
repositories {
maven("https://libraries.minecraft.net")
}
extensions.configure(NMSToolsExtension::class) {
jvm = jvmVersion.getOrDefault(key, 21)
version = value
}
dependencies {
compileOnly(project(":core"))
compileOnly("org.jetbrains:annotations:26.0.2")
}
}
tasks.register<RunServer>("runServer-$key") {
group = "servers"
minecraftVersion(value.split("-")[0])
minHeapSize = serverMinHeap
maxHeapSize = serverMaxHeap
pluginJars(tasks.jar.flatMap { it.archiveFile })
javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(jvmVersion.getOrDefault(key, 21))}
runDirectory.convention(layout.buildDirectory.dir("run/$key"))
systemProperty("disable.watchdog", "")
systemProperty("net.kyori.ansi.colorLevel", color)
systemProperty("com.mojang.eula.agree", true)
systemProperty("iris.errorReporting", errorReporting)
}
}
tasks {
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
nmsBindings.forEach { key, _ ->
from(project(":nms:$key").tasks.named("remap").map { zipTree(it.outputs.files.singleFile) })
}
from(project(":core").tasks.shadowJar.flatMap { it.archiveFile }.map { zipTree(it) })
archiveFileName.set("Iris-${project.version}.jar")
}
register<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 authToken = project.findProperty("sentry.auth.token") ?: System.getenv("SENTRY_AUTH_TOKEN")
val org = "volmit-software"
val projectName = "iris"
exec(cli, "releases", "new", "--auth-token", authToken, "-o", org, "-p", projectName, version)
exec(cli, "releases", "set-commits", "--auth-token", authToken, "-o", org, "-p", projectName, version, "--auto", "--ignore-missing")
exec(cli, "releases", "finalize", "--auth-token", authToken, "-o", org, "-p", projectName, version)
cli.delete()
}
}
}
fun exec(vararg command: Any) {
val p = ProcessBuilder(command.map { it.toString() })
.start()
p.inputStream.reader().useLines { it.forEach(::println) }
p.errorStream.reader().useLines { it.forEach(::println) }
p.waitFor()
}
dependencies {
implementation(project(":core"))
}
configurations.configureEach {
resolutionStrategy.cacheChangingModulesFor(60, "minutes")
resolutionStrategy.cacheDynamicVersionsFor(60, "minutes")
}
allprojects {
apply<JavaPlugin>()
repositories {
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
maven("https://repo.codemc.org/repository/maven-public/")
maven("https://mvn.lumine.io/repository/maven-public/")
maven("https://jitpack.io")
maven("https://s01.oss.sonatype.org/content/repositories/snapshots")
maven("https://mvn.lumine.io/repository/maven/")
maven("https://repo.triumphteam.dev/snapshots")
maven("https://repo.mineinabyss.com/releases")
maven("https://hub.jeff-media.com/nexus/repository/jeff-media-public/")
maven("https://repo.nexomc.com/releases/")
}
dependencies {
// Provided or Classpath
compileOnly("org.projectlombok:lombok:1.18.36")
annotationProcessor("org.projectlombok:lombok:1.18.36")
}
/**
* We need parameter meta for the decree command system
*/
tasks {
compileJava {
options.compilerArgs.add("-parameters")
options.encoding = "UTF-8"
}
javadoc {
options.encoding = "UTF-8"
options.quiet()
//options.addStringOption("Xdoclint:none") // TODO: Re-enable this
}
register<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" }
}
}

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:0.6.0-dev.0'
compileOnly 'com.github.LoneDev6:api-itemsadder:3.4.1-r4'
compileOnly 'com.github.PlaceholderAPI:placeholderapi:2.11.3'
compileOnly 'com.github.Ssomar-Developement:SCore:4.23.10.8'
compileOnly 'net.Indyuce:MMOItems-API:6.9.5-SNAPSHOT'
compileOnly 'com.willfp:EcoItems:5.44.0'
//implementation files('libs/CustomItems.jar')
}
java {
disableAutoTargetJvm()
}
/**
* Gradle is weird sometimes, we need to delete the plugin yml from the build folder to actually filter properly.
*/
file(jar.archiveFile.get().getAsFile().getParentFile().getParentFile().getParentFile().getAbsolutePath() + '/build/resources/main/plugin.yml').delete()
/**
* Expand properties into plugin yml
*/
processResources {
filesMatching('**/plugin.yml') {
expand(
'name': rootProject.name.toString(),
'version': rootProject.version.toString(),
'main': main.toString(),
'apiversion': apiVersion.toString()
)
}
}

View File

@@ -1,151 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2021 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
java
`java-library`
id("com.gradleup.shadow")
id("io.sentry.jvm.gradle")
}
val apiVersion = "1.19"
val main = "com.volmit.iris.Iris"
repositories {
maven("https://nexus.phoenixdevt.fr/repository/maven-public/")
maven("https://repo.auxilor.io/repository/maven-public/")
}
/**
* Dependencies.
*
* Provided or classpath dependencies are not shaded and are available on the runtime classpath
*
* Shaded dependencies are not available at runtime, nor are they available on mvn central so they
* need to be shaded into the jar (increasing binary size)
*
* Dynamically loaded dependencies are defined in the plugin.yml (updating these must be updated in the
* plugin.yml also, otherwise they wont be available). These do not increase binary size). Only declare
* these dependencies if they are available on mvn central.
*/
dependencies {
// Provided or Classpath
compileOnly("org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT")
compileOnly("org.apache.logging.log4j:log4j-api:2.19.0")
compileOnly("org.apache.logging.log4j:log4j-core:2.19.0")
compileOnly("commons-io:commons-io:2.13.0")
compileOnly("commons-lang:commons-lang:2.6")
compileOnly("com.github.oshi:oshi-core:5.8.5")
compileOnly("org.lz4:lz4-java:1.8.0")
// Third Party Integrations
compileOnly("com.nexomc:nexo:1.6.0")
compileOnly("com.github.LoneDev6:api-itemsadder:3.4.1-r4")
compileOnly("com.github.PlaceholderAPI:placeholderapi:2.11.3")
compileOnly("com.github.Ssomar-Developement:SCore:4.23.10.8")
compileOnly("net.Indyuce:MMOItems-API:6.9.5-SNAPSHOT")
compileOnly("com.willfp:EcoItems:5.44.0")
//implementation files("libs/CustomItems.jar")
// Shaded
implementation("com.dfsek:paralithic:0.8.1")
implementation("io.papermc:paperlib:1.0.5")
implementation("net.kyori:adventure-text-minimessage:4.17.0")
implementation("net.kyori:adventure-platform-bukkit:4.3.4")
implementation("net.kyori:adventure-api:4.17.0")
implementation("org.bstats:bstats-bukkit:3.1.0")
//implementation("org.bytedeco:javacpp:1.5.10")
//implementation("org.bytedeco:cuda-platform:12.3-8.9-1.5.10")
compileOnly("io.lumine:Mythic-Dist:5.2.1")
compileOnly("io.lumine:MythicCrucible-Dist:2.0.0")
// Dynamically Loaded
compileOnly("io.timeandspace:smoothie-map:2.0.2")
compileOnly("it.unimi.dsi:fastutil:8.5.8")
compileOnly("com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2")
compileOnly("org.zeroturnaround:zt-zip:1.14")
compileOnly("com.google.code.gson:gson:2.10.1")
compileOnly("org.ow2.asm:asm:9.2")
compileOnly("com.google.guava:guava:33.0.0-jre")
compileOnly("bsf:bsf:2.4.0")
compileOnly("rhino:js:1.7R2")
compileOnly("com.github.ben-manes.caffeine:caffeine:3.0.6")
compileOnly("org.apache.commons:commons-lang3:3.12.0")
compileOnly("com.github.oshi:oshi-core:6.6.5")
}
java {
disableAutoTargetJvm()
}
sentry {
includeSourceContext = true
org = "volmit-software"
projectName = "iris"
authToken = findProperty("sentry.auth.token") as String? ?: System.getenv("SENTRY_AUTH_TOKEN")
}
tasks {
/**
* We need parameter meta for the decree command system
*/
compileJava {
options.compilerArgs.add("-parameters")
options.encoding = "UTF-8"
}
/**
* Expand properties into plugin yml
*/
processResources {
inputs.properties(
"name" to rootProject.name,
"version" to rootProject.version,
"apiVersion" to apiVersion,
"main" to main
)
filesMatching("**/plugin.yml") {
expand(inputs.properties)
}
}
shadowJar {
mergeServiceFiles()
relocate("com.dfsek.paralithic", "com.volmit.iris.util.paralithic")
relocate("io.papermc.lib", "com.volmit.iris.util.paper")
relocate("net.kyori", "com.volmit.iris.util.kyori")
relocate("org.bstats", "com.volmit.iris.util.metrics")
relocate("io.sentry", "com.volmit.iris.util.sentry")
//minimize()
dependencies {
exclude(dependency("org.ow2.asm:asm:"))
exclude(dependency("org.jetbrains:"))
}
}
}
/**
* Gradle is weird sometimes, we need to delete the plugin yml from the build folder to actually filter properly.
*/
afterEvaluate {
layout.buildDirectory.file("resources/main/plugin.yml").get().asFile.delete()
}

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,8 +45,6 @@ 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 switch (c) {
@@ -132,46 +130,21 @@ 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 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 = false;
public int maxConcurrency = 256;
}
@Data
public static class IrisSettingsPerformance {
private IrisSettingsEngineSVC engineSVC = new IrisSettingsEngineSVC();
public boolean trimMantleInStudio = false;
public int mantleKeepAlive = 30;
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
@@ -203,13 +176,11 @@ 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;
public boolean useConsoleCustomColors = true;
public boolean useCustomColorsIngame = true;
public boolean adjustVanillaHeight = false;
public String forceMainWorld = "";
public int spinh = -20;
public int spins = 7;
@@ -223,13 +194,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;
@@ -251,14 +215,4 @@ public class IrisSettings {
public boolean disableTimeAndWeather = true;
public boolean autoStartDefaultStudio = false;
}
@Data
public static class IrisSettingsEngineSVC {
public boolean useVirtualThreads = true;
public int priority = Thread.NORM_PRIORITY;
public int getPriority() {
return Math.max(Math.min(priority, Thread.MAX_PRIORITY), Thread.MIN_PRIORITY);
}
}
}

View File

@@ -28,28 +28,20 @@ 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;
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 org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import static com.volmit.iris.core.nms.datapack.IDataFixer.Dimension.*;
public class ServerConfigurator {
public static void configure() {
@@ -71,12 +63,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);
}
}
@@ -86,22 +76,20 @@ 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);
}
}
private static KList<File> getDatapacksFolder() {
private static List<File> getDatapacksFolder() {
if (!IrisSettings.get().getGeneral().forceMainWorld.isEmpty()) {
return new KList<File>().qadd(new File(Bukkit.getWorldContainer(), IrisSettings.get().getGeneral().forceMainWorld + "/datapacks"));
}
KList<File> worlds = new KList<>();
Bukkit.getServer().getWorlds().forEach(w -> worlds.add(new File(w.getWorldFolder(), "datapacks")));
if (worlds.isEmpty()) worlds.add(new File(Bukkit.getWorldContainer(), ServerProperties.LEVEL_NAME + "/datapacks"));
return worlds;
}
@@ -111,17 +99,57 @@ public class ServerConfigurator {
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<>();
File packs = new File("plugins/Iris/packs");
double ultimateMaxHeight = 0;
double ultimateMinHeight = 0;
if (packs.exists() && packs.isDirectory()) {
for (File pack : packs.listFiles()) {
IrisData data = IrisData.get(pack);
if (pack.isDirectory()) {
File dimensionsFolder = new File(pack, "dimensions");
if (dimensionsFolder.exists() && dimensionsFolder.isDirectory()) {
for (File file : dimensionsFolder.listFiles()) {
if (file.isFile() && file.getName().endsWith(".json")) {
IrisDimension dim = data.getDimensionLoader().load(file.getName().split("\\Q.\\E")[0]);
if (ultimateMaxHeight < dim.getDimensionHeight().getMax()) {
ultimateMaxHeight = dim.getDimensionHeight().getMax();
}
if (ultimateMinHeight > dim.getDimensionHeight().getMin()) {
ultimateMinHeight = dim.getDimensionHeight().getMin();
}
}
}
}
}
}
}
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);
if (packs.exists()) {
for (File i : packs.listFiles()) {
if (i.isDirectory()) {
Iris.verbose("Checking Pack: " + i.getPath());
IrisData data = IrisData.get(i);
File dims = new File(i, "dimensions");
if (dims.exists()) {
for (File j : dims.listFiles()) {
if (j.getName().endsWith(".json")) {
IrisDimension dim = data.getDimensionLoader().load(j.getName().split("\\Q.\\E")[0]);
if (dim == null) {
continue;
}
Iris.verbose(" Checking Dimension " + dim.getLoadFile().getPath());
for (File dpack : getDatapacksFolder()) {
dim.installDataPack(fixer, () -> data, dpack, ultimateMaxHeight, ultimateMinHeight);
}
}
}
}
}
}
}
Iris.info("Data Packs Setup!");
@@ -130,40 +158,57 @@ public class ServerConfigurator {
}
private static void verifyDataPacksPost(boolean allowRestarting) {
boolean bad = allPacks()
.map(data -> {
Iris.verbose("Checking Pack: " + data.getDataFolder().getPath());
var loader = data.getDimensionLoader();
return loader.loadAll(loader.getPossibleKeys())
.stream()
.map(ServerConfigurator::verifyDataPackInstalled)
.toList()
.contains(false);
})
.toList()
.contains(true);
if (!bad) return;
File packs = new File("plugins/Iris/packs");
boolean bad = false;
if (packs.exists()) {
for (File i : packs.listFiles()) {
if (i.isDirectory()) {
Iris.verbose("Checking Pack: " + i.getPath());
IrisData data = IrisData.get(i);
File dims = new File(i, "dimensions");
if (allowRestarting) {
restart();
} else if (INMS.get().supportsDataPacks()) {
Iris.error("============================================================================");
Iris.error(C.ITALIC + "You need to restart your server to properly generate custom biomes.");
Iris.error(C.ITALIC + "By continuing, Iris will use backup biomes in place of the custom biomes.");
Iris.error("----------------------------------------------------------------------------");
Iris.error(C.UNDERLINE + "IT IS HIGHLY RECOMMENDED YOU RESTART THE SERVER BEFORE GENERATING!");
Iris.error("============================================================================");
if (dims.exists()) {
for (File j : dims.listFiles()) {
if (j.getName().endsWith(".json")) {
IrisDimension dim = data.getDimensionLoader().load(j.getName().split("\\Q.\\E")[0]);
for (Player i : Bukkit.getOnlinePlayers()) {
if (i.isOp() || i.hasPermission("iris.all")) {
VolmitSender sender = new VolmitSender(i, Iris.instance.getTag("WARNING"));
sender.sendMessage("There are some Iris Packs that have custom biomes in them");
sender.sendMessage("You need to restart your server to use these packs.");
if (dim == null) {
Iris.error("Failed to load " + j.getPath() + " ");
continue;
}
if (!verifyDataPackInstalled(dim)) {
bad = true;
}
}
}
}
}
}
}
J.sleep(3000);
if (bad) {
if (allowRestarting) {
restart();
} else if (INMS.get().supportsDataPacks()) {
Iris.error("============================================================================");
Iris.error(C.ITALIC + "You need to restart your server to properly generate custom biomes.");
Iris.error(C.ITALIC + "By continuing, Iris will use backup biomes in place of the custom biomes.");
Iris.error("----------------------------------------------------------------------------");
Iris.error(C.UNDERLINE + "IT IS HIGHLY RECOMMENDED YOU RESTART THE SERVER BEFORE GENERATING!");
Iris.error("============================================================================");
for (Player i : Bukkit.getOnlinePlayers()) {
if (i.isOp() || i.hasPermission("iris.all")) {
VolmitSender sender = new VolmitSender(i, Iris.instance.getTag("WARNING"));
sender.sendMessage("There are some Iris Packs that have custom biomes in them");
sender.sendMessage("You need to restart your server to use these packs.");
}
}
J.sleep(3000);
}
}
}
@@ -173,7 +218,7 @@ public class ServerConfigurator {
Iris.warn("This will only happen when your pack changes (updates/first time setup)");
Iris.warn("(You can disable this auto restart in iris settings)");
J.s(() -> {
Iris.warn("Looks like the restart command didn't work. Stopping the server instead!");
Iris.warn("Looks like the restart command diddn't work. Stopping the server instead!");
Bukkit.shutdown();
}, 100);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart");
@@ -181,24 +226,22 @@ public class ServerConfigurator {
}
public static boolean verifyDataPackInstalled(IrisDimension dimension) {
IrisData idm = IrisData.get(Iris.instance.getDataFolder("packs", dimension.getLoadKey()));
KSet<String> keys = new KSet<>();
boolean warn = false;
for (IrisBiome i : dimension.getAllBiomes(dimension::getLoader)) {
for (IrisBiome i : dimension.getAllBiomes(() -> idm)) {
if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) {
keys.add(dimension.getLoadKey() + ":" + j.getId());
}
}
}
String key = getWorld(dimension.getLoader());
if (key == null) key = dimension.getLoadKey();
else key += "/" + dimension.getLoadKey();
if (!INMS.get().supportsDataPacks()) {
if (!keys.isEmpty()) {
Iris.warn("===================================================================================");
Iris.warn("Pack " + key + " has " + keys.size() + " custom biome(s). ");
Iris.warn("Pack " + dimension.getLoadKey() + " has " + keys.size() + " custom biome(s). ");
Iris.warn("Your server version does not yet support datapacks for iris.");
Iris.warn("The world will generate these biomes as backup biomes.");
Iris.warn("====================================================================================");
@@ -217,74 +260,10 @@ public class ServerConfigurator {
}
if (warn) {
Iris.error("The Pack " + key + " is INCAPABLE of generating custom biomes");
Iris.error("The Pack " + dimension.getLoadKey() + " is INCAPABLE of generating custom biomes");
Iris.error("If not done automatically, restart your server before generating with this pack!");
}
return !warn;
}
public static Stream<IrisData> allPacks() {
return Stream.concat(listFiles(new File("plugins/Iris/packs")),
listFiles(Bukkit.getWorldContainer()).map(w -> new File(w, "iris/pack")))
.filter(File::isDirectory)
.map(IrisData::get);
}
@Nullable
public static String getWorld(@NonNull IrisData data) {
String worldContainer = Bukkit.getWorldContainer().getAbsolutePath();
if (!worldContainer.endsWith(File.separator)) worldContainer += File.separator;
String path = data.getDataFolder().getAbsolutePath();
if (!path.startsWith(worldContainer)) return null;
int l = path.endsWith(File.separator) ? 11 : 10;
return path.substring(worldContainer.length(), path.length() - l);
}
private static Stream<File> listFiles(File parent) {
var files = parent.listFiles();
return files == null ? Stream.empty() : Arrays.stream(files);
}
@Data
public static class DimensionHeight {
private final IDataFixer fixer;
private IrisRange overworld = new IrisRange();
private IrisRange nether = new IrisRange();
private IrisRange end = new IrisRange();
private int logicalOverworld = 0;
private int logicalNether = 0;
private int logicalEnd = 0;
public Stream<IrisDimension> merge(IrisData data) {
Iris.verbose("Checking Pack: " + data.getDataFolder().getPath());
var loader = data.getDimensionLoader();
return loader.loadAll(loader.getPossibleKeys())
.stream()
.peek(this::merge);
}
public void merge(IrisDimension dimension) {
overworld.merge(dimension.getDimensionHeight());
nether.merge(dimension.getDimensionHeight());
end.merge(dimension.getDimensionHeight());
logicalOverworld = Math.max(logicalOverworld, dimension.getLogicalHeight());
logicalNether = Math.max(logicalNether, dimension.getLogicalHeightNether());
logicalEnd = Math.max(logicalEnd, dimension.getLogicalHeightEnd());
}
public String overworldType() {
return fixer.createDimension(OVERRWORLD, overworld, logicalOverworld).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

@@ -20,13 +20,13 @@ package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.datapack.DataVersion;
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.context.IrisContext;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
@@ -36,7 +36,6 @@ 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.nbt.mca.MCAFile;
import com.volmit.iris.util.nbt.mca.MCAUtil;
import com.volmit.iris.util.parallel.MultiBurst;
@@ -63,56 +62,57 @@ 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 = "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());
for (World world : Bukkit.getWorlds()) {
try {
if (IrisToolbelt.access(world).getEngine() != null) {
IrisWorlds.add(world);
}
pw.println("========================================");
pw.println();
pw.println();
} catch (Exception e) {
// no
}
pw.close();
Iris.info("DUMPED! See " + fi.getAbsolutePath());
} catch (Throwable e) {
e.printStackTrace();
}
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();
}
if (lowestUnloadDuration >= (long) engine.getMantle().getTectonicDuration()) {
lowestUnloadDuration = (long) engine.getMantle().getTectonicDuration();
}
for (Chunk chunk : world.getLoadedChunks()) {
if (chunk.isLoaded()) {
TotalLoadedChunks++;
}
}
}
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")
@@ -128,7 +128,7 @@ public class CommandDeveloper implements DecreeExecutor {
File tectonicplates = new File(folder, "mantle");
for (File i : Objects.requireNonNull(tectonicplates.listFiles())) {
TectonicPlate.read(maxHeight, i, true);
TectonicPlate.read(maxHeight, i);
c++;
Iris.info("Loaded count: " + c );
@@ -140,7 +140,7 @@ public class CommandDeveloper implements DecreeExecutor {
public void packBenchmark(
@Param(description = "The pack to bench", aliases = {"pack"}, defaultValue = "overworld")
IrisDimension dimension,
@Param(description = "Radius in regions", defaultValue = "2048")
@Param(description = "Radius in regions", defaultValue = "5")
int radius,
@Param(description = "Open GUI while benchmarking", defaultValue = "false")
boolean gui
@@ -234,8 +234,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;
@@ -252,7 +251,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;
@@ -271,7 +270,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,10 +20,12 @@ package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
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.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;
@@ -41,7 +43,9 @@ import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Difficulty;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.configuration.ConfigurationSection;
@@ -51,13 +55,16 @@ import org.bukkit.entity.Player;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.Console;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.volmit.iris.Iris.service;
import static com.volmit.iris.core.service.EditSVC.deletingWorld;
import static com.volmit.iris.core.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;
@@ -66,12 +73,14 @@ import static org.bukkit.Bukkit.getServer;
public class CommandIris implements DecreeExecutor {
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;
String WorldEngine;
@@ -85,7 +94,9 @@ public class CommandIris implements DecreeExecutor {
@Param(aliases = "dimension", description = "The dimension type to create the world with", defaultValue = "default")
IrisDimension type,
@Param(description = "The seed to generate the world with", defaultValue = "1337")
long seed
long seed,
@Param(description = "If it should convert the dimension to match the vanilla height system.", defaultValue = "false")
boolean vanillaheight
) {
if(sender() instanceof Player) {
if (incompatibilities.get("Multiverse-Core")) {
@@ -129,6 +140,7 @@ public class CommandIris implements DecreeExecutor {
.seed(seed)
.sender(sender())
.studio(false)
.smartVanillaHeight(vanillaheight)
.create();
} catch (Throwable e) {
sender().sendMessage(C.RED + "Exception raised during creation. See the console for more details.");
@@ -171,6 +183,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)
@@ -252,17 +274,6 @@ public class CommandIris implements DecreeExecutor {
return;
}
sender().sendMessage(C.GREEN + "Removing world: " + world.getName());
if (!IrisToolbelt.evacuate(world)) {
sender().sendMessage(C.RED + "Failed to evacuate world: " + world.getName());
return;
}
if (!Bukkit.unloadWorld(world, false)) {
sender().sendMessage(C.RED + "Failed to unload world: " + world.getName());
return;
}
try {
if (IrisToolbelt.removeWorld(world)) {
sender().sendMessage(C.GREEN + "Successfully removed " + world.getName() + " from bukkit.yml");
@@ -275,32 +286,27 @@ public class CommandIris implements DecreeExecutor {
}
IrisToolbelt.evacuate(world, "Deleting world");
deletingWorld = true;
if (!delete) {
deletingWorld = false;
return;
}
VolmitSender sender = sender();
J.a(() -> {
int retries = 12;
Bukkit.unloadWorld(world, false);
int retries = 12;
if (delete) {
if (deleteDirectory(world.getWorldFolder())) {
sender.sendMessage(C.GREEN + "Successfully removed world folder");
sender().sendMessage(C.GREEN + "Successfully removed world folder");
} else {
while(true){
if (deleteDirectory(world.getWorldFolder())){
sender.sendMessage(C.GREEN + "Successfully removed world folder");
sender().sendMessage(C.GREEN + "Successfully removed world folder");
break;
}
retries--;
if (retries == 0){
sender.sendMessage(C.RED + "Failed to remove world folder");
sender().sendMessage(C.RED + "Failed to remove world folder");
break;
}
J.sleep(3000);
}
}
deletingWorld = false;
});
}
deletingWorld = false;
}
public static boolean deleteDirectory(File dir) {
@@ -399,7 +405,7 @@ public class CommandIris implements DecreeExecutor {
) {
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";
String url = "https://github.com/IrisDimensions/overworld/releases/download/" + Iris.OVERWORLD_TAG + "/overworld.zip";
Iris.service(StudioSVC.class).downloadRelease(sender(), url, trim, overwrite);
} else {
Iris.service(StudioSVC.class).downloadSearch(sender(), "IrisDimensions/" + pack + "/" + branch, trim, overwrite);
@@ -585,10 +591,10 @@ public class CommandIris implements DecreeExecutor {
continue;
}
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
WorldCreator c = new WorldCreator(s)
new WorldCreator(s)
.generator(getDefaultWorldGenerator(s, generator))
.environment(IrisData.loadAnyDimension(generator).getEnvironment());
INMS.get().createWorld(c);
.environment(IrisData.loadAnyDimension(generator).getEnvironment())
.createWorld();
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
}
} catch (Throwable e) {
@@ -643,6 +649,6 @@ public class CommandIris implements DecreeExecutor {
ff.mkdirs();
service(StudioSVC.class).installIntoWorld(sender, dim.getLoadKey(), ff.getParentFile());
}
return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey());
return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey(), false);
}
}

View File

@@ -28,8 +28,6 @@ import com.volmit.iris.core.tools.IrisConverter;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.util.data.Cuboid;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.data.registry.Materials;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
@@ -38,9 +36,12 @@ 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.misc.E;
import com.volmit.iris.util.scheduling.Queue;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
@@ -53,7 +54,7 @@ import java.util.*;
@Decree(name = "object", aliases = "o", origin = DecreeOrigin.PLAYER, studio = true, description = "Iris object manipulation")
public class CommandObject implements DecreeExecutor {
private static final Set<Material> skipBlocks = Set.of(Materials.GRASS, Material.SNOW, Material.VINE, Material.TORCH, Material.DEAD_BUSH,
private static final Set<Material> skipBlocks = Set.of(E.getOrDefault(Material.class, "GRASS", "SHORT_GRASS"), Material.SNOW, Material.VINE, Material.TORCH, Material.DEAD_BUSH,
Material.POPPY, Material.DANDELION);
public static IObjectPlacer createPlacer(World world, Map<Block, BlockData> futureBlockChanges) {
@@ -78,10 +79,7 @@ public class CommandObject implements DecreeExecutor {
futureBlockChanges.put(block, block.getBlockData());
if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase());
Iris.warn("Tried to place custom block at " + x + ", " + y + ", " + z + " which is not supported!");
} else block.setBlockData(d);
block.setBlockData(d);
}
@Override
@@ -241,8 +239,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();
@@ -418,10 +415,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();
@@ -482,10 +475,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();
@@ -533,10 +522,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

@@ -19,7 +19,9 @@
package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.gui.PregeneratorJob;
import com.volmit.iris.core.pregenerator.LazyPregenerator;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.decree.DecreeExecutor;
@@ -27,9 +29,12 @@ 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;
@Decree(name = "pregen", aliases = "pregenerate", description = "Pregenerate your Iris worlds!")
public class CommandPregen implements DecreeExecutor {
@Decree(description = "Pregenerate a world")
@@ -39,9 +44,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) {
@@ -49,12 +52,13 @@ public class CommandPregen implements DecreeExecutor {
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);
int w = (radius >> 9 + 1) * 2;
IrisToolbelt.pregenerate(PregenTask
.builder()
.center(new Position2(center.getBlockX(), center.getBlockZ()))
.gui(gui)
.radiusX(radius)
.radiusZ(radius)
.center(new Position2(center.getBlockX() >> 9, center.getBlockZ() >> 9))
.gui(true)
.width(w)
.height(w)
.build(), world);
String msg = C.GREEN + "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);

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

@@ -24,6 +24,7 @@ import com.volmit.iris.core.pregenerator.IrisPregenerator;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.core.tools.IrisPackBenchmarking;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.format.Form;
@@ -40,13 +41,12 @@ 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;
import static com.volmit.iris.core.tools.IrisPackBenchmarking.benchmarkInProgress;
public class PregeneratorJob implements PregenListener {
private static final Color COLOR_EXISTS = parseColor("#4d7d5b");
private static final Color COLOR_BLACK = parseColor("#4d7d5b");
@@ -56,7 +56,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,33 +67,26 @@ 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..."};
this.task = task;
this.pregenerator = new IrisPregenerator(task, method, this);
max = new Position2(0, 0);
min = new Position2(Integer.MAX_VALUE, Integer.MAX_VALUE);
task.iterateAllChunks((xx, zz) -> {
min.setX(Math.min(xx, min.getX()));
min.setZ(Math.min(zz, min.getZ()));
max.setX(Math.max(xx, max.getX()));
max.setZ(Math.max(zz, max.getZ()));
min = new Position2(0, 0);
task.iterateRegions((xx, zz) -> {
min.setX(Math.min(xx << 5, min.getX()));
min.setZ(Math.min(zz << 5, min.getZ()));
max.setX(Math.max((xx << 5) + 31, max.getX()));
max.setZ(Math.max((zz << 5) + 31, max.getZ()));
});
if (IrisSettings.get().getGui().isUseServerLaunchedGuis() && task.isGui()) {
@@ -106,44 +99,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) {
@@ -173,7 +162,7 @@ public class PregeneratorJob implements PregenListener {
}
public void drawRegion(int x, int z, Color color) {
J.a(() -> task.iterateChunks(x, z, (xx, zz) -> {
J.a(() -> PregenTask.iterateRegion(x, z, (xx, zz) -> {
draw(xx, zz, color);
J.sleep(3);
}));
@@ -193,7 +182,7 @@ public class PregeneratorJob implements PregenListener {
J.a(() -> {
pregenerator.close();
close();
instance.compareAndSet(this, null);
instance = null;
});
}
@@ -233,10 +222,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 +243,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 +307,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,7 +30,6 @@ 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;
@@ -57,8 +56,6 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.BiFunction;
import static com.volmit.iris.util.data.registry.Attributes.MAX_HEALTH;
public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener, MouseMotionListener, MouseInputListener {
private static final long serialVersionUID = 2094606939770332040L;
private final KList<LivingEntity> lastEntities = new KList<>();
@@ -639,7 +636,7 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
k.add("Pos: " + h.getLocation().getBlockX() + ", " + h.getLocation().getBlockY() + ", " + h.getLocation().getBlockZ());
k.add("UUID: " + h.getUniqueId());
k.add("HP: " + h.getHealth() + " / " + h.getAttribute(MAX_HEALTH).getValue());
k.add("HP: " + h.getHealth() + " / " + h.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
drawCardTR(g, k);
}

View File

@@ -55,10 +55,10 @@ public class IrisRenderer {
IrisBiome b = renderer.getBiome((int) Math.round(x), renderer.getMaxHeight() - 1, (int) Math.round(z));
IrisBiomeGeneratorLink g = b.getGenerators().get(0);
Color c;
if (g.getMax() <= 0) {
if (g.getMax(renderer) <= 0) {
// Max is below water level, so it is most likely an ocean biome
c = Color.BLUE;
} else if (g.getMin() < 0) {
} else if (g.getMin(renderer) < 0) {
// Min is below water level, but max is not, so it is most likely a shore biome
c = Color.YELLOW;
} else {

View File

@@ -2,7 +2,7 @@ package com.volmit.iris.core.link;
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.data.IrisBlockData;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@@ -49,7 +49,7 @@ public abstract class ExternalDataProvider {
* @param blockId The id of the block to get
* @param state The state of the block to get
* @return Corresponding {@link BlockData} to the blockId
* may return {@link IrisCustomData} for blocks that need a world for placement
* may return {@link IrisBlockData} for blocks that need a world for placement
* @throws MissingResourceException when the blockId is invalid
*/
@NotNull
@@ -77,7 +77,7 @@ public abstract class ExternalDataProvider {
/**
* This method is used for placing blocks that need to use the plugins api
* it will only be called when the {@link ExternalDataProvider#getBlockData(Identifier, KMap)} returned a {@link IrisCustomData}
* it will only be called when the {@link ExternalDataProvider#getBlockData(Identifier, KMap)} returned a {@link IrisBlockData}
*
* @param engine The engine of the world the block is being placed in
* @param block The block where the block should be placed

View File

@@ -6,7 +6,7 @@ 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.data.IrisBlockData;
import com.volmit.iris.util.reflect.WrappedField;
import com.volmit.iris.util.reflect.WrappedReturningMethod;
import org.bukkit.Bukkit;
@@ -64,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 new IrisCustomData(blockData, ExternalDataSVC.buildState(blockId, state));
return new IrisBlockData(blockData, ExternalDataSVC.buildState(blockId, state));
}
@NotNull

View File

@@ -27,7 +27,7 @@ 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.data.IrisBlockData;
import com.volmit.iris.util.math.RNG;
import io.lumine.mythic.bukkit.BukkitAdapter;
import io.lumine.mythic.bukkit.utils.serialize.Chroma;
@@ -71,7 +71,7 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider {
CustomBlockItemContext blockItemContext = crucibleItem.getBlockData();
FurnitureItemContext furnitureItemContext = crucibleItem.getFurnitureData();
if (furnitureItemContext != null) {
return new IrisCustomData(B.getAir(), ExternalDataSVC.buildState(blockId, state));
return new IrisBlockData(B.getAir(), ExternalDataSVC.buildState(blockId, state));
} else if (blockItemContext != null) {
return blockItemContext.getBlockData();
}

View File

@@ -18,33 +18,19 @@
package com.volmit.iris.core.link;
import com.google.common.collect.Sets;
import com.volmit.iris.Iris;
import com.volmit.iris.core.tools.IrisToolbelt;
import io.lumine.mythic.api.adapters.AbstractLocation;
import io.lumine.mythic.api.config.MythicLineConfig;
import io.lumine.mythic.api.skills.conditions.ILocationCondition;
import io.lumine.mythic.bukkit.MythicBukkit;
import io.lumine.mythic.bukkit.adapters.BukkitWorld;
import io.lumine.mythic.bukkit.events.MythicConditionLoadEvent;
import io.lumine.mythic.core.skills.SkillCondition;
import io.lumine.mythic.core.utils.annotations.MythicCondition;
import io.lumine.mythic.core.utils.annotations.MythicField;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import javax.annotation.Nullable;
import java.util.*;
import java.util.Collection;
public class MythicMobsLink {
public MythicMobsLink() {
if (getPlugin() == null) return;
Iris.instance.registerListener(new ConditionListener());
}
public boolean isEnabled() {
@@ -62,70 +48,12 @@ public class MythicMobsLink {
* @param location The location
* @return The mob, or null if it can't be spawned
*/
public @Nullable Entity spawnMob(String mob, Location location) {
public @Nullable
Entity spawnMob(String mob, Location location) {
return isEnabled() ? MythicBukkit.inst().getMobManager().spawnMob(mob, location).getEntity().getBukkitEntity() : null;
}
public Collection<String> getMythicMobTypes() {
return isEnabled() ? MythicBukkit.inst().getMobManager().getMobNames() : List.of();
}
private static class ConditionListener implements Listener {
@EventHandler
public void on(MythicConditionLoadEvent event) {
switch (event.getConditionName()) {
case "irisbiome" -> event.register(new IrisBiomeCondition(event.getConditionName(), event.getConfig()));
case "irisregion" -> event.register(new IrisRegionCondition(event.getConditionName(), event.getConfig()));
}
}
}
@MythicCondition(author = "CrazyDev22", name = "irisbiome", description = "Tests if the target is within the given list of biomes")
public static class IrisBiomeCondition extends SkillCondition implements ILocationCondition {
@MythicField(name = "biome", aliases = {"b"}, description = "A list of biomes to check")
private Set<String> biomes = Sets.newConcurrentHashSet();
@MythicField(name = "surface", aliases = {"s"}, description = "If the biome check should only be performed on the surface")
private boolean surface;
public IrisBiomeCondition(String line, MythicLineConfig mlc) {
super(line);
String b = mlc.getString(new String[]{"biome", "b"}, "");
biomes.addAll(Arrays.asList(b.split(",")));
surface = mlc.getBoolean(new String[]{"surface", "s"}, false);
}
@Override
public boolean check(AbstractLocation target) {
var access = IrisToolbelt.access(((BukkitWorld) target.getWorld()).getBukkitWorld());
if (access == null) return false;
var engine = access.getEngine();
if (engine == null) return false;
var biome = surface ?
engine.getSurfaceBiome(target.getBlockX(), target.getBlockZ()) :
engine.getBiomeOrMantle(target.getBlockX(), target.getBlockY() - engine.getMinHeight(), target.getBlockZ());
return biomes.contains(biome.getLoadKey());
}
}
@MythicCondition(author = "CrazyDev22", name = "irisbiome", description = "Tests if the target is within the given list of biomes")
public static class IrisRegionCondition extends SkillCondition implements ILocationCondition {
@MythicField(name = "region", aliases = {"r"}, description = "A list of regions to check")
private Set<String> regions = Sets.newConcurrentHashSet();
public IrisRegionCondition(String line, MythicLineConfig mlc) {
super(line);
String b = mlc.getString(new String[]{"region", "r"}, "");
regions.addAll(Arrays.asList(b.split(",")));
}
@Override
public boolean check(AbstractLocation target) {
var access = IrisToolbelt.access(((BukkitWorld) target.getWorld()).getBukkitWorld());
if (access == null) return false;
var engine = access.getEngine();
if (engine == null) return false;
var region = engine.getRegion(target.getBlockX(), target.getBlockZ());
return regions.contains(region.getLoadKey());
}
return isEnabled() ? MythicBukkit.inst().getMobManager().getMobNames() : null;
}
}

View File

@@ -11,7 +11,7 @@ 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.data.IrisBlockData;
import com.volmit.iris.util.math.RNG;
import org.bukkit.Color;
import org.bukkit.block.Block;
@@ -49,9 +49,9 @@ 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 new IrisCustomData(data, blockState);
return new IrisBlockData(data, blockState);
} else if (NexoFurniture.isFurniture(blockId.key())) {
return new IrisCustomData(B.getAir(), blockState);
return new IrisBlockData(B.getAir(), blockState);
}
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
@@ -125,7 +125,7 @@ public class NexoDataProvider extends ExternalDataProvider {
@NotNull
@Override
public Identifier[] getBlockTypes() {
return NexoItems.itemNames().stream()
return Arrays.stream(NexoItems.itemNames())
.map(i -> new Identifier("nexo", i))
.filter(i -> {
try {
@@ -140,7 +140,7 @@ public class NexoDataProvider extends ExternalDataProvider {
@NotNull
@Override
public Identifier[] getItemTypes() {
return NexoItems.itemNames().stream()
return Arrays.stream(NexoItems.itemNames())
.map(i -> new Identifier("nexo", i))
.filter(i -> {
try {

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

@@ -300,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());
}

View File

@@ -45,7 +45,6 @@ import lombok.ToString;
import java.io.*;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
@@ -241,10 +240,8 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
for (String i : s) {
burst.queue(() -> {
T t = load(i);
if (t == null)
return;
synchronized (m) {
if (t != null) {
m.add(t);
}
});

View File

@@ -23,29 +23,19 @@ import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import org.bukkit.Bukkit;
import java.util.List;
import java.util.Map;
public class INMS {
private static final Map<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",
"1.21.5", "v1_21_R4"
"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"
);
private static final List<Version> PACKS = List.of(
new Version(21, 4, "31020"),
new Version(21, 2, "31000"),
new Version(20, 1, "3910")
);
//@done
private static final INMSBinding binding = bind();
public static final String OVERWORLD_TAG = getOverworldTag();
public static INMSBinding get() {
return binding;
@@ -96,26 +86,4 @@ public class INMS {
return new NMSBinding1X();
}
private static String getOverworldTag() {
var version = Bukkit.getServer().getBukkitVersion().split("-")[0].split("\\.", 3);
int major = 0;
int minor = 0;
if (version.length > 2) {
major = Integer.parseInt(version[1]);
minor = Integer.parseInt(version[2]);
} else if (version.length == 2) {
major = Integer.parseInt(version[1]);
}
for (var p : PACKS) {
if (p.major > major || p.minor > minor)
continue;
return p.tag;
}
return "3910";
}
private record Version(int major, int minor, String tag) {}
}

View File

@@ -18,7 +18,6 @@
package com.volmit.iris.core.nms;
import com.volmit.iris.core.nms.container.AutoClosing;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.engine.framework.Engine;
@@ -31,12 +30,15 @@ import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess;
import com.volmit.iris.util.nbt.tag.CompoundTag;
import org.bukkit.*;
import org.bukkit.block.Biome;
import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.generator.structure.Structure;
import org.bukkit.inventory.ItemStack;
import java.awt.*;
import java.awt.Color;
public interface INMSBinding {
@@ -89,13 +91,7 @@ public interface INMSBinding {
MCABiomeContainer newBiomeContainer(int min, int max);
default World createWorld(WorldCreator c) {
if (missingDimensionTypes(true, true, true))
throw new IllegalStateException("Missing dimenstion types to create world");
try (var ignored = injectLevelStems()) {
ignored.storeContext();
return c.createWorld();
}
return c.createWorld();
}
int countCustomBiomes();
@@ -129,14 +125,4 @@ public interface INMSBinding {
}
KList<String> getStructureKeys();
AutoClosing injectLevelStems();
default AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
return null;
}
boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end);
void removeCustomDimensions(World world);
}

View File

@@ -1,39 +0,0 @@
package com.volmit.iris.core.nms.container;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.function.NastyRunnable;
import lombok.AllArgsConstructor;
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;
@Override
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,28 +1,11 @@
package com.volmit.iris.core.nms.datapack;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisRange;
import com.volmit.iris.util.json.JSONObject;
public interface IDataFixer {
default JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
return json;
}
JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json);
JSONObject rawDimension(Dimension dimension);
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);
return obj;
}
enum Dimension {
OVERRWORLD,
NETHER,
THE_END
}
JSONObject fixDimension(JSONObject json);
}

View File

@@ -1,81 +1,18 @@
package com.volmit.iris.core.nms.datapack.v1192;
import com.volmit.iris.core.nms.datapack.IDataFixer;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.util.json.JSONObject;
import java.util.Map;
public class DataFixerV1192 implements IDataFixer {
private static final Map<Dimension, String> DIMENSIONS = Map.of(
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.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 fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
return json;
}
@Override
public JSONObject rawDimension(Dimension dimension) {
return new JSONObject(DIMENSIONS.get(dimension));
public JSONObject fixDimension(JSONObject json) {
return json;
}
}

View File

@@ -1,6 +1,6 @@
package com.volmit.iris.core.nms.datapack.v1206;
import com.volmit.iris.core.nms.datapack.v1192.DataFixerV1192;
import com.volmit.iris.core.nms.datapack.IDataFixer;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisBiomeCustomSpawn;
import com.volmit.iris.engine.object.IrisBiomeCustomSpawnType;
@@ -10,7 +10,7 @@ import com.volmit.iris.util.json.JSONObject;
import java.util.Locale;
public class DataFixerV1206 extends DataFixerV1192 {
public class DataFixerV1206 implements IDataFixer {
@Override
public JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
int spawnRarity = biome.getSpawnRarity();
@@ -45,8 +45,7 @@ public class DataFixerV1206 extends DataFixerV1192 {
}
@Override
public JSONObject rawDimension(Dimension dimension) {
JSONObject json = super.rawDimension(dimension);
public JSONObject fixDimension(JSONObject json) {
if (!(json.get("monster_spawn_light_level") instanceof JSONObject lightLevel))
return json;
var value = (JSONObject) lightLevel.remove("value");

View File

@@ -20,9 +20,7 @@ package com.volmit.iris.core.nms.v1X;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMSBinding;
import com.volmit.iris.core.nms.container.AutoClosing;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
@@ -120,26 +118,6 @@ public class NMSBinding1X implements INMSBinding {
return new KList<>(list);
}
@Override
public AutoClosing injectLevelStems() {
return new AutoClosing(() -> {});
}
@Override
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
return injectLevelStems();
}
@Override
public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) {
return false;
}
@Override
public void removeCustomDimensions(World world) {
}
@Override
public CompoundTag serializeEntity(Entity location) {
return null;

View File

@@ -28,7 +28,6 @@ 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 KMap<Long, Pair<Long, AtomicInteger>> lastUse = new KMap<>();
@@ -109,7 +108,6 @@ public class ChunkUpdater {
}
}
} catch (Exception e) {
Iris.reportError(e);
e.printStackTrace();
}
}, 0, 3, TimeUnit.SECONDS);
@@ -164,14 +162,11 @@ 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;
}
task.iterateChunks(rX, rZ, (x, z) -> {
PregenTask.iterateRegion(rX, rZ, (x, z) -> {
while (paused.get() && !cancelled.get()) {
J.sleep(50);
}
@@ -315,7 +310,6 @@ public class ChunkUpdater {
world.save();
}).get();
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
}
@@ -354,8 +348,8 @@ public class ChunkUpdater {
int width = maxZ - minZ + 1;
return new Dimensions(new Position2(minX, minZ), new Position2(maxX, maxZ), height * width, PregenTask.builder()
.radiusZ((int) Math.ceil(width / 2d * 512))
.radiusX((int) Math.ceil(height / 2d * 512))
.width((int) Math.ceil(width / 2d))
.height((int) Math.ceil(height / 2d))
.center(new Position2(oX, oZ))
.build());
}

View File

@@ -19,6 +19,7 @@
package com.volmit.iris.core.pregenerator;
import com.volmit.iris.Iris;
import com.volmit.iris.core.pack.IrisPack;
import com.volmit.iris.core.tools.IrisPackBenchmarking;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
@@ -31,33 +32,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 +62,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 +75,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);
task.iterateAllChunks((_a, _b) -> totalChunks.incrementAndGet());
generated = new AtomicInteger(0);
generatedLast = new AtomicInteger(0);
generatedLastMinute = new AtomicInteger(0);
totalChunks = new AtomicInteger(0);
task.iterateRegions((_a, _b) -> totalChunks.addAndGet(1024));
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,13 +122,12 @@ public class IrisPregenerator {
}
private long computeETA() {
double d = (long) (totalChunks.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() - cached.get()) * ((double) (M.ms() - startTime.get()) / ((double) generated.get() - cached.get()))) :
((totalChunks.get() - generated.get()) * ((double) (M.ms() - startTime.get()) / (double) generated.get())) :
// If no, use quick function (which is less accurate over time but responds better to the initial delay)
((totalChunks.get() - generated.get() - cached.get()) / chunksPerSecond.getAverage()) * 1000
((totalChunks.get() - generated.get()) / chunksPerSecond.getAverage()) * 1000
);
return Double.isFinite(d) && d != INVALID ? (long) d : 0;
}
@@ -171,15 +139,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);
}
}
@@ -228,7 +194,7 @@ public class IrisPregenerator {
} else if (!regions) {
hit = true;
listener.onRegionGenerating(x, z);
task.iterateChunks(x, z, (xx, zz) -> {
PregenTask.iterateRegion(x, z, (xx, zz) -> {
while (paused.get() && !shutdown.get()) {
J.sleep(50);
}
@@ -269,8 +235,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
@@ -279,10 +245,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

@@ -32,26 +32,17 @@ import java.util.Comparator;
@Data
public class PregenTask {
private static final Position2 ZERO = new Position2(0, 0);
private static final KList<Position2> ORDER_CENTER = computeChunkOrder();
private static final KMap<Position2, KList<Position2>> ORDERS = new KMap<>();
@Builder.Default
private final boolean gui = false;
private boolean gui = false;
@Builder.Default
private final Position2 center = new Position2(0, 0);
private Position2 center = new Position2(0, 0);
@Builder.Default
private final int radiusX = 1;
private int width = 1;
@Builder.Default
private final int radiusZ = 1;
private final Bounds bounds = new Bounds();
protected PregenTask(boolean gui, Position2 center, int radiusX, int radiusZ) {
this.gui = gui;
this.center = new ProxiedPos(center);
this.radiusX = radiusX;
this.radiusZ = radiusZ;
bounds.update();
}
private int height = 1;
public static void iterateRegion(int xr, int zr, Spiraled s, Position2 pull) {
for (Position2 i : ORDERS.computeIfAbsent(pull, PregenTask::computeOrder)) {
@@ -79,72 +70,29 @@ public class PregenTask {
return p;
}
public void iterateRegions(Spiraled s) {
var bound = bounds.region();
new Spiraler(bound.sizeX, bound.sizeZ, ((x, z) -> {
if (bound.check(x, z)) s.on(x, z);
})).setOffset(center.getX() >> 9, center.getZ() >> 9).drain();
private static KList<Position2> computeChunkOrder() {
Position2 center = new Position2(15, 15);
KList<Position2> p = new KList<>();
new Spiraler(33, 33, (x, z) -> {
int xx = x + 15;
int zz = z + 15;
if (xx < 0 || xx > 31 || zz < 0 || zz > 31) {
return;
}
p.add(new Position2(xx, zz));
}).drain();
p.sort(Comparator.comparing((i) -> i.distance(center)));
return p;
}
public void iterateChunks(int rX, int rZ, Spiraled s) {
var bound = bounds.chunk();
iterateRegion(rX, rZ, ((x, z) -> {
if (bound.check(x, z)) s.on(x, z);
}));
public void iterateRegions(Spiraled s) {
new Spiraler(getWidth() * 2, getHeight() * 2, s)
.setOffset(center.getX(), center.getZ()).drain();
}
public void iterateAllChunks(Spiraled s) {
iterateRegions(((rX, rZ) -> iterateChunks(rX, rZ, s)));
}
private class Bounds {
private Bound chunk = null;
private Bound region = null;
public void update() {
int maxX = center.getX() + radiusX;
int maxZ = center.getZ() + radiusZ;
int minX = center.getX() - radiusX;
int minZ = center.getZ() - radiusZ;
chunk = new Bound(minX >> 4, minZ >> 4, Math.ceilDiv(maxX, 16), Math.ceilDiv(maxZ, 16));
region = new Bound(minX >> 9, minZ >> 9, Math.ceilDiv(maxX, 512), Math.ceilDiv(maxZ, 512));
}
public Bound chunk() {
if (chunk == null) update();
return chunk;
}
public Bound region() {
if (region == null) update();
return region;
}
}
private record Bound(int minX, int maxX, int minZ, int maxZ, int sizeX, int sizeZ) {
private Bound(int minX, int minZ, int maxX, int maxZ) {
this(minX, maxX, minZ, maxZ, maxZ - minZ + 1, maxZ - minZ + 1);
}
boolean check(int x, int z) {
return x >= minX && x <= maxX && z >= minZ && z <= maxZ;
}
}
private static class ProxiedPos extends Position2 {
public ProxiedPos(Position2 p) {
super(p.getX(), p.getZ());
}
@Override
public void setX(int x) {
throw new IllegalStateException("This Position2 may not be modified");
}
@Override
public void setZ(int z) {
throw new IllegalStateException("This Position2 may not be modified");
}
new Spiraler(getWidth() * 2, getHeight() * 2, (x, z) -> iterateRegion(x, z, s))
.setOffset(center.getX(), center.getZ()).drain();
}
}

View File

@@ -1,70 +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();
static PregenCache create(File directory) {
if (directory == null) return EMPTY;
return new PregenCacheImpl(directory);
}
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() {
}
};
}

View File

@@ -1,218 +0,0 @@
package com.volmit.iris.core.pregenerator.cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.RemovalCause;
import com.volmit.iris.Iris;
import com.volmit.iris.util.data.Varint;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.documentation.RegionCoordinates;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.parallel.HyperLock;
import lombok.RequiredArgsConstructor;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import org.jetbrains.annotations.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import java.io.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
@NotThreadSafe
@RequiredArgsConstructor
class PregenCacheImpl implements PregenCache {
private static final int SIZE = 32;
private final File directory;
private final HyperLock hyperLock = new HyperLock(SIZE * 2, true);
private final LoadingCache<Pos, Plate> cache = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.maximumSize(SIZE)
.removalListener(this::onRemoval)
.evictionListener(this::onRemoval)
.build(this::load);
@ChunkCoordinates
public boolean isChunkCached(int x, int z) {
var plate = cache.get(new Pos(x >> 10, z >> 10));
if (plate == null) return false;
return plate.isCached((x >> 5) & 31, (z >> 5) & 31, r -> r.isCached(x & 31, z & 31));
}
@RegionCoordinates
public boolean isRegionCached(int x, int z) {
var plate = cache.get(new Pos(x >> 5, z >> 5));
if (plate == null) return false;
return plate.isCached(x & 31, z & 31, Region::isCached);
}
@ChunkCoordinates
public void cacheChunk(int x, int z) {
var plate = cache.get(new Pos(x >> 10, z >> 10));
plate.cache((x >> 5) & 31, (z >> 5) & 31, r -> r.cache(x & 31, z & 31));
}
@RegionCoordinates
public void cacheRegion(int x, int z) {
var plate = cache.get(new Pos(x >> 5, z >> 5));
plate.cache(x & 31, z & 31, Region::cache);
}
public void write() {
cache.asMap().values().forEach(this::write);
}
private Plate load(Pos key) {
hyperLock.lock(key.x, key.z);
try {
File file = fileForPlate(key);
if (!file.exists()) return new Plate(key);
try (var in = new DataInputStream(new LZ4BlockInputStream(new FileInputStream(file)))) {
return new Plate(key, in);
} catch (IOException e){
Iris.error("Failed to read pregen cache " + file);
Iris.reportError(e);
e.printStackTrace();
return new Plate(key);
}
} finally {
hyperLock.unlock(key.x, key.z);
}
}
private void write(Plate plate) {
hyperLock.lock(plate.pos.x, plate.pos.z);
try {
File file = fileForPlate(plate.pos);
try {
IO.write(file, out -> new DataOutputStream(new LZ4BlockOutputStream(out)), plate::write);
} catch (IOException e) {
Iris.error("Failed to write pregen cache " + file);
Iris.reportError(e);
e.printStackTrace();
}
} finally {
hyperLock.unlock(plate.pos.x, plate.pos.z);
}
}
private void onRemoval(@Nullable Pos key, @Nullable Plate plate, RemovalCause cause) {
if (plate == null) return;
write(plate);
}
private File fileForPlate(Pos pos) {
if (!directory.exists() && !directory.mkdirs())
throw new IllegalStateException("Cannot create directory: " + directory.getAbsolutePath());
return new File(directory, "c." + pos.x + "." + pos.z + ".lz4b");
}
private static class Plate {
private final Pos pos;
private short count;
private Region[] regions;
public Plate(Pos pos) {
this.pos = pos;
count = 0;
regions = new Region[1024];
}
public Plate(Pos pos, DataInput in) throws IOException {
this.pos = pos;
count = (short) Varint.readSignedVarInt(in);
if (count == 1024) return;
regions = new Region[1024];
for (int i = 0; i < 1024; i++) {
if (in.readBoolean()) continue;
regions[i] = new Region(in);
}
}
public boolean isCached(int x, int z, Predicate<Region> predicate) {
if (count == 1024) return true;
Region region = regions[x * 32 + z];
if (region == null) return false;
return predicate.test(region);
}
public void cache(int x, int z, Predicate<Region> predicate) {
if (count == 1024) return;
Region region = regions[x * 32 + z];
if (region == null) regions[x * 32 + z] = region = new Region();
if (predicate.test(region)) count++;
}
public void write(DataOutput out) throws IOException {
Varint.writeSignedVarInt(count, out);
if (count == 1024) return;
for (Region region : regions) {
out.writeBoolean(region == null);
if (region == null) continue;
region.write(out);
}
}
}
private static class Region {
private short count;
private long[] words;
public Region() {
count = 0;
words = new long[64];
}
public Region(DataInput in) throws IOException {
count = (short) Varint.readSignedVarInt(in);
if (count == 1024) return;
words = new long[64];
for (int i = 0; i < 64; i++) {
words[i] = Varint.readUnsignedVarLong(in);
}
}
public boolean cache() {
if (count == 1024) return false;
count = 1024;
words = null;
return true;
}
public boolean cache(int x, int z) {
if (count == 1024) return false;
int i = x * 32 + z;
int w = i >> 6;
long b = 1L << (i & 63);
var cur = (words[w] & b) != 0;
if (cur) return false;
if (++count == 1024) {
words = null;
return true;
} else words[w] |= b;
return false;
}
public boolean isCached() {
return count == 1024;
}
public boolean isCached(int x, int z) {
int i = x * 32 + z;
return count == 1024 || (words[i >> 6] & 1L << (i & 63)) != 0;
}
public void write(DataOutput out) throws IOException {
Varint.writeSignedVarInt(count, out);
if (isCached()) return;
for (long word : words) {
Varint.writeUnsignedVarLong(word, out);
}
}
}
private record Pos(int x, int z) {}
}

View File

@@ -1,48 +0,0 @@
package com.volmit.iris.core.pregenerator.cache;
import lombok.AllArgsConstructor;
@AllArgsConstructor
class SynchronizedCache implements PregenCache {
private final PregenCache cache;
@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();
}
}
}

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", Thread.MIN_PRIORITY);
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

@@ -1,7 +1,6 @@
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;
@@ -12,23 +11,5 @@ public class IrisSafeguard {
Iris.info("Enabled Iris SafeGuard");
ServerBootSFG.BootCheck();
}
public static void earlySplash() {
if (ServerBootSFG.safeguardPassed || IrisSettings.get().getGeneral().DoomsdayAnnihilationSelfDestructMode)
return;
Iris.instance.splash();
UtilsSFG.splash();
}
public static String mode() {
if (unstablemode) {
return "unstable";
} else if (warningmode) {
return "warning";
} else {
return "stable";
}
}
}

View File

@@ -3,7 +3,6 @@ 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;
@@ -30,7 +29,6 @@ public class ServerBootSFG {
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;
@@ -112,12 +110,6 @@ public class ServerBootSFG {
severityMedium++;
}
if (IrisContextInjector.isMissingDimensionTypes()) {
missingDimensionTypes = true;
joiner.add("Missing Dimension Types");
severityHigh++;
}
allIncompatibilities = joiner.toString();
safeguardPassed = (severityHigh == 0 && severityMedium == 0 && severityLow == 0);
@@ -160,9 +152,13 @@ public class ServerBootSFG {
}
public static boolean enoughDiskSpace() {
File freeSpace = Bukkit.getWorldContainer();
File freeSpace = new File(Bukkit.getWorldContainer() + ".");
double gigabytes = freeSpace.getFreeSpace() / (1024.0 * 1024.0 * 1024.0);
return gigabytes > 3;
if (gigabytes > 3){
return true;
} else {
return false;
}
}
private static boolean checkJavac(String path) {

View File

@@ -37,12 +37,7 @@ public class UtilsSFG {
}
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.");
Iris.safeguard(C.RED + "- Iris only supports 1.19.2 > 1.21.3");
}
if (!ServerBootSFG.passedserversoftware) {
Iris.safeguard(C.YELLOW + "Unsupported Server Software");

View File

@@ -1,108 +0,0 @@
package com.volmit.iris.core.service;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.cache.PregenCache;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.plugin.IrisService;
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.util.function.Function;
public class GlobalCacheSVC implements IrisService {
private static final Cache<String, PregenCache> REFERENCE_CACHE = Caffeine.newBuilder().weakValues().build();
private final KMap<String, PregenCache> globalCache = new KMap<>();
private transient boolean lastState;
private static boolean disabled = true;
@Override
public void onEnable() {
disabled = false;
lastState = !IrisSettings.get().getWorld().isGlobalPregenCache();
if (lastState) return;
Bukkit.getWorlds().forEach(this::createCache);
}
@Override
public void onDisable() {
disabled = true;
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) {
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) {
return REFERENCE_CACHE.get(worldName, provider);
}
@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,246 +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.IrisData;
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 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 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();
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();
trimAlive.begin();
unloadAlive.begin();
trimActiveAlive.begin();
unloadActiveAlive.begin();
updateTicker.start();
cacheTicker.start();
//trimTicker.start();
//unloadTicker.start();
instance = this;
}
@Override
public void onDisable() {
service.shutdown();
updateTicker.interrupt();
worlds.keySet().forEach(this::remove);
worlds.clear();
public void engineStatus() {
boolean trimAlive = trimTicker.isAlive();
boolean unloadAlive = unloadTicker.isAlive();
Iris.info("Status:");
Iris.info("- Trim: " + trimAlive);
Iris.info("- Unload: " + unloadAlive);
}
public void engineStatus(VolmitSender sender) {
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 + "- 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 + "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 + "- Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize()));
sender.sendMessage(C.DARK_PURPLE + "-------------------------");
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 {
queuedTectonicPlates.set(0);
tectonicPlates.set(0);
loadedChunks.set(0);
unloaderAlive.set(0);
trimmerAlive.set(0);
totalWorlds.set(0);
double maxDuration = Long.MIN_VALUE;
double minDuration = Long.MAX_VALUE;
for (var entry : worlds.entrySet()) {
var registered = entry.getValue();
if (registered.closed) continue;
totalWorlds.incrementAndGet();
unloaderAlive.addAndGet(registered.unloaderAlive() ? 1 : 0);
trimmerAlive.addAndGet(registered.trimmerAlive() ? 1 : 0);
var engine = registered.getEngine();
if (engine == null) continue;
queuedTectonicPlates.addAndGet((int) engine.getMantle().getUnloadRegionCount());
tectonicPlates.addAndGet(engine.getMantle().getLoadedRegionCount());
loadedChunks.addAndGet(entry.getKey().getLoadedChunks().length);
double duration = engine.getMantle().getAdjustedIdleDuration();
if (duration > maxDuration) maxDuration = duration;
if (duration < minDuration) minDuration = duration;
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());
}
maxIdleDuration.set(maxDuration);
minIdleDuration.set(minDuration);
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();
}
}
worlds.values().forEach(Registered::update);
} catch (Throwable e) {
e.printStackTrace();
if (!unloadTicker.isAlive()) {
Iris.info(C.RED + "UnloadTicker found dead! Booting it up!");
try {
UnloadLogic();
} catch (Exception e) {
Iris.error("What happened?");
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 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();
}
}, RNG.r.nextInt(1000), 1000, 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(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;
}
}, RNG.r.nextInt(1000), 1000, 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,7 +24,6 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
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.pack.IrisPack;
import com.volmit.iris.core.project.IrisProject;
import com.volmit.iris.core.tools.IrisToolbelt;
@@ -65,7 +64,7 @@ public class StudioSVC implements IrisService {
if (!f.exists()) {
Iris.info("Downloading Default Pack " + pack);
if (pack.equals("overworld")) {
String url = "https://github.com/IrisDimensions/overworld/releases/download/" + INMS.OVERWORLD_TAG + "/overworld.zip";
String url = "https://github.com/IrisDimensions/overworld/releases/download/" + Iris.OVERWORLD_TAG + "/overworld.zip";
Iris.service(StudioSVC.class).downloadRelease(Iris.getSender(), url, false, false);
} else {
downloadSearch(Iris.getSender(), pack, false);

View File

@@ -27,7 +27,6 @@ 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.data.Cuboid;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.plugin.IrisService;
@@ -35,6 +34,7 @@ import com.volmit.iris.util.scheduling.J;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Sapling;
import org.bukkit.event.EventHandler;
@@ -142,9 +142,7 @@ public class TreeSVC implements IrisService {
public void set(int x, int y, int z, BlockData d) {
Block b = event.getWorld().getBlockAt(x, y, z);
BlockState state = b.getState();
if (d instanceof IrisCustomData data)
state.setBlockData(data.getBase());
else state.setBlockData(d);
state.setBlockData(d);
blockStateList.add(b.getState());
dataCache.put(new Location(event.getWorld(), x, y, z), d);
}
@@ -215,17 +213,12 @@ public class TreeSVC implements IrisService {
block = false;
if (!iGrow.isCancelled()) {
for (BlockState state : iGrow.getBlocks()) {
Location l = state.getLocation();
for (BlockState block : iGrow.getBlocks()) {
Location l = block.getLocation();
BlockData d = dataCache.get(l);
if (d == null) continue;
Block block = l.getBlock();
if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase(), false);
Iris.service(ExternalDataSVC.class).processUpdate(engine, block, data.getCustom());
} else block.setBlockData(d);
if (dataCache.containsKey(l)) {
l.getBlock().setBlockData(dataCache.get(l), false);
}
}
}
});

View File

@@ -30,12 +30,15 @@ import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.matter.Matter;
import com.volmit.iris.util.matter.WorldMatter;
import com.volmit.iris.util.misc.E;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.S;
import com.volmit.iris.util.scheduling.SR;
import com.volmit.iris.util.scheduling.jobs.Job;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -51,14 +54,13 @@ 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;
import static com.volmit.iris.util.data.registry.Particles.CRIT_MAGIC;
import static com.volmit.iris.util.data.registry.Particles.REDSTONE;
import java.util.concurrent.atomic.AtomicInteger;
public class WandSVC implements IrisService {
private static final Particle CRIT_MAGIC = E.getOrDefault(Particle.class, "CRIT_MAGIC", "CRIT");
private static final Particle REDSTONE = E.getOrDefault(Particle.class, "REDSTONE", "DUST");
private static final int MS_PER_TICK = Integer.parseInt(System.getProperty("iris.ms_per_tick", "30"));
private static ItemStack dust;
@@ -81,8 +83,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());
@@ -201,9 +201,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);
@@ -362,7 +360,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

@@ -22,7 +22,6 @@ import com.google.common.util.concurrent.AtomicDouble;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.object.IrisDimension;
@@ -84,6 +83,7 @@ public class IrisCreator {
* Benchmark mode
*/
private boolean benchmark = false;
private boolean smartVanillaHeight = false;
public static boolean removeFromBukkitYml(String name) throws IOException {
YamlConfiguration yml = YamlConfiguration.loadConfiguration(BUKKIT_YML);
@@ -137,6 +137,7 @@ public class IrisCreator {
.name(name)
.seed(seed)
.studio(studio)
.smartVanillaHeight(smartVanillaHeight)
.create();
ServerConfigurator.installDataPacks(false);
@@ -171,7 +172,7 @@ public class IrisCreator {
try {
J.sfut(() -> {
world.set(INMS.get().createWorld(wc));
world.set(wc.createWorld());
}).get();
} catch (Throwable e) {
e.printStackTrace();

View File

@@ -9,43 +9,51 @@ import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.exceptions.IrisException;
import com.volmit.iris.util.format.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;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Clock;
import java.time.LocalDateTime;
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 boolean gui;
public IrisPackBenchmarking(IrisDimension dimension, int radius, boolean gui) {
instance = this;
this.dimension = dimension;
this.radius = radius;
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 ");
IO.delete(new File(Bukkit.getWorldContainer(), "benchmark"));
benchmarkInProgress = true;
File file = new File("benchmark");
if (file.exists()) {
deleteDirectory(file.toPath());
}
createBenchmark();
while (!IrisToolbelt.isIrisWorld(Bukkit.getWorld("benchmark"))) {
J.sleep(1000);
@@ -58,9 +66,13 @@ public class IrisPackBenchmarking {
}
public boolean getBenchmarkInProgress() {
return benchmarkInProgress;
}
public void finishedBenchmark(KList<Integer> cps) {
try {
String time = Form.duration((long) stopwatch.getMilliseconds());
String time = Form.duration(stopwatch.getMillis());
Engine engine = IrisToolbelt.access(Bukkit.getWorld("benchmark")).getEngine();
Iris.info("-----------------");
Iris.info("Results:");
@@ -71,7 +83,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");
@@ -127,18 +143,13 @@ public class IrisPackBenchmarking {
}
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)
.width(radius)
.height(radius)
.build(), Bukkit.getWorld("benchmark")
);
}
private double calculateAverage(KList<Integer> list) {
@@ -167,4 +178,26 @@ public class IrisPackBenchmarking {
private int findHighest(KList<Integer> list) {
return Collections.max(list);
}
private boolean deleteDirectory(Path dir) {
try {
Files.walkFileTree(dir, new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}

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;
@@ -142,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);
}
/**

View File

@@ -21,13 +21,10 @@ package com.volmit.iris.core.tools;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.platform.BukkitChunkGenerator;
import com.volmit.iris.util.reflect.WrappedField;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.WorldType;
import org.bukkit.generator.ChunkGenerator;
import sun.misc.Unsafe;
import java.io.File;
@@ -35,6 +32,7 @@ public class IrisWorldCreator {
private String name;
private boolean studio = false;
private String dimensionName = null;
private boolean smartVanillaHeight = false;
private long seed = 1337;
public IrisWorldCreator() {
@@ -66,6 +64,11 @@ public class IrisWorldCreator {
return this;
}
public IrisWorldCreator smartVanillaHeight(boolean smartVanillaHeight) {
this.smartVanillaHeight = smartVanillaHeight;
return this;
}
public WorldCreator create() {
IrisDimension dim = IrisData.loadAnyDimension(dimensionName);
@@ -79,7 +82,7 @@ public class IrisWorldCreator {
.build();
ChunkGenerator g = new BukkitChunkGenerator(w, studio, studio
? dim.getLoader().getDataFolder() :
new File(w.worldFolder(), "iris/pack"), dimensionName);
new File(w.worldFolder(), "iris/pack"), dimensionName, smartVanillaHeight);
return new WorldCreator(name)

View File

@@ -20,6 +20,8 @@ package com.volmit.iris.core.wand;
import com.volmit.iris.util.data.Cuboid;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.misc.E;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.entity.Player;
@@ -27,9 +29,8 @@ import org.bukkit.util.Vector;
import java.awt.*;
import static com.volmit.iris.util.data.registry.Particles.REDSTONE;
public class WandSelection {
private static final Particle REDSTONE = E.getOrDefault(Particle.class, "REDSTONE", "DUST");
private final Cuboid c;
private final Player p;
private static final double STEP = 0.10;

View File

@@ -21,10 +21,10 @@ package com.volmit.iris.engine;
import com.google.common.util.concurrent.AtomicDouble;
import com.google.gson.Gson;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.events.IrisEngineHotloadEvent;
import com.volmit.iris.core.gui.PregeneratorJob;
import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.core.nms.container.BlockPos;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.project.IrisProject;
@@ -53,6 +53,7 @@ import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
@@ -62,10 +63,11 @@ import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Data
@EqualsAndHashCode(exclude = "context")
@@ -90,12 +92,12 @@ public class IrisEngine implements Engine {
private final AtomicBoolean cleaning;
private final ChronoLatch cleanLatch;
private final SeedManager seedManager;
private CompletableFuture<Long> hash32;
private EngineMode mode;
private EngineEffects effects;
private EngineExecutionEnvironment execution;
private EngineWorldManager worldManager;
private volatile int parallelism;
private volatile int minHeight;
private boolean failing;
private boolean closed;
private int cacheId;
@@ -128,6 +130,7 @@ public class IrisEngine implements Engine {
getData().setEngine(this);
getData().loadPrefetch(this);
Iris.info("Initializing Engine: " + target.getWorld().name() + "/" + target.getDimension().getLoadKey() + " (" + target.getDimension().getDimensionHeight() + " height) Seed: " + getSeedManager().getSeed());
minHeight = 0;
failing = false;
closed = false;
art = J.ar(this::tickRandomPlayer, 0);
@@ -171,20 +174,8 @@ public class IrisEngine implements Engine {
complex = new IrisComplex(this);
execution = new IrisExecutionEnvironment(this);
effects = new IrisEngineEffects(this);
hash32 = new CompletableFuture<>();
setupMode();
J.a(this::computeBiomeMaxes);
J.a(() -> {
File[] roots = getData().getLoaders()
.values()
.stream()
.map(ResourceLoader::getFolderName)
.map(n -> new File(getData().getDataFolder(), n))
.filter(File::exists)
.filter(File::isDirectory)
.toArray(File[]::new);
hash32.complete(IO.hashRecursive(roots));
});
} catch (Throwable e) {
Iris.error("FAILED TO SETUP ENGINE!");
e.printStackTrace();
@@ -473,7 +464,7 @@ public class IrisEngine implements Engine {
getEngineData().getStatistics().generatedChunk();
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
Hunk<BlockData> blocks = vblocks.listen((xx, y, zz, t) -> catchBlockUpdates(x + xx, y, z + zz, t));
Hunk<BlockData> blocks = vblocks.listen((xx, y, zz, t) -> catchBlockUpdates(x + xx, y + getMinHeight(), z + zz, t));
if (getDimension().isDebugChunkCrossSections() && ((x >> 4) % getDimension().getDebugCrossSectionsMod() == 0 || (z >> 4) % getDimension().getDebugCrossSectionsMod() == 0)) {
for (int i = 0; i < 16; i++) {

View File

@@ -23,12 +23,11 @@ import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.mantle.EngineMantle;
import com.volmit.iris.engine.mantle.MantleComponent;
import com.volmit.iris.engine.mantle.components.MantleCarvingComponent;
import com.volmit.iris.engine.mantle.components.MantleFluidBodyComponent;
import com.volmit.iris.engine.mantle.components.MantleJigsawComponent;
import com.volmit.iris.engine.mantle.components.MantleObjectComponent;
import com.volmit.iris.engine.mantle.components.*;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.Mantle;
import lombok.*;
@@ -58,6 +57,7 @@ public class IrisEngineMantle implements EngineMantle {
registerComponent(jigsaw);
object = new MantleObjectComponent(this);
registerComponent(object);
registerComponent(new MantleStaticComponent(this));
}
@Override

View File

@@ -55,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;
@@ -63,7 +62,6 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -301,6 +299,28 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
energy += 1.2;
}
//@builder
IrisBiome biome = IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()
? getEngine().getSurfaceBiome(c) : null;
IrisEntitySpawn v = IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()
? spawnRandomly(Stream.concat(getData().getSpawnerLoader()
.loadAll(getDimension().getEntitySpawners())
.shuffleCopy(RNG.r).stream()
.filter(this::canSpawn)
.filter((i) -> i.isValid(biome))
.flatMap((i) -> stream(i, initial)),
Stream.concat(getData().getSpawnerLoader()
.loadAll(getEngine().getRegion(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
.shuffleCopy(RNG.r).stream().filter(this::canSpawn)
.flatMap((i) -> stream(i, initial)),
getData().getSpawnerLoader()
.loadAll(getEngine().getSurfaceBiome(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
.shuffleCopy(RNG.r).stream().filter(this::canSpawn)
.flatMap((i) -> stream(i, initial))))
.collect(Collectors.toList()))
.popRandom(RNG.r) : null;
//@done
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
getSpawnersFromMarkers(c).forEach((blockf, spawners) -> {
if (spawners.isEmpty()) {
@@ -315,67 +335,94 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
});
}
if (!IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()) {
return;
}
if (v != null && v.getReferenceSpawner() != null) {
int maxEntCount = v.getReferenceSpawner().getMaxEntitiesPerChunk();
//@builder
Predicate<IrisSpawner> filter = i -> i.canSpawn(getEngine(), c.getX(), c.getZ());
ChunkCounter counter = new ChunkCounter(c.getEntities());
for (Entity i : c.getEntities()) {
if (i instanceof LivingEntity) {
if (-maxEntCount <= 0) {
return;
}
}
}
IrisBiome biome = getEngine().getSurfaceBiome(c);
IrisEntitySpawn v = spawnRandomly(Stream.concat(getData().getSpawnerLoader()
.loadAll(getDimension().getEntitySpawners())
.shuffleCopy(RNG.r)
.stream()
.filter(filter)
.filter((i) -> i.isValid(biome)),
Stream.concat(getData()
.getSpawnerLoader()
.loadAll(getEngine().getRegion(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
.shuffleCopy(RNG.r)
.stream()
.filter(filter),
getData().getSpawnerLoader()
.loadAll(getEngine().getSurfaceBiome(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
.shuffleCopy(RNG.r)
.stream()
.filter(filter)))
.filter(counter)
.flatMap((i) -> stream(i, initial))
.collect(Collectors.toList()))
.getRandom();
//@done
if (v == null || v.getReferenceSpawner() == null)
return;
try {
spawn(c, v);
} catch (Throwable e) {
J.s(() -> spawn(c, v));
try {
spawn(c, v);
} catch (Throwable e) {
J.s(() -> spawn(c, v));
}
}
}
private void spawn(Chunk c, IrisEntitySpawn i) {
IrisSpawner ref = i.getReferenceSpawner();
int s = i.spawn(getEngine(), c, RNG.r);
actuallySpawned += s;
if (s > 0) {
ref.spawn(getEngine(), c.getX(), c.getZ());
energy -= s * ((i.getEnergyMultiplier() * ref.getEnergyMultiplier() * 1));
boolean allow = true;
if (!i.getReferenceSpawner().getMaximumRatePerChunk().isInfinite()) {
allow = false;
IrisEngineChunkData cd = getEngine().getEngineData().getChunk(c.getX(), c.getZ());
IrisEngineSpawnerCooldown sc = null;
for (IrisEngineSpawnerCooldown j : cd.getCooldowns()) {
if (j.getSpawner().equals(i.getReferenceSpawner().getLoadKey())) {
sc = j;
break;
}
}
if (sc == null) {
sc = new IrisEngineSpawnerCooldown();
sc.setSpawner(i.getReferenceSpawner().getLoadKey());
cd.getCooldowns().add(sc);
}
if (sc.canSpawn(i.getReferenceSpawner().getMaximumRatePerChunk())) {
sc.spawn(getEngine());
allow = true;
}
}
if (allow) {
int s = i.spawn(getEngine(), c, RNG.r);
actuallySpawned += s;
if (s > 0) {
getCooldown(i.getReferenceSpawner()).spawn(getEngine());
energy -= s * ((i.getEnergyMultiplier() * i.getReferenceSpawner().getEnergyMultiplier() * 1));
}
}
}
private void spawn(IrisPosition pos, IrisEntitySpawn i) {
IrisSpawner ref = i.getReferenceSpawner();
if (!ref.canSpawn(getEngine(), pos.getX() >> 4, pos.getZ() >> 4))
return;
private void spawn(IrisPosition c, IrisEntitySpawn i) {
boolean allow = true;
int s = i.spawn(getEngine(), pos, RNG.r);
actuallySpawned += s;
if (s > 0) {
ref.spawn(getEngine(), pos.getX() >> 4, pos.getZ() >> 4);
energy -= s * ((i.getEnergyMultiplier() * ref.getEnergyMultiplier() * 1));
if (!i.getReferenceSpawner().getMaximumRatePerChunk().isInfinite()) {
allow = false;
IrisEngineChunkData cd = getEngine().getEngineData().getChunk(c.getX() >> 4, c.getZ() >> 4);
IrisEngineSpawnerCooldown sc = null;
for (IrisEngineSpawnerCooldown j : cd.getCooldowns()) {
if (j.getSpawner().equals(i.getReferenceSpawner().getLoadKey())) {
sc = j;
break;
}
}
if (sc == null) {
sc = new IrisEngineSpawnerCooldown();
sc.setSpawner(i.getReferenceSpawner().getLoadKey());
cd.getCooldowns().add(sc);
}
if (sc.canSpawn(i.getReferenceSpawner().getMaximumRatePerChunk())) {
sc.spawn(getEngine());
allow = true;
}
}
if (allow) {
int s = i.spawn(getEngine(), c, RNG.r);
actuallySpawned += s;
if (s > 0) {
getCooldown(i.getReferenceSpawner()).spawn(getEngine());
energy -= s * ((i.getEnergyMultiplier() * i.getReferenceSpawner().getEnergyMultiplier() * 1));
}
}
}
@@ -403,6 +450,31 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
return rarityTypes;
}
public boolean canSpawn(IrisSpawner i) {
return i.isValid(getEngine().getWorld().realWorld())
&& getCooldown(i).canSpawn(i.getMaximumRate());
}
private IrisEngineSpawnerCooldown getCooldown(IrisSpawner i) {
IrisEngineData ed = getEngine().getEngineData();
IrisEngineSpawnerCooldown cd = null;
for (IrisEngineSpawnerCooldown j : ed.getSpawnerCooldowns().copy()) {
if (j.getSpawner().equals(i.getLoadKey())) {
cd = j;
}
}
if (cd == null) {
cd = new IrisEngineSpawnerCooldown();
cd.setSpawner(i.getLoadKey());
cd.setLastSpawn(M.ms() - i.getMaximumRate().getInterval());
ed.getSpawnerCooldowns().add(cd);
}
return cd;
}
@Override
public void onTick() {
@@ -423,16 +495,9 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
return;
}
var ref = new WeakReference<>(e.getWorld());
int x = e.getX(), z = e.getZ();
J.s(() -> {
World world = ref.get();
if (world == null || !world.isChunkLoaded(x, z))
return;
energy += 0.3;
fixEnergy();
getEngine().cleanupMantleChunk(x, z);
}, IrisSettings.get().getPerformance().mantleCleanupDelay);
energy += 0.3;
fixEnergy();
getEngine().cleanupMantleChunk(e.getX(), e.getZ());
if (generated) {
//INMS.get().injectBiomesFromMantle(e, getMantle());
@@ -643,27 +708,4 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
return (double) entityCount / (getEngine().getWorld().realWorld().getLoadedChunks().length + 1) * 1.28;
}
@Data
private static class ChunkCounter implements Predicate<IrisSpawner> {
private final Entity[] entities;
private transient int index = 0;
private transient int count = 0;
@Override
public boolean test(IrisSpawner spawner) {
int max = spawner.getMaxEntitiesPerChunk();
if (max <= count)
return false;
while (index < entities.length) {
if (entities[index++] instanceof LivingEntity) {
if (++count >= max)
return false;
}
}
return true;
}
}
}

View File

@@ -21,7 +21,7 @@ package com.volmit.iris.engine.data.chunk;
import com.volmit.iris.core.nms.BiomeBaseInjector;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.util.data.IrisBiomeStorage;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.data.IrisBlockData;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@@ -121,7 +121,7 @@ public class LinkedTerrainChunk implements TerrainChunk {
@Override
public synchronized void setBlock(int x, int y, int z, BlockData blockData) {
if (blockData instanceof IrisCustomData d)
if (blockData instanceof IrisBlockData d)
blockData = d.getBase();
rawChunkData.setBlock(x, y, z, blockData);
}

View File

@@ -20,7 +20,7 @@ package com.volmit.iris.engine.data.chunk;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.BiomeBaseInjector;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.data.IrisBlockData;
import com.volmit.iris.util.nbt.mca.Chunk;
import com.volmit.iris.util.nbt.mca.NBTWorld;
import lombok.AllArgsConstructor;
@@ -89,7 +89,7 @@ public class MCATerrainChunk implements TerrainChunk {
if (blockData == null) {
Iris.error("NULL BD");
}
if (blockData instanceof IrisCustomData data)
if (blockData instanceof IrisBlockData data)
blockData = data.getBase();
mcaChunk.setBlockStateAt(xx, y, zz, NBTWorld.getCompound(blockData), false);

View File

@@ -18,16 +18,18 @@
package com.volmit.iris.engine.decorator;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorationPart;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.math.RNG;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
import org.bukkit.block.data.type.PointedDripstone;
public class IrisCeilingDecorator extends IrisEngineDecorator {
@@ -38,14 +40,12 @@ public class IrisCeilingDecorator extends IrisEngineDecorator {
@BlockCoordinates
@Override
public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) {
RNG rng = getRNG(realX, realZ);
IrisDecorator decorator = getDecorator(rng, biome, realX, realZ);
IrisDecorator decorator = getDecorator(biome, realX, realZ);
if (decorator != null) {
if (!decorator.isStacking()) {
data.set(x, height, z, fixFaces(decorator.getBlockData100(biome, rng, realX, height, realZ, getData()), data, x, z, realX, height, realZ));
data.set(x, height, z, fixFaces(decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()), realX, height, realZ));
} else {
int stack = decorator.getHeight(rng, realX, realZ, getData());
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData());
if (decorator.isScaleStack()) {
stack = Math.min((int) Math.ceil((double) max * ((double) stack / 100)), decorator.getAbsoluteMaxStack());
} else {
@@ -53,7 +53,7 @@ public class IrisCeilingDecorator extends IrisEngineDecorator {
}
if (stack == 1) {
data.set(x, height, z, decorator.getBlockDataForTop(biome, rng, realX, height, realZ, getData()));
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData()));
return;
}
@@ -66,8 +66,8 @@ public class IrisCeilingDecorator extends IrisEngineDecorator {
double threshold = (((double) i) / (double) (stack - 1));
BlockData bd = threshold >= decorator.getTopThreshold() ?
decorator.getBlockDataForTop(biome, rng, realX, h, realZ, getData()) :
decorator.getBlockData100(biome, rng, realX, h, realZ, getData());
decorator.getBlockDataForTop(biome, getRng(), realX, h, realZ, getData()) :
decorator.getBlockData100(biome, getRng(), realX, h, realZ, getData());
if (bd instanceof PointedDripstone) {
PointedDripstone.Thickness th = PointedDripstone.Thickness.BASE;
@@ -97,4 +97,24 @@ public class IrisCeilingDecorator extends IrisEngineDecorator {
}
}
}
private BlockData fixFaces(BlockData b, int x, int y, int z) {
if (B.isVineBlock(b)) {
MultipleFacing data = (MultipleFacing) b.clone();
boolean found = false;
for (BlockFace f : BlockFace.values()) {
if (!f.isCartesian())
continue;
Material m = getEngine().getMantle().get(x + f.getModX(), y + f.getModY(), z + f.getModZ()).getMaterial();
if (m.isSolid()) {
found = true;
data.setFace(f, m.isSolid());
}
}
if (!found)
data.setFace(BlockFace.UP, true);
return data;
}
return b;
}
}

View File

@@ -19,6 +19,7 @@
package com.volmit.iris.engine.decorator;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineAssignedComponent;
import com.volmit.iris.engine.framework.EngineDecorator;
@@ -26,42 +27,30 @@ import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorationPart;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.math.RNG;
import lombok.Getter;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockSupport;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
public abstract class IrisEngineDecorator extends EngineAssignedComponent implements EngineDecorator {
@Getter
private final RNG rng;
@Getter
private final IrisDecorationPart part;
private final long seed;
private final long modX, modZ;
public IrisEngineDecorator(Engine engine, String name, IrisDecorationPart part) {
super(engine, name + " Decorator");
this.part = part;
this.seed = getSeed() + 29356788 - (part.ordinal() * 10439677L);
this.modX = 29356788 ^ (part.ordinal() + 6);
this.modZ = 10439677 ^ (part.ordinal() + 1);
this.rng = new RNG(getSeed() + 29356788 - (part.ordinal() * 10439677L));
}
@BlockCoordinates
protected RNG getRNG(int x, int z) {
return new RNG(x * modX + z * modZ + seed);
}
protected IrisDecorator getDecorator(RNG rng, IrisBiome biome, double realX, double realZ) {
protected IrisDecorator getDecorator(IrisBiome biome, double realX, double realZ) {
KList<IrisDecorator> v = new KList<>();
RNG rng = new RNG(Cache.key((int) realX, (int) realZ));
RNG gRNG = new RNG(seed);
for (IrisDecorator i : biome.getDecorators()) {
try {
if (i.getPartOf().equals(part) && i.getBlockData(biome, gRNG, realX, realZ, getData()) != null) {
if (i.getPartOf().equals(part) && i.getBlockData(biome, this.rng, realX, realZ, getData()) != null) {
v.add(i);
}
} catch (Throwable e) {
@@ -76,40 +65,4 @@ public abstract class IrisEngineDecorator extends EngineAssignedComponent implem
return null;
}
protected BlockData fixFaces(BlockData b, Hunk<BlockData> hunk, int rX, int rZ, int x, int y, int z) {
if (B.isVineBlock(b)) {
MultipleFacing data = (MultipleFacing) b.clone();
data.getFaces().forEach(f -> data.setFace(f, false));
boolean found = false;
for (BlockFace f : BlockFace.values()) {
if (!f.isCartesian())
continue;
int yy = y + f.getModY();
BlockData r = getEngine().getMantle().get(x + f.getModX(), yy, z + f.getModZ());
if (r.isFaceSturdy(f.getOppositeFace(), BlockSupport.FULL)) {
found = true;
data.setFace(f, true);
continue;
}
int xx = rX + f.getModX();
int zz = rZ + f.getModZ();
if (xx < 0 || xx > 15 || zz < 0 || zz > 15 || yy < 0 || yy > hunk.getHeight())
continue;
r = hunk.get(xx, yy, zz);
if (r.isFaceSturdy(f.getOppositeFace(), BlockSupport.FULL)) {
found = true;
data.setFace(f, true);
}
}
if (!found)
data.setFace(BlockFace.DOWN, true);
return data;
}
return b;
}
}

View File

@@ -18,13 +18,13 @@
package com.volmit.iris.engine.decorator;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorationPart;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.math.RNG;
import org.bukkit.block.data.BlockData;
public class IrisSeaFloorDecorator extends IrisEngineDecorator {
@@ -35,8 +35,7 @@ public class IrisSeaFloorDecorator extends IrisEngineDecorator {
@BlockCoordinates
@Override
public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) {
RNG rng = getRNG(realX, realZ);
IrisDecorator decorator = getDecorator(rng, biome, realX, realZ);
IrisDecorator decorator = getDecorator(biome, realX, realZ);
if (decorator != null) {
if (!decorator.isStacking()) {
@@ -45,17 +44,17 @@ public class IrisSeaFloorDecorator extends IrisEngineDecorator {
return;
}
if (height >= 0 || height < getEngine().getHeight()) {
data.set(x, height, z, decorator.getBlockData100(biome, rng, realX, height, realZ, getData()));
data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
}
} else {
int stack = decorator.getHeight(rng, realX, realZ, getData());
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData());
if (decorator.isScaleStack()) {
int maxStack = max - height;
stack = (int) Math.ceil((double) maxStack * ((double) stack / 100));
} else stack = Math.min(stack, max - height);
if (stack == 1) {
data.set(x, height, z, decorator.getBlockDataForTop(biome, rng, realX, height, realZ, getData()));
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData()));
return;
}
@@ -67,8 +66,8 @@ public class IrisSeaFloorDecorator extends IrisEngineDecorator {
double threshold = ((double) i) / (stack - 1);
data.set(x, h, z, threshold >= decorator.getTopThreshold() ?
decorator.getBlockDataForTop(biome, rng, realX, h, realZ, getData()) :
decorator.getBlockData100(biome, rng, realX, h, realZ, getData()));
decorator.getBlockDataForTop(biome, getRng(), realX, h, realZ, getData()) :
decorator.getBlockData100(biome, getRng(), realX, h, realZ, getData()));
}
}
}

View File

@@ -18,13 +18,13 @@
package com.volmit.iris.engine.decorator;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorationPart;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.math.RNG;
import org.bukkit.block.data.BlockData;
public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
@@ -35,23 +35,22 @@ public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
@BlockCoordinates
@Override
public void decorate(int x, int z, int realX, int realX1, int realX_1, int realZ, int realZ1, int realZ_1, Hunk<BlockData> data, IrisBiome biome, int height, int max) {
RNG rng = getRNG(realX, realZ);
IrisDecorator decorator = getDecorator(rng, biome, realX, realZ);
IrisDecorator decorator = getDecorator(biome, realX, realZ);
if (decorator != null) {
if (!decorator.isStacking()) {
if (height >= 0 || height < getEngine().getHeight()) {
data.set(x, height + 1, z, decorator.getBlockData100(biome, rng, realX, height, realZ, getData()));
data.set(x, height + 1, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
}
} else {
int stack = decorator.getHeight(rng, realX, realZ, getData());
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData());
if (decorator.isScaleStack()) {
int maxStack = max - height;
stack = (int) Math.ceil((double) maxStack * ((double) stack / 100));
}
if (stack == 1) {
data.set(x, height, z, decorator.getBlockDataForTop(biome, rng, realX, height, realZ, getData()));
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData()));
return;
}
@@ -63,8 +62,8 @@ public class IrisSeaSurfaceDecorator extends IrisEngineDecorator {
double threshold = ((double) i) / (stack - 1);
data.set(x, h + 1, z, threshold >= decorator.getTopThreshold() ?
decorator.getBlockDataForTop(biome, rng, realX, h, realZ, getData()) :
decorator.getBlockData100(biome, rng, realX, h, realZ, getData()));
decorator.getBlockDataForTop(biome, getRng().nextParallelRNG(i), realX, h, realZ, getData()) :
decorator.getBlockData100(biome, getRng().nextParallelRNG(i), realX, h, realZ, getData()));
}
}
}

View File

@@ -18,13 +18,13 @@
package com.volmit.iris.engine.decorator;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorationPart;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.math.RNG;
import org.bukkit.block.data.BlockData;
public class IrisShoreLineDecorator extends IrisEngineDecorator {
@@ -42,8 +42,7 @@ public class IrisShoreLineDecorator extends IrisEngineDecorator {
Math.round(getComplex().getHeightStream().get(realX, realZ1)) < getComplex().getFluidHeight() ||
Math.round(getComplex().getHeightStream().get(realX, realZ_1)) < getComplex().getFluidHeight()
) {
RNG rng = getRNG(realX, realZ);
IrisDecorator decorator = getDecorator(rng, biome, realX, realZ);
IrisDecorator decorator = getDecorator(biome, realX, realZ);
if (decorator != null) {
if (!decorator.isForcePlace() && !decorator.getSlopeCondition().isDefault()
@@ -52,16 +51,16 @@ public class IrisShoreLineDecorator extends IrisEngineDecorator {
}
if (!decorator.isStacking()) {
data.set(x, height + 1, z, decorator.getBlockData100(biome, rng, realX, height, realZ, getData()));
data.set(x, height + 1, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
} else {
int stack = decorator.getHeight(rng, realX, realZ, getData());
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData());
if (decorator.isScaleStack()) {
int maxStack = max - height;
stack = (int) Math.ceil((double) maxStack * ((double) stack / 100));
} else stack = Math.min(max - height, stack);
if (stack == 1) {
data.set(x, height, z, decorator.getBlockDataForTop(biome, rng, realX, height, realZ, getData()));
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData()));
return;
}
@@ -69,8 +68,8 @@ public class IrisShoreLineDecorator extends IrisEngineDecorator {
int h = height + i;
double threshold = ((double) i) / (stack - 1);
data.set(x, h + 1, z, threshold >= decorator.getTopThreshold() ?
decorator.getBlockDataForTop(biome, rng, realX, h, realZ, getData()) :
decorator.getBlockData100(biome, rng, realX, h, realZ, getData()));
decorator.getBlockDataForTop(biome, getRng(), realX, h, realZ, getData()) :
decorator.getBlockData100(biome, getRng(), realX, h, realZ, getData()));
}
}
}

View File

@@ -19,6 +19,7 @@
package com.volmit.iris.engine.decorator;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.InferredType;
import com.volmit.iris.engine.object.IrisBiome;
@@ -27,11 +28,11 @@ import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.math.RNG;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
import org.bukkit.block.data.type.PointedDripstone;
public class IrisSurfaceDecorator extends IrisEngineDecorator {
@@ -47,8 +48,7 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
}
BlockData bd, bdx;
RNG rng = getRNG(realX, realZ);
IrisDecorator decorator = getDecorator(rng, biome, realX, realZ);
IrisDecorator decorator = getDecorator(biome, realX, realZ);
bdx = data.get(x, height, z);
boolean underwater = height < getDimension().getFluidHeight();
@@ -59,7 +59,7 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
}
if (!decorator.isStacking()) {
bd = decorator.getBlockData100(biome, rng, realX, height, realZ, getData());
bd = decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData());
if (!underwater) {
if (!canGoOn(bd, bdx) && (!decorator.isForcePlace() && decorator.getForceBlock() == null)) {
@@ -68,12 +68,12 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
}
if (decorator.getForceBlock() != null) {
data.set(x, height, z, fixFaces(decorator.getForceBlock().getBlockData(getData()), data, x, z, realX, height, realZ));
data.set(x, height, z, fixFaces(decorator.getForceBlock().getBlockData(getData()), x, height, z));
} else if (!decorator.isForcePlace()) {
if (decorator.getWhitelist() != null && decorator.getWhitelist().stream().noneMatch(d -> d.getBlockData(getData()).equals(bdx))) {
return;
}
if (decorator.getBlacklist() != null && decorator.getBlacklist().stream().anyMatch(d -> d.getBlockData(getData()).equals(bdx))) {
if (decorator.getBlacklist() != null && decorator.getWhitelist().stream().anyMatch(d -> d.getBlockData(getData()).equals(bdx))) {
return;
}
}
@@ -91,14 +91,14 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
}
if (B.isAir(data.get(x, height + 1, z))) {
data.set(x, height + 1, z, fixFaces(bd, data, x, z, realX, height + 1, realZ));
data.set(x, height + 1, z, fixFaces(bd, x, height + 1, z));
}
} else {
if (height < getDimension().getFluidHeight()) {
max = getDimension().getFluidHeight();
}
int stack = decorator.getHeight(rng, realX, realZ, getData());
int stack = decorator.getHeight(getRng().nextParallelRNG(Cache.key(realX, realZ)), realX, realZ, getData());
if (decorator.isScaleStack()) {
stack = Math.min((int) Math.ceil((double) max * ((double) stack / 100)), decorator.getAbsoluteMaxStack());
@@ -107,7 +107,7 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
}
if (stack == 1) {
data.set(x, height, z, decorator.getBlockDataForTop(biome, rng, realX, height, realZ, getData()));
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData()));
return;
}
@@ -115,8 +115,8 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
int h = height + i;
double threshold = ((double) i) / (stack - 1);
bd = threshold >= decorator.getTopThreshold() ?
decorator.getBlockDataForTop(biome, rng, realX, h, realZ, getData()) :
decorator.getBlockData100(biome, rng, realX, h, realZ, getData());
decorator.getBlockDataForTop(biome, getRng(), realX, h, realZ, getData()) :
decorator.getBlockData100(biome, getRng(), realX, h, realZ, getData());
if (bd == null) {
break;
@@ -158,4 +158,24 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
}
}
}
private BlockData fixFaces(BlockData b, int x, int y, int z) {
if (B.isVineBlock(b)) {
MultipleFacing data = (MultipleFacing) b.clone();
boolean found = false;
for (BlockFace f : BlockFace.values()) {
if (!f.isCartesian())
continue;
Material m = getEngine().getMantle().get(x + f.getModX(), y + f.getModY(), z + f.getModZ()).getMaterial();
if (m.isSolid()) {
found = true;
data.setFace(f, m.isSolid());
}
}
if (!found)
data.setFace(BlockFace.UP, true);
return data;
}
return b;
}
}

View File

@@ -42,7 +42,7 @@ import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.data.IrisBlockData;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.format.C;
@@ -75,12 +75,11 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.awt.Color;
import java.util.Arrays;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -140,9 +139,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
return getTarget().getWorld().minHeight();
}
default void setMinHeight(int min) {
getTarget().getWorld().minHeight(min);
}
void setMinHeight(int min);
@BlockCoordinates
default void generate(int x, int z, TerrainChunk tc, boolean multicore) throws WrongEngineBroException {
@@ -261,8 +258,10 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
if (B.isUpdatable(data)) {
getMantle().updateBlock(x, y, z);
}
if (data instanceof IrisCustomData) {
getMantle().getMantle().flag(x >> 4, z >> 4, MantleFlag.CUSTOM, true);
if (data instanceof IrisBlockData d) {
getMantle().getMantle().set(x, y, z, d.getCustom());
} else {
getMantle().getMantle().remove(x, y, z, Identifier.class);
}
}
@@ -289,79 +288,76 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
return;
}
var chunk = mantle.getChunk(c).use();
try {
Semaphore semaphore = new Semaphore(3);
chunk.raiseFlag(MantleFlag.ETCHED, () -> {
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> J.s(() -> {
mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> {
int betterY = y + getWorld().minHeight();
if (!TileData.setTileState(c.getBlock(x, betterY, z), v.getData()))
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), v.getData().getMaterial().name());
});
})));
chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> J.s(() -> {
mantle.iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> {
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
});
})));
var chunk = mantle.getChunk(c);
if (chunk.isFlagged(MantleFlag.ETCHED)) return;
chunk.flag(MantleFlag.ETCHED, true);
chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> J.s(() -> {
PrecisionStopwatch p = PrecisionStopwatch.start();
KMap<Long, Integer> updates = new KMap<>();
RNG r = new RNG(Cache.key(c.getX(), c.getZ()));
mantle.iterateChunk(c.getX(), c.getZ(), MatterCavern.class, (x, yf, z, v) -> {
int y = yf + getWorld().minHeight();
if (!B.isFluid(c.getBlock(x & 15, y, z & 15).getBlockData())) {
return;
}
boolean u = false;
if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.DOWN).getBlockData())) {
u = true;
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.WEST).getBlockData())) {
u = true;
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.EAST).getBlockData())) {
u = true;
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.SOUTH).getBlockData())) {
u = true;
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.NORTH).getBlockData())) {
u = true;
Semaphore semaphore = new Semaphore(3);
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> J.s(() -> {
mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> {
int betterY = y + getWorld().minHeight();
if (!TileData.setTileState(c.getBlock(x, betterY, z), v.getData()))
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), v.getData().getMaterial().name());
});
})));
chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> J.s(() -> {
mantle.iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> {
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
});
})));
chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> J.s(() -> {
PrecisionStopwatch p = PrecisionStopwatch.start();
KMap<Long, Integer> updates = new KMap<>();
RNG r = new RNG(Cache.key(c.getX(), c.getZ()));
mantle.iterateChunk(c.getX(), c.getZ(), MatterCavern.class, (x, yf, z, v) -> {
int y = yf + getWorld().minHeight();
if (!B.isFluid(c.getBlock(x & 15, y, z & 15).getBlockData())) {
return;
}
boolean u = false;
if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.DOWN).getBlockData())) {
u = true;
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.WEST).getBlockData())) {
u = true;
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.EAST).getBlockData())) {
u = true;
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.SOUTH).getBlockData())) {
u = true;
} else if (B.isAir(c.getBlock(x & 15, y, z & 15).getRelative(BlockFace.NORTH).getBlockData())) {
u = true;
}
if (u) {
updates.compute(Cache.key(x & 15, z & 15), (k, vv) -> {
if (vv != null) {
return Math.max(vv, y);
}
if (u) {
updates.compute(Cache.key(x & 15, z & 15), (k, vv) -> {
if (vv != null) {
return Math.max(vv, y);
}
return y;
});
}
return y;
});
updates.forEach((k, v) -> update(Cache.keyX(k), v, Cache.keyZ(k), c, r));
mantle.iterateChunk(c.getX(), c.getZ(), MatterUpdate.class, (x, yf, z, v) -> {
int y = yf + getWorld().minHeight();
if (v != null && v.isUpdate()) {
int vx = x & 15;
int vz = z & 15;
update(x, y, z, c, new RNG(Cache.key(c.getX(), c.getZ())));
if (vx > 0 && vx < 15 && vz > 0 && vz < 15) {
updateLighting(x, y, z, c);
}
}
});
mantle.deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class);
getMetrics().getUpdates().put(p.getMilliseconds());
}, RNG.r.i(0, 20))));
}
});
try {
semaphore.acquire(3);
} catch (InterruptedException ignored) {}
} finally {
chunk.release();
}
updates.forEach((k, v) -> update(Cache.keyX(k), v, Cache.keyZ(k), c, r));
mantle.iterateChunk(c.getX(), c.getZ(), MatterUpdate.class, (x, yf, z, v) -> {
int y = yf + getWorld().minHeight();
if (v != null && v.isUpdate()) {
int vx = x & 15;
int vz = z & 15;
update(x, y, z, c, new RNG(Cache.key(c.getX(), c.getZ())));
if (vx > 0 && vx < 15 && vz > 0 && vz < 15) {
updateLighting(x, y, z, c);
}
}
});
mantle.deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class);
getMetrics().getUpdates().put(p.getMilliseconds());
}, RNG.r.i(0, 20))));
try {
semaphore.acquire(3);
} catch (InterruptedException ignored) {}
}
private static Runnable run(Semaphore semaphore, Runnable runnable) {
@@ -458,11 +454,14 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
}
}
for (int i = nitems.length; i > 1; i--) {
int j = rng.nextInt(i);
ItemStack tmp = nitems[i - 1];
nitems[i - 1] = nitems[j];
nitems[j] = tmp;
for (int i = 0; i < 4; i++) {
try {
Arrays.parallelSort(nitems, (a, b) -> rng.nextInt());
break;
} catch (Throwable e) {
Iris.reportError(e);
}
}
inventory.setContents(nitems);
@@ -612,8 +611,6 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
int getGenerated();
CompletableFuture<Long> getHash32();
default <T> IrisPosition lookForStreamResult(T find, ProceduralStream<T> stream, Function2<T, T, Boolean> matcher, long timeout) {
AtomicInteger checked = new AtomicInteger();
AtomicLong time = new AtomicLong(M.ms());
@@ -829,6 +826,13 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
return new PlacedObject(piece.getPlacementOptions(), getData().getObjectLoader().load(object), id, x, z);
}
for (var staticPlacement : getDimension().getStaticPlacements().getObjects()) {
IrisObjectPlacement i = staticPlacement.placement();
if (i.getPlace().contains(object)) {
return new PlacedObject(i, getData().getObjectLoader().load(object), id, x, z);
}
}
IrisRegion region = getRegion(x, z);
for (IrisObjectPlacement i : region.getObjects()) {
@@ -854,25 +858,6 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
return getBiomeOrMantle(l.getBlockX(), l.getBlockY(), l.getBlockZ());
}
@Nullable
@BlockCoordinates
default Position2 getNearestStronghold(Position2 pos) {
KList<Position2> p = getDimension().getStrongholds(getSeedManager().getMantle());
if (p.isEmpty()) return null;
Position2 pr = null;
double d = Double.MAX_VALUE;
for (Position2 i : p) {
double dx = i.distance(pos);
if (dx < d) {
d = dx;
pr = i;
}
}
return pr;
}
default void gotoBiome(IrisBiome biome, Player player, boolean teleport) {
Set<String> regionKeys = getDimension()
.getAllRegions(this).stream()
@@ -893,10 +878,31 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
default void gotoJigsaw(IrisJigsawStructure s, Player player, boolean teleport) {
if (s.getLoadKey().equals(getDimension().getStronghold())) {
Position2 pr = getNearestStronghold(new Position2(player.getLocation().getBlockX(), player.getLocation().getBlockZ()));
if (pr == null) {
KList<Position2> p = getDimension().getStrongholds(getSeedManager().getMantle());
if (p.isEmpty()) {
player.sendMessage(C.GOLD + "No strongholds in world.");
} else {
}
Position2 px = new Position2(player.getLocation().getBlockX(), player.getLocation().getBlockZ());
Position2 pr = null;
double d = Double.MAX_VALUE;
Iris.debug("Ps: " + p.size());
for (Position2 i : p) {
Iris.debug("- " + i.getX() + " " + i.getZ());
}
for (Position2 i : p) {
double dx = i.distance(px);
if (dx < d) {
d = dx;
pr = i;
}
}
if (pr != null) {
Location ll = new Location(player.getWorld(), pr.getX(), 40, pr.getZ());
J.s(() -> player.teleport(ll));
}

View File

@@ -97,6 +97,51 @@ public abstract class EngineAssignedWorldManager extends EngineAssignedComponent
}
}
@EventHandler
public void onItemUse(PlayerInteractEvent e) {
if (e.getItem() == null || e.getHand() != EquipmentSlot.HAND) {
return;
}
if (e.getAction() == Action.LEFT_CLICK_BLOCK || e.getAction() == Action.LEFT_CLICK_AIR) {
return;
}
if (e.getPlayer().getWorld().equals(getTarget().getWorld().realWorld()) && e.getItem().getType() == Material.ENDER_EYE) {
if (e.getClickedBlock() != null && e.getClickedBlock().getType() == Material.END_PORTAL_FRAME) {
return;
}
KList<Position2> positions = getEngine().getDimension().getStrongholds(getEngine().getSeedManager().getMantle());
if (positions.isEmpty()) {
return;
}
Position2 playerPos = new Position2(e.getPlayer().getLocation().getBlockX(), e.getPlayer().getLocation().getBlockZ());
Position2 pr = positions.get(0);
double d = pr.distance(playerPos);
for (Position2 pos : positions) {
double distance = pos.distance(playerPos);
if (distance < d) {
d = distance;
pr = pos;
}
}
if (e.getPlayer().getGameMode() != GameMode.CREATIVE) {
if (e.getItem().getAmount() > 1) {
e.getPlayer().getInventory().getItemInMainHand().setAmount(e.getItem().getAmount() - 1);
} else {
e.getPlayer().getInventory().setItemInMainHand(null);
}
}
EnderSignal eye = e.getPlayer().getWorld().spawn(e.getPlayer().getLocation().clone().add(0, 0.5F, 0), EnderSignal.class);
eye.setTargetLocation(new Location(e.getPlayer().getWorld(), pr.getX(), 40, pr.getZ()));
eye.getWorld().playSound(eye, Sound.ENTITY_ENDER_EYE_LAUNCH, 1, 1);
Iris.debug("ESignal: " + eye.getTargetLocation().getBlockX() + " " + eye.getTargetLocation().getBlockX());
}
}
@EventHandler
public void on(WorldUnloadEvent e) {
if (e.getWorld().equals(getTarget().getWorld().realWorld())) {

View File

@@ -47,7 +47,9 @@ public class EnginePlayer {
}
public void tick() {
if (sample() || !IrisSettings.get().getWorld().isEffectSystem())
sample();
if (!IrisSettings.get().getWorld().isEffectSystem())
return;
J.a(() -> {
@@ -79,22 +81,22 @@ public class EnginePlayer {
return M.ms() - lastSample;
}
public boolean sample() {
Location current = player.getLocation().clone();
if (current.getWorld() != engine.getWorld().realWorld())
return true;
public void sample() {
try {
if (ticksSinceLastSample() > 55 && current.distanceSquared(lastLocation) > 9 * 9) {
lastLocation = current;
if (ticksSinceLastSample() > 55 && player.getLocation().distanceSquared(lastLocation) > 9 * 9) {
lastLocation = player.getLocation().clone();
lastSample = M.ms();
biome = engine.getBiome(current);
region = engine.getRegion(current);
sampleBiomeRegion();
}
return false;
} catch (Throwable e) {
Iris.reportError(e);
}
return true;
}
private void sampleBiomeRegion() {
Location l = player.getLocation();
biome = engine.getBiome(l);
region = engine.getRegion(l);
}
}

View File

@@ -13,7 +13,6 @@ import com.volmit.iris.engine.object.IrisLootTable;
import com.volmit.iris.engine.object.TileData;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.math.RNG;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@@ -79,11 +78,7 @@ public class WorldObjectPlacer implements IObjectPlacer {
}
}
if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase());
Iris.warn("Tried to place custom block at " + x + ", " + y + ", " + z + " which is not supported!");
} else block.setBlockData(d);
block.setBlockData(d);
}
@Override

View File

@@ -25,6 +25,7 @@ import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.placer.WorldObjectPlacer;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.data.IrisBlockData;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG;
@@ -154,6 +155,9 @@ public class PlannedStructure {
return v.place(xx, height, zz, placer, options, rng, (b, data) -> {
e.set(b.getX(), b.getY(), b.getZ(), v.getLoadKey() + "@" + id);
e.set(b.getX(), b.getY(), b.getZ(), container);
if (data instanceof IrisBlockData d) {
e.set(b.getX(), b.getY(), b.getZ(), d.getCustom());
}
}, null, getData().getEngine() != null ? getData() : eng.getData()) != -1;
}

View File

@@ -34,7 +34,6 @@ import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.hunk.Hunk;
@@ -105,10 +104,7 @@ public interface EngineMantle extends IObjectPlacer {
@Override
default void set(int x, int y, int z, BlockData d) {
if (d instanceof IrisCustomData data) {
getMantle().set(x, y, z, data.getBase());
getMantle().set(x, y, z, data.getCustom());
} else getMantle().set(x, y, z, d == null ? AIR : d);
getMantle().set(x, y, z, d == null ? AIR : d);
}
@Override
@@ -289,25 +285,23 @@ public interface EngineMantle extends IObjectPlacer {
}
default void cleanupChunk(int x, int z) {
if (!isCovered(x, z)) return;
MantleChunk chunk = getMantle().getChunk(x, z).use();
try {
chunk.raiseFlag(MantleFlag.CLEANED, () -> {
chunk.deleteSlices(BlockData.class);
chunk.deleteSlices(String.class);
chunk.deleteSlices(MatterCavern.class);
chunk.deleteSlices(MatterFluidBody.class);
if (!getMantle().hasFlag(x, z, MantleFlag.CLEANED) && isCovered(x, z)) {
getMantle().raiseFlag(x, z, MantleFlag.CLEANED, () -> {
getMantle().deleteChunkSlice(x, z, BlockData.class);
getMantle().deleteChunkSlice(x, z, String.class);
getMantle().deleteChunkSlice(x, z, MatterCavern.class);
getMantle().deleteChunkSlice(x, z, MatterFluidBody.class);
});
} finally {
chunk.release();
}
}
default long getUnloadRegionCount() {
return getMantle().getUnloadRegionCount();
default long getToUnload(){
return getMantle().getToUnload().size();
}
default double getAdjustedIdleDuration() {
return getMantle().getAdjustedIdleDuration();
default long getNotQueuedLoadedRegions(){
return getMantle().getLoadedRegions().size() - getMantle().getToUnload().size();
}
default double getTectonicDuration(){
return getMantle().getAdjustedIdleDuration().get();
}
}

View File

@@ -29,7 +29,6 @@ import com.volmit.iris.engine.object.IrisPosition;
import com.volmit.iris.engine.object.TileData;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.function.Function3;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.MantleChunk;
@@ -60,9 +59,8 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
this.x = x;
this.z = z;
int r = radius / 4;
for (int i = -r; i <= r; i++) {
for (int j = -r; j <= r; j++) {
for (int i = -radius; i <= radius; i++) {
for (int j = -radius; j <= radius; j++) {
cachedChunks.put(Cache.key(i + x, j + z), mantle.getChunk(i + x, j + z).use());
}
}
@@ -144,7 +142,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
if (cx >= this.x - radius && cx <= this.x + radius
&& cz >= this.z - radius && cz <= this.z + radius) {
MantleChunk chunk = cachedChunks.computeIfAbsent(Cache.key(cx, cz), k -> mantle.getChunk(cx, cz).use());
MantleChunk chunk = cachedChunks.get(Cache.key(cx, cz));
if (chunk == null) {
Iris.error("Mantle Writer Accessed " + cx + "," + cz + " and came up null (and yet within bounds!)");
@@ -153,8 +151,6 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
Matter matter = chunk.getOrCreate(y >> 4);
matter.slice(matter.getClass(t)).set(x & 15, y & 15, z & 15, t);
} else {
Iris.error("Mantle Writer Accessed chunk out of bounds" + cx + "," + cz);
}
}
@@ -170,10 +166,7 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
@Override
public void set(int x, int y, int z, BlockData d) {
if (d instanceof IrisCustomData data) {
setData(x, y, z, data.getBase());
setData(x, y, z, data.getCustom());
} else setData(x, y, z, d);
setData(x, y, z, d);
}
@Override
@@ -642,10 +635,9 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
@Override
public void close() {
var iterator = cachedChunks.values().iterator();
while (iterator.hasNext()) {
iterator.next().release();
iterator.remove();
}
cachedChunks.values().removeIf(c -> {
c.release();
return true;
});
}
}

View File

@@ -58,21 +58,21 @@ public class MantleCarvingComponent extends IrisMantleComponent {
@ChunkCoordinates
private void carve(IrisCarving carving, MantleWriter writer, RNG rng, int cx, int cz) {
carving.doCarving(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4, 0);
carving.doCarving(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4);
}
private int computeRadius() {
var dimension = getDimension();
int max = 0;
max = Math.max(max, dimension.getCarving().getMaxRange(getData(), 0));
max = Math.max(max, dimension.getCarving().getMaxRange(getData()));
for (var i : dimension.getAllRegions(this::getData)) {
max = Math.max(max, i.getCarving().getMaxRange(getData(), 0));
max = Math.max(max, i.getCarving().getMaxRange(getData()));
}
for (var i : dimension.getAllBiomes(this::getData)) {
max = Math.max(max, i.getCarving().getMaxRange(getData(), 0));
max = Math.max(max, i.getCarving().getMaxRange(getData()));
}
return max;

View File

@@ -90,10 +90,8 @@ public class MantleJigsawComponent extends IrisMantleComponent {
private boolean placeStructures(MantleWriter writer, long seed, int x, int z, KList<IrisJigsawStructurePlacement> structures,
KSet<Position2> cachedRegions, KMap<String, KSet<Position2>> cache, KMap<Position2, Double> distanceCache) {
IrisJigsawStructurePlacement i = pick(structures, seed, x, z);
try {
if (i == null || checkMinDistances(i.collectMinDistances(), x, z, cachedRegions, cache, distanceCache))
return false;
} catch (Throwable ignored) {}
if (i == null || checkMinDistances(i.collectMinDistances(), x, z, cachedRegions, cache, distanceCache))
return false;
RNG rng = new RNG(seed);
IrisPosition position = new IrisPosition((x << 4) + rng.nextInt(15), 0, (z << 4) + rng.nextInt(15));
IrisJigsawStructure structure = getData().getJigsawStructureLoader().load(i.getStructure());
@@ -161,7 +159,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
@ChunkCoordinates
private IrisJigsawStructurePlacement pick(List<IrisJigsawStructurePlacement> structures, long seed, int x, int z) {
return IRare.pick(structures.stream()
.filter(p -> p.shouldPlace(getData(), getDimension().getJigsawStructureDivisor(), jigsaw(), x, z))
.filter(p -> p.shouldPlace(getDimension().getJigsawStructureDivisor(), jigsaw(), x, z))
.toList(), new RNG(seed).nextDouble());
}

View File

@@ -19,6 +19,7 @@
package com.volmit.iris.engine.mantle.components;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.mantle.EngineMantle;
import com.volmit.iris.engine.mantle.IrisMantleComponent;
@@ -29,6 +30,7 @@ import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisBlockData;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.format.Form;
@@ -38,11 +40,13 @@ import com.volmit.iris.util.matter.MatterStructurePOI;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.noise.NoiseType;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import lombok.Getter;
import org.bukkit.util.BlockVector;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
@@ -115,6 +119,9 @@ public class MantleObjectComponent extends IrisMantleComponent {
if (objectPlacement.isDolphinTarget() && objectPlacement.isUnderwater() && B.isStorageChest(data)) {
writer.setData(b.getX(), b.getY(), b.getZ(), MatterStructurePOI.BURIED_TREASURE);
}
if (data instanceof IrisBlockData d) {
writer.setData(b.getX(), b.getY(), b.getZ(), d.getCustom());
}
}, null, getData());
}
}
@@ -158,99 +165,67 @@ public class MantleObjectComponent extends IrisMantleComponent {
private int computeRadius() {
var dimension = getDimension();
AtomicInteger xg = new AtomicInteger();
AtomicInteger zg = new AtomicInteger();
KSet<String> objects = new KSet<>();
KMap<IrisObjectScale, KList<String>> scalars = new KMap<>();
for (var region : dimension.getAllRegions(this::getData)) {
for (var j : region.getObjects()) {
if (j.getScale().canScaleBeyond()) {
scalars.put(j.getScale(), j.getPlace());
for (var placement : region.getObjects()) {
if (placement.getScale().canScaleBeyond()) {
scalars.put(placement.getScale(), placement.getPlace());
} else {
objects.addAll(j.getPlace());
objects.addAll(placement.getPlace());
}
}
}
for (var biome : dimension.getAllBiomes(this::getData)) {
for (var j : biome.getObjects()) {
if (j.getScale().canScaleBeyond()) {
scalars.put(j.getScale(), j.getPlace());
} else {
objects.addAll(j.getPlace());
for (var biome : region.getAllBiomes(this::getData)) {
for (var placement : biome.getObjects()) {
if (placement.getScale().canScaleBeyond()) {
scalars.put(placement.getScale(), placement.getPlace());
} else {
objects.addAll(placement.getPlace());
}
}
}
}
BurstExecutor e = getEngineMantle().getTarget().getBurster().burst(objects.size());
return computeObjectRadius(objects, scalars, getEngineMantle().getTarget().getBurster(), getData());
}
static int computeObjectRadius(KSet<String> objects, KMap<IrisObjectScale, KList<String>> scalars, MultiBurst burst, IrisData data) {
AtomicInteger x = new AtomicInteger();
AtomicInteger z = new AtomicInteger();
BurstExecutor e = burst.burst(objects.size());
KMap<String, BlockVector> sizeCache = new KMap<>();
for (String i : objects) {
for (String loadKey : objects) {
e.queue(() -> {
try {
BlockVector bv = sizeCache.computeIfAbsent(i, (k) -> {
try {
return IrisObject.sampleSize(getData().getObjectLoader().findFile(i));
} catch (IOException ex) {
Iris.reportError(ex);
ex.printStackTrace();
}
return null;
});
if (bv == null) {
throw new RuntimeException();
}
BlockVector bv = sampleSize(sizeCache, data, loadKey);
if (Math.max(bv.getBlockX(), bv.getBlockZ()) > 128) {
Iris.warn("Object " + i + " has a large size (" + bv + ") and may increase memory usage!");
Iris.warn("Object " + loadKey + " has a large size (" + bv + ") and may increase memory usage!");
}
synchronized (xg) {
xg.getAndSet(Math.max(bv.getBlockX(), xg.get()));
}
synchronized (zg) {
zg.getAndSet(Math.max(bv.getBlockZ(), zg.get()));
}
x.getAndUpdate(i -> Math.max(bv.getBlockX(), i));
z.getAndUpdate(i -> Math.max(bv.getBlockZ(), i));
} catch (Throwable ed) {
Iris.reportError(ed);
}
});
}
for (Map.Entry<IrisObjectScale, KList<String>> entry : scalars.entrySet()) {
double ms = entry.getKey().getMaximumScale();
for (String j : entry.getValue()) {
for (String loadKey : entry.getValue()) {
e.queue(() -> {
try {
BlockVector bv = sizeCache.computeIfAbsent(j, (k) -> {
try {
return IrisObject.sampleSize(getData().getObjectLoader().findFile(j));
} catch (IOException ioException) {
Iris.reportError(ioException);
ioException.printStackTrace();
}
return null;
});
if (bv == null) {
throw new RuntimeException();
}
BlockVector bv = sampleSize(sizeCache, data, loadKey);
if (Math.max(bv.getBlockX(), bv.getBlockZ()) > 128) {
Iris.warn("Object " + j + " has a large size (" + bv + ") and may increase memory usage! (Object scaled up to " + Form.pc(ms, 2) + ")");
Iris.warn("Object " + loadKey + " has a large size (" + bv + ") and may increase memory usage! (Object scaled up to " + Form.pc(ms, 2) + ")");
}
synchronized (xg) {
xg.getAndSet((int) Math.max(Math.ceil(bv.getBlockX() * ms), xg.get()));
}
synchronized (zg) {
zg.getAndSet((int) Math.max(Math.ceil(bv.getBlockZ() * ms), zg.get()));
}
x.getAndUpdate(i -> (int) Math.max(Math.ceil(bv.getBlockX() * ms), i));
x.getAndUpdate(i -> (int) Math.max(Math.ceil(bv.getBlockZ() * ms), i));
} catch (Throwable ee) {
Iris.reportError(ee);
@@ -260,6 +235,20 @@ public class MantleObjectComponent extends IrisMantleComponent {
}
e.complete();
return Math.max(xg.get(), zg.get());
return Math.max(x.get(), z.get());
}
private static BlockVector sampleSize(KMap<String, BlockVector> sizeCache, IrisData data, String loadKey) {
BlockVector bv = sizeCache.computeIfAbsent(loadKey, (k) -> {
try {
return IrisObject.sampleSize(data.getObjectLoader().findFile(loadKey));
} catch (IOException ioException) {
Iris.reportError(ioException);
ioException.printStackTrace();
}
return null;
});
return Objects.requireNonNull(bv, "sampleSize returned a null block vector");
}
}

View File

@@ -0,0 +1,59 @@
package com.volmit.iris.engine.mantle.components;
import com.volmit.iris.engine.mantle.EngineMantle;
import com.volmit.iris.engine.mantle.IrisMantleComponent;
import com.volmit.iris.engine.mantle.MantleWriter;
import com.volmit.iris.engine.object.IrisObjectScale;
import com.volmit.iris.engine.object.IrisStaticPlacement;
import com.volmit.iris.engine.object.NoiseStyle;
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.ChunkContext;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG;
import lombok.Getter;
public class MantleStaticComponent extends IrisMantleComponent {
private final CNG cng;
@Getter
private final int radius = computeRadius();
public MantleStaticComponent(EngineMantle engineMantle) {
super(engineMantle, MantleFlag.STATIC, 1);
cng = NoiseStyle.STATIC.create(new RNG(seed()));
}
@Override
public void generateLayer(MantleWriter writer, int x, int z, ChunkContext context) {
RNG rng = new RNG(cng.fit(Integer.MIN_VALUE, Integer.MAX_VALUE, x, z));
for (IrisStaticPlacement placement : getDimension().getStaticPlacements().getAll(x, z)) {
placement.place(writer, rng, getData());
}
}
private int computeRadius() {
var placements = getDimension().getStaticPlacements();
KSet<String> objects = new KSet<>();
KMap<IrisObjectScale, KList<String>> scalars = new KMap<>();
for (var staticPlacement : placements.getObjects()) {
var placement = staticPlacement.placement();
if (placement.getScale().canScaleBeyond()) {
scalars.put(placement.getScale(), placement.getPlace());
} else {
objects.addAll(placement.getPlace());
}
}
int jigsaw = placements.getStructures()
.stream()
.mapToInt(staticPlacement -> staticPlacement.maxDimension(getData()))
.max()
.orElse(0);
int object = MantleObjectComponent.computeObjectRadius(objects, scalars, getEngineMantle().getTarget().getBurster(), getData());
return Math.max(jigsaw, object);
}
}

View File

@@ -25,7 +25,10 @@ import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineMode;
import com.volmit.iris.engine.framework.EngineStage;
import com.volmit.iris.engine.framework.IrisEngineMode;
import com.volmit.iris.engine.modifier.*;
import com.volmit.iris.engine.modifier.IrisCarveModifier;
import com.volmit.iris.engine.modifier.IrisDepositModifier;
import com.volmit.iris.engine.modifier.IrisPerfectionModifier;
import com.volmit.iris.engine.modifier.IrisPostModifier;
import org.bukkit.block.data.BlockData;
public class ModeOverworld extends IrisEngineMode implements EngineMode {
@@ -38,7 +41,6 @@ public class ModeOverworld extends IrisEngineMode implements EngineMode {
var post = new IrisPostModifier(getEngine());
var deposit = new IrisDepositModifier(getEngine());
var perfection = new IrisPerfectionModifier(getEngine());
var custom = new IrisCustomModifier(getEngine());
EngineStage sBiome = (x, z, k, p, m, c) -> biome.actuate(x, z, p, m, c);
EngineStage sGenMatter = (x, z, k, p, m, c) -> generateMatter(x >> 4, z >> 4, m, c);
EngineStage sTerrain = (x, z, k, p, m, c) -> terrain.actuate(x, z, k, m, c);
@@ -48,7 +50,6 @@ public class ModeOverworld extends IrisEngineMode implements EngineMode {
EngineStage sPost = (x, z, k, p, m, c) -> post.modify(x, z, k, m, c);
EngineStage sInsertMatter = (x, z, K, p, m, c) -> getMantle().insertMatter(x >> 4, z >> 4, BlockData.class, K, m);
EngineStage sPerfection = (x, z, k, p, m, c) -> perfection.modify(x, z, k, m, c);
EngineStage sCustom = (x, z, k, p, m, c) -> custom.modify(x, z, k, m, c);
registerStage(burst(
sGenMatter,
@@ -64,6 +65,6 @@ public class ModeOverworld extends IrisEngineMode implements EngineMode {
sDecorant
));
registerStage(sPerfection);
registerStage(sCustom);
}
}

View File

@@ -43,6 +43,7 @@ import org.bukkit.block.data.BlockData;
public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
private final RNG rng;
private final BlockData AIR = Material.CAVE_AIR.createBlockData();
private final BlockData WATER = Material.WATER.createBlockData();
private final BlockData LAVA = Material.LAVA.createBlockData();
private final IrisDecorantActuator decorant;
@@ -56,7 +57,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
public void onModify(int x, int z, Hunk<BlockData> output, boolean multicore, ChunkContext context) {
PrecisionStopwatch p = PrecisionStopwatch.start();
Mantle mantle = getEngine().getMantle().getMantle();
MantleChunk mc = getEngine().getMantle().getMantle().getChunk(x, z).use();
MantleChunk mc = getEngine().getMantle().getMantle().getChunk(x, z);
KMap<Long, KList<Integer>> positions = new KMap<>();
KMap<IrisPosition, MatterCavern> walls = new KMap<>();
Consumer4<Integer, Integer, Integer, MatterCavern> iterator = (xx, yy, zz, c) -> {
@@ -102,7 +103,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
}
if (c.isWater()) {
output.set(rx, yy, rz, context.getFluid().get(rx, rz));
output.set(rx, yy, rz, WATER);
} else if (c.isLava()) {
output.set(rx, yy, rz, LAVA);
} else {
@@ -165,7 +166,6 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
});
getEngine().getMetrics().getDeposit().put(p.getMilliseconds());
mc.release();
}
private void processZone(Hunk<BlockData> output, MantleChunk mc, Mantle mantle, CaveZone zone, int rx, int rz, int xx, int zz) {
@@ -211,6 +211,14 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
biome.setInferredType(InferredType.CAVE);
for (IrisDecorator i : biome.getDecorators()) {
if (i.getPartOf().equals(IrisDecorationPart.NONE) && B.isSolid(output.get(rx, zone.getFloor() - 1, rz))) {
decorant.getSurfaceDecorator().decorate(rx, rz, xx, xx, xx, zz, zz, zz, output, biome, zone.getFloor() - 1, zone.airThickness());
} else if (i.getPartOf().equals(IrisDecorationPart.CEILING) && B.isSolid(output.get(rx, zone.getCeiling() + 1, rz))) {
decorant.getCeilingDecorator().decorate(rx, rz, xx, xx, xx, zz, zz, zz, output, biome, zone.getCeiling(), zone.airThickness());
}
}
KList<BlockData> blocks = biome.generateLayers(getDimension(), xx, zz, rng, 3, zone.floor, getData(), getComplex());
for (int i = 0; i < zone.floor - 1; i++) {
@@ -252,14 +260,6 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
output.set(rx, zone.ceiling + i + 1, rz, b);
}
}
for (IrisDecorator i : biome.getDecorators()) {
if (i.getPartOf().equals(IrisDecorationPart.NONE) && B.isSolid(output.get(rx, zone.getFloor() - 1, rz))) {
decorant.getSurfaceDecorator().decorate(rx, rz, xx, xx, xx, zz, zz, zz, output, biome, zone.getFloor() - 1, zone.airThickness());
} else if (i.getPartOf().equals(IrisDecorationPart.CEILING) && B.isSolid(output.get(rx, zone.getCeiling() + 1, rz))) {
decorant.getCeilingDecorator().decorate(rx, rz, xx, xx, xx, zz, zz, zz, output, biome, zone.getCeiling(), zone.airThickness());
}
}
}
@Data

View File

@@ -1,43 +0,0 @@
package com.volmit.iris.engine.modifier;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineAssignedModifier;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import org.bukkit.block.data.BlockData;
public class IrisCustomModifier extends EngineAssignedModifier<BlockData> {
public IrisCustomModifier(Engine engine) {
super(engine, "Custom");
}
@Override
public void onModify(int x, int z, Hunk<BlockData> output, boolean multicore, ChunkContext context) {
var mc = getEngine().getMantle().getMantle().getChunk(x >> 4, z >> 4);
if (!mc.isFlagged(MantleFlag.CUSTOM_ACTIVE)) return;
mc.use();
BurstExecutor burst = MultiBurst.burst.burst(output.getHeight());
burst.setMulticore(multicore);
for (int y = 0; y < output.getHeight(); y++) {
int finalY = y;
burst.queue(() -> {
for (int rX = 0; rX < output.getWidth(); rX++) {
for (int rZ = 0; rZ < output.getDepth(); rZ++) {
BlockData b = output.get(rX, finalY, rZ);
if (!(b instanceof IrisCustomData d)) continue;
mc.getOrCreate(finalY >> 4)
.slice(Identifier.class)
.set(rX, finalY & 15, rZ, d.getCustom());
output.set(rX, finalY, rZ, d.getBase());
}
}
});
}
burst.complete();
mc.release();
}
}

View File

@@ -200,7 +200,7 @@ public class IrisBiome extends IrisRegistrant implements IRare {
KMap<String, Integer> l = new KMap<>();
for (IrisBiomeGeneratorLink i : getGenerators()) {
l.put(i.getGenerator(), i.getMax());
l.put(i.getGenerator(), i.getMax(engine));
}
@@ -216,7 +216,7 @@ public class IrisBiome extends IrisRegistrant implements IRare {
KMap<String, Integer> l = new KMap<>();
for (IrisBiomeGeneratorLink i : getGenerators()) {
l.put(i.getGenerator(), i.getMin());
l.put(i.getGenerator(), i.getMin(engine));
}
return l;
@@ -457,7 +457,7 @@ public class IrisBiome extends IrisRegistrant implements IRare {
int maxHeight = 0;
for (IrisBiomeGeneratorLink i : getGenerators()) {
maxHeight += i.getMax();
maxHeight += i.getMax(engine);
}
return maxHeight;
@@ -470,7 +470,7 @@ public class IrisBiome extends IrisRegistrant implements IRare {
int maxHeight = 0;
for (IrisBiomeGeneratorLink i : getGenerators()) {
maxHeight += i.getMax();
maxHeight += i.getMax(engine);
}
int gg = 0;

View File

@@ -18,7 +18,9 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.interpolation.IrisInterpolation;
@@ -37,16 +39,18 @@ public class IrisBiomeGeneratorLink {
@RegistryListResource(IrisGenerator.class)
@Desc("The generator id")
private String generator = "default";
@DependsOn({"min", "max"})
@DependsOn({ "min", "max" })
@Required
@MinNumber(-2032) // TODO: WARNING HEIGHT
@MaxNumber(2032) // TODO: WARNING HEIGHT
@Desc("The min block value (value + fluidHeight)")
@Getter(AccessLevel.NONE)
private int min = 0;
@DependsOn({"min", "max"})
@DependsOn({ "min", "max" })
@Required
@MinNumber(-2032) // TODO: WARNING HEIGHT
@MaxNumber(2032) // TODO: WARNING HEIGHT
@Getter(AccessLevel.NONE)
@Desc("The max block value (value + fluidHeight)")
private int max = 0;
@@ -62,6 +66,70 @@ public class IrisBiomeGeneratorLink {
});
}
private int[] getBiomeGeneratorsRaw(Engine engine) {
int max = engine.getDimension().getMinHeight();
int min = engine.getDimension().getMaxHeight();
for (IrisBiome biome : engine.getAllBiomes()) {
for (IrisBiomeGeneratorLink i : biome.getGenerators()) {
int biomeRawMax = i.getMaxRaw();
int biomeRawMin = i.getMinRaw();
if (max < biomeRawMax)
max = biomeRawMax;
if (min > biomeRawMin)
min = biomeRawMin;
}
}
return new int[] { min, max };
}
private int calculateHeight(Engine engine, int option) {
int dmx = engine.getDimension().getMaxHeight();
int dmn = engine.getDimension().getMinHeight();
int[] heights = getBiomeGeneratorsRaw(engine);
int gmx = heights[1];
int gmn = heights[0];
int mx = getMaxRaw();
int mn = getMinRaw();
if (engine.getDimension().isSmartVanillaHeight()) {
if (mx > 0)
mx = Math.min((int) (((float) mx / (float) gmx) * 300.0f), 300);
if (mx < 0)
mx = Math.min((int) (((float) mx / (float) gmn) * 300.0f), 56);
if (mn > 0)
mn = Math.min((int) (((float) mn / (float) gmx) * 300.0f), 300);
if (mn < 0)
mn = Math.min((int) (((float) mn / (float) gmn) * 300.0f), 56);
}
if (option == 1) {
return mx;
}
if (option == 0) {
return mn;
}
Iris.error("Fatal Generator error!");
return 0;
}
public int getMax(Engine engine) {
return calculateHeight(engine, 1);
}
public int getMin(Engine engine) {
return calculateHeight(engine, 0);
}
private int getMaxRaw() {
return max;
}
private int getMinRaw() {
return min;
}
public double getHeight(DataProvider xg, double x, double z, long seed) {
double g = getCachedGenerator(xg).getHeight(x, z, seed);
g = g < 0 ? 0 : g;

View File

@@ -19,7 +19,6 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.nms.INMS;
@@ -35,8 +34,8 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.EntityType;
import java.util.Map;
@@ -203,14 +202,6 @@ public class IrisBlockData extends IrisRegistrant {
public TileData tryGetTile(IrisData data) {
//TODO Do like a registry thing with the tile data registry. Also update the parsing of data to include **block** entities.
var type = getBlockData(data).getMaterial();
if (type == Material.SPAWNER && this.data.containsKey("entitySpawn")) {
String id = (String) this.data.get("entitySpawn");
if (tileData == null) tileData = new KMap<>();
KMap<String, Object> spawnData = (KMap<String, Object>) tileData.computeIfAbsent("SpawnData", k -> new KMap<>());
KMap<String, Object> entity = (KMap<String, Object>) spawnData.computeIfAbsent("entity", k -> new KMap<>());
entity.putIfAbsent("id", Identifier.fromString(id).toString());
}
if (!INMS.get().hasTile(type) || tileData == null || tileData.isEmpty())
return null;
return new TileData(type, this.tileData);

View File

@@ -61,25 +61,21 @@ public class IrisCarving {
@BlockCoordinates
public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int depth) {
doCarving(writer, rng, engine, x, y, z, depth, -1);
public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) {
doCarving(writer, rng, engine, x, y, z, -1);
}
@BlockCoordinates
public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) {
int nextRecursion = recursion + 1;
public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int waterHint) {
if (caves.isNotEmpty()) {
for (IrisCavePlacer i : caves) {
if (recursion > i.getMaxRecursion()) continue;
i.generateCave(writer, rng, engine, x, y, z, nextRecursion, waterHint);
i.generateCave(writer, rng, engine, x, y, z, waterHint);
}
}
if (ravines.isNotEmpty()) {
for (IrisRavinePlacer i : ravines) {
if (recursion > i.getMaxRecursion()) continue;
i.generateRavine(writer, rng, engine, x, y, z, nextRecursion, waterHint);
i.generateRavine(writer, rng, engine, x, y, z, waterHint);
}
}
@@ -108,18 +104,15 @@ public class IrisCarving {
}
}
public int getMaxRange(IrisData data, int recursion) {
public int getMaxRange(IrisData data) {
int max = 0;
int nextRecursion = recursion + 1;
for (IrisCavePlacer i : caves) {
if (recursion > i.getMaxRecursion()) continue;
max = Math.max(max, i.getSize(data, nextRecursion));
max = Math.max(max, i.getSize(data));
}
for (IrisRavinePlacer i : ravines) {
if (recursion > i.getMaxRecursion()) continue;
max = Math.max(max, i.getSize(data, nextRecursion));
max = Math.max(max, i.getSize(data));
}
if (elipsoids.isNotEmpty()) {

View File

@@ -66,10 +66,10 @@ public class IrisCave extends IrisRegistrant {
}
public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) {
generate(writer, rng, engine, x, y, z, 0, -1);
generate(writer, rng, engine, x, y, z, -1);
}
public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) {
public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int waterHint) {
double girth = getWorm().getGirth().get(rng, x, z, engine.getData());
KList<IrisPosition> points = getWorm().generate(rng, engine.getData(), writer, verticalRange, x, y, z, (at) -> {
@@ -92,7 +92,7 @@ public class IrisCave extends IrisRegistrant {
int h = Math.min(Math.max(highestWater, waterHint), engine.getDimension().getFluidHeight());
for (IrisPosition i : points) {
fork.doCarving(writer, rng, engine, i.getX(), i.getY(), i.getZ(), recursion, h);
fork.doCarving(writer, rng, engine, i.getX(), i.getY(), i.getZ(), h);
}
MatterCavern c = new MatterCavern(true, customBiome, (byte) 0);
@@ -108,7 +108,7 @@ public class IrisCave extends IrisRegistrant {
}
public int getMaxSize(IrisData data, int depth) {
return getWorm().getMaxDistance() + fork.getMaxRange(data, depth);
public int getMaxSize(IrisData data) {
return getWorm().getMaxDistance() + fork.getMaxRange(data);
}
}

View File

@@ -50,10 +50,6 @@ public class IrisCavePlacer implements IRare {
@Desc("The cave to place")
@RegistryListResource(IrisCave.class)
private String cave;
@MinNumber(1)
@MaxNumber(256)
@Desc("The maximum recursion depth")
private int maxRecursion = 16;
@Desc("If set to true, this cave is allowed to break the surface")
private boolean breakSurface = true;
@Desc("The height range this cave can spawn at. If breakSurface is false, the output of this range will be clamped by the current world height to prevent surface breaking.")
@@ -64,10 +60,10 @@ public class IrisCavePlacer implements IRare {
}
public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z) {
generateCave(mantle, rng, engine, x, y, z, 0, -1);
generateCave(mantle, rng, engine, x, y, z, -1);
}
public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z, int recursion, int waterHint) {
public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z, int waterHint) {
if (fail.get()) {
return;
}
@@ -96,18 +92,18 @@ public class IrisCavePlacer implements IRare {
}
try {
cave.generate(mantle, rng, engine, x + rng.nextInt(15), y, z + rng.nextInt(15), recursion, waterHint);
cave.generate(mantle, rng, engine, x + rng.nextInt(15), y, z + rng.nextInt(15), waterHint);
} catch (Throwable e) {
e.printStackTrace();
fail.set(true);
}
}
public int getSize(IrisData data, int depth) {
public int getSize(IrisData data) {
IrisCave cave = getRealCave(data);
if (cave != null) {
return cave.getMaxSize(data, depth);
return cave.getMaxSize(data);
}
return 32;

View File

@@ -1,66 +0,0 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.AutoClosing;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.misc.ServerProperties;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
import java.util.List;
import static com.volmit.iris.Iris.instance;
public class IrisContextInjector implements Listener {
@Getter
private static boolean missingDimensionTypes = false;
private AutoClosing autoClosing = null;
public IrisContextInjector() {
if (!Bukkit.getWorlds().isEmpty()) return;
String levelName = ServerProperties.LEVEL_NAME;
List<String> irisWorlds = irisWorlds();
boolean overworld = irisWorlds.contains(levelName);
boolean nether = irisWorlds.contains(levelName + "_nether");
boolean end = irisWorlds.contains(levelName + "_end");
if (INMS.get().missingDimensionTypes(overworld, nether, end)) {
missingDimensionTypes = true;
return;
}
if (overworld || nether || end) {
autoClosing = INMS.get().injectUncached(overworld, nether, end);
}
instance.registerListener(this);
}
@EventHandler(priority = EventPriority.LOWEST)
public void on(WorldInitEvent event) {
if (autoClosing != null) {
autoClosing.close();
autoClosing = null;
}
instance.unregisterListener(this);
}
private List<String> irisWorlds() {
var config = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML);
ConfigurationSection section = config.getConfigurationSection("worlds");
if (section == null) return List.of();
return section.getKeys(false)
.stream()
.filter(k -> section.getString(k + ".generator", "").startsWith("Iris"))
.toList();
}
}

View File

@@ -19,8 +19,6 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.ServerConfigurator.DimensionHeight;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.nms.INMS;
@@ -28,7 +26,6 @@ import com.volmit.iris.core.nms.datapack.IDataFixer;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONObject;
@@ -57,6 +54,73 @@ import java.io.IOException;
public class IrisDimension extends IrisRegistrant {
public static final BlockData STONE = Material.STONE.createBlockData();
public static final BlockData WATER = Material.WATER.createBlockData();
private static final String DP_OVERWORLD_DEFAULT = """
{
"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
}""";
private static final String DP_NETHER_DEFAULT = """
{
"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
}""";
private static final String DP_END_DEFAULT = """
{
"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
}""";
private final transient AtomicCache<Position2> parallaxSize = new AtomicCache<>();
private final transient AtomicCache<CNG> rockLayerGenerator = new AtomicCache<>();
private final transient AtomicCache<CNG> fluidLayerGenerator = new AtomicCache<>();
@@ -170,6 +234,8 @@ public class IrisDimension extends IrisRegistrant {
private IrisRange dimensionHeightEnd = new IrisRange(-64, 320);
@Desc("Define the min and max Y bounds of this dimension. Please keep in mind that Iris internally generates from 0 to (max - min). \n\nFor example at -64 to 320, Iris is internally generating to 0 to 384, then on outputting chunks, it shifts it down by the min height (64 blocks). The default is -64 to 320. \n\nThe fluid height is placed at (fluid height + min height). So a fluid height of 63 would actually show up in the world at 1.")
private IrisRange dimensionHeightNether = new IrisRange(-64, 320);
@Desc("Enable smart vanilla height")
private boolean smartVanillaHeight = false;
@RegistryListResource(IrisBiome.class)
@Desc("Keep this either undefined or empty. Setting any biome name into this will force iris to only generate the specified biome. Great for testing.")
private String focus = "";
@@ -244,6 +310,8 @@ public class IrisDimension extends IrisRegistrant {
@MaxNumber(318)
@Desc("The Subterrain Fluid Layer Height")
private int caveLavaHeight = 8;
@Desc("Static Placements for objects and structures")
private IrisStaticPlacements staticPlacements = new IrisStaticPlacements();
public int getMaxHeight() {
return (int) getDimensionHeight().getMax();
@@ -379,35 +447,61 @@ public class IrisDimension extends IrisRegistrant {
return landBiomeStyle;
}
public void installBiomes(IDataFixer fixer, DataProvider data, KList<File> folders, KSet<String> biomes) {
getAllBiomes(data)
.stream()
.filter(IrisBiome::isCustom)
.map(IrisBiome::getCustomDerivitives)
.flatMap(KList::stream)
.parallel()
.forEach(j -> {
String json = j.generateJson(fixer);
synchronized (biomes) {
if (!biomes.add(j.getId())) {
Iris.verbose("Duplicate Data Pack Biome: " + getLoadKey() + "/" + j.getId());
return;
}
public boolean installDataPack(IDataFixer fixer, DataProvider data, File datapacks, double ultimateMaxHeight, double ultimateMinHeight) {
boolean write = false;
boolean changed = false;
IO.delete(new File(datapacks, "iris/data/" + getLoadKey().toLowerCase()));
for (IrisBiome i : getAllBiomes(data)) {
if (i.isCustom()) {
write = true;
for (IrisBiomeCustom j : i.getCustomDerivitives()) {
File output = new File(datapacks, "iris/data/" + getLoadKey().toLowerCase() + "/worldgen/biome/" + j.getId() + ".json");
if (!output.exists()) {
changed = true;
}
for (File datapacks : folders) {
File output = new File(datapacks, "iris/data/" + getLoadKey().toLowerCase() + "/worldgen/biome/" + j.getId() + ".json");
Iris.verbose(" Installing Data Pack Biome: " + output.getPath());
output.getParentFile().mkdirs();
try {
IO.writeAll(output, json);
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
Iris.verbose(" Installing Data Pack Biome: " + output.getPath());
output.getParentFile().mkdirs();
try {
IO.writeAll(output, j.generateJson(fixer));
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
});
}
}
}
if (!dimensionHeight.equals(new IrisRange(-64, 320)) && this.name.equalsIgnoreCase("overworld")) {
Iris.verbose(" Installing Data Pack Dimension Types: \"minecraft:overworld\", \"minecraft:the_nether\", \"minecraft:the_end\"");
dimensionHeight.setMax(ultimateMaxHeight);
dimensionHeight.setMin(ultimateMinHeight);
changed = writeDimensionType(fixer, changed, datapacks);
}
if (write) {
File mcm = new File(datapacks, "iris/pack.mcmeta");
try {
IO.writeAll(mcm, """
{
"pack": {
"description": "Iris Data Pack. This pack contains all installed Iris Packs' resources.",
"pack_format": {}
}
}
""".replace("{}", INMS.get().getDataVersion().getPackFormat() + ""));
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
Iris.verbose(" Installing Data Pack MCMeta: " + mcm.getPath());
}
return changed;
}
@Override
@@ -425,55 +519,66 @@ public class IrisDimension extends IrisRegistrant {
}
public static void writeShared(KList<File> folders, DimensionHeight height) {
Iris.verbose(" Installing Data Pack Dimension Types: \"iris:overworld\", \"iris:the_nether\", \"iris:the_end\"");
for (File datapacks : folders) {
write(datapacks, "overworld", height.overworldType());
write(datapacks, "the_nether", height.netherType());
write(datapacks, "the_end", height.endType());
}
String raw = """
{
"pack": {
"description": "Iris Data Pack. This pack contains all installed Iris Packs' resources.",
"pack_format": {}
}
}
""".replace("{}", INMS.get().getDataVersion().getPackFormat() + "");
for (File datapacks : folders) {
File mcm = new File(datapacks, "iris/pack.mcmeta");
try {
IO.writeAll(mcm, raw);
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
Iris.verbose(" Installing Data Pack MCMeta: " + mcm.getPath());
}
}
private static void write(File datapacks, String type, String json) {
File dimType = new File(datapacks, "iris/data/iris/dimension_type/" + type + ".json");
File dimTypeVanilla = new File(datapacks, "iris/data/minecraft/dimension_type/" + type + ".json");
dimType.getParentFile().mkdirs();
public boolean writeDimensionType(IDataFixer fixer, boolean changed, File datapacks) {
File dimTypeOverworld = new File(datapacks, "iris/data/minecraft/dimension_type/overworld.json");
if (!dimTypeOverworld.exists())
changed = true;
dimTypeOverworld.getParentFile().mkdirs();
try {
IO.writeAll(dimType, json);
IO.writeAll(dimTypeOverworld, generateDatapackJsonOverworld(fixer));
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
if (IrisSettings.get().getGeneral().adjustVanillaHeight || dimTypeVanilla.exists()) {
dimTypeVanilla.getParentFile().mkdirs();
try {
IO.writeAll(dimTypeVanilla, json);
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
File dimTypeNether = new File(datapacks, "iris/data/minecraft/dimension_type/the_nether.json");
if (!dimTypeNether.exists())
changed = true;
dimTypeNether.getParentFile().mkdirs();
try {
IO.writeAll(dimTypeNether, generateDatapackJsonNether(fixer));
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
File dimTypeEnd = new File(datapacks, "iris/data/minecraft/dimension_type/the_end.json");
if (!dimTypeEnd.exists())
changed = true;
dimTypeEnd.getParentFile().mkdirs();
try {
IO.writeAll(dimTypeEnd, generateDatapackJsonEnd(fixer));
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
return changed;
}
private String generateDatapackJsonOverworld(IDataFixer fixer) {
JSONObject obj = new JSONObject(DP_OVERWORLD_DEFAULT);
obj.put("min_y", dimensionHeight.getMin());
obj.put("height", dimensionHeight.getMax() - dimensionHeight.getMin());
obj.put("logical_height", logicalHeight);
return fixer.fixDimension(obj).toString(4);
}
private String generateDatapackJsonNether(IDataFixer fixer) {
JSONObject obj = new JSONObject(DP_NETHER_DEFAULT);
obj.put("min_y", dimensionHeightNether.getMin());
obj.put("height", dimensionHeightNether.getMax() - dimensionHeightNether.getMin());
obj.put("logical_height", logicalHeightNether);
return fixer.fixDimension(obj).toString(4);
}
private String generateDatapackJsonEnd(IDataFixer fixer) {
JSONObject obj = new JSONObject(DP_END_DEFAULT);
obj.put("min_y", dimensionHeightEnd.getMin());
obj.put("height", dimensionHeightEnd.getMax() - dimensionHeightEnd.getMin());
obj.put("logical_height", logicalHeightEnd);
return fixer.fixDimension(obj).toString(4);
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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.object;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import lombok.Data;
@Data
public class IrisEngineChunkData {
private long chunk;
private KList<IrisEngineSpawnerCooldown> cooldowns = new KList<>();
public void cleanup(Engine engine) {
for (IrisEngineSpawnerCooldown i : getCooldowns().copy()) {
IrisSpawner sp = engine.getData().getSpawnerLoader().load(i.getSpawner());
if (sp == null || i.canSpawn(sp.getMaximumRate())) {
getCooldowns().remove(i);
}
}
}
public boolean isEmpty() {
return cooldowns.isEmpty();
}
}

View File

@@ -20,31 +20,51 @@ package com.volmit.iris.engine.object;
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.collection.KList;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class IrisEngineData extends IrisSpawnerCooldowns {
public class IrisEngineData {
private IrisEngineStatistics statistics = new IrisEngineStatistics();
private KMap<Long, IrisSpawnerCooldowns> chunks = new KMap<>();
private KList<IrisEngineSpawnerCooldown> spawnerCooldowns = new KList<>();
private KList<IrisEngineChunkData> chunks = new KList<>();
private Long seed = null;
public void removeChunk(int x, int z) {
chunks.remove(Cache.key(x, z));
long k = Cache.key(x, z);
chunks.removeWhere((i) -> i.getChunk() == k);
}
public IrisSpawnerCooldowns getChunk(int x, int z) {
return chunks.computeIfAbsent(Cache.key(x, z), k -> new IrisSpawnerCooldowns());
public IrisEngineChunkData getChunk(int x, int z) {
long k = Cache.key(x, z);
for (IrisEngineChunkData i : chunks) {
if (i.getChunk() == k) {
return i;
}
}
IrisEngineChunkData c = new IrisEngineChunkData();
c.setChunk(k);
chunks.add(c);
return c;
}
public void cleanup(Engine engine) {
super.cleanup(engine);
for (IrisEngineSpawnerCooldown i : getSpawnerCooldowns().copy()) {
IrisSpawner sp = engine.getData().getSpawnerLoader().load(i.getSpawner());
chunks.values().removeIf(chunk -> {
chunk.cleanup(engine);
return chunk.isEmpty();
});
if (sp == null || i.canSpawn(sp.getMaximumRate())) {
getSpawnerCooldowns().remove(i);
}
}
for (IrisEngineChunkData i : chunks.copy()) {
i.cleanup(engine);
if (i.isEmpty()) {
getChunks().remove(i);
}
}
}
}

View File

@@ -29,6 +29,7 @@ import com.volmit.iris.util.format.C;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.misc.E;
import com.volmit.iris.util.plugin.Chunks;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
@@ -56,8 +57,6 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import static com.volmit.iris.util.data.registry.Particles.ITEM;
@SuppressWarnings("ALL")
@Accessors(chain = true)
@NoArgsConstructor
@@ -67,6 +66,7 @@ import static com.volmit.iris.util.data.registry.Particles.ITEM;
@Data
@EqualsAndHashCode(callSuper = false)
public class IrisEntity extends IrisRegistrant {
private static final Particle ITEM = E.getOrDefault(Particle.class, "ITEM_CRACK", "ITEM");
@Required
@Desc("The type of entity to spawn. To spawn a mythic mob, set this type to unknown and define mythic type.")
private EntityType type = EntityType.UNKNOWN;

View File

@@ -28,6 +28,7 @@ import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.math.Vector3d;
import com.volmit.iris.util.matter.MatterMarker;
import com.volmit.iris.util.matter.slices.MarkerMatter;
import io.lumine.mythic.bukkit.adapters.BukkitEntity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -37,6 +38,9 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.util.BoundingBox;
@Snippet("entity-spawn")
@Accessors(chain = true)
@@ -112,8 +116,8 @@ public class IrisEntitySpawn implements IRare {
World world = gen.getWorld().realWorld();
if (spawns > 0) {
if (referenceMarker != null && referenceMarker.shouldExhaust()) {
gen.getMantle().getMantle().remove(c.getX(), c.getY() - gen.getWorld().minHeight(), c.getZ(), MatterMarker.class);
if (referenceMarker != null) {
gen.getMantle().getMantle().remove(c.getX(), c.getY(), c.getZ(), MatterMarker.class);
}
for (int id = 0; id < spawns; id++) {

View File

@@ -24,7 +24,6 @@ import com.dfsek.paralithic.eval.parser.Scope;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.IrisExpressionFunction.FunctionContext;
import com.volmit.iris.engine.object.annotations.ArrayType;
import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.Required;
@@ -47,14 +46,12 @@ import lombok.experimental.Accessors;
@Data
@EqualsAndHashCode(callSuper = false)
public class IrisExpression extends IrisRegistrant {
private static final Parser parser = new Parser();
@ArrayType(type = IrisExpressionLoad.class, min = 1)
@Desc("Variables to use in this expression")
private KList<IrisExpressionLoad> variables = new KList<>();
@ArrayType(type = IrisExpressionFunction.class, min = 1)
@Desc("Functions to use in this expression")
private KList<IrisExpressionFunction> functions = new KList<>();
@Required
@Desc("The expression. Inherited variables are x, y and z. Avoid using those variable names.")
private String expression;
@@ -65,7 +62,6 @@ public class IrisExpression extends IrisRegistrant {
private Expression expression() {
return expressionCache.aquire(() -> {
Scope scope = new Scope(); // Create variable scope. This scope can hold both constants and invocation variables.
Parser parser = new Parser();
try {
for (IrisExpressionLoad i : variables) {
@@ -80,12 +76,6 @@ public class IrisExpression extends IrisRegistrant {
Iris.error("Script Variable load error in " + getLoadFile().getPath());
}
for (IrisExpressionFunction f : functions) {
if (!f.isValid()) continue;
f.setData(getLoader());
parser.registerFunction(f.getName(), f);
}
try {
return parser.parse(getExpression(), scope);
} catch (Throwable e) {
@@ -113,7 +103,7 @@ public class IrisExpression extends IrisRegistrant {
g[m++] = z;
g[m] = -1;
return expression().evaluate(new FunctionContext(rng), g);
return expression().evaluate(g);
}
public double evaluate(RNG rng, double x, double y, double z) {
@@ -127,7 +117,7 @@ public class IrisExpression extends IrisRegistrant {
g[m++] = y;
g[m] = z;
return expression().evaluate(new FunctionContext(rng), g);
return expression().evaluate(g);
}
@Override

View File

@@ -1,101 +0,0 @@
package com.volmit.iris.engine.object;
import com.dfsek.paralithic.functions.dynamic.Context;
import com.dfsek.paralithic.functions.dynamic.DynamicFunction;
import com.dfsek.paralithic.node.Statefulness;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.MinNumber;
import com.volmit.iris.engine.object.annotations.Required;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.math.RNG;
import lombok.*;
import lombok.experimental.Accessors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@Snippet("expression-function")
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Desc("Represents a function to use in your expression. Do not set the name to x, y, or z, also don't duplicate names.")
@Data
@EqualsAndHashCode(callSuper = false)
public class IrisExpressionFunction implements DynamicFunction {
@Required
@Desc("The function to assign this value to. Do not set the name to x, y, or z")
private String name;
@Desc("If defined, this variable will use a generator style as it's value")
private IrisGeneratorStyle styleValue = null;
@Desc("If defined, iris will use an internal stream from the engine as it's value")
private IrisEngineStreamType engineStreamValue = null;
@MinNumber(2)
@Desc("Number of arguments for the function")
private int args = 2;
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private transient final KMap<FunctionContext, Provider> cache = new KMap<>();
private transient IrisData data;
public boolean isValid() {
return styleValue != null || engineStreamValue != null;
}
@Override
public int getArgNumber() {
if (engineStreamValue != null) return 2;
return Math.max(args, 2);
}
@NotNull
@Override
public Statefulness statefulness() {
return Statefulness.STATEFUL;
}
@Override
public double eval(double... doubles) {
return 0;
}
@Override
public double eval(@Nullable Context raw, double... args) {
return cache.computeIfAbsent((FunctionContext) raw, context -> {
assert context != null;
if (engineStreamValue != null) {
var stream = engineStreamValue.get(data.getEngine());
return d -> stream.get(d[0], d[1]);
}
if (styleValue != null) {
return styleValue.createNoCache(context.rng, data)::noise;
}
return d -> Double.NaN;
}).eval(args);
}
public record FunctionContext(@NonNull RNG rng) implements Context {
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
FunctionContext that = (FunctionContext) o;
return rng.getSeed() == that.rng.getSeed();
}
@Override
public int hashCode() {
return Long.hashCode(rng.getSeed());
}
}
@FunctionalInterface
private interface Provider {
double eval(double... args);
}
}

View File

@@ -23,11 +23,12 @@ import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.Required;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.stream.ProceduralStream;
import lombok.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Snippet("expression-load")
@@ -56,9 +57,6 @@ public class IrisExpressionLoad {
private transient AtomicCache<ProceduralStream<Double>> streamCache = new AtomicCache<>();
private transient AtomicCache<Double> valueCache = new AtomicCache<>();
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private transient final KMap<Long, CNG> styleCache = new KMap<>();
public double getValue(RNG rng, IrisData data, double x, double z) {
if (engineValue != null) {
@@ -70,8 +68,7 @@ public class IrisExpressionLoad {
}
if (styleValue != null) {
return styleCache.computeIfAbsent(rng.getSeed(), k -> styleValue.createNoCache(new RNG(k), data))
.noise(x, z);
return styleValue.create(rng, data).noise(x, z);
}
return staticValue;
@@ -87,8 +84,7 @@ public class IrisExpressionLoad {
}
if (styleValue != null) {
return styleCache.computeIfAbsent(rng.getSeed(), k -> styleValue.createNoCache(new RNG(k), data))
.noise(x, y, z);
return styleValue.create(rng, data).noise(x, y, z);
}
return staticValue;

View File

@@ -139,14 +139,6 @@ public class IrisJigsawStructure extends IrisRegistrant {
loadPiece(i, pools, pieces);
}
if (pieces.isEmpty()) {
int max = 0;
for (String i : getPieces()) {
max = Math.max(max, getLoader().getJigsawPieceLoader().load(i).getMax2dDimension());
}
return max;
}
int avg = 0;
for (String i : pieces) {

View File

@@ -19,8 +19,13 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.engine.object.annotations.ArrayType;
import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.MaxNumber;
import com.volmit.iris.engine.object.annotations.MinNumber;
import com.volmit.iris.engine.object.annotations.RegistryListResource;
import com.volmit.iris.engine.object.annotations.Required;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.documentation.ChunkCoordinates;
@@ -49,7 +54,6 @@ public class IrisJigsawStructurePlacement implements IRare {
private int rarity = 100;
@Required
@DependsOn({"spacing", "separation"})
@Desc("The salt to use when generating the structure (to differentiate structures)")
@MinNumber(Long.MIN_VALUE)
@MaxNumber(Long.MAX_VALUE)
@@ -57,26 +61,16 @@ public class IrisJigsawStructurePlacement implements IRare {
@Required
@MinNumber(0)
@DependsOn({"salt", "separation"})
@Desc("Average distance in chunks between two neighboring generation attempts")
private int spacing = -1;
@Required
@MinNumber(0)
@DependsOn({"salt", "spacing"})
@Desc("Minimum distance in chunks between two neighboring generation attempts\nThe maximum distance of two neighboring generation attempts is 2*spacing - separation")
private int separation = -1;
@Desc("The method used to spread the structure")
private SpreadType spreadType = SpreadType.LINEAR;
@DependsOn({"spreadType"})
@Desc("The noise style to use when spreadType is set to 'NOISE'\nThis ignores the spacing and separation parameters")
private IrisGeneratorStyle style = new IrisGeneratorStyle();
@DependsOn({"spreadType", "style"})
@Desc("Threshold for noise style")
private double threshold = 0.5;
private SpreadType spreadType = SpreadType.TRIANGULAR;
@ArrayType(type = IrisJigsawMinDistance.class)
@Desc("List of minimum distances to check for")
@@ -95,29 +89,20 @@ public class IrisJigsawStructurePlacement implements IRare {
}
private void calculateMissing(double divisor, long seed) {
if (salt != 0 && separation > 0 && spacing > 0)
return;
seed *= (long) structure.hashCode() * rarity;
seed = seed + hashCode();
if (salt == 0) {
salt = new RNG(seed).l(Integer.MIN_VALUE, Integer.MAX_VALUE);
salt = new RNG(seed).nextLong(Integer.MIN_VALUE, Integer.MAX_VALUE);
}
if (separation == -1 || spacing == -1) {
separation = (int) Math.round(rarity / divisor);
spacing = new RNG(seed).i(separation, separation * 2);
spacing = new RNG(seed).nextInt(separation, separation * 2);
}
}
@ChunkCoordinates
public boolean shouldPlace(IrisData data, double divisor, long seed, int x, int z) {
public boolean shouldPlace(double divisor, long seed, int x, int z) {
calculateMissing(divisor, seed);
if (spreadType != SpreadType.NOISE)
return shouldPlaceSpread(seed, x, z);
return style.create(new RNG(seed + salt), data).noise(x, z) > threshold;
}
private boolean shouldPlaceSpread(long seed, int x, int z) {
if (separation > spacing) {
separation = spacing;
Iris.warn("JigsawStructurePlacement: separation must be less than or equal to spacing");
@@ -138,9 +123,7 @@ public class IrisJigsawStructurePlacement implements IRare {
@Desc("Linear spread")
LINEAR(RNG::i),
@Desc("Triangular spread")
TRIANGULAR((rng, bound) -> (rng.i(bound) + rng.i(bound)) / 2),
@Desc("Noise based spread\nThis ignores the spacing and separation parameters")
NOISE((rng, bound) -> 0);
TRIANGULAR((rng, bound) -> (rng.i(bound) + rng.i(bound)) / 2);
private final SpreadMethod method;
SpreadType(SpreadMethod method) {

View File

@@ -51,10 +51,10 @@ public class IrisMarker extends IrisRegistrant {
private boolean emptyAbove = true;
@Desc("If this marker is used, what is the chance it removes itself. For example 25% (0.25) would mean that on average 4 uses will remove a specific marker. Set this below 0 (-1) to never exhaust & set this to 1 or higher to always exhaust on first use.")
private double exhaustionChance = 0;
private double exhaustionChance = 0.33;
public boolean shouldExhaust() {
return exhaustionChance > RNG.r.nextDouble();
return RNG.r.chance(exhaustionChance);
}
@Override

View File

@@ -29,7 +29,7 @@ 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.data.B;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.data.IrisBlockData;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.interpolation.IrisInterpolation;
import com.volmit.iris.util.json.JSONObject;
@@ -53,6 +53,8 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
import org.bukkit.block.data.Waterlogged;
@@ -941,7 +943,7 @@ public class IrisObject extends IrisRegistrant {
if (j.isExact() ? k.matches(data) : k.getMaterial().equals(data.getMaterial())) {
BlockData newData = j.getReplace(rng, i.getX() + x, i.getY() + y, i.getZ() + z, rdata).clone();
if (newData.getMaterial() == data.getMaterial() && !(newData instanceof IrisCustomData || data instanceof IrisCustomData))
if (newData.getMaterial() == data.getMaterial() && !(newData instanceof IrisBlockData || data instanceof IrisBlockData))
data = data.merge(newData);
else
data = newData;
@@ -1010,9 +1012,8 @@ public class IrisObject extends IrisRegistrant {
}
boolean wouldReplace = B.isSolid(placer.get(xx, yy, zz)) && B.isVineBlock(data);
boolean place = !data.getMaterial().equals(Material.AIR) && !data.getMaterial().equals(Material.CAVE_AIR) && !wouldReplace;
if (data instanceof IrisCustomData || place) {
if (!data.getMaterial().equals(Material.AIR) && !data.getMaterial().equals(Material.CAVE_AIR) && !wouldReplace) {
placer.set(xx, yy, zz, data);
if (tile != null) {
placer.setTile(xx, yy, zz, tile);

View File

@@ -50,10 +50,4 @@ public class IrisRange {
public boolean contains(int v) {
return v >= min && v <= max;
}
public IrisRange merge(IrisRange other) {
min = Math.min(min, other.min);
max = Math.max(max, other.max);
return this;
}
}

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