Compare commits

..

99 Commits

Author SHA1 Message Date
Aidan Aeternum 28c4941941 v+ 2026-06-12 21:10:21 -04:00
Aidan Aeternum d452f10fd9 Merge pull request #1241 from VolmitSoftware/dev
3.9.2
2026-06-12 21:09:46 -04:00
Julian Krings e7d89cadd8 fix compile 2026-04-12 11:58:33 +02:00
Julian Krings cddd6b16d6 add CraftEngine data provider (#1227) 2026-04-12 11:55:36 +02:00
Julian Krings b2ac4e7f93 fix invalid json for ultrawarm dimensions on 1.21.11 2026-04-12 11:55:36 +02:00
Julian Krings c2bb32459f fix ambient particles breaking datapack generation on 1.21.11 2026-04-12 11:55:35 +02:00
Brian Neumann-Fopiano 41888e33f6 Fixing fallbacks for macos Folk
Compiles fine, just stricter defaults
2026-02-11 00:01:23 -05:00
Aidan Aeternum 25fa2553e5 v+ 2026-02-02 03:28:49 -05:00
Aidan Aeternum 86f78baecf Merge pull request #1236 from VolmitSoftware/dev
3.9.1
2026-02-02 03:28:30 -05:00
Julian Krings c31158578f fix datapack generation on 1.21.11 2026-01-29 16:40:33 +01:00
Aidan Aeternum 4e86d7d634 v+ 2026-01-27 20:09:25 -05:00
Aidan Aeternum 62fe29cf34 Merge pull request #1235 from VolmitSoftware/dev
3.9.0
2026-01-27 20:08:36 -05:00
Julian Krings a3bcea4f3e increase memory assumption per region 2026-01-26 21:37:29 +01:00
Julian Krings 7befce1084 initial 1.21.11 support 2026-01-23 11:46:15 +01:00
Aidan Aeternum 351a1aa495 v+ 2026-01-15 02:50:30 -05:00
Aidan Aeternum d2cb8a9032 Merge pull request #1234 from VolmitSoftware/dev
3.8.2
2026-01-15 02:50:03 -05:00
Julian Krings 509715087c fix typo 2026-01-13 15:11:21 +01:00
Julian Krings 12527ecdd8 improve cachedChunks lookup in the mantle writer 2026-01-05 14:58:58 +01:00
Julian Krings 01a2999e03 decrease locking for mantle generation 2026-01-05 14:58:09 +01:00
Julian Krings dbafe84fa5 make context dereference method fail-safe 2026-01-02 14:12:44 +01:00
Julian Krings 40b020fc5d improve matter generator once again 2026-01-02 14:10:35 +01:00
Julian Krings d15f7d62d1 cleanup async world ticker 2026-01-02 14:10:35 +01:00
Julian Krings f9c062c794 improve mantle cleanup to prevent thread starvation 2026-01-02 14:10:34 +01:00
Aidan Aeternum 6a89b8bd06 v+ 2026-01-02 06:17:00 -05:00
Aidan Aeternum 194fcb2ea7 Merge pull request #1232 from VolmitSoftware/dev
3.8.1
2026-01-02 06:16:28 -05:00
Julian Krings 3b68f855b2 get back some speed by loading four mantle regions into cache at once 2025-12-31 13:38:42 +01:00
Julian Krings cfbf68d37a add check for headless environments to the edit command 2025-12-31 13:01:18 +01:00
Julian Krings 9999f3e429 fix chunk artifacts 2025-12-31 13:00:45 +01:00
Julian Krings 97fa0562a4 fix custom block data 2025-12-23 22:51:41 +01:00
Julian Krings 3abe671851 suppress unchecked cast warning for the ChunkedDataCache 2025-12-18 18:53:59 +01:00
Julian Krings e164a3bb5c Merge branch 'feat/safeguard' into dev
# Conflicts:
#	build.gradle.kts
#	core/src/main/java/com/volmit/iris/Iris.java
2025-12-18 18:44:36 +01:00
Julian Krings 4dfb4441e4 fix buildscript 2025-12-18 14:23:51 +01:00
Julian Krings e686f67453 add command to fix offsets of all objects 2025-12-18 14:23:35 +01:00
Julian Krings e2eed4812a ignore empty objects for shrinkwrap 2025-12-18 14:22:40 +01:00
Julian Krings 1737833bfe fix legacy object parsing 2025-12-18 14:22:21 +01:00
piexel a4c5f46c37 Fix /iris object convert for .schem files with 128+ block types 2025-12-18 11:25:38 +01:00
piexel 025fa833c4 Fix Grass won't place on moss blocks 2025-12-18 11:21:16 +01:00
Julian Krings 98cc82cc3d Fix jigsaw editor bricking when opening a piece a missing object 2025-12-18 11:13:43 +01:00
Julian Krings 298365f588 fix studio open not working when not in spectator 2025-12-18 11:06:09 +01:00
Julian Krings 90e5720e2e improve buildscript 2025-12-18 11:05:28 +01:00
Julian Krings 7cd43791f4 fix offset with shrinkwrap 2025-12-18 11:05:14 +01:00
Julian Krings a251d192ad fix loot for objects underground 2025-12-18 11:00:04 +01:00
Julian Krings abfff28f43 fix redstone not rotating 2025-12-18 10:59:57 +01:00
Julian Krings fbdae4c928 improve overwriting of the regenerated chunks 2025-12-18 10:59:32 +01:00
Aidan Aeternum 93ca26e368 v+ 2025-12-17 12:12:25 -05:00
Aidan Aeternum 8c1db1c223 Merge pull request #1231 from VolmitSoftware/dev
3.8.0
2025-12-17 12:11:28 -05:00
Julian Krings 123708601f improve pregen cache 2025-12-01 16:01:54 +01:00
Julian Krings b5ab4968ba fix compile 2025-11-30 15:36:36 +01:00
Julian Krings 93ae6037bd whoops forgot to disable craftbukkit relocations on <=1.20.4 2025-11-29 11:49:15 +01:00
Julian Krings dd8e487a3b fix tile entity serialization on paper 1.21.6+ servers 2025-11-29 11:13:30 +01:00
Julian Krings d3c8377a12 allow switching between buildtools and userdev 2025-11-29 11:12:16 +01:00
Julian Krings 84f3687c0c update compat for iron bars 2025-11-27 16:09:31 +01:00
Julian Krings ed1e1f1181 whoops forgot those providers 2025-11-26 21:33:03 +01:00
Julian Krings 528c97f367 replace IrisCustomData class with a proxy to keep full access to the base BlockData 2025-11-26 21:32:13 +01:00
Julian Krings f7a459f3bc initial 1.21.9/10 bindings 2025-11-26 21:25:05 +01:00
Julian Krings cd179b4321 reintroduce native threads for the updater as a setting and cleanup 2025-11-26 20:55:48 +01:00
Julian Krings 6373dbb1b8 potential optimization for the noise cache 2025-11-21 16:21:54 +01:00
Julian Krings 0b0797f876 minor optimization for chunk updater 2025-11-21 16:21:31 +01:00
Julian Krings 446acefc91 minor optimization for the mantle writer 2025-11-21 16:21:02 +01:00
Julian Krings 7a44e555b2 rename noise cache size setting and decrease default value 2025-11-21 16:20:32 +01:00
Julian Krings 57d4c2935c add cache sizes to engine status 2025-11-21 16:16:15 +01:00
Julian Krings 234fb1b0c4 also include parent class for schema generation 2025-11-08 00:58:12 +01:00
Julian Krings 0882b5acc4 use parent shared classloader to reflect intelij behavior 2025-11-06 22:32:28 +01:00
Julian Krings 18da26e1fa minor performance improvement 2025-11-06 22:27:14 +01:00
Julian Krings 65aa95f2a5 fix wrong radius when marking mantle chunks as completed 2025-11-06 22:25:37 +01:00
Julian Krings 5330ddc4ec fix deleting object ids with mantle cleanup 2025-11-06 22:20:30 +01:00
Julian Krings a7fdd37569 fix studio loot command 2025-11-06 22:16:27 +01:00
Julian Krings a226fea9e2 fix regen command 2025-11-06 16:22:02 +01:00
Julian Krings 8cea165a29 even more performance improvements 2025-11-06 15:29:03 +01:00
Julian Krings 1d7cba184c fix linear palette not growing correctly 2025-11-06 14:41:39 +01:00
Julian Krings 4ca7ea3911 minor speed improvements 2025-11-01 22:36:25 +01:00
Julian Krings ea5919def2 stop writing first access each time the engine is opened 2025-10-30 16:40:35 +01:00
Julian Krings be35e49302 use coroutines for mantle generation 2025-10-30 16:40:08 +01:00
Julian Krings aadd03990a optimize data palette for mantle slices 2025-10-27 19:53:47 +01:00
Julian Krings 38a579453d optimize noise cache 2025-10-26 13:49:03 +01:00
Julian Krings 0bf5da2ca1 optimize object maps 2025-10-26 13:48:11 +01:00
Julian Krings 317848692e improve regen speed 2025-10-06 14:12:01 +02:00
Julian Krings 22118de9e9 fix object smart bore 2025-10-06 14:10:37 +02:00
Julian Krings d7039d120b fix place commands causing unwanted block updates 2025-10-06 13:00:00 +02:00
Julian Krings 979ee4e7d8 switch hashing algorithm for objects once more 2025-10-05 21:46:12 +02:00
Julian Krings f68d45bd30 dynamically resolve snippet classes 2025-10-05 00:21:38 +02:00
Julian Krings b86d7f303e restructure the shared kts classloader to be more consistent 2025-10-05 00:20:55 +02:00
Julian Krings c573843314 fix kts dependency resolver 2025-10-05 00:17:57 +02:00
Julian Krings 51a7bef18e whoops forgot escaping the path 2025-10-04 17:19:11 +02:00
Julian Krings 0e237aa1ad fix generated build.gradle.kts on external dives on windows 2025-10-04 13:41:48 +02:00
Julian Krings b46c413f6b make gradle setup print to console on failure 2025-10-04 13:40:47 +02:00
Julian Krings f3ef1ca2ae fix typo in preprocessors description 2025-10-04 13:40:07 +02:00
Julian Krings 703e61dd54 fix preprocessors not applying reliably 2025-10-04 13:39:33 +02:00
Aidan Aeternum e1ec6b7827 v+ 2025-10-03 16:08:05 -04:00
Aidan Aeternum f94292fdac Merge pull request #1228 from VolmitSoftware/dev
3.7.11
2025-10-03 16:07:47 -04:00
Julian Krings 7d153bf985 optimize objects to avoid hash collision 2025-10-02 15:25:37 +02:00
Julian Krings f85f15ed02 fix converter for complex schematic 2025-10-02 11:43:16 +02:00
Julian Krings 867686eced fix deserialisation of unversioned mantle plates 2025-10-01 12:57:38 +02:00
Julian Krings 526efd3ae1 restructure safeguard 2025-09-29 15:45:56 +02:00
Aidan Aeternum 9d796bd2a0 v+ 2025-09-27 07:34:58 -04:00
Aidan Aeternum 1a9a5d80ad Merge pull request #1223 from VolmitSoftware/dev
3.7.10
2025-09-27 07:34:31 -04:00
Julian Krings c5c7f9bdc5 fix minor issue with nms tools 2025-09-22 18:10:34 +02:00
Julian Krings 01a421b732 add file extensions to the script property descriptions 2025-09-21 22:35:34 +02:00
Julian Krings ae92bcf194 add kts hook for chunk updates 2025-09-21 22:30:48 +02:00
181 changed files with 8233 additions and 3453 deletions
+44 -53
View File
@@ -1,8 +1,6 @@
import com.volmit.nmstools.NMSToolsExtension
import com.volmit.nmstools.NMSToolsPlugin
import de.undercouch.gradle.tasks.download.Download
import org.gradle.jvm.toolchain.JavaLanguageVersion
import xyz.jpenilla.runpaper.task.RunServer
import xyz.jpenilla.runtask.service.DownloadsAPIService
import kotlin.system.exitProcess
/*
@@ -25,19 +23,18 @@ import kotlin.system.exitProcess
buildscript {
repositories.maven("https://jitpack.io")
dependencies.classpath("com.github.VolmitSoftware:NMSTools:c5cbc46ce6")
dependencies.classpath("com.github.VolmitSoftware:NMSTools:c88961416f")
}
plugins {
java
`java-library`
alias(libs.plugins.shadow)
alias(libs.plugins.download)
alias(libs.plugins.runPaper)
}
group = "com.volmit"
version = "3.7.2-1.20.1-1.21.8"
version = "3.9.2-1.20.1-1.21.11"
apply<ApiGenerator>()
@@ -54,50 +51,46 @@ registerCustomOutputTask("PixelFury", "C://Users/repix/workplace/Iris/1.21.3 - D
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("PsychoLT", "/Users/brianfopiano/Developer/RemoteGit/[Minecraft Server]/plugins")
registerCustomOutputTaskUnix("PixelMac", "/Users/test/Desktop/mcserver/plugins")
registerCustomOutputTaskUnix("CrazyDev22LT", "/home/julian/Desktop/server/plugins")
// ==============================================================
val serverMinHeap = "2G"
val serverMaxHeap = "8G"
val serverMinHeap = "10G"
val serverMaxHeap = "10G"
val additionalFlags = "-XX:+AlwaysPreTouch"
//Valid values are: none, truecolor, indexed256, indexed16, indexed8
val color = "truecolor"
val errorReporting = findProperty("errorReporting") as Boolean? ?: false
val errorReporting = "true" == findProperty("errorReporting")
val nmsBindings = mapOf(
"v1_21_R5" to "1.21.7-R0.1-SNAPSHOT",
"v1_21_R4" to "1.21.5-R0.1-SNAPSHOT",
"v1_21_R3" to "1.21.4-R0.1-SNAPSHOT",
"v1_21_R2" to "1.21.3-R0.1-SNAPSHOT",
"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",
"v1_21_R7" to "1.21.11-R0.1-SNAPSHOT",
"v1_21_R6" to "1.21.10-R0.1-SNAPSHOT",
"v1_21_R5" to "1.21.8-R0.1-SNAPSHOT",
"v1_21_R4" to "1.21.5-R0.1-SNAPSHOT",
"v1_21_R3" to "1.21.4-R0.1-SNAPSHOT",
"v1_21_R2" to "1.21.3-R0.1-SNAPSHOT",
"v1_21_R1" to "1.21.1-R0.1-SNAPSHOT",
"v1_20_R4" to "1.20.6-R0.1-SNAPSHOT",
"v1_20_R3" to "1.20.4-R0.1-SNAPSHOT",
"v1_20_R2" to "1.20.2-R0.1-SNAPSHOT",
"v1_20_R1" to "1.20.1-R0.1-SNAPSHOT",
)
val jvmVersion = mapOf<String, Int>()
nmsBindings.forEach { key, value ->
nmsBindings.forEach { (key, value) ->
project(":nms:$key") {
apply<JavaPlugin>()
apply<NMSToolsPlugin>()
repositories {
maven("https://libraries.minecraft.net")
}
extensions.configure(NMSToolsExtension::class) {
nmsBinding {
jvm = jvmVersion.getOrDefault(key, 21)
version = value
type = NMSBinding.Type.DIRECT
}
dependencies {
compileOnly(project(":core"))
compileOnly(rootProject.libs.annotations)
compileOnly(rootProject.libs.byteBuddy.core)
compileOnly(rootProject.libs.platformUtils) {
isTransitive = false
}
}
}
@@ -114,33 +107,25 @@ nmsBindings.forEach { key, value ->
systemProperty("com.mojang.eula.agree", true)
systemProperty("iris.suppressReporting", !errorReporting)
jvmArgs("-javaagent:${project(":core:agent").tasks.jar.flatMap { it.archiveFile }.get().asFile.absolutePath}")
jvmArgs(additionalFlags.split(' '))
}
}
tasks.register<RunServer>("runFolia-$key") {
group = "servers"
downloadsApiService = DownloadsAPIService.folia(project)
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.suppressReporting", !errorReporting)
jvmArgs("-javaagent:${project(":core:agent").tasks.jar.flatMap { it.archiveFile }.get().asFile.absolutePath}")
val included: Configuration by configurations.creating
val jarJar: Configuration by configurations.creating
dependencies {
for (key in nmsBindings.keys) {
included(project(":nms:$key", "reobf"))
}
included(project(":core", "shadow"))
jarJar(project(":core:agent"))
}
tasks {
jar {
inputs.files(included)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
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) })
from(project(":core:agent").tasks.jar.flatMap { it.archiveFile })
from(jarJar, provider { included.resolve().map(::zipTree) })
archiveFileName.set("Iris-${project.version}.jar")
}
@@ -203,6 +188,12 @@ configurations.configureEach {
allprojects {
apply<JavaPlugin>()
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
repositories {
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
@@ -215,7 +206,7 @@ allprojects {
maven("https://mvn.lumine.io/repository/maven-public/") // mythic
maven("https://nexus.phoenixdevt.fr/repository/maven-public/") //MMOItems
maven("https://repo.onarandombox.com/content/groups/public/") //Multiverse Core
maven("https://repo.thenextlvl.net/releases") //Worlds
maven("https://repo.momirealms.net/releases/") //CraftEngine
}
dependencies {
@@ -251,14 +242,14 @@ allprojects {
}
}
if (JavaVersion.current().toString() != "21") {
if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_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("You must run gradle on Java 21 or newer. 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("1. Configure the project for Java 21 toolchain")
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")
+23 -2
View File
@@ -1,11 +1,32 @@
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
kotlin("jvm") version "2.0.20"
kotlin("jvm") version embeddedKotlinVersion
}
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
kotlin {
jvmToolchain(21)
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
}
}
repositories {
mavenCentral()
gradlePluginPortal()
maven("https://jitpack.io")
}
dependencies {
implementation("org.ow2.asm:asm:9.8")
}
implementation("com.github.VolmitSoftware:NMSTools:c88961416f")
implementation("io.papermc.paperweight:paperweight-userdev:2.0.0-beta.18")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
}
+182
View File
@@ -0,0 +1,182 @@
import NMSBinding.Type
import com.volmit.nmstools.NMSToolsExtension
import com.volmit.nmstools.NMSToolsPlugin
import io.papermc.paperweight.userdev.PaperweightUser
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
import io.papermc.paperweight.userdev.PaperweightUserExtension
import io.papermc.paperweight.userdev.attribute.Obfuscation
import io.papermc.paperweight.util.constants.REOBF_CONFIG
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.gradle.api.*
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.LibraryElements
import org.gradle.api.attributes.Usage
import org.gradle.api.model.ObjectFactory
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.tasks.TaskAction
import org.gradle.internal.extensions.core.extra
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.jvm.toolchain.JavaToolchainService
import org.gradle.work.DisableCachingByDefault
import java.io.RandomAccessFile
import javax.inject.Inject
class NMSBinding : Plugin<Project> {
override fun apply(target: Project): Unit = with(target) {
val config = extra["nms"] as? Config ?: throw GradleException("No NMS binding configuration found")
val jvm = config.jvm
val type = config.type
if (type == Type.USER_DEV) {
plugins.apply(PaperweightUser::class.java)
dependencies.extensions.findByType(PaperweightUserDependenciesExtension::class.java)
?.paperDevBundle(config.version)
val java = extensions.findByType(JavaPluginExtension::class.java) ?: throw GradleException("Java plugin not found")
java.toolchain.languageVersion.set(JavaLanguageVersion.of(jvm))
val javaToolchains = project.extensions.getByType(JavaToolchainService::class.java) ?: throw GradleException("Java toolchain service not found")
extensions.configure(PaperweightUserExtension::class.java) {
it.javaLauncher.set(javaToolchains.launcherFor(java.toolchain))
}
} else {
extra["nmsTools.useBuildTools"] = type == Type.BUILD_TOOLS
plugins.apply(NMSToolsPlugin::class.java)
extensions.configure(NMSToolsExtension::class.java) {
it.jvm.set(jvm)
it.version.set(config.version)
}
configurations.register(REOBF_CONFIG) { conf ->
conf.isCanBeConsumed = true
conf.isCanBeResolved = false
conf.attributes {
it.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
it.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
it.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR))
it.attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL))
it.attribute(Obfuscation.OBFUSCATION_ATTRIBUTE, objects.named(Obfuscation.OBFUSCATED))
}
conf.outgoing.artifact(tasks.named("remap"))
}
}
val (major, minor) = config.version.parseVersion()
if (major <= 20 && minor <= 4) return@with
tasks.register("convert", ConversionTask::class.java, type)
tasks.named("compileJava") { it.dependsOn("convert") }
rootProject.tasks.named("prepareKotlinBuildScriptModel") { it.dependsOn("$path:convert") }
}
@DisableCachingByDefault
abstract class ConversionTask @Inject constructor(type: Type) : DefaultTask() {
private val pattern: Regex
private val replacement: String
init {
group = "nms"
inputs.property("type", type)
val java = project.extensions.findByType(JavaPluginExtension::class.java) ?: throw GradleException("Java plugin not found")
val source = java.sourceSets.named("main").map { it.allJava }
inputs.files(source)
outputs.files(source)
if (type == Type.USER_DEV) {
pattern = "org\\.bukkit\\.craftbukkit\\.${project.name}".toRegex()
replacement = "org.bukkit.craftbukkit"
} else {
pattern = "org\\.bukkit\\.craftbukkit\\.(?!${project.name})".toRegex()
replacement = "org.bukkit.craftbukkit.${project.name}."
}
}
@TaskAction
fun process() {
val dispatcher = Dispatchers.IO.limitedParallelism(16)
runBlocking {
for (file in inputs.files) {
if (file.extension !in listOf("java"))
continue
launch(dispatcher) {
val output = ArrayList<String>()
var changed = false
file.bufferedReader().use {
for (line in it.lines()) {
if (line.startsWith("package") || line.isBlank()) {
output += line
continue
}
if (!line.startsWith("import")) {
if (!changed) return@launch
else {
output += line
continue
}
}
if (!line.contains(pattern)) {
output += line
continue
}
output += line.replace(pattern, replacement)
changed = true
}
}
if (changed) {
RandomAccessFile(file, "r").use { raf ->
val bytes = ByteArray(NEW_LINE_BYTES.size)
raf.seek(raf.length() - bytes.size)
raf.readFully(bytes)
if (bytes.contentEquals(NEW_LINE_BYTES))
output += ""
}
file.writer().use {
val iterator = output.iterator()
while (iterator.hasNext()) {
it.append(iterator.next())
if (iterator.hasNext())
it.append(NEW_LINE)
}
}
}
}
}
}
}
}
enum class Type {
USER_DEV,
BUILD_TOOLS,
DIRECT,
}
}
private val NEW_LINE = System.lineSeparator()
private val NEW_LINE_BYTES = NEW_LINE.encodeToByteArray()
private fun String.parseVersion() = substringBefore('-').split(".").let {
it[1].toInt() to it[2].toInt()
}
class Config(
var jvm: Int = 21,
var type: Type = Type.DIRECT
) {
lateinit var version: String
}
fun Project.nmsBinding(action: Config.() -> Unit) {
extra["nms"] = Config().apply(action)
plugins.apply(NMSBinding::class.java)
}
private inline fun <reified T : Named> ObjectFactory.named(name: String): T = named(T::class.java, name)
+34 -19
View File
@@ -1,6 +1,8 @@
import io.github.slimjar.func.slimjarHelper
import io.github.slimjar.resolver.data.Mirror
import org.ajoberstar.grgit.Grgit
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import java.net.URI
/*
@@ -67,21 +69,19 @@ dependencies {
isTransitive = false
}
compileOnly(libs.multiverseCore)
compileOnly(libs.worlds)
compileOnly(libs.craftengine.core)
compileOnly(libs.craftengine.bukkit)
//compileOnly(libs.sparrowNbt)
// Shaded
implementation(slimjarHelper("spigot"))
implementation(rootProject.libs.platformUtils) {
isTransitive = false
}
// Dynamically Loaded
slim(libs.paralithic)
slim(libs.paperlib)
slim(libs.adventure.api)
slim(libs.adventure.minimessage)
slim(libs.adventure.platform)
slim(libs.adventure.gson)
slim(libs.adventure.legacy)
slim(libs.bstats)
slim(libs.sentry)
@@ -113,19 +113,24 @@ dependencies {
slim(libs.mavenCore)
}
}
constraints {
slim(libs.gson)
compileOnly(libs.gson)
}
}
java {
disableAutoTargetJvm()
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
kotlin {
jvmToolchain(21)
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
}
}
sentry {
url = "http://sentry.volmit.com:8080/"
url = "http://sentry.volmit.com:8080"
autoInstallation.enabled = false
includeSourceContext = true
@@ -141,7 +146,8 @@ slimJar {
))
relocate("com.dfsek.paralithic", "$lib.paralithic")
relocate("net.kyori.audience", "$lib.audience")
relocate("io.papermc.lib", "$lib.paper")
relocate("net.kyori", "$lib.kyori")
relocate("org.bstats", "$lib.metrics")
relocate("io.sentry", "$lib.sentry")
relocate("org.apache.maven", "$lib.maven")
@@ -151,6 +157,7 @@ slimJar {
relocate("com.google.inject", "$lib.guice")
relocate("org.dom4j", "$lib.dom4j")
relocate("org.jaxen", "$lib.jaxen")
relocate("com.github.benmanes.caffeine", "$lib.caffeine")
}
tasks {
@@ -183,20 +190,28 @@ tasks {
relocate("io.github.slimjar", "$lib.slimjar")
exclude("modules/loader-agent.isolated-jar")
}
sentryCollectSourcesJava {
dependsOn(generateTemplates)
}
}
val templateSource = file("src/main/templates")
val templateDest = layout.buildDirectory.dir("generated/sources/templates")
val templateDest = layout.buildDirectory.dir("generated/sources/templates")!!
val generateTemplates = tasks.register<Copy>("generateTemplates") {
inputs.properties(
"environment" to if (project.hasProperty("release")) "production" else "development",
"environment" to when {
project.hasProperty("release") -> "production"
project.hasProperty("argghh") -> "Argghh!"
else -> "development"
},
"commit" to provider {
val res = runCatching { project.extensions.getByType<Grgit>().head().id }
res.getOrDefault("")
.takeIf { it.length == 40 } ?: {
logger.error("Git commit hash not found", res.exceptionOrNull())
.takeIf { it.length == 40 } ?: run {
this.logger.error("Git commit hash not found", res.exceptionOrNull())
"unknown"
}()
}
},
)
@@ -216,4 +231,4 @@ rootProject.tasks.named("prepareKotlinBuildScriptModel") {
sourceSets.main {
java.srcDir(generateTemplates.map { it.outputs })
}
}
+18 -151
View File
@@ -28,7 +28,6 @@ import com.volmit.iris.core.link.IrisPapiExpansion;
import com.volmit.iris.core.link.MultiverseCoreLink;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import com.volmit.iris.core.pregenerator.LazyPregenerator;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.tools.IrisToolbelt;
@@ -43,7 +42,6 @@ import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.exceptions.IrisException;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.function.NastyRunnable;
import com.volmit.iris.util.io.FileWatcher;
import com.volmit.iris.util.io.IO;
@@ -53,17 +51,15 @@ import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.misc.Bindings;
import com.volmit.iris.util.misc.SlimJar;
import com.volmit.iris.util.misc.getHardware;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitPlugin;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.plugin.chunk.ChunkTickets;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Queue;
import com.volmit.iris.util.scheduling.ShurikenQueue;
import lombok.NonNull;
import de.crazydev22.platformutils.Platform;
import de.crazydev22.platformutils.PlatformUtils;
import org.bukkit.*;
import org.bukkit.block.data.BlockData;
import org.bukkit.command.Command;
@@ -81,14 +77,10 @@ import java.io.*;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware;
@SuppressWarnings("CanBeFinal")
public class Iris extends VolmitPlugin implements Listener {
private static final Queue<Runnable> syncJobs = new ShurikenQueue<>();
@@ -98,7 +90,7 @@ public class Iris extends VolmitPlugin implements Listener {
public static MultiverseCoreLink linkMultiverseCore;
public static IrisCompat compat;
public static FileWatcher configWatcher;
public static Platform platform;
public static ChunkTickets tickets;
private static VolmitSender sender;
private static Thread shutdownHook;
@@ -310,21 +302,19 @@ public class Iris extends VolmitPlugin implements Listener {
public static void info(String format, Object... args) {
msg(C.WHITE + String.format(format, args));
}
public static void safeguard(String format, Object... args) {
msg(C.RESET + String.format(format, args));
}
@SuppressWarnings("deprecation")
public static void later(NastyRunnable object) {
try {
platform.getAsyncScheduler().runDelayed(task -> {
Bukkit.getScheduler().scheduleAsyncDelayedTask(instance, () ->
{
try {
object.run();
} catch (Throwable e) {
e.printStackTrace();
Iris.reportError(e);
}
}, RNG.r.i(5, 60), TimeUnit.SECONDS);
}, RNG.r.i(100, 1200));
} catch (IllegalPluginAccessException ignored) {
}
@@ -421,6 +411,7 @@ public class Iris extends VolmitPlugin implements Listener {
pw.println();
pw.println();
}
pw.println("[%%__USER__%%,%%__RESOURCE__%%,%%__PRODUCT__%%,%%__BUILTBYBIT__%%]");
pw.close();
Iris.info("DUMPED! See " + fi.getAbsolutePath());
@@ -444,23 +435,22 @@ public class Iris extends VolmitPlugin implements Listener {
private void enable() {
services = new KMap<>();
platform = PlatformUtils.createPlatform(this);
setupAudience();
Bindings.setupSentry();
initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class<? extends IrisService>) i.getClass(), (IrisService) i));
IO.delete(new File("iris"));
compat = IrisCompat.configured(getDataFile("compat.json"));
ServerConfigurator.configure();
IrisSafeguard.IrisSafeguardSystem();
IrisSafeguard.execute();
getSender().setTag(getTag());
IrisSafeguard.splash(true);
IrisSafeguard.splash();
tickets = new ChunkTickets();
linkMultiverseCore = new MultiverseCoreLink();
configWatcher = new FileWatcher(getDataFile("settings.json"));
services.values().forEach(IrisService::onEnable);
services.values().forEach(this::registerListener);
addShutdownHook();
J.s(() -> {
//J.a(IrisSafeguard::suggestPaper); //TODO reimplement this
J.a(() -> IO.delete(getTemp()));
J.a(LazyPregenerator::loadLazyGenerators, 100);
J.a(this::bstats);
@@ -468,7 +458,6 @@ public class Iris extends VolmitPlugin implements Listener {
J.sr(this::tickQueue, 0);
J.s(this::setupPapi);
J.a(ServerConfigurator::configure, 20);
IrisSafeguard.splash(false);
autoStartStudio();
checkForBukkitWorlds(s -> true);
@@ -510,13 +499,8 @@ public class Iris extends VolmitPlugin implements Listener {
WorldCreator c = new WorldCreator(s)
.generator(gen)
.environment(dim.getEnvironment());
INMS.get().createWorldAsync(c)
.thenAccept(w -> Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"))
.exceptionally(e -> {
Iris.error("Failed to load world " + s + "!");
e.printStackTrace();
return null;
});
INMS.get().createWorld(c);
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
} catch (Throwable e) {
Iris.error("Failed to load world " + s + "!");
e.printStackTrace();
@@ -535,9 +519,10 @@ public class Iris extends VolmitPlugin implements Listener {
Player r = new KList<>(getServer().getOnlinePlayers()).getRandom();
Iris.service(StudioSVC.class).open(r != null ? new VolmitSender(r) : getSender(), 1337, IrisSettings.get().getGenerator().getDefaultWorldType(), (w) -> {
J.s(() -> {
var spawn = w.getSpawnLocation();
for (Player i : getServer().getOnlinePlayers()) {
i.setGameMode(GameMode.SPECTATOR);
platform.teleportAsync(i, new Location(w, 0, 200, 0));
i.teleport(spawn);
}
});
});
@@ -566,11 +551,12 @@ public class Iris extends VolmitPlugin implements Listener {
enable();
super.onEnable();
Bukkit.getPluginManager().registerEvents(this, this);
setupChecks();
}
public void onDisable() {
if (IrisSafeguard.isForceShutdown()) return;
services.values().forEach(IrisService::onDisable);
Bukkit.getScheduler().cancelTasks(this);
HandlerList.unregisterAll((Plugin) this);
postShutdown.forEach(Runnable::run);
super.onDisable();
@@ -596,49 +582,7 @@ public class Iris extends VolmitPlugin implements Listener {
@Override
public String getTag(String subTag) {
if (unstablemode) {
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.RED + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
}
if (warningmode) {
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.GOLD + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
}
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.IRIS + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
}
private boolean setupChecks() {
boolean passed = true;
Iris.info("Version Information: " + instance.getServer().getVersion() + " | " + instance.getServer().getBukkitVersion());
if (INMS.get() instanceof NMSBinding1X) {
passed = false;
Iris.warn("============================================");
Iris.warn("=");
Iris.warn("=");
Iris.warn("=");
Iris.warn("Iris is not compatible with this version of Minecraft.");
Iris.warn("=");
Iris.warn("=");
Iris.warn("=");
Iris.warn("============================================");
}
try {
Class.forName("io.papermc.paper.configuration.PaperConfigurations");
} catch (ClassNotFoundException e) {
Iris.info(C.RED + "Iris requires paper or above to function properly..");
return false;
}
try {
Class.forName("org.purpurmc.purpur.PurpurConfig");
} catch (ClassNotFoundException e) {
Iris.info("We recommend using Purpur for the best experience with Iris.");
Iris.info("Purpur is a fork of Paper that is optimized for performance and stability.");
Iris.info("Plugins that work on Spigot / Paper work on Purpur.");
Iris.info("You can download it here: https://purpurmc.org");
return false;
}
return passed;
return IrisSafeguard.mode().tag(subTag);
}
private void checkConfigHotload() {
@@ -746,88 +690,11 @@ public class Iris extends VolmitPlugin implements Listener {
}
public void splash() {
if (!IrisSettings.get().getGeneral().isSplashLogoStartup()) {
return;
}
String padd = Form.repeat(" ", 8);
String padd2 = Form.repeat(" ", 4);
String[] info = {"", "", "", "", "", padd2 + C.IRIS + " Iris", padd2 + C.GRAY + " by " + "<rainbow>Volmit Software", padd2 + C.GRAY + " v" + C.IRIS + getDescription().getVersion()};
if (unstablemode) {
info = new String[]{"", "", "", "", "", padd2 + C.RED + " Iris", padd2 + C.GRAY + " by " + C.DARK_RED + "Volmit Software", padd2 + C.GRAY + " v" + C.RED + getDescription().getVersion()};
}
if (warningmode) {
info = new String[]{"", "", "", "", "", padd2 + C.GOLD + " Iris", padd2 + C.GRAY + " by " + C.GOLD + "Volmit Software", padd2 + C.GRAY + " v" + C.GOLD + getDescription().getVersion()};
}
String[] splashstable = {
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.IRIS + " .(((()))). ",
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.IRIS + " .((((((())))))). ",
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.IRIS + " ((((((((())))))))) " + C.GRAY + " @",
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.IRIS + " ((((((((-))))))))) " + C.GRAY + " @@",
padd + C.GRAY + "@@@&&" + C.IRIS + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
padd + C.GRAY + "@@" + C.IRIS + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
padd + C.GRAY + "@" + C.IRIS + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
padd + C.GRAY + "" + C.IRIS + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@",
padd + C.GRAY + "" + C.IRIS + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
};
String[] splashunstable = {
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.RED + " .(((()))). ",
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.RED + " .((((((())))))). ",
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.RED + " ((((((((())))))))) " + C.GRAY + " @",
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.RED + " ((((((((-))))))))) " + C.GRAY + " @@",
padd + C.GRAY + "@@@&&" + C.RED + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
padd + C.GRAY + "@@" + C.RED + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
padd + C.GRAY + "@" + C.RED + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
padd + C.GRAY + "" + C.RED + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@",
padd + C.GRAY + "" + C.RED + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
};
String[] splashwarning = {
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.GOLD + " .(((()))). ",
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.GOLD + " .((((((())))))). ",
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.GOLD + " ((((((((())))))))) " + C.GRAY + " @",
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.GOLD + " ((((((((-))))))))) " + C.GRAY + " @@",
padd + C.GRAY + "@@@&&" + C.GOLD + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
padd + C.GRAY + "@@" + C.GOLD + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
padd + C.GRAY + "@" + C.GOLD + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
padd + C.GRAY + "" + C.GOLD + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@",
padd + C.GRAY + "" + C.GOLD + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
};
String[] splash;
File freeSpace = new File(Bukkit.getWorldContainer() + ".");
if (unstablemode) {
splash = splashunstable;
} else if (warningmode) {
splash = splashwarning;
} else {
splash = splashstable;
}
if (!passedserversoftware) {
Iris.info("Server type & version: " + C.RED + Bukkit.getVersion());
} else { Iris.info("Server type & version: " + Bukkit.getVersion()); }
Iris.info("Java: " + getJava());
if (getHardware.getProcessMemory() < 5999) {
Iris.warn("6GB+ Ram is recommended");
Iris.warn("Process Memory: " + getHardware.getProcessMemory() + " MB");
}
Iris.info("Bukkit distro: " + Bukkit.getName());
Iris.info("Server type & version: " + Bukkit.getName() + " v" + Bukkit.getVersion());
Iris.info("Custom Biomes: " + INMS.get().countCustomBiomes());
setupChecks();
printPacks();
for (int i = 0; i < info.length; i++) {
splash[i] += info[i];
}
Iris.info("\n\n " + new KList<>(splash).toString("\n") + "\n");
IrisSafeguard.mode().trySplash();
}
private void printPacks() {
@@ -159,7 +159,7 @@ public class IrisSettings {
private IrisSettingsEngineSVC engineSVC = new IrisSettingsEngineSVC();
public boolean trimMantleInStudio = false;
public int mantleKeepAlive = 30;
public int cacheSize = 4_096;
public int noiseCacheSize = 1_024;
public int resourceLoaderCacheSize = 1_024;
public int objectLoaderCacheSize = 4_096;
public int scriptLoaderCacheSize = 512;
@@ -170,13 +170,16 @@ public class IrisSettings {
if (tectonicPlateSize > 0)
return tectonicPlateSize;
return (int) (getHardware.getProcessMemory() / 200L);
return (int) (getHardware.getProcessMemory() / 512L);
}
}
@Data
public static class IrisSettingsUpdater {
public int maxConcurrency = 256;
public boolean nativeThreads = false;
public double threadMultiplier = 2;
public double chunkLoadSensitivity = 0.7;
public MsRange emptyMsRange = new MsRange(80, 100);
public MsRange defaultMsRange = new MsRange(20, 40);
@@ -185,6 +188,10 @@ public class IrisSettings {
return Math.max(Math.abs(maxConcurrency), 1);
}
public double getThreadMultiplier() {
return Math.min(Math.abs(threadMultiplier), 0.1);
}
public double getChunkLoadSensitivity() {
return Math.min(chunkLoadSensitivity, 0.9);
}
@@ -243,6 +250,7 @@ public class IrisSettings {
public int maxBiomeChildDepth = 4;
public boolean preventLeafDecay = true;
public boolean useMulticore = false;
public boolean useMulticoreMantle = false;
public boolean offsetNoiseTypes = false;
public boolean earlyCustomBlocks = false;
}
@@ -179,14 +179,11 @@ public class ServerConfigurator {
Iris.warn("New data pack entries have been installed in Iris! Restarting server!");
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)");
if (!Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart")) {
Iris.warn("Looks like the restart command didn't work. Stopping the server instead!");
Bukkit.shutdown();
}
J.s(() -> {
Iris.warn("Looks like the restart command didn't work. Stopping the server instead!");
Bukkit.shutdown();
}, 100);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart");
});
}
@@ -31,7 +31,9 @@ import com.volmit.iris.core.tools.IrisPackBenchmarking;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisPosition;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
@@ -52,6 +54,7 @@ import com.volmit.iris.util.nbt.mca.MCAFile;
import com.volmit.iris.util.nbt.mca.MCAUtil;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.jobs.Job;
import lombok.SneakyThrows;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
@@ -92,6 +95,124 @@ public class CommandDeveloper implements DecreeExecutor {
Iris.reportError(new Exception("This is a test"));
}
@Decree(description = "Dev cmd to fix all the broken objects caused by faulty shrinkwarp")
public void fixObjects(
@Param(aliases = "dimension", description = "The dimension type to create the world with")
IrisDimension type
) {
if (type == null) {
sender().sendMessage("Type cant be null?");
return;
}
IrisData dm = IrisData.get(Iris.instance.getDataFolder("packs", type.getLoadKey()));
var loader = dm.getObjectLoader();
var processed = new KMap<String, IrisPosition>();
var objects = loader.getPossibleKeys();
var pieces = dm.getJigsawPieceLoader().getPossibleKeys();
var sender = sender();
sender.sendMessage(C.IRIS + "Found " + objects.length + " objects in " + type.getLoadKey());
sender.sendMessage(C.IRIS + "Found " + pieces.length + " jigsaw pieces in " + type.getLoadKey());
final int total = objects.length;
final AtomicInteger completed = new AtomicInteger();
final AtomicInteger changed = new AtomicInteger();
new Job() {
@Override
public String getName() {
return "Fixing Objects";
}
@Override
public void execute() {
Arrays.stream(pieces).parallel()
.map(dm.getJigsawPieceLoader()::load)
.filter(Objects::nonNull)
.forEach(piece -> {
var offset = processed.compute(piece.getObject(), (key, o) -> {
if (o != null) return o;
var obj = loader.load(key);
if (obj == null) return new IrisPosition();
obj.shrinkwrap();
try {
if (!obj.getShrinkOffset().isZero()) {
changed.incrementAndGet();
obj.write(obj.getLoadFile());
}
completeWork();
} catch (IOException e) {
Iris.error("Failed to write object " + obj.getLoadKey());
e.printStackTrace();
return new IrisPosition();
}
return new IrisPosition(obj.getShrinkOffset());
});
if (offset.getX() == 0 && offset.getY() == 0 && offset.getZ() == 0)
return;
piece.getConnectors().forEach(connector -> connector.setPosition(connector.getPosition().add(offset)));
try {
IO.writeAll(piece.getLoadFile(), dm.getGson().toJson(piece));
} catch (IOException e) {
Iris.error("Failed to write jigsaw piece " + piece.getLoadKey());
e.printStackTrace();
}
});
Arrays.stream(loader.getPossibleKeys()).parallel()
.filter(key -> !processed.containsKey(key))
.map(loader::load)
.forEach(obj -> {
if (obj == null) {
completeWork();
return;
}
obj.shrinkwrap();
if (obj.getShrinkOffset().isZero()) {
completeWork();
return;
}
try {
obj.write(obj.getLoadFile());
completeWork();
changed.incrementAndGet();
} catch (IOException e) {
Iris.error("Failed to write object " + obj.getLoadKey());
e.printStackTrace();
}
});
}
@Override
public void completeWork() {
completed.incrementAndGet();
}
@Override
public int getTotalWork() {
return total;
}
@Override
public int getWorkCompleted() {
return completed.get();
}
}.execute(sender, () -> {
var failed = total - completed.get();
if (failed != 0) sender.sendMessage(C.IRIS + "" + failed + " objects failed!");
if (changed.get() != 0) sender.sendMessage(C.IRIS + "" + changed.get() + " objects had their offsets changed!");
else sender.sendMessage(C.IRIS + "No objects had their offsets changed!");
});
}
@Decree(description = "Test")
public void mantle(@Param(defaultValue = "false") boolean plate, @Param(defaultValue = "21474836474") String name) throws Throwable {
var base = Iris.instance.getDataFile("dump", "pv." + name + ".ttp.lz4b.bin");
@@ -46,6 +46,16 @@ public class CommandEdit implements DecreeExecutor {
sender().sendMessage(C.RED + "You must be in a studio world!");
return true;
}
if (GraphicsEnvironment.isHeadless()) {
sender().sendMessage(C.RED + "Cannot open files in headless environments!");
return true;
}
if (!Desktop.isDesktopSupported()) {
sender().sendMessage(C.RED + "Desktop is not supported by this environment!");
return true;
}
return false;
}
@@ -42,6 +42,7 @@ import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.*;
import java.util.List;
@@ -157,8 +158,13 @@ public class CommandIris implements DecreeExecutor {
return;
}
Iris.platform.teleportAsync(target, world.getSpawnLocation()).thenRun(() ->
new VolmitSender(target).sendMessage(C.GREEN + "You have been teleported to " + world.getName() + "."));
new BukkitRunnable() {
@Override
public void run() {
target.teleport(world.getSpawnLocation());
new VolmitSender(target).sendMessage(C.GREEN + "You have been teleported to " + world.getName() + ".");
}
}.runTask(Iris.instance);
}
@Decree(description = "Print version information")
@@ -38,7 +38,6 @@ import com.volmit.iris.util.decree.specialhandlers.ObjectHandler;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.Direction;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.Queue;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
@@ -79,9 +78,9 @@ public class CommandObject implements DecreeExecutor {
futureBlockChanges.put(block, block.getBlockData());
if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase());
block.setBlockData(data.getBase(), false);
Iris.warn("Tried to place custom block at " + x + ", " + y + ", " + z + " which is not supported!");
} else block.setBlockData(d);
} else block.setBlockData(d, false);
}
@Override
@@ -124,11 +123,21 @@ public class CommandObject implements DecreeExecutor {
tile.toBukkitTry(world.getBlockAt(xx, yy, zz));
}
@Override
public <T> void setData(int xx, int yy, int zz, T data) {
}
@Override
public <T> T getData(int xx, int yy, int zz, Class<T> t) {
return null;
}
@Override
public Engine getEngine() {
return null;
}
}.sync(world);
};
}
@Decree(description = "Check the composition of an object")
@@ -140,7 +149,7 @@ public class CommandObject implements DecreeExecutor {
sender().sendMessage("Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD() + "");
sender().sendMessage("Blocks Used: " + NumberFormat.getIntegerInstance().format(o.getBlocks().size()));
Queue<BlockData> queue = o.getBlocks().enqueueValues();
var queue = o.getBlocks().values();
Map<Material, Set<BlockData>> unsorted = new HashMap<>();
Map<BlockData, Integer> amounts = new HashMap<>();
Map<Material, Integer> materials = new HashMap<>();
@@ -47,16 +47,20 @@ import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.math.*;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.parallel.SyncExecutor;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.O;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.scheduling.jobs.ParallelQueueJob;
import de.crazydev22.platformutils.scheduler.task.Task;
import com.volmit.iris.util.scheduling.jobs.ParallelRadiusJob;
import io.papermc.lib.PaperLib;
import org.bukkit.*;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.util.BlockVector;
@@ -73,8 +77,8 @@ import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
@@ -171,76 +175,55 @@ public class CommandStudio implements DecreeExecutor {
PlatformChunkGenerator plat = IrisToolbelt.access(world);
Engine engine = plat.getEngine();
DecreeContext.touch(sender);
try (var executor = Iris.platform.createRegionExecutor(20)) {
try (SyncExecutor executor = new SyncExecutor(20);
var service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())
) {
int x = loc.getBlockX() >> 4;
int z = loc.getBlockZ() >> 4;
int rad = engine.getMantle().getRadius();
var mantle = engine.getMantle().getMantle();
var chunkMap = new KMap<Position2, MantleChunk>();
ParallelQueueJob<Position2> prep = new ParallelQueueJob<>() {
ParallelRadiusJob prep = new ParallelRadiusJob(Integer.MAX_VALUE, service) {
@Override
public void execute(Position2 pos) {
var cpos = pos.add(x, z);
if (Math.abs(pos.getX()) <= radius && Math.abs(pos.getZ()) <= radius) {
mantle.deleteChunk(cpos.getX(), cpos.getZ());
protected void execute(int rX, int rZ) {
if (Math.abs(rX) <= radius && Math.abs(rZ) <= radius) {
mantle.deleteChunk(rX + x, rZ + z);
return;
}
chunkMap.put(cpos, mantle.getChunk(cpos.getX(), cpos.getZ()));
mantle.deleteChunk(cpos.getX(), cpos.getZ());
rX += x;
rZ += z;
chunkMap.put(new Position2(rX, rZ), mantle.getChunk(rX, rZ));
mantle.deleteChunk(rX, rZ);
}
@Override
public String getName() {
return "Preparing Mantle";
}
};
for (int xx = -(radius + rad); xx <= radius + rad; xx++) {
for (int zz = -(radius + rad); zz <= radius + rad; zz++) {
prep.queue(new Position2(xx, zz));
}
}
}.retarget(radius + rad, 0, 0);
CountDownLatch pLatch = new CountDownLatch(1);
prep.execute(sender(), pLatch::countDown);
pLatch.await();
ParallelQueueJob<Position2> job = new ParallelQueueJob<>() {
ParallelRadiusJob job = new ParallelRadiusJob(Integer.MAX_VALUE, service) {
@Override
public void execute(Position2 p) {
plat.injectChunkReplacement(world, p.getX(), p.getZ(), executor);
protected void execute(int x, int z) {
plat.injectChunkReplacement(world, x, z, executor);
}
@Override
public String getName() {
return "Regenerating";
}
};
for (int i = -radius; i <= radius; i++) {
for (int j = -radius; j <= radius; j++) {
job.queue(new Position2(i + x, j + z));
}
}
}.retarget(radius, x, z);
CountDownLatch latch = new CountDownLatch(1);
job.execute(sender(), latch::countDown);
latch.await();
int sections = mantle.getWorldHeight() >> 4;
chunkMap.forEach((pos, chunk) -> {
var c = mantle.getChunk(pos.getX(), pos.getZ()).use();
try {
c.copyFlags(chunk);
c.clear();
for (int y = 0; y < sections; y++) {
var slice = chunk.get(y);
if (slice == null) continue;
var s = c.getOrCreate(y);
slice.getSliceMap().forEach(s::putSlice);
}
} finally {
c.release();
}
});
chunkMap.forEach((pos, chunk) ->
mantle.getChunk(pos.getX(), pos.getZ()).copyFrom(chunk));
} catch (Throwable e) {
sender().sendMessage("Error while regenerating chunks");
e.printStackTrace();
@@ -332,25 +315,31 @@ public class CommandStudio implements DecreeExecutor {
return;
}
Player player = player();
var scheduler = Iris.platform.getEntityScheduler(player);
scheduler.run(() -> {
sender().sendMessage(C.GREEN + "Opening inventory now!");
player.openInventory(inv);
scheduler.runAtFixedRate(refresh -> {
if (!player.getOpenInventory().getType().equals(InventoryType.CHEST)) {
refresh.cancel();
return;
}
O<Integer> ta = new O<>();
ta.set(-1);
if (!add) {
inv.clear();
}
var sender = sender();
var player = player();
var engine = engine();
engine().addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player.getWorld(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ(), 1);
}, null, 1, fast ? 5 : 35);
}, null);
ta.set(Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () ->
{
if (!player.getOpenInventory().getType().equals(InventoryType.CHEST)) {
Bukkit.getScheduler().cancelTask(ta.get());
sender.sendMessage(C.GREEN + "Opened inventory!");
return;
}
if (!add) {
inv.clear();
}
engine.addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player.getWorld(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ(), 1);
}, 0, fast ? 5 : 35));
sender().sendMessage(C.GREEN + "Opening inventory now!");
player().openInventory(inv);
}
@Decree(description = "Calculate the chance for each region to generate", origin = DecreeOrigin.PLAYER)
@@ -373,7 +362,7 @@ public class CommandStudio implements DecreeExecutor {
var loc = player.getLocation();
int totalTasks = d * d;
AtomicInteger completedTasks = new AtomicInteger(0);
Task c = J.ar(() -> sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding regions"), 0);
int c = J.ar(() -> sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding regions"), 0);
new Spiraler(d, d, (x, z) -> executor.queue(() -> {
var region = engine.getRegion((x << 4) + 8, (z << 4) + 8);
data.computeIfAbsent(region.getLoadKey(), (k) -> new AtomicInteger(0))
@@ -382,7 +371,7 @@ public class CommandStudio implements DecreeExecutor {
})).setOffset(loc.getBlockX(), loc.getBlockZ()).drain();
executor.complete();
multiBurst.close();
c.cancel();
J.car(c);
sender.sendMessage(C.GREEN + "Done!");
var loader = engine.getData().getRegionLoader();
@@ -407,7 +396,9 @@ public class CommandStudio implements DecreeExecutor {
var loc = player().getLocation();
int totalTasks = d * d;
AtomicInteger completedTasks = new AtomicInteger(0);
var c = J.ar(() -> sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding structures"), 0);
int c = J.ar(() -> {
sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding structures");
}, 0);
new Spiraler(d, d, (x, z) -> executor.queue(() -> {
var struct = engine.getStructureAt(x, z);
@@ -419,7 +410,7 @@ public class CommandStudio implements DecreeExecutor {
executor.complete();
multiBurst.close();
if (c != null) c.cancel();
J.car(c);
for (var key : data.keySet()) {
var list = data.get(key);
@@ -697,9 +688,14 @@ public class CommandStudio implements DecreeExecutor {
}
sender().sendMessage(C.GREEN + "Sending you to the studio world!");
Player player = player();
Iris.platform.teleportAsync(player, Iris.service(StudioSVC.class).getActiveProject().getActiveProvider().getTarget().getWorld().spawnLocation());
Iris.platform.getEntityScheduler(player).run(() -> player.setGameMode(GameMode.SPECTATOR), null);
var player = player();
PaperLib.teleportAsync(player(), Iris.service(StudioSVC.class)
.getActiveProject()
.getActiveProvider()
.getTarget()
.getWorld()
.spawnLocation()
).thenRun(() -> player.setGameMode(GameMode.SPECTATOR));
}
@Decree(description = "Update your dimension projects VSCode workspace")
@@ -715,7 +711,7 @@ public class CommandStudio implements DecreeExecutor {
}
}
@Decree(aliases = "find-objects", description = "Get information about nearby structures", origin = DecreeOrigin.PLAYER)
@Decree(aliases = "find-objects", description = "Get information about nearby structures")
public void objects() {
if (!IrisToolbelt.isIrisWorld(player().getWorld())) {
sender().sendMessage(C.RED + "You must be in an Iris world");
@@ -728,29 +724,21 @@ public class CommandStudio implements DecreeExecutor {
sender().sendMessage("You must be in an iris world.");
return;
}
KMap<Position2, CompletableFuture<Chunk>> chunks = new KMap<>();
var location = player().getLocation();
int bx = location.getBlockX() >> 4;
int bz = location.getBlockZ() >> 4;
KList<Chunk> chunks = new KList<>();
int bx = player().getLocation().getChunk().getX();
int bz = player().getLocation().getChunk().getZ();
Spiraled spiraled = (x, z) -> chunks.putIfAbsent(new Position2(x, z), Iris.platform.getChunkAtAsync(world, x, z));
try {
var player = player();
var task = Iris.platform.getEntityScheduler(player).run(() -> {
var target = player.getTargetBlockExact(48, FluidCollisionMode.NEVER);
if (target == null) return;
Location l = target.getLocation();
Location l = player().getTargetBlockExact(48, FluidCollisionMode.NEVER).getLocation();
int cx = l.getBlockX() >> 4;
int cz = l.getBlockZ() >> 4;
new Spiraler(3, 3, (x, z) -> spiraled.on(x + cx, z + cz)).drain();
}, null);
if (task != null) task.getResult().join();
int cx = l.getChunk().getX();
int cz = l.getChunk().getZ();
new Spiraler(3, 3, (x, z) -> chunks.addIfMissing(world.getChunkAt(x + cx, z + cz))).drain();
} catch (Throwable e) {
Iris.reportError(e);
}
new Spiraler(3, 3, (x, z) -> spiraled.on(x + bx, z + bz)).drain();
new Spiraler(3, 3, (x, z) -> chunks.addIfMissing(world.getChunkAt(x + bx, z + bz))).drain();
sender().sendMessage("Capturing IGenData from " + chunks.size() + " nearby chunks.");
try {
File ff = Iris.instance.getDataFile("reports/" + M.ms() + ".txt");
@@ -760,11 +748,11 @@ public class CommandStudio implements DecreeExecutor {
pw.println("Iris Version: " + Iris.instance.getDescription().getVersion());
pw.println("Bukkit Version: " + Bukkit.getBukkitVersion());
pw.println("MC Version: " + Bukkit.getVersion());
//pw.println("PaperSpigot: " + (PaperLib.isPaper() ? "Yup!" : "Nope!")); //TODO update this
pw.println("PaperSpigot: " + (PaperLib.isPaper() ? "Yup!" : "Nope!"));
pw.println("Report Captured At: " + new Date());
pw.println("Chunks: (" + chunks.size() + "): ");
for (Position2 i : chunks.keySet()) {
for (Chunk i : chunks) {
pw.println("- [" + i.getX() + ", " + i.getZ() + "]");
}
@@ -789,31 +777,25 @@ public class CommandStudio implements DecreeExecutor {
Iris.reportError(e);
}
KSet<String> biomes = new KSet<>();
KSet<String> caveBiomes = new KSet<>();
KMap<String, KMap<String, KSet<String>>> objects = new KMap<>();
KList<String> biomes = new KList<>();
KList<String> caveBiomes = new KList<>();
KMap<String, KMap<String, KList<String>>> objects = new KMap<>();
var engine = engine();
assert engine != null;
for (Chunk i : chunks) {
for (int j = 0; j < 16; j += 3) {
KList<CompletableFuture<?>> futures = new KList<>(chunks.size());
for (var future : chunks.values()) {
futures.add(future.thenAccept(i -> {
int bX = i.getX() << 4;
int bZ = i.getZ() << 4;
for (int j = 0; j < 16; j += 3) {
for (int k = 0; k < 16; k += 3) {
IrisBiome bb = engine.getSurfaceBiome(bX + j, bZ + k);
IrisBiome bxf = engine.getCaveBiome(bX + j, bZ + k);
biomes.add(bb.getName() + " [" + Form.capitalize(String.valueOf(bb.getInferredType()).toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")");
caveBiomes.add(bxf.getName() + " (" + bxf.getLoadFile().getName() + ")");
exportObjects(bb, pw, engine, objects);
exportObjects(bxf, pw, engine, objects);
}
for (int k = 0; k < 16; k += 3) {
assert engine() != null;
IrisBiome bb = engine().getSurfaceBiome((i.getX() * 16) + j, (i.getZ() * 16) + k);
IrisBiome bxf = engine().getCaveBiome((i.getX() * 16) + j, (i.getZ() * 16) + k);
biomes.addIfMissing(bb.getName() + " [" + Form.capitalize(bb.getInferredType().name().toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")");
caveBiomes.addIfMissing(bxf.getName() + " (" + bxf.getLoadFile().getName() + ")");
exportObjects(bb, pw, engine(), objects);
exportObjects(bxf, pw, engine(), objects);
}
}));
}
}
CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).join();
regions = Objects.requireNonNull(new File(world.getWorldFolder().getPath() + "/region").list()).length;
@@ -833,13 +815,6 @@ public class CommandStudio implements DecreeExecutor {
pw.println("- " + i);
}
pw.println();
pw.println("== Cave Biome Info ==");
pw.println("Found " + caveBiomes.size() + " Cave Biome(s): ");
for (String i : caveBiomes) {
pw.println("- " + i);
}
pw.println();
pw.println("== Object Info ==");
@@ -865,8 +840,8 @@ public class CommandStudio implements DecreeExecutor {
}
}
private void exportObjects(IrisBiome bb, PrintWriter pw, Engine g, KMap<String, KMap<String, KSet<String>>> objects) {
String n1 = bb.getName() + " [" + Form.capitalize(String.valueOf(bb.getInferredType()).toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")";
private void exportObjects(IrisBiome bb, PrintWriter pw, Engine g, KMap<String, KMap<String, KList<String>>> objects) {
String n1 = bb.getName() + " [" + Form.capitalize(bb.getInferredType().name().toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")";
int m = 0;
KSet<String> stop = new KSet<>();
for (IrisObjectPlacement f : bb.getObjects()) {
@@ -891,7 +866,7 @@ public class CommandStudio implements DecreeExecutor {
String n3 = nn3;
objects.computeIfAbsent(n1, (k1) -> new KMap<>())
.computeIfAbsent(n2, (k) -> new KSet<>()).add(n3);
.computeIfAbsent(n2, (k) -> new KList<>()).addIfMissing(n3);
}
}
}
@@ -74,22 +74,22 @@ public class CommandWhat implements DecreeExecutor {
} catch (Throwable e) {
Iris.reportError(e);
sender().sendMessage("Non-Iris Biome: " + player().getLocation().getBlock().getBiome().name());
var loc = player().getLocation();
var sender = sender();
Iris.platform.getRegionScheduler().run(loc, () -> {
var biome = loc.getBlock().getBiome();
if (biome != Biome.CUSTOM && biome.getKey().getNamespace().equals("minecraft"))
return;
sender.sendMessage("Data Pack Biome: " + INMS.get().getTrueBiomeBaseKey(loc) + " (ID: " + INMS.get().getTrueBiomeBaseId(INMS.get().getTrueBiomeBase(loc)) + ")");
});
if (player().getLocation().getBlock().getBiome().equals(Biome.CUSTOM)) {
try {
sender().sendMessage("Data Pack Biome: " + INMS.get().getTrueBiomeBaseKey(player().getLocation()) + " (ID: " + INMS.get().getTrueBiomeBaseId(INMS.get().getTrueBiomeBase(player().getLocation())) + ")");
} catch (Throwable ee) {
Iris.reportError(ee);
}
}
}
}
@Decree(description = "What region am i in?", origin = DecreeOrigin.PLAYER)
public void region() {
try {
var loc = player().getLocation();
IrisRegion r = engine().getRegion(loc);
Chunk chunk = world().getChunkAt(player().getLocation().getBlockZ() / 16, player().getLocation().getBlockZ() / 16);
IrisRegion r = engine().getRegion(chunk);
sender().sendMessage("IRegion: " + r.getLoadKey() + " (" + r.getName() + ")");
} catch (Throwable e) {
@@ -98,7 +98,7 @@ public class CommandWhat implements DecreeExecutor {
}
}
@Decree(description = "What block am i looking at?", origin = DecreeOrigin.PLAYER, sync = true)
@Decree(description = "What block am i looking at?", origin = DecreeOrigin.PLAYER)
public void block() {
BlockData bd;
try {
@@ -18,10 +18,9 @@
package com.volmit.iris.core.edit;
import com.volmit.iris.Iris;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.AR;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.SR;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
@@ -80,7 +79,7 @@ public class BlockSignal {
e.setTicksLived(1);
e.setVelocity(new Vector(0, 0, 0));
new AR(20) {
new SR(20) {
@Override
public void run() {
if (e.isDead()) {
@@ -88,10 +87,9 @@ public class BlockSignal {
return;
}
Iris.platform.teleportAsync(e, tg.clone()).thenAccept(b -> {
e.setTicksLived(1);
e.setVelocity(new Vector(0, 0, 0));
}).join();
e.setTicksLived(1);
e.teleport(tg.clone());
e.setVelocity(new Vector(0, 0, 0));
}
};
@@ -30,7 +30,6 @@ import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import de.crazydev22.platformutils.scheduler.task.Task;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
@@ -56,20 +55,20 @@ public class JigsawEditor implements Listener {
private final IrisJigsawPiece piece;
private final Location origin;
private final Cuboid cuboid;
private final Task ticker;
private final int ticker;
private final KMap<IrisPosition, Runnable> falling = new KMap<>();
private final ChronoLatch cl = new ChronoLatch(100);
private Location target;
public JigsawEditor(Player player, IrisJigsawPiece piece, IrisObject object, File saveLocation) {
if (editors.containsKey(player)) {
editors.get(player).close();
}
if (object == null) throw new RuntimeException("Object is null! " + piece.getObject());
editors.compute(player, ($, current) -> {
if (current != null) {
current.exit();
}
return this;
});
editors.put(player, this);
if (object == null) {
throw new RuntimeException("Object is null! " + piece.getObject());
}
this.object = object;
this.player = player;
origin = player.getLocation().clone().add(0, 7, 0);
@@ -107,26 +106,21 @@ public class JigsawEditor implements Listener {
}
public Location toLocation(IrisPosition i) {
return toBlock(origin.clone()
return origin.clone()
.add(new Vector(i.getX(), i.getY(), i.getZ()))
.add(object.getCenter()));
.add(object.getCenter())
.getBlock()
.getLocation();
}
public IrisPosition toPosition(Location l) {
return new IrisPosition(l.clone()
return new IrisPosition(l.clone().getBlock().getLocation()
.subtract(origin.clone())
.subtract(object.getCenter())
.add(1, 1, 1)
.toVector());
}
private Location toBlock(Location location) {
location.setX(Math.floor(location.getX()));
location.setY(Math.floor(location.getY()));
location.setZ(Math.floor(location.getZ()));
return location;
}
@EventHandler
public void on(PlayerInteractEvent e) {
if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
@@ -203,7 +197,7 @@ public class JigsawEditor implements Listener {
}
public void exit() {
if (ticker != null) ticker.cancel();
J.car(ticker);
Iris.instance.unregisterListener(this);
try {
J.sfut(() -> {
@@ -763,7 +763,7 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
int xx = (int) getWorldX(hx);
int zz = (int) getWorldZ(hz);
int h = engine.getComplex().getRoundedHeighteightStream().get(xx, zz);
Iris.platform.teleportAsync(player, new Location(player.getWorld(), xx, h, zz));
player.teleport(new Location(player.getWorld(), xx, h, zz));
notify("Teleporting to " + xx + ", " + h + ", " + zz);
} else {
notify("No player in world, can't teleport.");
@@ -157,7 +157,7 @@ public abstract class ExternalDataProvider implements Listener {
protected static List<BlockProperty> YAW_FACE_BIOME_PROPERTIES = List.of(
BlockProperty.ofEnum(BiomeColor.class, "matchBiome", null),
BlockProperty.ofBoolean("randomYaw", false),
BlockProperty.ofFloat("yaw", 0, 0, 360f, false, true),
BlockProperty.ofDouble("yaw", 0, 0, 360f, false, true),
BlockProperty.ofBoolean("randomFace", true),
new BlockProperty(
"face",
@@ -1,68 +0,0 @@
package com.volmit.iris.core.link;
import lombok.NonNull;
import net.thenextlvl.worlds.api.WorldsProvider;
import net.thenextlvl.worlds.api.generator.GeneratorType;
import net.thenextlvl.worlds.api.generator.LevelStem;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.concurrent.CompletableFuture;
public class FoliaWorldsLink {
private static FoliaWorldsLink instance;
private final Object provider;
private FoliaWorldsLink(Object provider) {
this.provider = provider;
}
public static FoliaWorldsLink get() {
if(instance == null) {
synchronized (FoliaWorldsLink.class) {
try {
Server.class.getDeclaredMethod("isGlobalTickThread");
instance = new FoliaWorldsLink(Bukkit.getServicesManager().load(WorldsProvider.class));
} catch (Throwable e) {
instance = new FoliaWorldsLink(null);
}
}
}
return instance;
}
public boolean isActive() {
return provider != null;
}
@Nullable
public CompletableFuture<World> createWorld(@NonNull WorldCreator creator) {
if (provider == null) return null;
return ((WorldsProvider) provider)
.levelBuilder(new File(Bukkit.getWorldContainer(), creator.name()).toPath())
.name(creator.name())
.seed(creator.seed())
.levelStem(switch (creator.environment()) {
case CUSTOM, NORMAL -> LevelStem.OVERWORLD;
case NETHER -> LevelStem.NETHER;
case THE_END -> LevelStem.END;
})
.chunkGenerator(creator.generator())
.biomeProvider(creator.biomeProvider())
.generatorType(switch (creator.type()) {
case NORMAL -> GeneratorType.NORMAL;
case FLAT -> GeneratorType.FLAT;
case LARGE_BIOMES -> GeneratorType.LARGE_BIOMES;
case AMPLIFIED -> GeneratorType.AMPLIFIED;
})
.structures(creator.generateStructures())
.hardcore(creator.hardcore())
.build()
.createAsync();
}
}
@@ -0,0 +1,159 @@
package com.volmit.iris.core.link.data;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.math.RNG;
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
import net.momirealms.craftengine.bukkit.api.CraftEngineItems;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.properties.BooleanProperty;
import net.momirealms.craftengine.core.block.properties.IntegerProperty;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Stream;
public class CraftEngineDataProvider extends ExternalDataProvider {
public CraftEngineDataProvider() {
super("CraftEngine");
}
private static final BlockProperty[] FURNITURE_PROPERTIES = new BlockProperty[] {
BlockProperty.ofBoolean("randomYaw", false),
BlockProperty.ofDouble("yaw", 0, 0, 360f, false, true),
BlockProperty.ofBoolean("randomPitch", false),
BlockProperty.ofDouble("pitch", 0, 0, 360f, false, true),
};
@Override
public void init() {
}
@Override
public @NotNull List<BlockProperty> getBlockProperties(@NotNull Identifier blockId) throws MissingResourceException {
var block = CraftEngineBlocks.byId(Key.of(blockId.namespace(), blockId.key()));
if (block != null) return block.properties()
.stream()
.map(CraftEngineDataProvider::convert)
.toList();
var furniture = CraftEngineFurniture.byId(Key.of(blockId.namespace(), blockId.key()));
if (furniture != null) {
BlockProperty[] properties = Arrays.copyOf(FURNITURE_PROPERTIES, 5);
properties[4] = new BlockProperty(
"variant",
String.class,
furniture.anyVariantName(),
furniture.variants().keySet(),
Function.identity()
);
return List.of(properties);
}
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@Override
public @NotNull ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
var item = CraftEngineItems.byId(Key.of(itemId.namespace(), itemId.key()));
if (item == null) throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
return item.buildItemStack();
}
@Override
public @NotNull BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
var key = Key.of(blockId.namespace(), blockId.key());
if (CraftEngineBlocks.byId(key) == null && CraftEngineFurniture.byId(key) == null)
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
return IrisCustomData.of(B.getAir(), ExternalDataSVC.buildState(blockId, state));
}
@Override
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
var pair = ExternalDataSVC.parseState(blockId);
var key = Key.of(blockId.namespace(), blockId.key());
var state = pair.getB();
var customBlock = CraftEngineBlocks.byId(key);
if (customBlock != null) {
ImmutableBlockState blockState = customBlock.defaultState();
for (var entry : state.entrySet()) {
var property = customBlock.getProperty(entry.getKey());
if (property == null) continue;
var tag = property.optional(entry.getValue()).orElse(null);
if (tag == null) continue;
blockState = ImmutableBlockState.with(blockState, property, tag);
}
CraftEngineBlocks.place(block.getLocation(), blockState, false);
return;
}
var furniture = CraftEngineFurniture.byId(key);
if (furniture == null) return;
var location = parseYawAndPitch(engine, block, state);
String variant = state.getOrDefault("variant", furniture.anyVariantName());
CraftEngineFurniture.place(location, furniture, variant, false);
}
private static Location parseYawAndPitch(@NotNull Engine engine, @NotNull Block block, @NotNull Map<String, String> state) {
Location location = block.getLocation();
long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY();
RNG rng = new RNG(seed);
if ("true".equals(state.get("randomYaw"))) {
location.setYaw(rng.f(0, 360));
} else if (state.containsKey("yaw")) {
location.setYaw(Float.parseFloat(state.get("yaw")));
}
if ("true".equals(state.get("randomPitch"))) {
location.setPitch(rng.f(0, 360));
} else if (state.containsKey("pitch")) {
location.setPitch(Float.parseFloat(state.get("pitch")));
}
return location;
}
@Override
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
return (switch (dataType) {
case ENTITY -> Stream.<Key>empty();
case ITEM -> CraftEngineItems.loadedItems().keySet().stream();
case BLOCK -> Stream.concat(CraftEngineBlocks.loadedBlocks().keySet().stream(),
CraftEngineFurniture.loadedFurniture().keySet().stream());
}).map(key -> new Identifier(key.namespace(), key.value())).toList();
}
@Override
public boolean isValidProvider(@NotNull Identifier id, DataType dataType) {
Key key = Key.of(id.namespace(), id.key());
return switch (dataType) {
case ENTITY -> false;
case ITEM -> CraftEngineItems.byId(key) != null;
case BLOCK -> (CraftEngineBlocks.byId(key) != null || CraftEngineFurniture.byId(key) != null);
};
}
private static <T extends Comparable<T>> BlockProperty convert(Property<T> raw) {
return switch (raw) {
case BooleanProperty property -> BlockProperty.ofBoolean(property.name(), property.defaultValue());
case IntegerProperty property -> BlockProperty.ofLong(property.name(), property.defaultValue(), property.min, property.max, false, false);
default -> new BlockProperty(raw.name(), raw.valueClass(), raw.defaultValue(), raw.possibleValues(), raw::valueName);
};
}
}
@@ -67,7 +67,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 IrisCustomData.of(blockData, ExternalDataSVC.buildState(blockId, state));
}
@NotNull
@@ -5,7 +5,6 @@ import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.IrisCustomData;
import dev.lone.itemsadder.api.CustomBlock;
import dev.lone.itemsadder.api.CustomStack;
@@ -19,12 +18,13 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
import java.util.Set;
import java.util.stream.Collectors;
public class ItemAdderDataProvider extends ExternalDataProvider {
private final KSet<String> itemNamespaces = new KSet<>();
private final KSet<String> blockNamespaces = new KSet<>();
private volatile Set<String> itemNamespaces = Set.of();
private volatile Set<String> blockNamespaces = Set.of();
public ItemAdderDataProvider() {
super("ItemsAdder");
@@ -47,7 +47,7 @@ public class ItemAdderDataProvider extends ExternalDataProvider {
if (block == null) {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
return new IrisCustomData(block.getBaseBlockData(), blockId);
return IrisCustomData.of(block.getBaseBlockData(), blockId);
}
@NotNull
@@ -94,9 +94,9 @@ public class ItemAdderDataProvider extends ExternalDataProvider {
private void updateNamespaces(DataType dataType) {
var namespaces = getTypes(dataType).stream().map(Identifier::namespace).collect(Collectors.toSet());
var currentNamespaces = dataType == DataType.ITEM ? itemNamespaces : blockNamespaces;
currentNamespaces.removeIf(n -> !namespaces.contains(n));
currentNamespaces.addAll(namespaces);
if (dataType == DataType.ITEM) itemNamespaces = namespaces;
else blockNamespaces = namespaces;
Iris.debug("Updated ItemAdder namespaces: " + dataType + " - " + namespaces);
}
@Override
@@ -33,7 +33,7 @@ public class KGeneratorsDataProvider extends ExternalDataProvider {
@Override
public @NotNull BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
if (Main.getGenerators().get(blockId.key()) == null) throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
return new IrisCustomData(Material.STRUCTURE_VOID.createBlockData(), ExternalDataSVC.buildState(blockId, state));
return IrisCustomData.of(Material.STRUCTURE_VOID.createBlockData(), ExternalDataSVC.buildState(blockId, state));
}
@Override
@@ -72,7 +72,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 IrisCustomData.of(B.getAir(), ExternalDataSVC.buildState(blockId, state));
} else if (blockItemContext != null) {
return blockItemContext.getBlockData();
}
@@ -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 IrisCustomData.of(data, blockState);
} else if (NexoFurniture.isFurniture(blockId.key())) {
return new IrisCustomData(B.getAir(), blockState);
return IrisCustomData.of(B.getAir(), blockState);
}
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
@@ -50,16 +50,15 @@ import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Optional;
import java.util.*;
@Data
public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
private static final KMap<File, IrisData> dataLoaders = new KMap<>();
private final File dataFolder;
private final int id;
private final PackEnvironment environment;
private boolean closed = false;
private PackEnvironment environment;
private ResourceLoader<IrisBiome> biomeLoader;
private ResourceLoader<IrisLootTable> lootLoader;
private ResourceLoader<IrisRegion> regionLoader;
@@ -92,7 +91,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
this.engine = null;
this.dataFolder = dataFolder;
this.id = RNG.r.imax();
this.environment = PackEnvironment.create(this);
hotloaded();
}
@@ -105,7 +103,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
}
public static void dereference() {
dataLoaders.v().forEach(IrisData::cleanupEngine);
dataLoaders.values().forEach(IrisData::cleanupEngine);
}
public static int cacheSize() {
@@ -350,7 +348,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
public synchronized void hotloaded() {
closed = false;
environment.close();
possibleSnippets = new KMap<>();
builder = new GsonBuilder()
.addDeserializationExclusionStrategy(this)
@@ -382,6 +379,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
this.imageLoader = registerLoader(IrisImage.class);
this.scriptLoader = registerLoader(IrisScript.class);
this.matterObjectLoader = registerLoader(IrisMatterObject.class);
this.environment = PackEnvironment.create(this);
builder.registerTypeAdapterFactory(KeyedType::createTypeAdapter);
gson = builder.create();
@@ -389,6 +387,10 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
.map(IrisDimension::getDataScripts)
.flatMap(KList::stream)
.forEach(environment::execute);
if (engine != null) {
engine.hotload();
}
}
public void dump() {
@@ -404,6 +406,33 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
possibleSnippets.clear();
}
public Set<Class<?>> resolveSnippets() {
var result = new HashSet<Class<?>>();
var processed = new HashSet<Class<?>>();
var excluder = gson.excluder();
var queue = new LinkedList<Class<?>>(loaders.keySet());
while (!queue.isEmpty()) {
var type = queue.poll();
if (excluder.excludeClass(type, false) || !processed.add(type))
continue;
if (type.isAnnotationPresent(Snippet.class))
result.add(type);
try {
for (var field : type.getDeclaredFields()) {
if (excluder.excludeField(field, false))
continue;
queue.add(field.getType());
}
} catch (Throwable ignored) {
}
}
return result;
}
public String toLoadKey(File f) {
if (f.getPath().startsWith(getDataFolder().getPath())) {
String[] full = f.getPath().split("\\Q" + File.separator + "\\E");
@@ -35,7 +35,7 @@ import java.io.File;
@Data
public abstract class IrisRegistrant {
@Desc("Preprocess this object in-memory when it's loaded, run scripts using the variable 'Iris.getPreprocessorObject()' and modify properties about this object before it's used.")
@Desc("Preprocess this object in-memory when it's loaded, run scripts using the variable 'object' and modify properties about this object before it's used.\nFile extension: .proc.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(min = 1, type = String.class)
private KList<String> preprocessors = new KList<>();
@@ -46,6 +46,7 @@ import lombok.ToString;
import java.io.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@@ -170,7 +171,6 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
return possibleKeys;
}
KSet<String> m = new KSet<>();
KList<File> files = getFolders();
if (files == null) {
@@ -178,6 +178,7 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
return possibleKeys;
}
HashSet<String> m = new HashSet<>();
for (File i : files) {
for (File j : matchAllFiles(i, (f) -> f.getName().endsWith(".json"))) {
m.add(i.toURI().relativize(j.toURI()).getPath().replaceAll("\\Q.json\\E", ""));
@@ -319,7 +320,8 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
return null;
}
firstAccess.add(name);
var set = firstAccess;
if (set != null) firstAccess.add(name);
return loadCache.get(name);
}
@@ -342,21 +344,24 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
}
din.close();
file.deleteOnExit();
Iris.info("Loading " + s.size() + " prefetch " + getFolderName());
firstAccess = null;
loadAllParallel(s);
}
public void saveFirstAccess(Engine engine) throws IOException {
if (firstAccess == null) return;
String id = "DIM" + Math.abs(engine.getSeedManager().getSeed() + engine.getDimension().getVersion() + engine.getDimension().getLoadKey().hashCode());
File file = Iris.instance.getDataFile("prefetch/" + id + "/" + Math.abs(getFolderName().hashCode()) + ".ipfch");
file.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(file);
GZIPOutputStream gzo = new CustomOutputStream(fos, 9);
DataOutputStream dos = new DataOutputStream(gzo);
dos.writeInt(firstAccess.size());
var set = firstAccess;
firstAccess = null;
dos.writeInt(set.size());
for (String i : firstAccess) {
for (String i : set) {
dos.writeUTF(i);
}
@@ -28,9 +28,11 @@ import java.util.List;
public class INMS {
private static final Version CURRENT = Boolean.getBoolean("iris.no-version-limit") ?
new Version(Integer.MAX_VALUE, Integer.MAX_VALUE, null) :
new Version(21, 8, null);
new Version(21, 11, null);
private static final List<Version> REVISION = List.of(
new Version(21, 11, "v1_21_R7"),
new Version(21, 9, "v1_21_R6"),
new Version(21, 6, "v1_21_R5"),
new Version(21, 5, "v1_21_R4"),
new Version(21, 4, "v1_21_R3"),
@@ -19,11 +19,8 @@
package com.volmit.iris.core.nms;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.container.AutoClosing;
import com.volmit.iris.core.link.FoliaWorldsLink;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.nms.container.StructurePlacement;
import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.engine.framework.Engine;
@@ -44,7 +41,6 @@ import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack;
import java.awt.Color;
import java.util.concurrent.CompletableFuture;
import java.util.List;
public interface INMSBinding {
@@ -103,15 +99,6 @@ public interface INMSBinding {
return c.createWorld();
}
default CompletableFuture<World> createWorldAsync(WorldCreator c) {
try {
var link = FoliaWorldsLink.get();
return link.isActive() ? link.createWorld(c) : CompletableFuture.completedFuture(createWorld(c));
} catch (Throwable e) {
return CompletableFuture.failedFuture(e);
}
}
int countCustomBiomes();
void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk);
@@ -135,7 +122,7 @@ public interface INMSBinding {
Color getBiomeColor(Location location, BiomeColor type);
default DataVersion getDataVersion() {
return DataVersion.V1192;
return DataVersion.V1_19_2;
}
default int getSpawnChunkCount(World world) {
@@ -17,7 +17,7 @@ public class BlockProperty {
private final Function<Object, String> nameFunction;
private final Function<Object, Object> jsonFunction;
public <T extends Comparable<T>> BlockProperty(
public <T extends Comparable<T>> BlockProperty(
String name,
Class<T> type,
T defaultValue,
@@ -42,7 +42,7 @@ public class BlockProperty {
);
}
public static BlockProperty ofFloat(String name, float defaultValue, float min, float max, boolean exclusiveMin, boolean exclusiveMax) {
public static BlockProperty ofDouble(String name, float defaultValue, float min, float max, boolean exclusiveMin, boolean exclusiveMax) {
return new BoundedDouble(
name,
defaultValue,
@@ -54,6 +54,18 @@ public class BlockProperty {
);
}
public static BlockProperty ofLong(String name, long defaultValue, long min, long max, boolean exclusiveMin, boolean exclusiveMax) {
return new BoundedLong(
name,
defaultValue,
min,
max,
exclusiveMin,
exclusiveMax,
(l) -> Long.toString(l)
);
}
public static BlockProperty ofBoolean(String name, boolean defaultValue) {
return new BlockProperty(
name,
@@ -122,6 +134,36 @@ public class BlockProperty {
return Objects.hash(name, values, type);
}
private static class BoundedLong extends BlockProperty {
private final long min, max;
private final boolean exclusiveMin, exclusiveMax;
public BoundedLong(
String name,
long defaultValue,
long min,
long max,
boolean exclusiveMin,
boolean exclusiveMax,
Function<Long, String> nameFunction
) {
super(name, Long.class, defaultValue, List.of(), nameFunction);
this.min = min;
this.max = max;
this.exclusiveMin = exclusiveMin;
this.exclusiveMax = exclusiveMax;
}
@Override
public JSONObject buildJson() {
return super.buildJson()
.put("minimum", min)
.put("maximum", max)
.put("exclusiveMinimum", exclusiveMin)
.put("exclusiveMaximum", exclusiveMax);
}
}
private static class BoundedDouble extends BlockProperty {
private final double min, max;
private final boolean exclusiveMin, exclusiveMax;
@@ -4,6 +4,7 @@ import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.datapack.v1192.DataFixerV1192;
import com.volmit.iris.core.nms.datapack.v1206.DataFixerV1206;
import com.volmit.iris.core.nms.datapack.v1213.DataFixerV1213;
import com.volmit.iris.core.nms.datapack.v1217.DataFixerV1217;
import com.volmit.iris.util.collection.KMap;
import lombok.AccessLevel;
import lombok.Getter;
@@ -14,9 +15,10 @@ import java.util.function.Supplier;
@Getter
public enum DataVersion {
UNSUPPORTED("0.0.0", 0, () -> null),
V1192("1.19.2", 10, DataFixerV1192::new),
V1205("1.20.6", 41, DataFixerV1206::new),
V1213("1.21.3", 57, DataFixerV1213::new);
V1_19_2("1.19.2", 10, DataFixerV1192::new),
V1_20_5("1.20.6", 41, DataFixerV1206::new),
V1_21_3("1.21.3", 57, DataFixerV1213::new),
V1_21_11("1.21.11", 75, DataFixerV1217::new);
private static final KMap<DataVersion, IDataFixer> cache = new KMap<>();
@Getter(AccessLevel.NONE)
private final Supplier<IDataFixer> constructor;
@@ -0,0 +1,170 @@
package com.volmit.iris.core.nms.datapack.v1217;
import com.volmit.iris.core.nms.datapack.v1213.DataFixerV1213;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject;
import java.util.Map;
public class DataFixerV1217 extends DataFixerV1213 {
private static final Map<Dimension, String> DIMENSIONS = Map.of(
Dimension.OVERWORLD, """
{
"ambient_light": 0.0,
"attributes": {
"minecraft:audio/ambient_sounds": {
"mood": {
"block_search_extent": 8,
"offset": 2.0,
"sound": "minecraft:ambient.cave",
"tick_delay": 6000
}
},
"minecraft:audio/background_music": {
"creative": {
"max_delay": 24000,
"min_delay": 12000,
"sound": "minecraft:music.creative"
},
"default": {
"max_delay": 24000,
"min_delay": 12000,
"sound": "minecraft:music.game"
}
},
"minecraft:visual/cloud_color": "#ccffffff",
"minecraft:visual/fog_color": "#c0d8ff",
"minecraft:visual/sky_color": "#78a7ff"
},
"timelines": "#minecraft:in_overworld"
}""",
Dimension.NETHER, """
{
"ambient_light": 0.1,
"attributes": {
"minecraft:gameplay/sky_light_level": 4.0,
"minecraft:gameplay/snow_golem_melts": true,
"minecraft:visual/fog_end_distance": 96.0,
"minecraft:visual/fog_start_distance": 10.0,
"minecraft:visual/sky_light_color": "#7a7aff",
"minecraft:visual/sky_light_factor": 0.0
},
"cardinal_light": "nether",
"skybox": "none",
"timelines": "#minecraft:in_nether"
}""",
Dimension.END, """
{
"ambient_light": 0.25,
"attributes": {
"minecraft:audio/ambient_sounds": {
"mood": {
"block_search_extent": 8,
"offset": 2.0,
"sound": "minecraft:ambient.cave",
"tick_delay": 6000
}
},
"minecraft:audio/background_music": {
"default": {
"max_delay": 24000,
"min_delay": 6000,
"replace_current_music": true,
"sound": "minecraft:music.end"
}
},
"minecraft:visual/fog_color": "#181318",
"minecraft:visual/sky_color": "#000000",
"minecraft:visual/sky_light_color": "#e580ff",
"minecraft:visual/sky_light_factor": 0.0
},
"skybox": "end",
"timelines": "#minecraft:in_end"
}"""
);
@Override
public JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
json = super.fixCustomBiome(biome, json);
var effects = json.getJSONObject("effects");
var attributes = new JSONObject();
attributes.put("minecraft:visual/fog_color", effects.remove("fog_color"));
attributes.put("minecraft:visual/sky_color", effects.remove("sky_color"));
attributes.put("minecraft:visual/water_fog_color", effects.remove("water_fog_color"));
JSONObject particle = (JSONObject) effects.remove("particle");
if (particle != null) {
particle.put("particle", particle.remove("options"));
attributes.put("minecraft:visual/ambient_particles", new JSONArray()
.put(particle));
}
json.put("attributes", attributes);
return json;
}
@Override
public void fixDimension(Dimension dimension, JSONObject json) {
super.fixDimension(dimension, json);
var attributes = new JSONObject();
if ((Boolean) json.remove("ultrawarm")) {
attributes.put("minecraft:gameplay/water_evaporates", true);
attributes.put("minecraft:gameplay/fast_lava", true);
attributes.put("minecraft:gameplay/snow_golem_melts", true);
attributes.put("minecraft:visual/default_dripstone_particle", new JSONObject()
.put("type", "minecraft:dripping_dripstone_lava"));
}
if ((Boolean) json.remove("bed_works")) {
attributes.put("minecraft:gameplay/bed_rule", new JSONObject()
.put("can_set_spawn", "always")
.put("can_sleep", "when_dark")
.put("error_message", new JSONObject()
.put("translate", "block.minecraft.bed.no_sleep")));
} else {
attributes.put("minecraft:gameplay/bed_rule", new JSONObject()
.put("can_set_spawn", "never")
.put("can_sleep", "never")
.put("explodes", true));
}
attributes.put("minecraft:gameplay/respawn_anchor_works", json.remove("respawn_anchor_works"));
attributes.put("minecraft:gameplay/piglins_zombify", json.remove("piglin_safe"));
attributes.put("minecraft:gameplay/can_start_raid", json.remove("has_raids"));
var cloud_height = json.remove("cloud_height");
if (cloud_height != null) attributes.put("minecraft:visual/cloud_height", cloud_height);
boolean natural = (Boolean) json.remove("natural");
attributes.put("minecraft:gameplay/nether_portal_spawns_piglin", natural);
if (natural != (dimension == Dimension.OVERWORLD)) {
attributes.put("minecraft:gameplay/eyeblossom_open", natural);
attributes.put("minecraft:gameplay/creaking_active", natural);
}
//json.put("has_fixed_time", json.remove("fixed_time") != null); //TODO investigate
json.put("attributes", attributes);
json.remove("effects");
var defaults = new JSONObject(DIMENSIONS.get(dimension));
merge(json, defaults);
}
private void merge(JSONObject base, JSONObject override) {
for (String key : override.keySet()) {
switch (base.opt(key)) {
case null -> base.put(key, override.opt(key));
case JSONObject base1 when override.opt(key) instanceof JSONObject override1 -> merge(base1, override1);
case JSONArray base1 when override.opt(key) instanceof JSONArray override1 -> {
for (Object o : override1) {
base1.put(o);
}
}
default -> {}
}
}
}
}
@@ -2,25 +2,24 @@ package com.volmit.iris.core.pregenerator;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.service.PreservationSVC;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.plugin.chunk.TicketHolder;
import com.volmit.iris.util.profile.LoadBalancer;
import com.volmit.iris.util.scheduling.J;
import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -30,7 +29,7 @@ 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<>();
private final TicketHolder holder;
private final RollingSequence chunksPerSecond = new RollingSequence(5);
private final AtomicInteger totalMaxChunks = new AtomicInteger();
private final AtomicInteger chunksProcessed = new AtomicInteger();
@@ -39,13 +38,13 @@ public class ChunkUpdater {
private final AtomicBoolean serverEmpty = new AtomicBoolean(true);
private final AtomicLong lastCpsTime = new AtomicLong(M.ms());
private final int maxConcurrency = IrisSettings.get().getUpdater().getMaxConcurrency();
private final int coreLimit = (int) Math.max(Runtime.getRuntime().availableProcessors() * IrisSettings.get().getUpdater().getThreadMultiplier(), 1);
private final Semaphore semaphore = new Semaphore(maxConcurrency);
private final LoadBalancer loadBalancer = new LoadBalancer(semaphore, maxConcurrency, IrisSettings.get().getUpdater().emptyMsRange);
private final AtomicLong startTime = new AtomicLong();
private final Dimensions dimensions;
private final PregenTask task;
private final ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
private final ExecutorService chunkExecutor = Executors.newVirtualThreadPerTaskExecutor();
private final ExecutorService chunkExecutor = IrisSettings.get().getUpdater().isNativeThreads() ? Executors.newFixedThreadPool(coreLimit) : Executors.newVirtualThreadPerTaskExecutor();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private final CountDownLatch latch;
private final Engine engine;
@@ -54,6 +53,7 @@ public class ChunkUpdater {
public ChunkUpdater(World world) {
this.engine = IrisToolbelt.access(world).getEngine();
this.world = world;
this.holder = Iris.tickets.getHolder(world);
this.dimensions = calculateWorldDimensions(new File(world.getWorldFolder(), "region"));
this.task = dimensions.task();
this.totalMaxChunks.set(dimensions.count * 1024);
@@ -112,7 +112,6 @@ public class ChunkUpdater {
e.printStackTrace();
}
}, 0, 3, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(this::unloadChunks, 0, 1, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(() -> {
boolean empty = Bukkit.getOnlinePlayers().isEmpty();
if (serverEmpty.getAndSet(empty) == empty)
@@ -127,6 +126,7 @@ public class ChunkUpdater {
t.setPriority(Thread.MAX_PRIORITY);
t.start();
Iris.service(PreservationSVC.class).register(t);
} catch (Exception e) {
e.printStackTrace();
}
@@ -139,8 +139,6 @@ public class ChunkUpdater {
chunkExecutor.shutdown();
chunkExecutor.awaitTermination(5, TimeUnit.SECONDS);
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
scheduler.shutdownNow();
unloadAndSaveAllChunks();
} catch (Exception ignored) {}
@@ -199,20 +197,16 @@ public class ChunkUpdater {
return;
}
var mc = engine.getMantle().getMantle().getChunk(x, z).use();
try {
Chunk c = world.getChunkAt(x, z);
engine.getMantle().getMantle().getChunk(c);
engine.updateChunk(c);
for (int xx = -1; xx <= 1; xx++) {
for (int zz = -1; zz <= 1; zz++) {
var counter = lastUse.get(Cache.key(x + xx, z + zz));
if (counter != null) counter.getB().decrementAndGet();
}
}
removeTickets(x, z);
} finally {
chunksUpdated.incrementAndGet();
chunksProcessed.getAndIncrement();
mc.release();
}
}
@@ -222,7 +216,7 @@ public class ChunkUpdater {
for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) {
if (!Iris.platform.isChunkGenerated(world, x + dx, z + dz)) {
if (!PaperLib.isChunkGenerated(world, x + dx, z + dz)) {
return false;
}
}
@@ -234,41 +228,16 @@ public class ChunkUpdater {
for (int dz = -1; dz <= 1; dz++) {
int xx = x + dx;
int zz = z + dz;
executor.submit(() -> {
try {
Chunk c;
try {
c = Iris.platform.getChunkAtAsync(world, xx, zz, false, true)
.thenApply(chunk -> {
if (chunk != null)
chunk.addPluginChunkTicket(Iris.instance);
return chunk;
}).get();
} catch (InterruptedException | ExecutionException e) {
generated.set(false);
return;
}
if (c == null) {
generated.set(false);
return;
}
if (!c.isLoaded()) {
var future = J.sfut(() -> c.load(false));
if (future != null) future.join();
}
if (!Iris.platform.isChunkGenerated(c.getWorld(), xx, zz))
generated.set(false);
var pair = lastUse.computeIfAbsent(Cache.key(c), k -> new Pair<>(0L, new AtomicInteger(-1)));
pair.setA(M.ms());
pair.getB().updateAndGet(i -> i == -1 ? 1 : ++i);
} finally {
latch.countDown();
}
});
PaperLib.getChunkAtAsync(world, xx, zz, false, true)
.thenAccept(chunk -> {
if (chunk == null || !chunk.isGenerated()) {
latch.countDown();
generated.set(false);
return;
}
holder.addTicket(chunk);
latch.countDown();
});
}
}
@@ -277,27 +246,16 @@ public class ChunkUpdater {
} catch (InterruptedException e) {
Iris.info("Interrupted while waiting for chunks to load");
}
return generated.get();
if (generated.get()) return true;
removeTickets(x, z);
return false;
}
private synchronized void unloadChunks() {
for (var key : new ArrayList<>(lastUse.keySet())) {
if (key == null) continue;
var pair = lastUse.get(key);
if (pair == null) continue;
var lastUseTime = pair.getA();
var counter = pair.getB();
if (lastUseTime == null || counter == null)
continue;
if (M.ms() - lastUseTime >= 5000 && counter.get() == 0) {
int x = Cache.keyX(key);
int z = Cache.keyZ(key);
J.s(() -> {
world.removePluginChunkTicket(x, z, Iris.instance);
world.unloadChunk(x, z);
lastUse.remove(key);
});
private void removeTickets(int x, int z) {
for (int xx = -1; xx <= 1; xx++) {
for (int zz = -1; zz <= 1; zz++) {
holder.removeTicket(x + xx, z + zz);
}
}
}
@@ -310,7 +268,6 @@ public class ChunkUpdater {
return;
}
unloadChunks();
world.save();
}).get();
} catch (Throwable e) {
@@ -22,6 +22,7 @@ import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.io.FileWriter;
@@ -234,13 +235,16 @@ public class DeepSearchPregenerator extends Thread implements Listener {
}
save();
jobs.remove(world.getName());
J.a(() -> {
while (deepFile.exists()) {
deepFile.delete();
J.sleep(1000);
new BukkitRunnable() {
@Override
public void run() {
while (deepFile.exists()){
deepFile.delete();
J.sleep(1000);
}
Iris.info("DeepSearch: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
}
Iris.info("DeepSearch: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
}, 10);
}.runTaskLater(Iris.instance, 20L);
} catch (Exception e) {
Iris.error("Failed to shutdown DeepSearch for " + world.getName());
e.printStackTrace();
@@ -11,6 +11,7 @@ import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import io.papermc.lib.PaperLib;
import lombok.Data;
import lombok.Getter;
import org.bukkit.Bukkit;
@@ -18,6 +19,7 @@ import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.io.IOException;
@@ -147,9 +149,23 @@ public class LazyPregenerator extends Thread implements Listener {
private void tickGenerate(Position2 chunk) {
executorService.submit(() -> {
Iris.platform.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true).thenAccept((i) -> {
Iris.verbose("Generated Async " + chunk);
}).join();
CountDownLatch latch = new CountDownLatch(1);
if (PaperLib.isPaper()) {
PaperLib.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true)
.thenAccept((i) -> {
Iris.verbose("Generated Async " + chunk);
latch.countDown();
});
} else {
J.s(() -> {
world.getChunkAt(chunk.getX(), chunk.getZ());
Iris.verbose("Generated " + chunk);
latch.countDown();
});
}
try {
latch.await();
} catch (InterruptedException ignored) {}
lazyGeneratedChunks.addAndGet(1);
});
}
@@ -222,13 +238,16 @@ public class LazyPregenerator extends Thread implements Listener {
}
save();
jobs.remove(world.getName());
J.a(() -> {
while (lazyFile.exists()){
lazyFile.delete();
J.sleep(1000);
new BukkitRunnable() {
@Override
public void run() {
while (lazyFile.exists()){
lazyFile.delete();
J.sleep(1000);
}
Iris.info("LazyGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
}
Iris.info("LazyGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
}, 20);
}.runTaskLater(Iris.instance, 20L);
} catch (Exception e) {
Iris.error("Failed to shutdown Lazygen for " + world.getName());
e.printStackTrace();
@@ -17,6 +17,7 @@ import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import io.papermc.lib.PaperLib;
import lombok.Data;
import lombok.Getter;
import org.apache.logging.log4j.core.util.ExecutorServices;
@@ -25,6 +26,7 @@ import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.scheduler.BukkitRunnable;
import org.checkerframework.checker.units.qual.N;
import java.io.File;
@@ -225,7 +227,7 @@ public class TurboPregenerator extends Thread implements Listener {
private void tickGenerate(Position2 chunk) {
executorService.submit(() -> {
CountDownLatch latch = new CountDownLatch(1);
Iris.platform.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true)
PaperLib.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true)
.thenAccept((i) -> {
latch.countDown();
});
@@ -300,13 +302,16 @@ public class TurboPregenerator extends Thread implements Listener {
}
save();
jobs.remove(world.getName());
J.a(() -> {
while (turboFile.exists()) {
turboFile.delete();
J.sleep(1000);
new BukkitRunnable() {
@Override
public void run() {
while (turboFile.exists()) {
turboFile.delete();
J.sleep(1000);
}
Iris.info("turboGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
}
Iris.info("turboGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
}, 20);
}.runTaskLater(Iris.instance, 20L);
} catch (Exception e) {
Iris.error("Failed to shutdown turbogen for " + world.getName());
e.printStackTrace();
@@ -24,9 +24,11 @@ public interface PregenCache {
void write();
void trim(long unloadDuration);
static PregenCache create(File directory) {
if (directory == null) return EMPTY;
return new PregenCacheImpl(directory);
return new PregenCacheImpl(directory, 16);
}
default PregenCache sync() {
@@ -51,19 +53,16 @@ public interface PregenCache {
}
@Override
public void cacheChunk(int x, int z) {
}
public void cacheChunk(int x, int z) {}
@Override
public void cacheRegion(int x, int z) {
}
public void cacheRegion(int x, int z) {}
@Override
public void write() {
public void write() {}
}
@Override
public void trim(long unloadDuration) {}
};
@@ -1,220 +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.github.benmanes.caffeine.cache.Scheduler;
import com.volmit.iris.Iris;
import com.volmit.iris.util.data.KCache;
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 java.io.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
@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)
.executor(KCache.EXECUTOR)
.scheduler(Scheduler.systemScheduler())
.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) {}
}
@@ -1,11 +1,6 @@
package com.volmit.iris.core.pregenerator.cache;
import lombok.AllArgsConstructor;
@AllArgsConstructor
class SynchronizedCache implements PregenCache {
private final PregenCache cache;
record SynchronizedCache(PregenCache cache) implements PregenCache {
@Override
public boolean isThreadSafe() {
return true;
@@ -45,4 +40,11 @@ class SynchronizedCache implements PregenCache {
cache.write();
}
}
@Override
public void trim(long unloadDuration) {
synchronized (cache) {
cache.trim(unloadDuration);
}
}
}
@@ -0,0 +1,73 @@
/*
* 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.pregenerator.methods;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.util.mantle.Mantle;
import io.papermc.lib.PaperLib;
import org.bukkit.World;
public class AsyncOrMedievalPregenMethod implements PregeneratorMethod {
private final PregeneratorMethod method;
public AsyncOrMedievalPregenMethod(World world, int threads) {
method = PaperLib.isPaper() ? new AsyncPregenMethod(world, threads) : new MedievalPregenMethod(world);
}
@Override
public void init() {
method.init();
}
@Override
public void close() {
method.close();
}
@Override
public void save() {
method.save();
}
@Override
public String getMethod(int x, int z) {
return method.getMethod(x, z);
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
method.generateChunk(x, z, listener);
}
@Override
public Mantle getMantle() {
return method.getMantle();
}
}
@@ -23,17 +23,17 @@ 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;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.J;
import io.papermc.lib.PaperLib;
import org.bukkit.Chunk;
import org.bukkit.World;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
@@ -48,7 +48,11 @@ public class AsyncPregenMethod implements PregeneratorMethod {
private final boolean urgent;
private final Map<Chunk, Long> lastUse;
public AsyncPregenMethod(World world) {
public AsyncPregenMethod(World world, int unusedThreads) {
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();
@@ -59,28 +63,26 @@ public class AsyncPregenMethod implements PregeneratorMethod {
private void unloadAndSaveAllChunks() {
try {
if (world == null) {
Iris.warn("World was null somehow...");
return;
}
long minTime = M.ms() - 10_000;
KList<CompletableFuture<?>> futures = new KList<>();
lastUse.entrySet().removeIf(i -> {
final Chunk chunk = i.getKey();
final Long lastUseTime = i.getValue();
if (!chunk.isLoaded() || lastUseTime == null)
return true;
if (lastUseTime < minTime) {
futures.add(Iris.platform.getRegionScheduler()
.run(chunk.getWorld(), chunk.getX(), chunk.getZ(), () -> chunk.unload())
.getResult());
return true;
J.sfut(() -> {
if (world == null) {
Iris.warn("World was null somehow...");
return;
}
return false;
});
futures.add(Iris.platform.getRegionScheduler().run(world, 0, 0, world::save).getResult());
CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).join();
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;
}
return false;
});
world.save();
}).get();
} catch (Throwable e) {
e.printStackTrace();
}
@@ -195,7 +197,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
public void generate(int x, int z, PregenListener listener) {
service.submit(() -> {
try {
Iris.platform.getChunkAtAsync(world, x, z, true, urgent).thenAccept((i) -> {
PaperLib.getChunkAtAsync(world, x, z, true, urgent).thenAccept((i) -> {
listener.onChunkGenerated(x, z);
listener.onChunkCleaned(x, z);
if (i == null) return;
@@ -220,7 +222,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
private class TicketExecutor implements Executor {
@Override
public void generate(int x, int z, PregenListener listener) {
Iris.platform.getChunkAtAsync(world, x, z, true, urgent)
PaperLib.getChunkAtAsync(world, x, z, true, urgent)
.exceptionally(e -> {
Iris.reportError(e);
e.printStackTrace();
@@ -0,0 +1,74 @@
/*
* 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.pregenerator.methods;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.util.mantle.Mantle;
import org.bukkit.World;
public class HybridPregenMethod implements PregeneratorMethod {
private final PregeneratorMethod inWorld;
private final World world;
public HybridPregenMethod(World world, int threads) {
this.world = world;
inWorld = new AsyncOrMedievalPregenMethod(world, threads);
}
@Override
public String getMethod(int x, int z) {
return "Hybrid<" + inWorld.getMethod(x, z) + ">";
}
@Override
public void init() {
inWorld.init();
}
@Override
public void close() {
inWorld.close();
}
@Override
public void save() {
inWorld.save();
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return inWorld.supportsRegions(x, z, listener);
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
inWorld.generateRegion(x, z, listener);
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
inWorld.generateChunk(x, z, listener);
}
@Override
public Mantle getMantle() {
return inWorld.getMantle();
}
}
@@ -0,0 +1,138 @@
/*
* 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.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;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class MedievalPregenMethod implements PregeneratorMethod {
private final World world;
private final KList<CompletableFuture<?>> futures;
private final Map<Chunk, Long> lastUse;
public MedievalPregenMethod(World world) {
this.world = world;
futures = new KList<>();
this.lastUse = new KMap<>();
}
private void waitForChunks() {
for (CompletableFuture<?> i : futures) {
try {
i.get();
} catch (Throwable e) {
e.printStackTrace();
}
}
futures.clear();
}
private void unloadAndSaveAllChunks() {
try {
J.sfut(() -> {
if (world == null) {
Iris.warn("World was null somehow...");
return;
}
for (Chunk i : new ArrayList<>(lastUse.keySet())) {
Long lastUseTime = lastUse.get(i);
if (lastUseTime != null && M.ms() - lastUseTime >= 10) {
i.unload();
lastUse.remove(i);
}
}
world.save();
}).get();
} catch (Throwable e) {
e.printStackTrace();
}
}
@Override
public void init() {
unloadAndSaveAllChunks();
}
@Override
public void close() {
unloadAndSaveAllChunks();
}
@Override
public void save() {
unloadAndSaveAllChunks();
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
throw new UnsupportedOperationException();
}
@Override
public String getMethod(int x, int z) {
return "Medieval";
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
if (futures.size() > IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())) {
waitForChunks();
}
listener.onChunkGenerating(x, z);
futures.add(J.sfut(() -> {
world.getChunkAt(x, z);
Chunk c = Bukkit.getWorld(world.getUID()).getChunkAt(x, z);
lastUse.put(c, M.ms());
listener.onChunkGenerated(x, z);
listener.onChunkCleaned(x, z);
}));
}
@Override
public Mantle getMantle() {
if (IrisToolbelt.isIrisWorld(world)) {
return IrisToolbelt.access(world).getEngine().getMantle().getMantle();
}
return null;
}
}
@@ -9,9 +9,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Optional;
import java.util.Scanner;
import java.util.*;
public class Gradle {
private static final boolean WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
@@ -38,10 +36,15 @@ public class Gradle {
cmd[0] = gradle.getAbsolutePath();
System.arraycopy(args, 0, cmd, 1, args.length);
var process = Runtime.getRuntime().exec(cmd, ENVIRONMENT, projectDir);
attach(process.getInputStream());
attach(process.getErrorStream());
var lines = Collections.synchronizedList(new ArrayList<String>());
attach(process.getInputStream(), lines);
attach(process.getErrorStream(), lines);
var code = process.waitFor();
if (code == 0) return;
if (code == 0) {
lines.forEach(Iris::debug);
return;
}
lines.forEach(Iris::error);
throw new RuntimeException("Gradle exited with code " + code);
}
@@ -91,12 +94,12 @@ public class Gradle {
.orElseThrow(() -> new RuntimeException("Failed to find java home, please set java.home system property"));
}
private static void attach(InputStream stream) {
Thread.ofVirtual().start(() -> {
private static void attach(InputStream stream, List<String> list) {
Thread.ofPlatform().start(() -> {
try (var in = new Scanner(stream)) {
while (in.hasNextLine()) {
String line = in.nextLine();
Iris.debug("[GRADLE] " + line);
list.add(line);
}
}
});
@@ -24,7 +24,6 @@ import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.core.scripting.environment.SimpleEnvironment;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.object.annotations.Snippet;
@@ -226,7 +225,7 @@ public class IrisProject {
sender.sendMessage("Can't find dimension: " + getName());
return;
} else if (sender.isPlayer()) {
sender.player().setGameMode(GameMode.SPECTATOR);
J.s(() -> sender.player().setGameMode(GameMode.SPECTATOR));
}
try {
@@ -326,7 +325,7 @@ public class IrisProject {
}
}
for (Class<?> i : Iris.getClasses("com.volmit.iris.engine.object.", Snippet.class)) {
for (Class<?> i : dm.resolveSnippets()) {
try {
String snipType = i.getDeclaredAnnotation(Snippet.class).value();
JSONObject o = new JSONObject();
@@ -38,6 +38,7 @@ import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.lang.reflect.Field;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
@@ -117,49 +118,13 @@ public class SchemaBuilder {
JSONArray required = new JSONArray();
JSONArray extended = new JSONArray();
if (c.isAssignableFrom(IrisRegistrant.class) || IrisRegistrant.class.isAssignableFrom(c)) {
for (Field k : IrisRegistrant.class.getDeclaredFields()) {
k.setAccessible(true);
if (Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
continue;
}
JSONObject property = buildProperty(k, c);
if (Boolean.TRUE == property.remove("!required")) {
required.put(k.getName());
}
if (Boolean.TRUE == property.remove("!top")) {
extended.put(property);
continue;
}
properties.put(k.getName(), property);
}
var parent = c.getSuperclass();
while (parent != null && IrisRegistrant.class.isAssignableFrom(parent)) {
buildProperties(properties, required, extended, parent);
parent = parent.getSuperclass();
}
for (Field k : c.getDeclaredFields()) {
k.setAccessible(true);
if (Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
continue;
}
JSONObject property = buildProperty(k, c);
if (Boolean.TRUE == property.remove("!required")) {
required.put(k.getName());
}
if (Boolean.TRUE == property.remove("!top")) {
extended.put(property);
continue;
}
properties.put(k.getName(), property);
}
buildProperties(properties, required, extended, c);
if (required.length() > 0) {
o.put("required", required);
@@ -174,6 +139,33 @@ public class SchemaBuilder {
return buildSnippet(o, c);
}
private void buildProperties(JSONObject properties, JSONArray required, JSONArray extended, Class<?> c) {
for (Field k : c.getDeclaredFields()) {
if (Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
continue;
}
try {
k.setAccessible(true);
} catch (InaccessibleObjectException e) {
continue;
}
JSONObject property = buildProperty(k, c);
if (Boolean.TRUE == property.remove("!top")) {
extended.put(property);
continue;
}
if (Boolean.TRUE == property.remove("!required")) {
required.put(k.getName());
}
properties.put(k.getName(), property);
}
}
private JSONObject buildProperty(Field k, Class<?> cl) {
JSONObject prop = new JSONObject();
String type = getType(k.getType());
@@ -616,7 +608,7 @@ public class SchemaBuilder {
if (present) d.add(" ");
if (value instanceof List) {
d.add(SYMBOL_LIMIT__N + " Default Value is an empty list");
} else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum()) && !KeyedType.isKeyed(cl)) {
} else if (!k.getType().isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(value instanceof Enum<?>) && !KeyedType.isKeyed(k.getType())) {
d.add(SYMBOL_LIMIT__N + " Default Value is a default object (create this object to see default properties)");
} else {
d.add(SYMBOL_LIMIT__N + " Default Value is " + value);
@@ -1,64 +0,0 @@
package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import io.papermc.lib.PaperLib;
import java.util.concurrent.atomic.AtomicBoolean;
public class IrisSafeguard {
private static final AtomicBoolean sfg = new AtomicBoolean(false);
public static boolean unstablemode = false;
public static boolean warningmode = false;
public static boolean stablemode = false;
public static void IrisSafeguardSystem() {
Iris.info("Enabled Iris SafeGuard");
ServerBootSFG.BootCheck();
}
public static void splash(boolean early) {
if (early && (ServerBootSFG.safeguardPassed || IrisSettings.get().getGeneral().DoomsdayAnnihilationSelfDestructMode))
return;
if (!sfg.getAndSet(true)) {
Iris.instance.splash();
UtilsSFG.splash();
}
}
public static String mode() {
if (unstablemode) {
return "unstable";
} else if (warningmode) {
return "warning";
} else {
return "stable";
}
}
public static void suggestPaper() {
PaperLib.suggestPaper(Iris.instance);
}
public static KMap<String, Object> asContext() {
KMap<String, Object> m = new KMap<>();
m.put("diskSpace", !ServerBootSFG.hasEnoughDiskSpace);
m.put("javaVersion", !ServerBootSFG.isCorrectJDK);
m.put("jre", ServerBootSFG.isJRE);
m.put("missingAgent", ServerBootSFG.missingAgent);
m.put("missingDimensionTypes", ServerBootSFG.missingDimensionTypes);
m.put("failedInjection", ServerBootSFG.failedInjection);
m.put("unsupportedVersion", ServerBootSFG.unsuportedversion);
m.put("serverSoftware", !ServerBootSFG.passedserversoftware);
KList<String> incompatiblePlugins = new KList<>();
ServerBootSFG.incompatibilities.forEach((plugin, present) -> {
if (present) incompatiblePlugins.add(plugin);
});
m.put("plugins", incompatiblePlugins);
return m;
}
}
@@ -1,80 +0,0 @@
package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.util.format.C;
public class ModesSFG {
public static void selectMode() {
if (IrisSafeguard.unstablemode) {
Iris.safeguard(C.DARK_RED + "Iris is running in Unstable Mode");
unstable();
}
if (IrisSafeguard.warningmode) {
Iris.safeguard(C.GOLD + "Iris is running in Warning Mode");
warning();
}
if (IrisSafeguard.stablemode) {
stable();
}
}
public static void stable() {
Iris.safeguard(C.BLUE + "Iris is running Stable");
}
public static void unstable() {
UtilsSFG.printIncompatibleWarnings();
if (IrisSafeguard.unstablemode) {
Iris.info("");
Iris.info(C.DARK_GRAY + "--==<" + C.RED + " IMPORTANT " + C.DARK_GRAY + ">==--");
Iris.info(C.RED + "Iris is running in unstable mode which may cause the following issues:");
Iris.info(C.DARK_RED + "Server Issues");
Iris.info(C.RED + "- Server won't boot");
Iris.info(C.RED + "- Data Loss");
Iris.info(C.RED + "- Unexpected behavior.");
Iris.info(C.RED + "- And More...");
Iris.info(C.DARK_RED + "World Issues");
Iris.info(C.RED + "- Worlds can't load due to corruption.");
Iris.info(C.RED + "- Worlds may slowly corrupt until they can't load.");
Iris.info(C.RED + "- World data loss.");
Iris.info(C.RED + "- And More...");
Iris.info(C.DARK_RED + "ATTENTION: " + C.RED + "While running Iris in unstable mode, you won't be eligible for support.");
Iris.info(C.DARK_RED + "CAUSE: " + C.RED + UtilsSFG.MSGIncompatibleWarnings());
if (IrisSettings.get().getGeneral().DoomsdayAnnihilationSelfDestructMode) {
Iris.info(C.DARK_RED + "Boot Unstable is set to true, continuing with the startup process.");
} else {
Iris.info(C.DARK_RED + "Go to plugins/iris/settings.json and set DoomsdayAnnihilationSelfDestructMode to true if you wish to proceed.");
while (true) {
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
// no
}
}
}
Iris.info("");
}
}
public static void warning() {
UtilsSFG.printIncompatibleWarnings();
if (IrisSafeguard.warningmode) {
Iris.info("");
Iris.info(C.DARK_GRAY + "--==<" + C.GOLD + " IMPORTANT " + C.DARK_GRAY + ">==--");
Iris.info(C.GOLD + "Iris is running in warning mode which may cause the following issues:");
Iris.info(C.YELLOW + "- Data Loss");
Iris.info(C.YELLOW + "- Errors");
Iris.info(C.YELLOW + "- Broken worlds");
Iris.info(C.YELLOW + "- Unexpected behavior.");
Iris.info(C.YELLOW + "- And perhaps further complications.");
Iris.info(C.GOLD + "CAUSE: " + C.YELLOW + UtilsSFG.MSGIncompatibleWarnings());
Iris.info("");
}
}
}
@@ -1,8 +0,0 @@
package com.volmit.iris.core.safeguard;
public class PerformanceSFG {
public static void calculatePerformance() {
}
}
@@ -1,194 +0,0 @@
package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisWorlds;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.agent.Agent;
import com.volmit.iris.util.collection.KSet;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.stream.Collectors;
import static com.volmit.iris.Iris.getJavaVersion;
import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
public class ServerBootSFG {
public static final Map<String, Boolean> incompatibilities = new HashMap<>();
public static boolean isCorrectJDK = true;
public static boolean hasEnoughDiskSpace = true;
public static boolean isJRE = false;
public static boolean hasPrivileges = true;
public static boolean unsuportedversion = false;
public static boolean missingDimensionTypes = false;
public static boolean missingAgent = false;
public static boolean failedInjection = false;
protected static boolean safeguardPassed;
public static boolean passedserversoftware = true;
protected static int count;
protected static byte severityLow;
protected static byte severityMedium;
protected static byte severityHigh;
public static String allIncompatibilities;
public static void BootCheck() {
Iris.info("Checking for possible conflicts..");
PluginManager pluginManager = Bukkit.getPluginManager();
Plugin[] plugins = pluginManager.getPlugins();
incompatibilities.clear();
incompatibilities.put("dynmap", false);
incompatibilities.put("Stratos", false);
String pluginName;
for (Plugin plugin : plugins) {
pluginName = plugin.getName();
Boolean flag = incompatibilities.get(pluginName);
if (flag != null && !flag) {
severityHigh++;
incompatibilities.put(pluginName, true);
}
}
StringJoiner joiner = new StringJoiner(", ");
for (Map.Entry<String, Boolean> entry : incompatibilities.entrySet()) {
if (entry.getValue()) {
joiner.add(entry.getKey());
}
}
// Legacy ServerInfo
String distro = Bukkit.getName().toLowerCase();
if (
!distro.contains("purpur") &&
!distro.contains("paper") &&
!distro.contains("spigot") &&
!distro.contains("pufferfish") &&
!distro.contains("bukkit")) {
passedserversoftware = false;
joiner.add("Server Software");
severityMedium++;
}
if (INMS.get() instanceof NMSBinding1X) {
unsuportedversion = true;
joiner.add("Unsupported Minecraft Version");
severityHigh++;
}
if (!List.of(21).contains(getJavaVersion())) {
isCorrectJDK = false;
joiner.add("Unsupported Java version");
severityMedium++;
}
if (!isJDK()) {
isJRE = true;
joiner.add("Unsupported JDK");
severityMedium++;
}
// if (!hasPrivileges()){
// hasPrivileges = false;
// joiner.add("Insufficient Privileges");
// severityMedium++;
// } Some servers dont like this
if (!enoughDiskSpace()){
hasEnoughDiskSpace = false;
joiner.add("Insufficient Disk Space");
severityMedium++;
}
if (!Agent.install()) {
missingAgent = true;
joiner.add("Missing Java Agent");
severityHigh++;
} else {
if (missingDimensionTypes()) {
missingDimensionTypes = true;
joiner.add("Missing Dimension Types");
severityHigh++;
}
if (!INMS.get().injectBukkit()) {
failedInjection = true;
joiner.add("Failed Bukkit Injection");
severityHigh++;
}
}
allIncompatibilities = joiner.toString();
safeguardPassed = (severityHigh == 0 && severityMedium == 0 && severityLow == 0);
count = severityHigh + severityMedium + severityLow;
if (safeguardPassed) {
stablemode = true;
Iris.safeguard("Stable mode has been activated.");
}
if (!safeguardPassed) {
if (severityMedium >= 1 && severityHigh == 0) {
warningmode = true;
Iris.safeguard("Warning mode has been activated.");
}
if (severityHigh >= 1) {
unstablemode = true;
Iris.safeguard("Unstable mode has been activated.");
}
}
}
public static boolean isJDK() {
try {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// If the compiler is null, it means this is a JRE environment, not a JDK.
return compiler != null;
} catch (Exception ignored) {}
return false;
}
public static boolean hasPrivileges() {
Path pv = Paths.get(Bukkit.getWorldContainer() + "iristest.json");
try (FileChannel fc = FileChannel.open(pv, StandardOpenOption.CREATE, StandardOpenOption.DELETE_ON_CLOSE, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
if (Files.isReadable(pv) && Files.isWritable(pv)) {
return true;
}
} catch (Exception e) {
return false;
}
return false;
}
public static boolean enoughDiskSpace() {
File freeSpace = Bukkit.getWorldContainer();
double gigabytes = freeSpace.getFreeSpace() / (1024.0 * 1024.0 * 1024.0);
return gigabytes > 3;
}
private static boolean checkJavac(String path) {
return !path.isEmpty() && (new File(path, "javac").exists() || new File(path, "javac.exe").exists());
}
private static boolean missingDimensionTypes() {
return INMS.get().missingDimensionTypes(getDimensionTypes().toArray(String[]::new));
}
private static KSet<String> getDimensionTypes() {
return IrisWorlds.get()
.getDimensions()
.map(IrisDimension::getDimensionTypeKey)
.collect(Collectors.toCollection(KSet::new));
}
}
@@ -1,76 +0,0 @@
package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris;
import com.volmit.iris.util.agent.Agent;
import com.volmit.iris.util.format.C;
public class UtilsSFG {
public static void splash() {
ModesSFG.selectMode();
}
public static void printIncompatibleWarnings() {
String[] parts = Iris.instance.getDescription().getVersion().split("-");
String minVersion = parts[1];
String maxVersion = parts[2];
if (ServerBootSFG.safeguardPassed) {
Iris.safeguard(C.BLUE + "0 Conflicts found");
} else {
if (IrisSafeguard.unstablemode) {
Iris.safeguard(C.DARK_RED + "" + ServerBootSFG.count + " Conflicts found");
}
if (IrisSafeguard.warningmode) {
Iris.safeguard(C.YELLOW + "" + ServerBootSFG.count + " Conflicts found");
}
if (ServerBootSFG.incompatibilities.get("dynmap")) {
Iris.safeguard(C.RED + "Dynmap");
Iris.safeguard(C.RED + "- The plugin Dynmap is not compatible with the server.");
Iris.safeguard(C.RED + "- If you want to have a map plugin like Dynmap, consider Bluemap.");
}
if (ServerBootSFG.incompatibilities.get("Stratos")) {
Iris.safeguard(C.YELLOW + "Stratos");
Iris.safeguard(C.YELLOW + "- Iris is not compatible with other worldgen plugins.");
}
if (ServerBootSFG.unsuportedversion) {
Iris.safeguard(C.RED + "Server Version");
Iris.safeguard(C.RED + "- Iris only supports " + minVersion + " > " + maxVersion);
}
if (ServerBootSFG.missingDimensionTypes) {
Iris.safeguard(C.RED + "Dimension Types");
Iris.safeguard(C.RED + "- Required Iris dimension types were not loaded.");
Iris.safeguard(C.RED + "- If this still happens after a restart please contact support.");
}
if (ServerBootSFG.missingAgent) {
Iris.safeguard(C.RED + "Java Agent");
Iris.safeguard(C.RED + "- Please enable dynamic agent loading by adding -XX:+EnableDynamicAgentLoading to your jvm arguments.");
Iris.safeguard(C.RED + "- or add the jvm argument -javaagent:" + Agent.AGENT_JAR.getPath());
}
if (!ServerBootSFG.passedserversoftware) {
Iris.safeguard(C.YELLOW + "Unsupported Server Software");
Iris.safeguard(C.YELLOW + "- Please consider using Paper or Purpur instead.");
}
if (!ServerBootSFG.hasPrivileges) {
Iris.safeguard(C.YELLOW + "Insufficient Privileges");
Iris.safeguard(C.YELLOW + "- The server has insufficient Privileges to run iris. Please contact support.");
}
if (!ServerBootSFG.hasEnoughDiskSpace) {
Iris.safeguard(C.YELLOW + "Insufficient Disk Space");
Iris.safeguard(C.YELLOW + "- The server has insufficient Free DiskSpace to run iris required 3GB+.");
}
if (!ServerBootSFG.isCorrectJDK) {
Iris.safeguard(C.YELLOW + "Unsupported java version");
Iris.safeguard(C.YELLOW + "- Please consider using JDK 21 Instead of JDK " + Iris.getJavaVersion());
}
if (ServerBootSFG.isJRE) {
Iris.safeguard(C.YELLOW + "Unsupported Server JDK");
Iris.safeguard(C.YELLOW + "- Please consider using JDK 21 Instead of JRE " + Iris.getJavaVersion());
}
}
}
public static String MSGIncompatibleWarnings() {
return ServerBootSFG.allIncompatibilities;
}
}
@@ -1,9 +1,12 @@
package com.volmit.iris.core.scripting.environment;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.scripting.func.UpdateExecutor;
import com.volmit.iris.core.scripting.kotlin.environment.IrisExecutionEnvironment;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.mantle.MantleChunk;
import lombok.NonNull;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.Nullable;
@@ -22,4 +25,6 @@ public interface EngineEnvironment extends PackEnvironment {
void postSpawnMob(@NonNull String script, @NonNull Location location, @NonNull Entity mob);
void preprocessObject(@NonNull String script, @NonNull IrisRegistrant object);
void updateChunk(@NonNull String script, @NonNull MantleChunk mantleChunk, @NonNull Chunk chunk, @NonNull UpdateExecutor executor);
}
@@ -2,6 +2,7 @@ package com.volmit.iris.core.scripting.environment;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.scripting.kotlin.environment.IrisPackExecutionEnvironment;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.math.RNG;
import lombok.NonNull;
import org.jetbrains.annotations.Nullable;
@@ -16,4 +17,6 @@ public interface PackEnvironment extends SimpleEnvironment {
@Nullable
Object createNoise(@NonNull String script, @NonNull RNG rng);
EngineEnvironment with(@NonNull Engine engine);
}
@@ -27,8 +27,4 @@ public interface SimpleEnvironment {
@Nullable
Object evaluate(@NonNull String script, @NonNull Class<?> type, @Nullable Map<@NonNull String, Object> vars);
default void close() {
}
}
@@ -0,0 +1,22 @@
package com.volmit.iris.core.scripting.func;
import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface UpdateExecutor {
@NotNull Runnable wrap(int delay, @NotNull Runnable runnable);
@NotNull
default Runnable wrap(@NotNull Runnable runnable) {
return wrap(1, runnable);
}
default void execute(@NotNull Runnable runnable) {
execute(1, runnable);
}
default void execute(int delay, @NotNull Runnable runnable) {
wrap(delay, runnable).run();
}
}
@@ -24,6 +24,7 @@ import com.volmit.iris.core.edit.BukkitBlockEditor;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.plugin.IrisService;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
@@ -37,7 +38,7 @@ public class EditSVC implements IrisService {
@Override
public void onEnable() {
this.editors = new KMap<>();
Iris.platform.getGlobalScheduler().runAtFixedRate(this::update, 1000, 1000);
Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::update, 1000, 1000);
}
@Override
@@ -1,13 +1,11 @@
package com.volmit.iris.core.service;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Scheduler;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.cache.PregenCache;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.KCache;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.Looper;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.World;
@@ -19,21 +17,33 @@ import org.bukkit.event.world.WorldUnloadEvent;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.function.Function;
public class GlobalCacheSVC implements IrisService {
private static final Cache<String, PregenCache> REFERENCE_CACHE = Caffeine.newBuilder()
.executor(KCache.EXECUTOR)
.scheduler(Scheduler.systemScheduler())
.weakValues()
.build();
private static final KMap<String, Reference<PregenCache>> REFERENCE_CACHE = new KMap<>();
private final KMap<String, PregenCache> globalCache = new KMap<>();
private transient boolean lastState;
private static boolean disabled = true;
private Looper trimmer;
@Override
public void onEnable() {
disabled = false;
trimmer = new Looper() {
@Override
protected long loop() {
var it = REFERENCE_CACHE.values().iterator();
while (it.hasNext()) {
var cache = it.next().get();
if (cache == null) it.remove();
else cache.trim(10_000);
}
return disabled ? -1 : 2_000;
}
};
trimmer.start();
lastState = !IrisSettings.get().getWorld().isGlobalPregenCache();
if (lastState) return;
Bukkit.getWorlds().forEach(this::createCache);
@@ -42,6 +52,9 @@ public class GlobalCacheSVC implements IrisService {
@Override
public void onDisable() {
disabled = true;
try {
trimmer.join();
} catch (InterruptedException ignored) {}
globalCache.qclear((world, cache) -> cache.write());
}
@@ -76,6 +89,7 @@ public class GlobalCacheSVC implements IrisService {
}
private void createCache(World world) {
if (!IrisToolbelt.isIrisWorld(world)) return;
globalCache.computeIfAbsent(world.getName(), GlobalCacheSVC::createDefault);
}
@@ -99,7 +113,15 @@ public class GlobalCacheSVC implements IrisService {
@NonNull
public static PregenCache createCache(@NonNull String worldName, @NonNull Function<String, PregenCache> provider) {
return REFERENCE_CACHE.get(worldName, provider);
PregenCache[] holder = new PregenCache[1];
REFERENCE_CACHE.compute(worldName, (name, ref) -> {
if (ref != null) {
if ((holder[0] = ref.get()) != null)
return ref;
}
return new WeakReference<>(holder[0] = provider.apply(worldName));
});
return holder[0];
}
@NonNull
@@ -3,7 +3,7 @@ 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.loader.ResourceLoader;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
@@ -14,6 +14,8 @@ import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.Looper;
import com.volmit.iris.util.stream.utility.CachedStream2D;
import com.volmit.iris.util.stream.utility.CachedStream3D;
import lombok.Synchronized;
import org.bukkit.Bukkit;
import org.bukkit.World;
@@ -27,6 +29,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
public class IrisEngineSVC implements IrisService {
private static final int TRIM_PERIOD = 2_000;
private final AtomicInteger tectonicLimit = new AtomicInteger(30);
private final AtomicInteger tectonicPlates = new AtomicInteger();
private final AtomicInteger queuedTectonicPlates = new AtomicInteger();
@@ -64,10 +67,26 @@ public class IrisEngineSVC implements IrisService {
}
public void engineStatus(VolmitSender sender) {
long[] sizes = new long[4];
long[] count = new long[4];
for (var cache : Iris.service(PreservationSVC.class).getCaches()) {
var type = switch (cache) {
case ResourceLoader<?> ignored -> 0;
case CachedStream2D<?> ignored -> 1;
case CachedStream3D<?> ignored -> 2;
default -> 3;
};
sizes[type] += cache.getSize();
count[type]++;
}
sender.sendMessage(C.DARK_PURPLE + "-------------------------");
sender.sendMessage(C.DARK_PURPLE + "Status:");
sender.sendMessage(C.DARK_PURPLE + "- Service: " + C.LIGHT_PURPLE + (service.isShutdown() ? "Shutdown" : "Running"));
sender.sendMessage(C.DARK_PURPLE + "- Updater: " + C.LIGHT_PURPLE + (updateTicker.isAlive() ? "Running" : "Stopped"));
sender.sendMessage(C.DARK_PURPLE + "- Period: " + C.LIGHT_PURPLE + Form.duration(TRIM_PERIOD));
sender.sendMessage(C.DARK_PURPLE + "- Trimmers: " + C.LIGHT_PURPLE + trimmerAlive.get());
sender.sendMessage(C.DARK_PURPLE + "- Unloaders: " + C.LIGHT_PURPLE + unloaderAlive.get());
sender.sendMessage(C.DARK_PURPLE + "Tectonic Plates:");
@@ -76,10 +95,14 @@ public class IrisEngineSVC implements IrisService {
sender.sendMessage(C.DARK_PURPLE + "- Queued: " + C.LIGHT_PURPLE + queuedTectonicPlates.get());
sender.sendMessage(C.DARK_PURPLE + "- Max Idle Duration: " + C.LIGHT_PURPLE + Form.duration(maxIdleDuration.get(), 2));
sender.sendMessage(C.DARK_PURPLE + "- Min Idle Duration: " + C.LIGHT_PURPLE + Form.duration(minIdleDuration.get(), 2));
sender.sendMessage(C.DARK_PURPLE + "Caches:");
sender.sendMessage(C.DARK_PURPLE + "- Resource: " + C.LIGHT_PURPLE + sizes[0] + " (" + count[0] + ")");
sender.sendMessage(C.DARK_PURPLE + "- 2D Stream: " + C.LIGHT_PURPLE + sizes[1] + " (" + count[1] + ")");
sender.sendMessage(C.DARK_PURPLE + "- 3D Stream: " + C.LIGHT_PURPLE + sizes[2] + " (" + count[2] + ")");
sender.sendMessage(C.DARK_PURPLE + "- Other: " + C.LIGHT_PURPLE + sizes[3] + " (" + count[3] + ")");
sender.sendMessage(C.DARK_PURPLE + "Other:");
sender.sendMessage(C.DARK_PURPLE + "- Iris Worlds: " + C.LIGHT_PURPLE + totalWorlds.get());
sender.sendMessage(C.DARK_PURPLE + "- Loaded Chunks: " + C.LIGHT_PURPLE + loadedChunks.get());
sender.sendMessage(C.DARK_PURPLE + "- Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize()));
sender.sendMessage(C.DARK_PURPLE + "-------------------------");
}
@@ -113,12 +136,12 @@ public class IrisEngineSVC implements IrisService {
@Override
protected long loop() {
try {
queuedTectonicPlates.set(0);
tectonicPlates.set(0);
loadedChunks.set(0);
unloaderAlive.set(0);
trimmerAlive.set(0);
totalWorlds.set(0);
int queuedPlates = 0;
int totalPlates = 0;
long chunks = 0;
int unloaders = 0;
int trimmers = 0;
int iris = 0;
double maxDuration = Long.MIN_VALUE;
double minDuration = Long.MAX_VALUE;
@@ -126,23 +149,30 @@ public class IrisEngineSVC implements IrisService {
var registered = entry.getValue();
if (registered.closed) continue;
totalWorlds.incrementAndGet();
unloaderAlive.addAndGet(registered.unloaderAlive() ? 1 : 0);
trimmerAlive.addAndGet(registered.trimmerAlive() ? 1 : 0);
iris++;
if (registered.unloaderAlive()) unloaders++;
if (registered.trimmerAlive()) trimmers++;
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);
queuedPlates += engine.getMantle().getUnloadRegionCount();
totalPlates += engine.getMantle().getLoadedRegionCount();
chunks += entry.getKey().getLoadedChunks().length;
double duration = engine.getMantle().getAdjustedIdleDuration();
if (duration > maxDuration) maxDuration = duration;
if (duration < minDuration) minDuration = duration;
}
trimmerAlive.set(trimmers);
unloaderAlive.set(unloaders);
tectonicPlates.set(totalPlates);
queuedTectonicPlates.set(queuedPlates);
maxIdleDuration.set(maxDuration);
minIdleDuration.set(minDuration);
loadedChunks.set(chunks);
totalWorlds.set(iris);
worlds.values().forEach(Registered::update);
} catch (Throwable e) {
@@ -157,7 +187,7 @@ public class IrisEngineSVC implements IrisService {
private final class Registered {
private final String name;
private final PlatformChunkGenerator access;
private final int offset = RNG.r.nextInt(1000);
private final int offset = RNG.r.nextInt(TRIM_PERIOD);
private transient ScheduledFuture<?> trimmer;
private transient ScheduledFuture<?> unloader;
private transient boolean closed;
@@ -194,7 +224,7 @@ public class IrisEngineSVC implements IrisService {
Iris.error("EngineSVC: Failed to trim for " + name);
e.printStackTrace();
}
}, offset, 2000, TimeUnit.MILLISECONDS);
}, offset, TRIM_PERIOD, TimeUnit.MILLISECONDS);
}
if (unloader == null || unloader.isDone() || unloader.isCancelled()) {
@@ -214,7 +244,7 @@ public class IrisEngineSVC implements IrisService {
Iris.error("EngineSVC: Failed to unload for " + name);
e.printStackTrace();
}
}, offset + 1000, 2000, TimeUnit.MILLISECONDS);
}, offset + TRIM_PERIOD / 2, TRIM_PERIOD, TimeUnit.MILLISECONDS);
}
}
@@ -22,6 +22,7 @@ import com.volmit.iris.Iris;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.J;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
@@ -70,18 +71,21 @@ public class ObjectSVC implements IrisService {
*/
private void revert(Map<Block, BlockData> blocks) {
Iterator<Map.Entry<Block, BlockData>> it = blocks.entrySet().iterator();
var scheduler = Iris.platform.getRegionScheduler();
for (int i = 0; i < 200 && it.hasNext(); i++) {
Map.Entry<Block, BlockData> entry = it.next();
Block block = entry.getKey();
BlockData data = entry.getValue();
it.remove();
Bukkit.getScheduler().runTask(Iris.instance, () -> {
int amount = 0;
while (it.hasNext()) {
Map.Entry<Block, BlockData> entry = it.next();
BlockData data = entry.getValue();
entry.getKey().setBlockData(data, false);
scheduler.run(block.getLocation(), () -> block.setBlockData(data, false));
}
it.remove();
if (it.hasNext()) {
J.s(() -> revert(blocks), 1);
}
amount++;
if (amount > 200) {
J.s(() -> revert(blocks), 1);
}
}
});
}
}
@@ -24,19 +24,22 @@ import com.volmit.iris.engine.framework.MeteredCache;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.KCache;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.Looper;
import org.jetbrains.annotations.Unmodifiable;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class PreservationSVC implements IrisService {
private final List<Thread> threads = new CopyOnWriteArrayList<>();
private final List<ExecutorService> services = new CopyOnWriteArrayList<>();
private final List<MeteredCache> caches = new CopyOnWriteArrayList<>();
private final List<WeakReference<MeteredCache>> caches = new CopyOnWriteArrayList<>();
private Looper dereferencer;
public void register(Thread t) {
@@ -48,22 +51,18 @@ public class PreservationSVC implements IrisService {
}
public void printCaches() {
long s = caches.stream().filter(i -> !i.isClosed()).mapToLong(MeteredCache::getSize).sum();
long m = caches.stream().filter(i -> !i.isClosed()).mapToLong(MeteredCache::getMaxSize).sum();
var c = getCaches();
long s = 0;
long m = 0;
double p = 0;
double mf = 0;
double mf = Math.max(c.size(), 1);
for (MeteredCache i : caches) {
if (i.isClosed()) {
continue;
}
mf++;
for (MeteredCache i : c) {
s += i.getSize();
m += i.getMaxSize();
p += i.getUsage();
}
mf = mf == 0 ? 1 : mf;
Iris.info("Cached " + Form.f(s) + " / " + Form.f(m) + " (" + Form.pc(p / mf) + ") from " + caches.size() + " Caches");
}
@@ -119,14 +118,29 @@ public class PreservationSVC implements IrisService {
}
public void updateCaches() {
caches.removeIf(MeteredCache::isClosed);
caches.removeIf(ref -> {
var c = ref.get();
return c == null || c.isClosed();
});
}
public void registerCache(MeteredCache cache) {
caches.add(cache);
caches.add(new WeakReference<>(cache));
}
public List<KCache<?, ?>> caches() {
return caches.stream().map(MeteredCache::getRawCache).collect(Collectors.toList());
return cacheStream().map(MeteredCache::getRawCache).collect(Collectors.toList());
}
@Unmodifiable
public List<MeteredCache> getCaches() {
return cacheStream().toList();
}
private Stream<MeteredCache> cacheStream() {
return caches.stream()
.map(WeakReference::get)
.filter(Objects::nonNull)
.filter(cache -> !cache.isClosed());
}
}
@@ -142,10 +142,9 @@ 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) {
if (d instanceof IrisCustomData data)
state.setBlockData(data.getBase());
Iris.service(ExternalDataSVC.class).processUpdate(engine, b, data.getCustom());
} else state.setBlockData(d);
else state.setBlockData(d);
blockStateList.add(b.getState());
dataCache.put(new Location(event.getWorld(), x, y, z), d);
}
@@ -190,6 +189,16 @@ public class TreeSVC implements IrisService {
}
@Override
public <T> void setData(int xx, int yy, int zz, T data) {
}
@Override
public <T> T getData(int xx, int yy, int zz, Class<T> t) {
return null;
}
@Override
public Engine getEngine() {
return engine;
@@ -208,7 +217,8 @@ public class TreeSVC implements IrisService {
event.setCancelled(true);
Iris.platform.getRegionScheduler().run(event.getLocation(), () -> {
J.s(() -> {
StructureGrowEvent iGrow = new StructureGrowEvent(event.getLocation(), event.getSpecies(), event.isFromBonemeal(), event.getPlayer(), blockStateList);
block = true;
Bukkit.getServer().getPluginManager().callEvent(iGrow);
@@ -225,7 +235,7 @@ public class TreeSVC implements IrisService {
if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase(), false);
Iris.service(ExternalDataSVC.class).processUpdate(engine, block, data.getCustom());
} else block.setBlockData(d);
} else block.setBlockData(d, false);
}
}
});
@@ -35,7 +35,6 @@ import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.SR;
import com.volmit.iris.util.scheduling.jobs.Job;
import com.volmit.iris.util.scheduling.jobs.ScanJob;
import org.bukkit.*;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
@@ -87,10 +86,82 @@ public class WandSVC implements IrisService {
Cuboid c = new Cuboid(f[0], f[1]);
IrisObject s = new IrisObject(c.getSizeX(), c.getSizeY(), c.getSizeZ());
new ScanJob("Scanning Selection", c, MS_PER_TICK, (bv, b) -> {
if (b.getType().equals(Material.AIR)) return;
s.setUnsigned(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), b, legacy);
}).execute(new VolmitSender(p), true, () -> {});
var it = c.chunkedIterator();
int total = c.getSizeX() * c.getSizeY() * c.getSizeZ();
var latch = new CountDownLatch(1);
var holder = Iris.tickets.getHolder(p.getWorld());
new Job() {
private int i;
private Chunk chunk;
@Override
public String getName() {
return "Scanning Selection";
}
@Override
public void execute() {
new SR() {
@Override
public void run() {
var time = M.ms() + MS_PER_TICK;
while (time > M.ms()) {
if (!it.hasNext()) {
if (chunk != null) {
holder.removeTicket(chunk);
chunk = null;
}
cancel();
latch.countDown();
return;
}
try {
var b = it.next();
var bChunk = b.getChunk();
if (chunk == null) {
chunk = bChunk;
holder.addTicket(chunk);
} else if (chunk != bChunk) {
holder.removeTicket(chunk);
holder.addTicket(bChunk);
chunk = bChunk;
}
if (b.getType().equals(Material.AIR))
continue;
BlockVector bv = b.getLocation().subtract(c.getLowerNE().toVector()).toVector().toBlockVector();
s.setUnsigned(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), b, legacy);
} finally {
i++;
}
}
}
};
try {
latch.await();
} catch (InterruptedException ignored) {}
}
@Override
public void completeWork() {}
@Override
public int getTotalWork() {
return total;
}
@Override
public int getWorkCompleted() {
return i;
}
}.execute(new VolmitSender(p), true, () -> {});
try {
latch.await();
} catch (InterruptedException ignored) {}
return s;
} catch (Throwable e) {
@@ -2,30 +2,21 @@ package com.volmit.iris.core.tools;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.util.data.Varint;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.nbt.io.NBTUtil;
import com.volmit.iris.util.nbt.io.NamedTag;
import com.volmit.iris.util.nbt.tag.*;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.reflect.V;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import de.crazydev22.platformutils.scheduler.task.Task;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import org.apache.commons.io.FileUtils;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.util.FileUtil;
import org.bukkit.util.Vector;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.io.*;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
@@ -40,13 +31,17 @@ public class IrisConverter {
sender.sendMessage("No schematic files to convert found in " + folder.getAbsolutePath());
return;
}
AtomicInteger counter = new AtomicInteger(0);
var stopwatch = PrecisionStopwatch.start();
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.submit(() -> {
for (File schem : fileList) {
try {
for (File schem : fileList) {
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
IrisObject object;
boolean largeObject = false;
NamedTag tag = null;
NamedTag tag;
try {
tag = NBTUtil.read(schem);
} catch (IOException e) {
@@ -54,23 +49,29 @@ public class IrisConverter {
throw new RuntimeException(e);
}
CompoundTag compound = (CompoundTag) tag.getTag();
int version = resolveVersion(compound);
if (!(version == 2 || version == 3))
throw new RuntimeException(C.RED + "Unsupported schematic version: " + version);
if (compound.containsKey("Palette") && compound.containsKey("Width") && compound.containsKey("Height") && compound.containsKey("Length")) {
compound = version == 3 ? (CompoundTag) compound.get("Schematic") : compound;
int objW = ((ShortTag) compound.get("Width")).getValue();
int objH = ((ShortTag) compound.get("Height")).getValue();
int objD = ((ShortTag) compound.get("Length")).getValue();
Task i = null;
int i = -1;
int mv = objW * objH * objD;
AtomicInteger v = new AtomicInteger(0);
if (mv > 500_000) {
if (mv > 2_000_000) {
largeObject = true;
Iris.info(C.GRAY + "Converting.. "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
Iris.info(C.GRAY + "Converting.. " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
Iris.info(C.GRAY + "- It may take a while");
if (sender.isPlayer()) {
i = J.ar(() -> sender.sendProgress((double) v.get() / mv, "Converting"), 0);
i = J.ar(() -> {
sender.sendProgress((double) v.get() / mv, "Converting");
}, 0);
}
}
compound = version == 3 ? (CompoundTag) compound.get("Blocks") : compound;
CompoundTag paletteTag = (CompoundTag) compound.get("Palette");
Map<Integer, BlockData> blockmap = new HashMap<>(paletteTag.size(), 0.9f);
for (Map.Entry<String, Tag<?>> entry : paletteTag.getValue().entrySet()) {
@@ -81,14 +82,16 @@ public class IrisConverter {
blockmap.put(blockId, bd);
}
ByteArrayTag byteArray = (ByteArrayTag) compound.get("BlockData");
boolean isBytes = version == 3 ? compound.getByteArrayTag("Data").length() < 128 : ((IntTag) compound.get("PaletteMax")).getValue() < 128;
ByteArrayTag byteArray = version == 3 ? (ByteArrayTag) compound.get("Data") : (ByteArrayTag) compound.get("BlockData");
byte[] originalBlockArray = byteArray.getValue();
IrisObject object = new IrisObject(objW, objH, objD);
var din = new DataInputStream(new ByteArrayInputStream(originalBlockArray));
object = new IrisObject(objW, objH, objD);
for (int h = 0; h < objH; h++) {
for (int d = 0; d < objD; d++) {
for (int w = 0; w < objW; w++) {
BlockData bd = blockmap.get((int) originalBlockArray[v.get()]);
int blockIndex = isBytes ? din.read() & 0xFF : Varint.readUnsignedVarInt(din);
BlockData bd = blockmap.get(blockIndex);
if (!bd.getMaterial().isAir()) {
object.setUnsigned(w, h, d, bd);
}
@@ -96,42 +99,59 @@ public class IrisConverter {
}
}
}
if (i != null) i.cancel();
if (i != -1) J.car(i);
try {
object.shrinkwrap();
object.write(new File(folder, schem.getName().replace(".schem", ".iob")));
} catch (IOException e) {
Iris.info(C.RED + "Failed to save: " + schem.getName());
throw new RuntimeException(e);
}
if (sender.isPlayer()) {
if (largeObject) {
sender.sendMessage(C.IRIS + "Converted "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis()));
} else {
sender.sendMessage(C.IRIS + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
counter.incrementAndGet();
if (sender.isPlayer()) {
if (largeObject) {
sender.sendMessage(C.IRIS + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis()));
} else {
sender.sendMessage(C.IRIS + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
}
}
if (largeObject) {
Iris.info(C.GRAY + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis()));
} else {
Iris.info(C.GRAY + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
}
FileUtils.delete(schem);
} catch (IOException e) {
sender.sendMessage(C.RED + "Failed to save: " + schem.getName());
throw new IOException(e);
}
if (largeObject) {
Iris.info(C.GRAY + "Converted "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis()));
} else {
Iris.info(C.GRAY + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
}
FileUtils.delete(schem);
}
} catch (Exception e) {
Iris.info(C.RED + "Failed to convert: " + schem.getName());
if (sender.isPlayer()) {
} catch (Exception e) {
sender.sendMessage(C.RED + "Failed to convert: " + schem.getName());
e.printStackTrace();
}
e.printStackTrace();
Iris.reportError(e);
}
}
sender.sendMessage(C.GRAY + "converted: " + fileList.length);
stopwatch.end();
if (counter.get() != 0) {
sender.sendMessage(C.GRAY + "Converted: " + counter.get() + " in " + Form.duration(stopwatch.getMillis()));
}
if (counter.get() < fileList.length) {
sender.sendMessage(C.RED + "Some schematics failed to convert. Check the console for details.");
}
});
}
private static int resolveVersion(CompoundTag compound) throws Exception {
try {
IntTag root = compound.getIntTag("Version");
if (root != null) {
return root.getValue();
}
CompoundTag schematic = (CompoundTag) compound.get("Schematic");
return schematic.getIntTag("Version").getValue();
} catch (NullPointerException e) {
throw new Exception("Cannot resolve schematic version", e);
}
}
}
@@ -32,6 +32,7 @@ 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 com.volmit.iris.util.scheduling.O;
import lombok.Data;
import lombok.experimental.Accessors;
import org.bukkit.*;
@@ -40,10 +41,8 @@ import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.IntSupplier;
import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML;
@@ -129,6 +128,8 @@ public class IrisCreator {
}
AtomicDouble pp = new AtomicDouble(0);
O<Boolean> done = new O<>();
done.set(false);
WorldCreator wc = new IrisWorldCreator()
.dimension(dimension)
.name(name)
@@ -142,7 +143,6 @@ public class IrisCreator {
PlatformChunkGenerator access = (PlatformChunkGenerator) wc.generator();
if (access == null) throw new IrisException("Access is null. Something bad happened.");
AtomicBoolean done = new AtomicBoolean(false);
J.a(() -> {
IntSupplier g = () -> {
if (access.getEngine() == null) {
@@ -166,11 +166,9 @@ public class IrisCreator {
});
final World world;
World world;
try {
world = J.sfut(() -> INMS.get().createWorldAsync(wc))
.thenCompose(Function.identity())
.get();
world = J.sfut(() -> INMS.get().createWorld(wc)).get();
} catch (Throwable e) {
done.set(true);
throw new IrisException("Failed to create world!", e);
@@ -179,15 +177,7 @@ public class IrisCreator {
done.set(true);
if (sender.isPlayer() && !benchmark) {
Iris.platform.getChunkAtAsync(world, 0, 0, true, true)
.thenApply(Objects::requireNonNull)
.thenApply(c -> c.getChunkSnapshot(true, false, false).getHighestBlockYAt(0, 0) + 1)
.thenAccept(y -> Iris.platform.teleportAsync(sender.player(), new Location(world, 0, y, 0)))
.exceptionally(err -> {
sender.sendMessage(C.RED + "Failed to teleport you to the world!");
err.printStackTrace();
return null;
});
J.s(() -> sender.player().teleport(new Location(world, 0, world.getHighestBlockYAt(0, 0) + 1, 0)));
}
if (studio || benchmark) {
@@ -24,8 +24,8 @@ 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.AsyncPregenMethod;
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;
import com.volmit.iris.engine.object.IrisDimension;
@@ -34,6 +34,7 @@ import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import java.io.File;
import java.io.IOException;
@@ -45,6 +46,7 @@ import java.util.Map;
* Hope you packed snacks & road sodas.
*/
public class IrisToolbelt {
@ApiStatus.Internal
public static Map<String, Boolean> toolbeltConfiguration = new HashMap<>();
/**
@@ -165,7 +167,8 @@ public class IrisToolbelt {
* @return the pregenerator job (already started)
*/
public static PregeneratorJob pregenerate(PregenTask task, PlatformChunkGenerator gen) {
return pregenerate(task, new AsyncPregenMethod(gen.getEngine().getWorld().realWorld()), gen.getEngine());
return pregenerate(task, new HybridPregenMethod(gen.getEngine().getWorld().realWorld(),
IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())), gen.getEngine());
}
/**
@@ -181,7 +184,7 @@ public class IrisToolbelt {
return pregenerate(task, access(world));
}
return pregenerate(task, new AsyncPregenMethod(world), null);
return pregenerate(task, new HybridPregenMethod(world, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())), null);
}
/**
@@ -195,7 +198,7 @@ public class IrisToolbelt {
if (!i.getName().equals(world.getName())) {
for (Player j : world.getPlayers()) {
new VolmitSender(j, Iris.instance.getTag()).sendMessage("You have been evacuated from this world.");
Iris.platform.teleportAsync(j, i.getSpawnLocation());
j.teleport(i.getSpawnLocation());
}
return true;
@@ -217,7 +220,7 @@ public class IrisToolbelt {
if (!i.getName().equals(world.getName())) {
for (Player j : world.getPlayers()) {
new VolmitSender(j, Iris.instance.getTag()).sendMessage("You have been evacuated from this world. " + m);
Iris.platform.teleportAsync(j, i.getSpawnLocation());
j.teleport(i.getSpawnLocation());
}
return true;
}
@@ -231,7 +234,11 @@ public class IrisToolbelt {
}
public static void retainMantleDataForSlice(String className) {
toolbeltConfiguration.put("retain.mantle." + className, true);
toolbeltConfiguration.put("retain.mantle." + className, Boolean.TRUE);
}
public static boolean isRetainingMantleDataForSlice(String className) {
return !toolbeltConfiguration.isEmpty() && toolbeltConfiguration.get("retain.mantle." + className) == Boolean.TRUE;
}
public static <T> T getMantleData(World world, int x, int y, int z, Class<T> of) {
@@ -89,7 +89,7 @@ public class IrisComplex implements DataProvider {
}
public IrisComplex(Engine engine, boolean simple) {
int cacheSize = IrisSettings.get().getPerformance().getCacheSize();
int cacheSize = IrisSettings.get().getPerformance().getNoiseCacheSize();
IrisBiome emptyBiome = new IrisBiome();
UUID focusUUID = UUID.nameUUIDFromBytes("focus".getBytes());
this.rng = new RNG(engine.getSeedManager().getComplex());
File diff suppressed because it is too large Load Diff
@@ -86,11 +86,13 @@ public class IrisEngineMantle implements EngineMantle {
.map(components::get)
.map(components -> {
int radius = components.stream()
.filter(MantleComponent::isEnabled)
.mapToInt(MantleComponent::getRadius)
.max()
.orElse(0);
return new Pair<>(List.copyOf(components), radius);
})
.filter(pair -> !pair.getA().isEmpty())
.toList();
int radius = 0;
@@ -23,6 +23,7 @@ import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineAssignedWorldManager;
import com.volmit.iris.engine.object.*;
@@ -43,6 +44,7 @@ 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.jobs.QueueJob;
import io.papermc.lib.PaperLib;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.bukkit.Chunk;
@@ -56,11 +58,11 @@ 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;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -77,6 +79,8 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
private final ChronoLatch cln;
private final ChronoLatch chunkUpdater;
private final ChronoLatch chunkDiscovery;
private final KMap<Long, Future<?>> cleanup = new KMap<>();
private final ScheduledExecutorService cleanupService;
private double energy = 25;
private int entityCount = 0;
private long charge = 0;
@@ -94,6 +98,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
looper = null;
chunkUpdater = null;
chunkDiscovery = null;
cleanupService = null;
id = -1;
}
@@ -105,6 +110,11 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
cl = new ChronoLatch(3000);
ecl = new ChronoLatch(250);
clw = new ChronoLatch(1000, true);
cleanupService = Executors.newSingleThreadScheduledExecutor(runnable -> {
var thread = new Thread(runnable, "Iris Mantle Cleanup " + getTarget().getWorld().name());
thread.setPriority(Thread.MIN_PRIORITY);
return thread;
});
id = engine.getCacheID();
energy = 25;
looper = new Looper() {
@@ -118,10 +128,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
getEngine().getWorld().tryGetRealWorld();
}
if (!IrisSettings.get().getWorld().isMarkerEntitySpawningSystem() && !IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()) {
return 3000;
}
if (getEngine().getWorld().hasRealWorld()) {
if (getEngine().getWorld().getPlayers().isEmpty()) {
return 5000;
@@ -135,6 +141,13 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
discoverChunks();
}
if (cln.flip()) {
engine.getEngineData().cleanup(getEngine());
}
if (!IrisSettings.get().getWorld().isMarkerEntitySpawningSystem() && !IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()) {
return 3000;
}
if (getDimension().isInfiniteEnergy()) {
energy += 1000;
@@ -146,10 +159,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
fixEnergy();
}
if (cln.flip()) {
engine.getEngineData().cleanup(getEngine());
}
if (precount != null) {
entityCount = 0;
for (Entity i : precount) {
@@ -177,7 +186,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
}
};
looper.setPriority(Thread.MIN_PRIORITY);
looper.setName("Iris World Manager");
looper.setName("Iris World Manager " + getTarget().getWorld().name());
looper.start();
}
@@ -186,54 +195,32 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
for (Player i : getEngine().getWorld().realWorld().getPlayers()) {
int r = 1;
int cX = i.getLocation().getBlockX() >> 4;
int cZ = i.getLocation().getBlockZ() >> 4;
for (int x = -r; x <= r; x++) {
for (int z = -r; z <= r; z++) {
mantle.getChunk(cX + x, cZ + z).flag(MantleFlag.DISCOVERED, true);
mantle.getChunk(i.getLocation().getChunk()).flag(MantleFlag.DISCOVERED, true);
}
}
}
}
private void updateChunks() {
int radius = 1;
int diameter = radius * 2 + 1;
int count = (diameter * diameter) + 1;
for (Player i : getEngine().getWorld().realWorld().getPlayers()) {
int r = 1;
var players = new KList<>(getEngine().getWorld().realWorld().getPlayers());
var latch = new CountDownLatch(count * players.size());
for (Player i : players) {
if (!i.isOnline() || !i.isValid() || i.isDead()) {
for (int j = 0; j < count; j++) {
latch.countDown();
}
continue;
}
Iris.platform.getEntityScheduler(i).run(() -> {
Chunk c = i.getLocation().getChunk();
for (int x = -radius; x <= radius; x++) {
for (int z = -radius; z <= radius; z++) {
int cX = c.getX() + x;
int cZ = c.getZ() + z;
if (!c.getWorld().isChunkLoaded(cX, cZ) || !Chunks.isSafe(getEngine().getWorld().realWorld(), cX, cZ)) {
latch.countDown();
continue;
}
Chunk c = i.getLocation().getChunk();
for (int x = -r; x <= r; x++) {
for (int z = -r; z <= r; z++) {
if (c.getWorld().isChunkLoaded(c.getX() + x, c.getZ() + z) && Chunks.isSafe(getEngine().getWorld().realWorld(), c.getX() + x, c.getZ() + z)) {
if (IrisSettings.get().getWorld().isPostLoadBlockUpdates()) {
Chunk cx = c.getWorld().getChunkAt(cX, cZ);
J.a(() -> {
getEngine().updateChunk(cx);
latch.countDown();
});
} else latch.countDown();
getEngine().updateChunk(c.getWorld().getChunkAt(c.getX() + x, c.getZ() + z));
}
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
Chunk cx = getEngine().getWorld().realWorld().getChunkAt(cX, cZ);
J.a(() -> getMantle().raiseFlag(cX, cZ, MantleFlag.INITIAL_SPAWNED_MARKER,
Chunk cx = getEngine().getWorld().realWorld().getChunkAt(c.getX() + x, c.getZ() + z);
int finalX = c.getX() + x;
int finalZ = c.getZ() + z;
J.a(() -> getMantle().raiseFlag(finalX, finalZ, MantleFlag.INITIAL_SPAWNED_MARKER,
() -> {
J.a(() -> spawnIn(cx, true), RNG.r.i(5, 200));
getSpawnersFromMarkers(cx).forEach((blockf, spawners) -> {
@@ -249,17 +236,8 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
}
}
}
latch.countDown();
}, () -> {
for (int j = 0; j < count; j++) {
latch.countDown();
}
});
}
}
try {
latch.await();
} catch (InterruptedException ignored) {}
}
private boolean onAsyncTick() {
@@ -452,22 +430,20 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
return;
}
var ref = new WeakReference<>(e.getWorld());
int cX = e.getX(), cZ = e.getZ();
J.s(() -> {
World world = ref.get();
if (world == null || !world.isChunkLoaded(cX, cZ))
return;
Long key = Cache.key(e);
cleanup.put(key, cleanupService.schedule(() -> {
cleanup.remove(key);
energy += 0.3;
fixEnergy();
getEngine().cleanupMantleChunk(cX, cZ);
}, IrisSettings.get().getPerformance().mantleCleanupDelay);
}, Math.max(IrisSettings.get().getPerformance().mantleCleanupDelay * 50L, 0), TimeUnit.MILLISECONDS));
if (generated) {
//INMS.get().injectBiomesFromMantle(e, getMantle());
if (!IrisSettings.get().getGenerator().earlyCustomBlocks) return;
e.addPluginChunkTicket(Iris.instance);
Iris.tickets.addTicket(e);
J.s(() -> {
var chunk = getMantle().getChunk(e).use();
int minY = getTarget().getWorld().minHeight();
@@ -479,12 +455,20 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
});
} finally {
chunk.release();
e.removePluginChunkTicket(Iris.instance);
Iris.tickets.removeTicket(e);
}
}, RNG.r.i(20, 60));
}
}
@Override
public void onChunkUnload(Chunk e) {
final var future = cleanup.remove(Cache.key(e));
if (future != null) {
future.cancel(false);
}
}
private void spawn(IrisPosition block, IrisSpawner spawner, boolean initial) {
if (getEngine().isClosed()) {
return;
@@ -520,8 +504,8 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
e.setCancelled(true);
warmupAreaAsync(e.getPlayer(), e.getTo(), () -> J.s(() -> {
ignoreTP.set(true);
Iris.platform.teleportAsync(e.getPlayer(), e.getTo(), e.getCause())
.thenRun(() -> ignoreTP.set(false));
e.getPlayer().teleport(e.getTo(), e.getCause());
ignoreTP.set(false);
}));
}
}
@@ -541,7 +525,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
}
futures.add(MultiBurst.burst.completeValue(()
-> Iris.platform.getChunkAtAsync(to.getWorld(),
-> PaperLib.getChunkAtAsync(to.getWorld(),
(to.getBlockX() >> 4) + finalI,
(to.getBlockZ() >> 4) + finalJ,
true, IrisSettings.get().getWorld().getAsyncTeleport().isUrgent()).get()));
@@ -578,17 +562,19 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
IrisPosition pos = new IrisPosition((c.getX() << 4) + x, y, (c.getZ() << 4) + z);
if (mark.isEmptyAbove()) {
Boolean remove = Iris.platform.getRegionScheduler()
.run(c.getWorld(), c.getX(), c.getZ(), () -> c.getBlock(x, y + 1, z).getType().isSolid() || c.getBlock(x, y + 2, z).getType().isSolid())
.getResult()
.exceptionally(e -> {
Iris.reportError(e);
e.printStackTrace();
return false;
})
.join();
AtomicBoolean remove = new AtomicBoolean(false);
if (remove == Boolean.TRUE) {
try {
J.sfut(() -> {
if (c.getBlock(x, y + 1, z).getBlockData().getMaterial().isSolid() || c.getBlock(x, y + 2, z).getBlockData().getMaterial().isSolid()) {
remove.set(true);
}
}).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
if (remove.get()) {
b.add(pos);
return;
}
@@ -18,6 +18,7 @@
package com.volmit.iris.engine.framework;
import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.math.RNG;
import org.bukkit.Chunk;
import org.bukkit.block.data.BlockData;
@@ -28,5 +29,5 @@ public interface BlockUpdater {
void updateChunk(Chunk c);
void update(int x, int y, int z, Chunk c, RNG rf);
void update(int x, int y, int z, Chunk c, MantleChunk mc, RNG rf);
}
@@ -48,6 +48,7 @@ import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.function.Function2;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.M;
@@ -64,6 +65,7 @@ import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.stream.ProceduralStream;
import io.papermc.lib.PaperLib;
import org.bukkit.*;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
@@ -293,20 +295,20 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
var chunk = mantle.getChunk(c).use();
try {
Semaphore semaphore = new Semaphore(3);
chunk.raiseFlag(MantleFlag.ETCHED, () -> {
Semaphore semaphore = new Semaphore(1024);
chunk.raiseFlagUnchecked(MantleFlag.ETCHED, () -> {
chunk.raiseFlagUnchecked(MantleFlag.TILE, run(semaphore, () -> {
chunk.iterate(TileWrapper.class, (x, y, z, v) -> {
Block block = c.getBlock(x & 15, y + getWorld().minHeight(), z & 15);
if (!TileData.setTileState(block, v.getData()))
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", block.getX(), block.getY(), block.getZ(), block.getType().getKey(), v.getData().getMaterial().getKey());
});
}, c, 1));
}, 0));
chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, run(semaphore, () -> {
chunk.iterate(Identifier.class, (x, y, z, v) -> {
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
});
}, c, 1));
}, 0));
chunk.raiseFlagUnchecked(MantleFlag.UPDATE, run(semaphore, () -> {
PrecisionStopwatch p = PrecisionStopwatch.start();
@@ -339,35 +341,48 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
for (int z = 0; z < 16; z++) {
if (grid[x][z] == Integer.MIN_VALUE)
continue;
update(x, grid[x][z], z, c, rng);
update(x, grid[x][z], z, c, chunk, rng);
}
}
chunk.iterate(MatterUpdate.class, (x, yf, z, v) -> {
int y = yf + getWorld().minHeight();
if (v != null && v.isUpdate()) {
update(x, y, z, c, rng);
update(x, y, z, c, chunk, rng);
}
});
chunk.deleteSlices(MatterUpdate.class);
getMetrics().getUpdates().put(p.getMilliseconds());
}, c, RNG.r.i(2, 20))); //Why is there a random delay here?
}, RNG.r.i(1, 20))); //Why is there a random delay here?
});
chunk.raiseFlagUnchecked(MantleFlag.SCRIPT, () -> {
var scripts = getDimension().getChunkUpdateScripts();
if (scripts == null || scripts.isEmpty())
return;
for (var script : scripts) {
getExecution().updateChunk(script, chunk, c, (delay, task) -> run(semaphore, task, delay));
}
});
try {
semaphore.acquire(3);
semaphore.acquire(1024);
} catch (InterruptedException ignored) {}
} finally {
chunk.release();
}
}
private static Runnable run(Semaphore semaphore, Runnable runnable, Chunk chunk, int delay) {
private static Runnable run(Semaphore semaphore, Runnable runnable, int delay) {
return () -> {
if (!semaphore.tryAcquire())
return;
try {
semaphore.acquire();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Iris.platform.getRegionScheduler().runDelayed(chunk.getWorld(), chunk.getX(), chunk.getZ(), () -> {
J.s(() -> {
try {
runnable.run();
} finally {
@@ -380,7 +395,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
@BlockCoordinates
@Override
default void update(int x, int y, int z, Chunk c, RNG rf) {
default void update(int x, int y, int z, Chunk c, MantleChunk mc, RNG rf) {
Block block = c.getBlock(x, y, z);
BlockData data = block.getBlockData();
blockUpdatedMetric();
@@ -393,17 +408,11 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
}
if (slot != null) {
KList<IrisLootTable> tables = getLootTables(rx, block);
KList<IrisLootTable> tables = getLootTables(rx, block, mc);
try {
Bukkit.getPluginManager().callEvent(new IrisLootEvent(this, block, slot, tables));
if (!tables.isEmpty()){
Iris.debug("IrisLootEvent has been accessed");
}
if (tables.isEmpty())
return;
if (tables.isEmpty()) return;
InventoryHolder m = (InventoryHolder) block.getState();
addItems(false, m.getInventory(), rx, tables, slot, c.getWorld(), x, y, z, 15);
@@ -469,13 +478,23 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
@BlockCoordinates
@Override
default KList<IrisLootTable> getLootTables(RNG rng, Block b) {
MantleChunk mc = getMantle().getMantle().getChunk(b.getChunk()).use();
try {
return getLootTables(rng, b, mc);
} finally {
mc.release();
}
}
@BlockCoordinates
default KList<IrisLootTable> getLootTables(RNG rng, Block b, MantleChunk mc) {
int rx = b.getX();
int rz = b.getZ();
int ry = b.getY() - getWorld().minHeight();
double he = getComplex().getHeightStream().get(rx, rz);
KList<IrisLootTable> tables = new KList<>();
PlacedObject po = getObjectPlacement(rx, ry, rz);
PlacedObject po = getObjectPlacement(rx, ry, rz, mc);
if (po != null && po.getPlacement() != null) {
if (B.isStorageChest(b.getBlockData())) {
IrisLootTable table = po.getPlacement().getTable(b.getBlockData(), getData());
@@ -526,9 +545,8 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
if (IrisLootEvent.callLootEvent(items, inv, world, x, y, z))
return;
if (world != null) {
final int cX = x >> 4, cZ = z >> 4;
Iris.platform.getChunkAtAsync(world, cX, cZ, true, false).thenAccept((c) -> {
if (PaperLib.isPaper() && getWorld().hasRealWorld()) {
PaperLib.getChunkAtAsync(getWorld().realWorld(), x >> 4, z >> 4).thenAccept((c) -> {
Runnable r = () -> {
for (ItemStack i : items) {
inv.addItem(i);
@@ -537,10 +555,10 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
scramble(inv, rng);
};
if (Iris.platform.isOwnedByCurrentRegion(world, cX, cZ)) {
if (Bukkit.isPrimaryThread()) {
r.run();
} else {
Iris.platform.getRegionScheduler().run(world, cX, cZ, r);
J.s(r);
}
});
} else {
@@ -799,7 +817,16 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
}
default PlacedObject getObjectPlacement(int x, int y, int z) {
String objectAt = getMantle().getMantle().get(x, y, z, String.class);
MantleChunk chunk = getMantle().getMantle().getChunk(x >> 4, z >> 4).use();
try {
return getObjectPlacement(x, y, z, chunk);
} finally {
chunk.release();
}
}
default PlacedObject getObjectPlacement(int x, int y, int z, MantleChunk chunk) {
String objectAt = chunk.get(x & 15, y, z & 15, String.class);
if (objectAt == null || objectAt.isEmpty()) {
return null;
}
@@ -809,7 +836,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
int id = Integer.parseInt(v[1]);
JigsawPieceContainer container = getMantle().getMantle().get(x, y, z, JigsawPieceContainer.class);
JigsawPieceContainer container = chunk.get(x & 15, y, z & 15, JigsawPieceContainer.class);
if (container != null) {
IrisJigsawPiece piece = container.load(getData());
if (piece.getObject().equals(object))
@@ -824,7 +851,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
}
}
IrisBiome biome = getBiome(x, y, z);
IrisBiome biome = getSurfaceBiome(x, z);
for (IrisObjectPlacement i : biome.getObjects()) {
if (i.getPlace().contains(object)) {
@@ -885,7 +912,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
player.sendMessage(C.GOLD + "No strongholds in world.");
} else {
Location ll = new Location(player.getWorld(), pr.getX(), 40, pr.getZ());
Iris.platform.teleportAsync(player, ll);
J.s(() -> player.teleport(ll));
}
return;
@@ -973,7 +1000,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
default void cleanupMantleChunk(int x, int z) {
if (IrisSettings.get().getPerformance().isTrimMantleInStudio() || !isStudio()) {
J.a(() -> getMantle().cleanupChunk(x, z));
getMantle().cleanupChunk(x, z);
}
}
}
@@ -20,34 +20,40 @@ package com.volmit.iris.engine.framework;
import com.volmit.iris.Iris;
import com.volmit.iris.core.events.IrisEngineHotloadEvent;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.plugin.VolmitSender;
import de.crazydev22.platformutils.scheduler.task.Task;
import org.bukkit.*;
import org.bukkit.entity.EnderSignal;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.WorldSaveEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.inventory.EquipmentSlot;
import java.util.concurrent.atomic.AtomicBoolean;
public abstract class EngineAssignedWorldManager extends EngineAssignedComponent implements EngineWorldManager, Listener {
private final Task task;
private final int taskId;
protected AtomicBoolean ignoreTP = new AtomicBoolean(false);
public EngineAssignedWorldManager() {
super(null, null);
task = null;
taskId = -1;
}
public EngineAssignedWorldManager(Engine engine) {
super(engine, "World");
Iris.instance.registerListener(this);
task = Iris.platform.getGlobalScheduler().runAtFixedRate(this::onTick, 1, 1);
taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::onTick, 0, 0);
}
@EventHandler
@@ -120,10 +126,17 @@ public abstract class EngineAssignedWorldManager extends EngineAssignedComponent
}
}
@EventHandler
public void on(ChunkUnloadEvent e) {
if (e.getChunk().getWorld().equals(getTarget().getWorld().realWorld())) {
onChunkUnload(e.getChunk());
}
}
@Override
public void close() {
super.close();
Iris.instance.unregisterListener(this);
if (task != null) task.cancel();
Bukkit.getScheduler().cancelTask(taskId);
}
}
@@ -45,6 +45,8 @@ public interface EngineWorldManager {
void onChunkLoad(Chunk e, boolean generated);
void onChunkUnload(Chunk e);
void chargeEnergy();
void teleportAsync(PlayerTeleportEvent e);
@@ -18,7 +18,6 @@
package com.volmit.iris.engine.framework;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.nms.container.BlockPos;
import com.volmit.iris.core.nms.container.Pair;
@@ -37,6 +36,7 @@ import com.volmit.iris.util.matter.MatterCavern;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.scheduling.jobs.SingleJob;
import org.bukkit.Location;
@@ -114,7 +114,7 @@ public interface Locator<T> {
default void find(Player player, boolean teleport, String message) {
find(player, location -> {
if (teleport) {
Iris.platform.teleportAsync(player, location);
J.s(() -> player.teleport(location));
} else {
player.sendMessage(C.GREEN + message + " at: " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ());
}
@@ -24,7 +24,6 @@ import com.volmit.iris.engine.object.IObjectPlacer;
import com.volmit.iris.engine.object.IrisObjectPlacement;
import com.volmit.iris.engine.object.TileData;
import com.volmit.iris.util.math.RNG;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData;
public class HeightmapObjectPlacer implements IObjectPlacer {
@@ -83,6 +82,16 @@ public class HeightmapObjectPlacer implements IObjectPlacer {
oplacer.setTile(param1Int1, param1Int2, param1Int3, param1TileData);
}
@Override
public <T> void setData(int xx, int yy, int zz, T data) {
oplacer.setData(xx, yy, zz, data);
}
@Override
public <T> T getData(int xx, int yy, int zz, Class<T> t) {
return oplacer.getData(xx, yy, zz, t);
}
@Override
public Engine getEngine() {
return null;
@@ -1,111 +0,0 @@
package com.volmit.iris.engine.framework.placer;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IObjectPlacer;
import com.volmit.iris.engine.object.TileData;
import lombok.EqualsAndHashCode;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import static com.volmit.iris.Iris.platform;
@EqualsAndHashCode
public class SafeObjectPlacer implements IObjectPlacer {
private final World world;
private final IObjectPlacer placer;
public SafeObjectPlacer(World world, IObjectPlacer placer) {
this.world = world;
this.placer = placer;
}
@Override
public int getHighest(int x, int z, IrisData data) {
if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) {
return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> getHighest(x, z, data))
.getResult()
.join();
}
return placer.getHighest(x, z, data);
}
@Override
public int getHighest(int x, int z, IrisData data, boolean ignoreFluid) {
if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) {
if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!");
return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> getHighest(x, z, data, ignoreFluid))
.getResult()
.join();
}
return placer.getHighest(x, z, data);
}
@Override
public void set(int x, int y, int z, BlockData d) {
if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) {
if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!");
platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> set(x, y, z, d)).getResult().join();
} else placer.set(x, y, z, d);
}
@Override
public BlockData get(int x, int y, int z) {
if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) {
if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!");
return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> get(x, y, z)).getResult().join();
}
return placer.get(x, y, z);
}
@Override
public boolean isPreventingDecay() {
return placer.isPreventingDecay();
}
@Override
public boolean isCarved(int x, int y, int z) {
return placer.isCarved(x, y, z);
}
@Override
public boolean isSolid(int x, int y, int z) {
if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) {
if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!");
return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> isSolid(x, y, z)).getResult().join();
}
return placer.isSolid(x, y, z);
}
@Override
public boolean isUnderwater(int x, int z) {
if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) {
if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!");
return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> isUnderwater(x, z)).getResult().join();
}
return placer.isUnderwater(x, z);
}
@Override
public int getFluidHeight() {
return placer.getFluidHeight();
}
@Override
public boolean isDebugSmartBore() {
return placer.isDebugSmartBore();
}
@Override
public void setTile(int xx, int yy, int zz, TileData tile) {
if (!platform.isOwnedByCurrentRegion(world, xx >> 4, zz >> 4)) {
if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!");
platform.getRegionScheduler().run(world, xx >> 4, zz >> 4, () -> setTile(xx, yy, zz, tile)).getResult().join();
} else placer.setTile(xx, yy, zz, tile);
}
@Override
public Engine getEngine() {
return placer.getEngine();
}
}
@@ -59,6 +59,11 @@ public class WorldObjectPlacer implements IObjectPlacer {
slot = InventorySlotType.STORAGE;
}
if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase(), false);
Iris.warn("Tried to place custom block at " + x + ", " + y + ", " + z + " which is not supported!");
} else block.setBlockData(d, false);
if (slot != null) {
RNG rx = new RNG(Cache.key(x, z));
KList<IrisLootTable> tables = engine.getLootTables(rx, block);
@@ -78,12 +83,6 @@ public class WorldObjectPlacer implements IObjectPlacer {
Iris.reportError(e);
}
}
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);
}
@Override
@@ -125,4 +124,13 @@ public class WorldObjectPlacer implements IObjectPlacer {
public void setTile(int xx, int yy, int zz, TileData tile) {
tile.toBukkitTry(world.getBlockAt(xx, yy + world.getMinHeight(), zz));
}
@Override
public <T> void setData(int xx, int yy, int zz, T data) {
}
@Override
public <T> T getData(int xx, int yy, int zz, Class<T> t) {
return null;
}
}
@@ -69,7 +69,7 @@ public class PlannedPiece {
this.setRotation(rot);
this.ogObject = data.getObjectLoader().load(piece.getObject());
this.object = structure.rotated(piece, rotation);
this.piece = rotation.rotateCopy(piece);
this.piece = rotation.rotateCopy(piece, new IrisPosition(object.getShrinkOffset()));
this.piece.setLoadKey(piece.getLoadKey());
this.object.setLoadKey(piece.getObject());
this.ogObject.setLoadKey(piece.getObject());
@@ -154,15 +154,14 @@ public class PlannedStructure {
JigsawStructureContainer structure = JigsawStructureContainer.toContainer(getStructure());
i.setRealPositions(xx, height, zz, placer);
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(), structure);
e.set(b.getX(), b.getY(), b.getZ(), piece);
placer.setData(b.getX(), b.getY(), b.getZ(), v.getLoadKey() + "@" + id);
placer.setData(b.getX(), b.getY(), b.getZ(), structure);
placer.setData(b.getX(), b.getY(), b.getZ(), piece);
}, null, getData().getEngine() != null ? getData() : eng.getData()) != -1;
}
//TODO properly fix for folia
public void place(WorldObjectPlacer placer, Consumer<Boolean> consumer) {
Iris.platform.getRegionScheduler().run(placer.getWorld(), position.getX() >> 4, position.getZ() >> 4, () -> consumer.accept(place(placer, placer.getMantle().getMantle(), placer.getEngine())));
J.s(() -> consumer.accept(place(placer, placer.getMantle().getMantle(), placer.getEngine())));
}
private void generateOutwards() {
@@ -29,8 +29,6 @@ import com.volmit.iris.engine.mantle.components.MantleObjectComponent;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisPosition;
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.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates;
@@ -38,7 +36,6 @@ import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.matter.*;
import com.volmit.iris.util.matter.slices.UpdateMatter;
import com.volmit.iris.util.parallel.MultiBurst;
@@ -49,10 +46,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static com.volmit.iris.util.parallel.StreamUtils.forEach;
import static com.volmit.iris.util.parallel.StreamUtils.streamRadius;
public interface EngineMantle {
public interface EngineMantle extends MatterGenerator {
BlockData AIR = B.get("AIR");
Mantle getMantle();
@@ -180,49 +174,6 @@ public interface EngineMantle {
return getEngine().burst();
}
@ChunkCoordinates
default void generateMatter(int x, int z, boolean multicore, ChunkContext context) {
if (!getEngine().getDimension().isUseMantle() || getMantle().hasFlag(x, z, MantleFlag.PLANNED)) {
return;
}
try (MantleWriter writer = getMantle().write(this, x, z, getRadius() * 2)) {
var iterator = getComponents().iterator();
while (iterator.hasNext()) {
var pair = iterator.next();
int radius = pair.getB();
boolean last = !iterator.hasNext();
forEach(streamRadius(x, z, radius),
pos -> pair.getA()
.stream()
.filter(MantleComponent::isEnabled)
.map(c -> new Pair<>(c, pos)),
p -> {
MantleComponent c = p.getA();
Position2 pos = p.getB();
int xx = pos.getX();
int zz = pos.getZ();
IrisContext.getOr(getEngine()).setChunkContext(context);
generateMantleComponent(writer, xx, zz, c, writer.acquireChunk(xx, zz), context);
},
multicore ? burst() : null
);
if (!last) continue;
forEach(streamRadius(x, z, radius),
p -> writer.acquireChunk(x, z).flag(MantleFlag.PLANNED, true),
multicore ? burst() : null
);
}
}
}
default void generateMantleComponent(MantleWriter writer, int x, int z, MantleComponent c, MantleChunk mc, ChunkContext context) {
mc.raiseFlag(MantleFlag.PLANNED, c.getFlag(), () -> {
if (c.isEnabled()) c.generateLayer(writer, x, z, context);
});
}
@ChunkCoordinates
default <T> void insertMatter(int x, int z, Class<T> t, Hunk<T> blocks, boolean multicore) {
if (!getEngine().getDimension().isUseMantle()) {
@@ -262,9 +213,6 @@ public interface EngineMantle {
default int getLoadedRegionCount() {
return getMantle().getLoadedRegionCount();
}
default long getLastUseMapMemoryUsage(){
return getMantle().LastUseMapMemoryUsage();
}
MantleJigsawComponent getJigsawComponent();
@@ -290,7 +238,7 @@ public interface EngineMantle {
if (!isCovered(x, z)) return;
MantleChunk chunk = getMantle().getChunk(x, z).use();
try {
chunk.raiseFlag(MantleFlag.CLEANED, () -> {
chunk.raiseFlagUnchecked(MantleFlag.CLEANED, () -> {
chunk.deleteSlices(BlockData.class);
chunk.deleteSlices(String.class);
chunk.deleteSlices(MatterCavern.class);
@@ -301,7 +249,7 @@ public interface EngineMantle {
}
}
default long getUnloadRegionCount() {
default int getUnloadRegionCount() {
return getMantle().getUnloadRegionCount();
}
@@ -40,13 +40,12 @@ import com.volmit.iris.util.matter.Matter;
import com.volmit.iris.util.matter.MatterCavern;
import com.volmit.iris.util.matter.TileWrapper;
import com.volmit.iris.util.noise.CNG;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import lombok.Data;
import org.bukkit.block.data.BlockData;
import org.bukkit.util.Vector;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import static com.volmit.iris.engine.mantle.EngineMantle.AIR;
@@ -54,25 +53,31 @@ import static com.volmit.iris.engine.mantle.EngineMantle.AIR;
public class MantleWriter implements IObjectPlacer, AutoCloseable {
private final EngineMantle engineMantle;
private final Mantle mantle;
private final KMap<Long, MantleChunk> cachedChunks;
private final Map<Long, MantleChunk> cachedChunks;
private final int radius;
private final int x;
private final int z;
public MantleWriter(EngineMantle engineMantle, Mantle mantle, int x, int z, int radius) {
public MantleWriter(EngineMantle engineMantle, Mantle mantle, int x, int z, int radius, boolean multicore) {
this.engineMantle = engineMantle;
this.mantle = mantle;
this.cachedChunks = new KMap<>();
this.radius = radius;
this.radius = radius * 2;
final int d = this.radius + 1;
this.cachedChunks = multicore ? new KMap<>(d * d, 0.75f, Math.max(32, Runtime.getRuntime().availableProcessors() * 4)) : new Long2ObjectOpenHashMap<>(d * d);
this.x = x;
this.z = z;
int r = radius / 4;
for (int i = -r; i <= r; i++) {
for (int j = -r; j <= r; j++) {
cachedChunks.put(Cache.key(i + x, j + z), mantle.getChunk(i + x, j + z).use());
}
}
final int parallelism = multicore ? Runtime.getRuntime().availableProcessors() / 2 : 4;
final var map = multicore ? cachedChunks : new KMap<Long, MantleChunk>(d * d, 1f, parallelism);
mantle.getChunks(
x - radius,
x + radius,
z - radius,
z + radius,
parallelism,
(i, j, c) -> map.put(Cache.key(i, j), c.use())
);
if (!multicore) cachedChunks.putAll(map);
}
private static Set<IrisPosition> getBallooned(Set<IrisPosition> vset, double radius) {
@@ -182,8 +187,13 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
Iris.error("Mantle Writer Accessed chunk out of bounds" + cx + "," + cz);
return null;
}
MantleChunk chunk = cachedChunks.computeIfAbsent(Cache.key(cx, cz), k -> mantle.getChunk(cx, cz).use());
if (chunk == null) Iris.error("Mantle Writer Accessed " + cx + "," + cz + " and came up null (and yet within bounds!)");
final Long key = Cache.key(cx, cz);
MantleChunk chunk = cachedChunks.get(key);
if (chunk == null) {
chunk = mantle.getChunk(cx, cz).use();
var old = cachedChunks.put(key, chunk);
if (old != null) old.release();
}
return chunk;
}
@@ -35,7 +35,6 @@ import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer;
import com.volmit.iris.util.noise.CNG;
import lombok.Getter;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -45,7 +44,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
private final CNG cng;
public MantleJigsawComponent(EngineMantle engineMantle) {
super(engineMantle, ReservedFlag.JIGSAW, 2);
super(engineMantle, ReservedFlag.JIGSAW, 1);
cng = NoiseStyle.STATIC.create(new RNG(jigsaw()));
}
@@ -119,7 +119,7 @@ public class IrisDepositModifier extends EngineAssignedModifier<BlockData> {
if (y > k.getMaxHeight() || y < k.getMinHeight() || y > height - 2)
continue;
for (BlockVector j : clump.getBlocks().keySet()) {
for (BlockVector j : clump.getBlocks().keys()) {
int nx = j.getBlockX() + x;
int ny = j.getBlockY() + y;
int nz = j.getBlockZ() + z;
@@ -18,13 +18,10 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.placer.SafeObjectPlacer;
import de.crazydev22.platformutils.Type;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.Nullable;
public interface IObjectPlacer {
int getHighest(int x, int z, IrisData data);
@@ -49,11 +46,9 @@ public interface IObjectPlacer {
void setTile(int xx, int yy, int zz, TileData tile);
Engine getEngine();
<T> void setData(int xx, int yy, int zz, T data);
default IObjectPlacer sync(World world) {
if (Iris.platform.getType() == Type.FOLIA)
return new SafeObjectPlacer(world, this);
return this;
}
<T> @Nullable T getData(int xx, int yy, int zz, Class<T> t);
Engine getEngine();
}
@@ -67,7 +67,6 @@ public class IrisCommand {
return;
}
var scheduler = Iris.platform.getGlobalScheduler();
for (String command : commands) {
command = (command.startsWith("/") ? command.replaceFirst("/", "") : command)
.replaceAll("\\Q{x}\\E", String.valueOf(at.getBlockX()))
@@ -75,9 +74,9 @@ public class IrisCommand {
.replaceAll("\\Q{z}\\E", String.valueOf(at.getBlockZ()));
final String finalCommand = command;
if (repeat) {
scheduler.runAtFixedRate(() -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), Math.max(delay, 1), Math.max(repeatDelay, 1));
Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), delay, repeatDelay);
} else {
scheduler.runDelayed(() -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), Math.max(delay, 1));
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), delay);
}
}
}
@@ -122,6 +122,10 @@ public class IrisCompat {
private static KList<IrisCompatabilityBlockFilter> getDefaultBlockCompatabilityFilters() {
KList<IrisCompatabilityBlockFilter> filters = new KList<>();
filters.add(new IrisCompatabilityBlockFilter("CHAIN", "IRON_CHAIN"));
filters.add(new IrisCompatabilityBlockFilter("GRASS", "SHORT_GRASS"));
filters.add(new IrisCompatabilityBlockFilter("SHORT_GRASS", "GRASS"));
// Below 1.16
filters.add(new IrisCompatabilityBlockFilter("WEEPING_VINES", "NETHER_FENCE"));
filters.add(new IrisCompatabilityBlockFilter("WEEPING_VINES_PLANT", "NETHER_FENCE"));
@@ -160,7 +164,7 @@ public class IrisCompat {
filters.add(new IrisCompatabilityBlockFilter("CRACKED_NETHER_BRICKS", "NETHER_BRICKS"));
filters.add(new IrisCompatabilityBlockFilter("CHISELED_NETHER_BRICKS", "NETHER_BRICKS"));
filters.add(new IrisCompatabilityBlockFilter("NETHER_FENCE", "LEGACY_NETHER_FENCE"));
filters.add(new IrisCompatabilityBlockFilter("CHAIN", "IRON_BARS"));
filters.add(new IrisCompatabilityBlockFilter("IRON_CHAIN", "IRON_BARS"));
filters.add(new IrisCompatabilityBlockFilter("NETHERITE_BLOCK", "QUARTZ_BLOCK"));
filters.add(new IrisCompatabilityBlockFilter("BLACKSTONE", "COBBLESTONE"));
filters.add(new IrisCompatabilityBlockFilter("BASALT", "STONE"));
@@ -254,7 +258,6 @@ public class IrisCompat {
filters.add(new IrisCompatabilityBlockFilter("BAMBOO", "BIRCH_FENCE"));
filters.add(new IrisCompatabilityBlockFilter("BAMBOO_SAPLING", "BIRCH_SAPLING"));
filters.add(new IrisCompatabilityBlockFilter("POTTED_BAMBOO", "POTTED_BIRCH_SAPLING"));
filters.add(new IrisCompatabilityBlockFilter("GRASS", "SHORT_GRASS"));
return filters;
}
@@ -249,14 +249,18 @@ public class IrisDimension extends IrisRegistrant {
@Desc("A list of globally applied pre-processors")
@ArrayType(type = IrisPreProcessors.class)
private KList<IrisPreProcessors> globalPreProcessors = new KList<>();
@Desc("A list of scripts executed on engine setup")
@Desc("A list of scripts executed on engine setup\nFile extension: .engine.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> engineScripts = new KList<>();
@Desc("A list of scripts executed on data setup")
@Desc("A list of scripts executed on data setup\nFile extension: .data.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> dataScripts = new KList<>();
@Desc("A list of scripts executed on chunk update\nFile extension: .update.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> chunkUpdateScripts = new KList<>();
@Desc("Use legacy rarity instead of modern one\nWARNING: Changing this may break expressions and image maps")
private boolean legacyRarity = true;
@@ -39,7 +39,7 @@ public class IrisDimensionMode {
private IrisDimensionModeType type = IrisDimensionModeType.OVERWORLD;
@RegistryListResource(IrisScript.class)
@Desc("The script to create the dimension mode instead of using provided types")
@Desc("The script to create the dimension mode instead of using provided types\nFile extension: .engine.kts")
private String script;
public EngineMode create(Engine engine) {
@@ -24,6 +24,7 @@ import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -193,7 +194,7 @@ public class IrisEffect {
if (sound != null) {
Location part = p.getLocation().clone().add(RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance));
schedule(p, () -> p.playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch)));
J.s(() -> p.playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch)));
}
if (particleEffect != null) {
@@ -203,7 +204,7 @@ public class IrisEffect {
part.add(RNG.r.d(), 0, RNG.r.d());
int offset = p.getWorld().getMinHeight();
if (extra != 0) {
schedule(p, () -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset),
J.s(() -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset),
part.getZ(),
particleCount,
randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX,
@@ -211,7 +212,7 @@ public class IrisEffect {
randomAltZ ? RNG.r.d(-particleAltZ, particleAltZ) : particleAltZ,
extra));
} else {
schedule(p, () -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(),
J.s(() -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(),
particleCount,
randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX,
randomAltY ? RNG.r.d(-particleAltY, particleAltY) : particleAltY,
@@ -230,10 +231,10 @@ public class IrisEffect {
return;
}
schedule(p, () -> p.removePotionEffect(getRealType()));
J.s(() -> p.removePotionEffect(getRealType()));
}
schedule(p, () -> p.addPotionEffect(new PotionEffect(getRealType(),
J.s(() -> p.addPotionEffect(new PotionEffect(getRealType(),
RNG.r.i(Math.min(potionTicksMax, potionTicksMin),
Math.max(potionTicksMax, potionTicksMin)),
getPotionStrength(),
@@ -253,7 +254,7 @@ public class IrisEffect {
if (sound != null) {
Location part = p.getLocation().clone().add(RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance));
schedule(p, () -> p.getWorld().playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch)));
J.s(() -> p.getWorld().playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch)));
}
if (particleEffect != null) {
@@ -261,7 +262,7 @@ public class IrisEffect {
part.add(RNG.r.d(), 0, RNG.r.d());
int offset = p.getWorld().getMinHeight();
if (extra != 0) {
schedule(p, () -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset),
J.s(() -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset),
part.getZ(),
particleCount,
randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX,
@@ -269,7 +270,7 @@ public class IrisEffect {
randomAltZ ? RNG.r.d(-particleAltZ, particleAltZ) : particleAltZ,
extra));
} else {
schedule(p, () -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(),
J.s(() -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(),
particleCount,
randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX,
randomAltY ? RNG.r.d(-particleAltY, particleAltY) : particleAltY,
@@ -277,8 +278,4 @@ public class IrisEffect {
}
}
}
private void schedule(Entity entity, Runnable task) {
Iris.platform.getEntityScheduler(entity).run(task, null);
}
}
@@ -33,6 +33,8 @@ import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.plugin.Chunks;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -48,11 +50,13 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.loot.LootContext;
import org.bukkit.loot.LootTable;
import org.bukkit.loot.Lootable;
import org.bukkit.util.Vector;
import java.util.Collection;
import java.util.Random;
import java.util.concurrent.TimeUnit;
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;
@@ -162,12 +166,12 @@ public class IrisEntity extends IrisRegistrant {
@Desc("Set to true if you want to apply all of the settings here to the mob, even though an external plugin has already done so. Scripts are always applied.")
private boolean applySettingsToCustomMobAnyways = false;
@Desc("Set the entity type to UNKNOWN, then define a script here which ends with the entity variable (the result). You can use Iris.getLocation() to find the target location. You can spawn any entity this way.")
@Desc("Set the entity type to UNKNOWN, then define a script here which ends with the entity variable (the result). You can use location to find the target location. You can spawn any entity this way.\nFile extension: .spawn.kts")
@RegistryListResource(IrisScript.class)
private String spawnerScript = "";
@ArrayType(min = 1, type = String.class)
@Desc("Set the entity type to UNKNOWN, then define a script here. You can use Iris.getLocation() to find the target location. You can spawn any entity this way.")
@Desc("Executed post spawn you can modify the entity however you want with it\nFile extension: .postspawn.kts")
@RegistryListResource(IrisScript.class)
private KList<String> postSpawnScripts = new KList<>();
@@ -179,34 +183,38 @@ public class IrisEntity extends IrisRegistrant {
return spawn(gen, at, new RNG(at.hashCode()));
}
public Entity spawn(Engine gen, final Location at, RNG rng) {
if (!Iris.platform.isOwnedByCurrentRegion(at)) {
try {
final Location finalAt = at;
return Iris.platform.getRegionScheduler().run(at, () -> spawn(gen, finalAt, rng))
.getResult()
.get(500, TimeUnit.MILLISECONDS);
} catch (Throwable e) {
return null;
}
}
public Entity spawn(Engine gen, Location at, RNG rng) {
if (!Chunks.isSafe(at)) {
return null;
}
if (isSpawnEffectRiseOutOfGround() && Chunks.hasPlayersNearby(at)) {
at.add(0, -5, 0);
if (isSpawnEffectRiseOutOfGround()) {
AtomicReference<Location> f = new AtomicReference<>(at);
try {
J.sfut(() -> {
if (Chunks.hasPlayersNearby(f.get())) {
Location b = f.get().clone();
Location start = new Location(b.getWorld(), b.getX(), b.getY() - 5, b.getZ());
f.set(start);
}
}).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
at = f.get();
}
Entity ee = doSpawn(at);
if (ee == null) {
if (ee == null && !Chunks.isSafe(at)) {
return null;
}
if (!spawnerScript.isEmpty() && ee == null) {
synchronized (this) {
try {
ee = (Entity) gen.getExecution().spawnMob(spawnerScript, at.clone());
ee = (Entity) gen.getExecution().spawnMob(spawnerScript, at);
} catch (Throwable ex) {
Iris.error("You must return an Entity in your scripts to use entity scripts!");
ex.printStackTrace();
@@ -233,96 +241,111 @@ public class IrisEntity extends IrisRegistrant {
int gg = 0;
for (IrisEntity i : passengers) {
e.addPassenger(i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++)));
}
if (e instanceof Attributable attributable) {
for (IrisAttributeModifier i : getAttributes()) {
i.apply(rng, attributable);
Entity passenger = i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++));
if (!Bukkit.isPrimaryThread()) {
J.s(() -> e.addPassenger(passenger));
}
}
if (e instanceof Lootable lootable && getLoot().getTables().isNotEmpty()) {
lootable.setLootTable(new LootTable() {
@Override
public NamespacedKey getKey() {
return new NamespacedKey(Iris.instance, "loot-" + IrisEntity.this.hashCode());
}
if (e instanceof Attributable) {
Attributable a = (Attributable) e;
@Override
public Collection<ItemStack> populateLoot(Random random, LootContext context) {
KList<ItemStack> items = new KList<>();
for (String fi : getLoot().getTables()) {
IrisLootTable i = gen.getData().getLootLoader().load(fi);
items.addAll(i.getLoot(gen.isStudio(), rng.nextParallelRNG(345911), InventorySlotType.STORAGE, at.getWorld(), at.getBlockX(), at.getBlockY(), at.getBlockZ()));
}
return items;
}
@Override
public void fillInventory(Inventory inventory, Random random, LootContext context) {
for (ItemStack i : populateLoot(random, context)) {
inventory.addItem(i);
}
gen.scramble(inventory, rng);
}
});
for (IrisAttributeModifier i : getAttributes()) {
i.apply(rng, a);
}
}
if (e instanceof LivingEntity living) {
living.setAI(isAi());
living.setCanPickupItems(isPickupItems());
if (e instanceof Lootable) {
Lootable l = (Lootable) e;
if (getLoot().getTables().isNotEmpty()) {
Location finalAt = at;
l.setLootTable(new LootTable() {
@Override
public NamespacedKey getKey() {
return new NamespacedKey(Iris.instance, "loot-" + IrisEntity.this.hashCode());
}
@Override
public Collection<ItemStack> populateLoot(Random random, LootContext context) {
KList<ItemStack> items = new KList<>();
for (String fi : getLoot().getTables()) {
IrisLootTable i = gen.getData().getLootLoader().load(fi);
items.addAll(i.getLoot(gen.isStudio(), rng.nextParallelRNG(345911), InventorySlotType.STORAGE, finalAt.getWorld(), finalAt.getBlockX(), finalAt.getBlockY(), finalAt.getBlockZ()));
}
return items;
}
@Override
public void fillInventory(Inventory inventory, Random random, LootContext context) {
for (ItemStack i : populateLoot(random, context)) {
inventory.addItem(i);
}
gen.scramble(inventory, rng);
}
});
}
}
if (e instanceof LivingEntity) {
LivingEntity l = (LivingEntity) e;
l.setAI(isAi());
l.setCanPickupItems(isPickupItems());
if (getLeashHolder() != null) {
living.setLeashHolder(getLeashHolder().spawn(gen, at, rng.nextParallelRNG(234548)));
l.setLeashHolder(getLeashHolder().spawn(gen, at, rng.nextParallelRNG(234548)));
}
living.setRemoveWhenFarAway(isRemovable());
l.setRemoveWhenFarAway(isRemovable());
if (getHelmet() != null && rng.i(1, getHelmet().getRarity()) == 1) {
living.getEquipment().setHelmet(getHelmet().get(gen.isStudio(), rng));
l.getEquipment().setHelmet(getHelmet().get(gen.isStudio(), rng));
}
if (getChestplate() != null && rng.i(1, getChestplate().getRarity()) == 1) {
living.getEquipment().setChestplate(getChestplate().get(gen.isStudio(), rng));
l.getEquipment().setChestplate(getChestplate().get(gen.isStudio(), rng));
}
if (getLeggings() != null && rng.i(1, getLeggings().getRarity()) == 1) {
living.getEquipment().setLeggings(getLeggings().get(gen.isStudio(), rng));
l.getEquipment().setLeggings(getLeggings().get(gen.isStudio(), rng));
}
if (getBoots() != null && rng.i(1, getBoots().getRarity()) == 1) {
living.getEquipment().setBoots(getBoots().get(gen.isStudio(), rng));
l.getEquipment().setBoots(getBoots().get(gen.isStudio(), rng));
}
if (getMainHand() != null && rng.i(1, getMainHand().getRarity()) == 1) {
living.getEquipment().setItemInMainHand(getMainHand().get(gen.isStudio(), rng));
l.getEquipment().setItemInMainHand(getMainHand().get(gen.isStudio(), rng));
}
if (getOffHand() != null && rng.i(1, getOffHand().getRarity()) == 1) {
living.getEquipment().setItemInOffHand(getOffHand().get(gen.isStudio(), rng));
l.getEquipment().setItemInOffHand(getOffHand().get(gen.isStudio(), rng));
}
}
if (e instanceof Ageable ageable && isBaby()) {
ageable.setBaby();
if (e instanceof Ageable && isBaby()) {
((Ageable) e).setBaby();
}
if (e instanceof Panda panda) {
panda.setMainGene(getPandaMainGene());
panda.setMainGene(getPandaHiddenGene());
if (e instanceof Panda) {
((Panda) e).setMainGene(getPandaMainGene());
((Panda) e).setMainGene(getPandaHiddenGene());
}
if (e instanceof Villager villager) {
if (e instanceof Villager) {
Villager villager = (Villager) e;
villager.setRemoveWhenFarAway(false);
villager.setPersistent(true);
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> {
villager.setPersistent(true);
}, 1);
}
if (e instanceof Mob mob) {
mob.setAware(isAware());
if (e instanceof Mob) {
Mob m = (Mob) e;
m.setAware(isAware());
}
if (spawnEffect != null) {
@@ -342,35 +365,41 @@ public class IrisEntity extends IrisRegistrant {
rawCommands.forEach(r -> r.run(fat));
}
if (isSpawnEffectRiseOutOfGround() && e instanceof LivingEntity living && Chunks.hasPlayersNearby(at)) {
e.setInvulnerable(true);
living.setAI(false);
living.setCollidable(false);
living.setNoDamageTicks(100000);
AtomicInteger t = new AtomicInteger(0);
Iris.platform.getRegionScheduler().runAtFixedRate(at, task -> {
if (t.get() > 100) {
task.cancel();
return;
}
Location finalAt1 = at;
t.incrementAndGet();
if (e.getLocation().getBlock().getType().isSolid() || living.getEyeLocation().getBlock().getType().isSolid()) {
Iris.platform.teleportAsync(e, at.add(0, 0.1, 0));
Material material = living.getEyeLocation().subtract(0, 2, 0).getBlock().getType();
if (!material.isAir()) e.getWorld().spawnParticle(ITEM, living.getEyeLocation(), 6, 0.2, 0.4, 0.2, 0.06f, new ItemStack(material));
if (M.r(0.2)) {
e.getWorld().playSound(e.getLocation(), Sound.BLOCK_CHORUS_FLOWER_GROW, 0.8f, 0.1f);
J.s(() -> {
if (isSpawnEffectRiseOutOfGround() && e instanceof LivingEntity && Chunks.hasPlayersNearby(finalAt1)) {
Location start = finalAt1.clone();
e.setInvulnerable(true);
((LivingEntity) e).setAI(false);
((LivingEntity) e).setCollidable(false);
((LivingEntity) e).setNoDamageTicks(100000);
AtomicInteger t = new AtomicInteger(0);
AtomicInteger v = new AtomicInteger(0);
v.set(J.sr(() -> {
if (t.get() > 100) {
J.csr(v.get());
return;
}
} else {
task.cancel();
living.setNoDamageTicks(0);
living.setCollidable(true);
living.setAI(true);
e.setInvulnerable(false);
}
}, 1, 1);
}
t.incrementAndGet();
if (e.getLocation().getBlock().getType().isSolid() || ((LivingEntity) e).getEyeLocation().getBlock().getType().isSolid()) {
e.teleport(start.add(new Vector(0, 0.1, 0)));
ItemStack itemCrackData = new ItemStack(((LivingEntity) e).getEyeLocation().clone().subtract(0, 2, 0).getBlock().getBlockData().getMaterial());
e.getWorld().spawnParticle(ITEM, ((LivingEntity) e).getEyeLocation(), 6, 0.2, 0.4, 0.2, 0.06f, itemCrackData);
if (M.r(0.2)) {
e.getWorld().playSound(e.getLocation(), Sound.BLOCK_CHORUS_FLOWER_GROW, 0.8f, 0.1f);
}
} else {
J.csr(v.get());
((LivingEntity) e).setNoDamageTicks(0);
((LivingEntity) e).setCollidable(true);
((LivingEntity) e).setAI(true);
e.setInvulnerable(false);
}
}, 0));
}
});
return e;
@@ -400,6 +429,29 @@ public class IrisEntity extends IrisRegistrant {
return null;
}
if (!Bukkit.isPrimaryThread()) {
// Someone called spawn (worldedit maybe?) on a non server thread
// Due to the structure of iris, we will call it sync and busy wait until it's done.
AtomicReference<Entity> ae = new AtomicReference<>();
try {
J.s(() -> ae.set(doSpawn(at)));
} catch (Throwable e) {
return null;
}
PrecisionStopwatch p = PrecisionStopwatch.start();
while (ae.get() == null) {
J.sleep(25);
if (p.getMilliseconds() > 500) {
return null;
}
}
return ae.get();
}
if (isSpecialType()) {
return Iris.service(ExternalDataSVC.class).spawnMob(at, Identifier.fromString(specialType));
}
@@ -36,14 +36,8 @@ import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.volmit.iris.Iris.platform;
@Snippet("entity-spawn")
@Accessors(chain = true)
@NoArgsConstructor
@@ -170,15 +164,8 @@ public class IrisEntitySpawn implements IRare {
return null;
}
if (!ignoreSurfaces) {
Location block = at.clone().subtract(0, 1, 0);
BlockData data = platform.getRegionScheduler()
.run(block, () -> block.getBlock().getBlockData())
.getResult()
.join();
if (!irisEntity.getSurface().matches(data)) {
return null;
}
if (!ignoreSurfaces && !irisEntity.getSurface().matches(at.clone().subtract(0, 1, 0).getBlock())) {
return null;
}
Vector3d boundingBox = INMS.get().getBoundingbox(irisEntity.getType());
@@ -212,22 +199,15 @@ public class IrisEntitySpawn implements IRare {
int startZ = center.getBlockZ() - (int) (boundingBox.z / 2);
int endZ = center.getBlockZ() + (int) (boundingBox.z / 2);
var region = platform.getRegionScheduler();
var lock = new Semaphore(Integer.MAX_VALUE, true);
var bool = new AtomicBoolean(true);
for (int x = startX; x <= endX; x++) {
for (int y = startY; y <= endY; y++) {
for (int z = startZ; z <= endZ; z++) {
Location l = new Location(world, x, y, z);
lock.acquireUninterruptibly();
region.run(l, () -> {
if (!bool.get()) return false;
return bool.compareAndSet(true, l.getBlock().getType() == Material.AIR);
}).getResult().exceptionally(f -> false).thenRun(lock::release);
if (world.getBlockAt(x, y, z).getType() != Material.AIR) {
return false;
}
}
}
}
lock.acquireUninterruptibly(Integer.MAX_VALUE);
return bool.get();
return true;
}
}
@@ -58,7 +58,7 @@ public class IrisGeneratorStyle {
private String expression = null;
@Desc("Use an Image map instead of a generated value")
private IrisImageMap imageMap = null;
@Desc("Instead of using the style property, use a custom noise generator to represent this style.")
@Desc("Instead of using the style property, use a custom noise generator to represent this style.\nFile extension: .noise.kts")
@RegistryListResource(IrisScript.class)
private String script = null;
@MinNumber(0.00001)
@@ -30,18 +30,15 @@ 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.VectorMap;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.interpolation.IrisInterpolation;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.math.AxisAlignedBB;
import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.math.*;
import com.volmit.iris.util.matter.MatterMarker;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.IrisLock;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.scheduling.jobs.Job;
import com.volmit.iris.util.stream.ProceduralStream;
@@ -65,7 +62,10 @@ import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.BiConsumer;
import java.util.stream.StreamSupport;
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@@ -75,17 +75,17 @@ public class IrisObject extends IrisRegistrant {
protected static final BlockData VAIR = B.get("VOID_AIR");
protected static final BlockData VAIR_DEBUG = B.get("COBWEB");
protected static final BlockData[] SNOW_LAYERS = new BlockData[]{B.get("minecraft:snow[layers=1]"), B.get("minecraft:snow[layers=2]"), B.get("minecraft:snow[layers=3]"), B.get("minecraft:snow[layers=4]"), B.get("minecraft:snow[layers=5]"), B.get("minecraft:snow[layers=6]"), B.get("minecraft:snow[layers=7]"), B.get("minecraft:snow[layers=8]")};
protected transient final IrisLock readLock = new IrisLock("read-conclock");
protected transient final Lock readLock;
protected transient final Lock writeLock;
@Getter
@Setter
protected transient volatile boolean smartBored = false;
@Getter
@Setter
protected transient IrisLock lock = new IrisLock("Preloadcache");
@Setter
protected transient AtomicCache<AxisAlignedBB> aabb = new AtomicCache<>();
private KMap<BlockVector, BlockData> blocks;
private KMap<BlockVector, TileData> states;
@Getter
private VectorMap<BlockData> blocks;
@Getter
private VectorMap<TileData> states;
@Getter
@Setter
private int w;
@@ -97,15 +97,21 @@ public class IrisObject extends IrisRegistrant {
private int h;
@Getter
@Setter
private transient BlockVector center;
private transient Vector3i center;
@Getter
private transient Vector3i shrinkOffset;
public IrisObject(int w, int h, int d) {
blocks = new KMap<>();
states = new KMap<>();
blocks = new VectorMap<>();
states = new VectorMap<>();
this.w = w;
this.h = h;
this.d = d;
center = new BlockVector(w / 2, h / 2, d / 2);
center = new Vector3i(w / 2, h / 2, d / 2);
shrinkOffset = new Vector3i(0, 0, 0);
var lock = new ReentrantReadWriteLock();
readLock = lock.readLock();
writeLock = lock.writeLock();
}
public IrisObject() {
@@ -161,10 +167,10 @@ public class IrisObject extends IrisRegistrant {
PrecisionStopwatch p = PrecisionStopwatch.start();
BlockData vair = debug ? VAIR_DEBUG : VAIR;
lock.lock();
writeLock.lock();
AtomicInteger applied = new AtomicInteger();
if (getBlocks().isEmpty()) {
lock.unlock();
if (blocks.isEmpty()) {
writeLock.unlock();
Iris.warn("Cannot Smart Bore " + getLoadKey() + " because it has 0 blocks in it.");
smartBored = true;
return;
@@ -173,7 +179,7 @@ public class IrisObject extends IrisRegistrant {
BlockVector max = new BlockVector(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE);
BlockVector min = new BlockVector(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
for (BlockVector i : getBlocks().keySet()) {
for (BlockVector i : blocks.keys()) {
max.setX(Math.max(i.getX(), max.getX()));
min.setX(Math.min(i.getX(), min.getX()));
max.setY(Math.max(i.getY(), max.getY()));
@@ -193,7 +199,7 @@ public class IrisObject extends IrisRegistrant {
int end = Integer.MIN_VALUE;
for (int ray = min.getBlockX(); ray <= max.getBlockX(); ray++) {
if (getBlocks().containsKey(new BlockVector(ray, finalRayY, rayZ))) {
if (blocks.containsKey(new Vector3i(ray, finalRayY, rayZ))) {
start = Math.min(ray, start);
end = Math.max(ray, end);
}
@@ -201,10 +207,10 @@ public class IrisObject extends IrisRegistrant {
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
for (int i = start; i <= end; i++) {
BlockVector v = new BlockVector(i, finalRayY, rayZ);
Vector3i v = new Vector3i(i, finalRayY, rayZ);
if (!B.isAir(getBlocks().get(v))) {
getBlocks().computeIfAbsent(v, (vv) -> vair);
if (!vair.equals(blocks.get(v))) {
blocks.computeIfAbsent(v, (vv) -> vair);
applied.getAndIncrement();
}
}
@@ -222,7 +228,7 @@ public class IrisObject extends IrisRegistrant {
int end = Integer.MIN_VALUE;
for (int ray = min.getBlockY(); ray <= max.getBlockY(); ray++) {
if (getBlocks().containsKey(new BlockVector(finalRayX, ray, rayZ))) {
if (blocks.containsKey(new Vector3i(finalRayX, ray, rayZ))) {
start = Math.min(ray, start);
end = Math.max(ray, end);
}
@@ -230,10 +236,10 @@ public class IrisObject extends IrisRegistrant {
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
for (int i = start; i <= end; i++) {
BlockVector v = new BlockVector(finalRayX, i, rayZ);
Vector3i v = new Vector3i(finalRayX, i, rayZ);
if (!B.isAir(getBlocks().get(v))) {
getBlocks().computeIfAbsent(v, (vv) -> vair);
if (!vair.equals(blocks.get(v))) {
blocks.computeIfAbsent(v, (vv) -> vair);
applied.getAndIncrement();
}
}
@@ -251,7 +257,7 @@ public class IrisObject extends IrisRegistrant {
int end = Integer.MIN_VALUE;
for (int ray = min.getBlockZ(); ray <= max.getBlockZ(); ray++) {
if (getBlocks().containsKey(new BlockVector(finalRayX, rayY, ray))) {
if (blocks.containsKey(new Vector3i(finalRayX, rayY, ray))) {
start = Math.min(ray, start);
end = Math.max(ray, end);
}
@@ -259,10 +265,10 @@ public class IrisObject extends IrisRegistrant {
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
for (int i = start; i <= end; i++) {
BlockVector v = new BlockVector(finalRayX, rayY, i);
Vector3i v = new Vector3i(finalRayX, rayY, i);
if (!B.isAir(getBlocks().get(v))) {
getBlocks().computeIfAbsent(v, (vv) -> vair);
if (!vair.equals(blocks.get(v))) {
blocks.computeIfAbsent(v, (vv) -> vair);
applied.getAndIncrement();
}
}
@@ -273,7 +279,7 @@ public class IrisObject extends IrisRegistrant {
burst.complete();
smartBored = true;
lock.unlock();
writeLock.unlock();
Iris.debug("Smart Bore: " + getLoadKey() + " in " + Form.duration(p.getMilliseconds(), 2) + " (" + Form.f(applied.get()) + ")");
}
@@ -284,13 +290,8 @@ public class IrisObject extends IrisRegistrant {
o.setLoadFile(getLoadFile());
o.setCenter(getCenter().clone());
for (BlockVector i : getBlocks().keySet()) {
o.getBlocks().put(i.clone(), Objects.requireNonNull(getBlocks().get(i)).clone());
}
for (BlockVector i : getStates().keySet()) {
o.getStates().put(i.clone(), Objects.requireNonNull(getStates().get(i)).clone());
}
blocks.forEach((i, v) -> o.blocks.put(i.clone(), v.clone()));
states.forEach((i, v) -> o.states.put(i.clone(), v.clone()));
return o;
}
@@ -300,22 +301,24 @@ public class IrisObject extends IrisRegistrant {
this.w = din.readInt();
this.h = din.readInt();
this.d = din.readInt();
center = new BlockVector(w / 2, h / 2, d / 2);
center = new Vector3i(w / 2, h / 2, d / 2);
int s = din.readInt();
for (int i = 0; i < s; i++) {
getBlocks().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), B.get(din.readUTF()));
blocks.put(new Vector3i(din.readShort(), din.readShort(), din.readShort()), B.get(din.readUTF()));
}
if (din.available() == 0)
return;
try {
int size = din.readInt();
for (int i = 0; i < size; i++) {
getStates().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), TileData.read(din));
states.put(new Vector3i(din.readShort(), din.readShort(), din.readShort()), TileData.read(din));
}
} catch (Throwable e) {
Iris.reportError(e);
}
}
@@ -325,9 +328,9 @@ public class IrisObject extends IrisRegistrant {
this.h = din.readInt();
this.d = din.readInt();
if (!din.readUTF().equals("Iris V2 IOB;")) {
return;
throw new HeaderException();
}
center = new BlockVector(w / 2, h / 2, d / 2);
center = new Vector3i(w / 2, h / 2, d / 2);
int s = din.readShort();
int i;
KList<String> palette = new KList<>();
@@ -339,13 +342,13 @@ public class IrisObject extends IrisRegistrant {
s = din.readInt();
for (i = 0; i < s; i++) {
getBlocks().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), B.get(palette.get(din.readShort())));
blocks.put(new Vector3i(din.readShort(), din.readShort(), din.readShort()), B.get(palette.get(din.readShort())));
}
s = din.readInt();
for (i = 0; i < s; i++) {
getStates().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), TileData.read(din));
states.put(new Vector3i(din.readShort(), din.readShort(), din.readShort()), TileData.read(din));
}
}
@@ -357,7 +360,7 @@ public class IrisObject extends IrisRegistrant {
dos.writeUTF("Iris V2 IOB;");
KList<String> palette = new KList<>();
for (BlockData i : getBlocks().values()) {
for (BlockData i : blocks.values()) {
palette.addIfMissing(i.getAsString());
}
@@ -367,21 +370,23 @@ public class IrisObject extends IrisRegistrant {
dos.writeUTF(i);
}
dos.writeInt(getBlocks().size());
dos.writeInt(blocks.size());
for (BlockVector i : getBlocks().keySet()) {
for (var entry : blocks) {
var i = entry.getKey();
dos.writeShort(i.getBlockX());
dos.writeShort(i.getBlockY());
dos.writeShort(i.getBlockZ());
dos.writeShort(palette.indexOf(getBlocks().get(i).getAsString()));
dos.writeShort(palette.indexOf(entry.getValue().getAsString()));
}
dos.writeInt(getStates().size());
for (BlockVector i : getStates().keySet()) {
dos.writeInt(states.size());
for (var entry : states) {
var i = entry.getKey();
dos.writeShort(i.getBlockX());
dos.writeShort(i.getBlockY());
dos.writeShort(i.getBlockZ());
getStates().get(i).toBinary(dos);
entry.getValue().toBinary(dos);
}
}
@@ -389,7 +394,7 @@ public class IrisObject extends IrisRegistrant {
AtomicReference<IOException> ref = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(1);
new Job() {
private int total = getBlocks().size() * 3 + getStates().size();
private int total = blocks.size() * 3 + states.size();
private int c = 0;
@Override
@@ -408,11 +413,11 @@ public class IrisObject extends IrisRegistrant {
KList<String> palette = new KList<>();
for (BlockData i : getBlocks().values()) {
for (BlockData i : blocks.values()) {
palette.addIfMissing(i.getAsString());
++c;
}
total -= getBlocks().size() - palette.size();
total -= blocks.size() - palette.size();
dos.writeShort(palette.size());
@@ -421,22 +426,24 @@ public class IrisObject extends IrisRegistrant {
++c;
}
dos.writeInt(getBlocks().size());
dos.writeInt(blocks.size());
for (BlockVector i : getBlocks().keySet()) {
for (var entry : blocks) {
var i = entry.getKey();
dos.writeShort(i.getBlockX());
dos.writeShort(i.getBlockY());
dos.writeShort(i.getBlockZ());
dos.writeShort(palette.indexOf(getBlocks().get(i).getAsString()));
dos.writeShort(palette.indexOf(entry.getValue().getAsString()));
++c;
}
dos.writeInt(getStates().size());
for (BlockVector i : getStates().keySet()) {
dos.writeInt(states.size());
for (var entry : states) {
var i = entry.getKey();
dos.writeShort(i.getBlockX());
dos.writeShort(i.getBlockY());
dos.writeShort(i.getBlockZ());
getStates().get(i).toBinary(dos);
entry.getValue().toBinary(dos);
++c;
}
} catch (IOException e) {
@@ -468,16 +475,14 @@ public class IrisObject extends IrisRegistrant {
}
public void read(File file) throws IOException {
var fin = new BufferedInputStream(new FileInputStream(file));
try {
try (var fin = new BufferedInputStream(new FileInputStream(file))) {
read(fin);
fin.close();
} catch (Throwable e) {
Iris.reportError(e);
fin.close();
fin = new BufferedInputStream(new FileInputStream(file));
readLegacy(fin);
fin.close();
if (!(e instanceof HeaderException))
Iris.reportError(e);
try (var fin = new BufferedInputStream(new FileInputStream(file))) {
readLegacy(fin);
}
}
}
@@ -502,10 +507,11 @@ public class IrisObject extends IrisRegistrant {
}
public void shrinkwrap() {
BlockVector min = new BlockVector();
BlockVector max = new BlockVector();
if (blocks.isEmpty()) return;
BlockVector min = new BlockVector(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
BlockVector max = new BlockVector(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
for (BlockVector i : getBlocks().keySet()) {
for (BlockVector i : blocks.keys()) {
min.setX(Math.min(min.getX(), i.getX()));
min.setY(Math.min(min.getY(), i.getY()));
min.setZ(Math.min(min.getZ(), i.getZ()));
@@ -517,62 +523,77 @@ public class IrisObject extends IrisRegistrant {
w = max.getBlockX() - min.getBlockX() + 1;
h = max.getBlockY() - min.getBlockY() + 1;
d = max.getBlockZ() - min.getBlockZ() + 1;
center = new BlockVector(w / 2, h / 2, d / 2);
center = new Vector3i(w / 2, h / 2, d / 2);
Vector3i offset = new Vector3i(
-center.getBlockX() - min.getBlockX(),
-center.getBlockY() - min.getBlockY(),
-center.getBlockZ() - min.getBlockZ()
);
if (offset.getBlockX() == 0 && offset.getBlockY() == 0 && offset.getBlockZ() == 0)
return;
VectorMap<BlockData> b = new VectorMap<>();
VectorMap<TileData> s = new VectorMap<>();
blocks.forEach((vector, data) -> {
vector.add(offset);
b.put(vector, data);
});
states.forEach((vector, data) -> {
vector.add(offset);
s.put(vector, data);
});
shrinkOffset = offset;
blocks = b;
states = s;
}
public void clean() {
KMap<BlockVector, BlockData> d = new KMap<>();
VectorMap<BlockData> d = new VectorMap<>();
d.putAll(blocks);
for (BlockVector i : getBlocks().keySet()) {
d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i)));
}
KMap<BlockVector, TileData> dx = new KMap<>();
for (BlockVector i : getBlocks().keySet()) {
d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i)));
}
for (BlockVector i : getStates().keySet()) {
dx.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getStates().get(i)));
}
VectorMap<TileData> dx = new VectorMap<>();
dx.putAll(states);
blocks = d;
states = dx;
}
public BlockVector getSigned(int x, int y, int z) {
public Vector3i getSigned(int x, int y, int z) {
if (x >= w || y >= h || z >= d) {
throw new RuntimeException(x + " " + y + " " + z + " exceeds limit of " + w + " " + h + " " + d);
}
return new BlockVector(x, y, z).subtract(center).toBlockVector();
return (Vector3i) new Vector3i(x, y, z).subtract(center);
}
public void setUnsigned(int x, int y, int z, BlockData block) {
BlockVector v = getSigned(x, y, z);
Vector3i v = getSigned(x, y, z);
if (block == null) {
getBlocks().remove(v);
getStates().remove(v);
blocks.remove(v);
states.remove(v);
} else {
getBlocks().put(v, block);
blocks.put(v, block);
}
}
public void setUnsigned(int x, int y, int z, Block block, boolean legacy) {
BlockVector v = getSigned(x, y, z);
Vector3i v = getSigned(x, y, z);
if (block == null) {
getBlocks().remove(v);
getStates().remove(v);
blocks.remove(v);
states.remove(v);
} else {
BlockData data = block.getBlockData();
getBlocks().put(v, data);
blocks.put(v, data);
TileData state = TileData.getTileState(block, legacy);
if (state != null) {
Iris.debug("Saved State " + v);
getStates().put(v, state);
states.put(v, state);
}
}
}
@@ -869,6 +890,9 @@ public class IrisObject extends IrisRegistrant {
try {
if (config.getMarkers().isNotEmpty() && placer.getEngine() != null) {
markers = new KMap<>();
var list = StreamSupport.stream(blocks.keys().spliterator(), false)
.collect(KList.collector());
for (IrisObjectMarker j : config.getMarkers()) {
IrisMarker marker = getLoader().getMarkerLoader().load(j.getMarker());
@@ -877,13 +901,12 @@ public class IrisObject extends IrisRegistrant {
}
int max = j.getMaximumMarkers();
for (BlockVector i : getBlocks().k().shuffle()) {
for (BlockVector i : list.shuffle()) {
if (max <= 0) {
break;
}
BlockData data = getBlocks().get(i);
BlockData data = blocks.get(i);
for (BlockData k : j.getMark(rdata)) {
if (max <= 0) {
@@ -891,8 +914,8 @@ public class IrisObject extends IrisRegistrant {
}
if (j.isExact() ? k.matches(data) : k.getMaterial().equals(data.getMaterial())) {
boolean a = !blocks.containsKey(new BlockVector(i.clone().add(new BlockVector(0, 1, 0))));
boolean fff = !blocks.containsKey(new BlockVector(i.clone().add(new BlockVector(0, 2, 0))));
boolean a = !blocks.containsKey((BlockVector) i.clone().add(new BlockVector(0, 1, 0)));
boolean fff = !blocks.containsKey((BlockVector) i.clone().add(new BlockVector(0, 2, 0)));
if (!marker.isEmptyAbove() || (a && fff)) {
markers.put(i, j.getMarker());
@@ -904,13 +927,14 @@ public class IrisObject extends IrisRegistrant {
}
}
for (BlockVector g : getBlocks().keySet()) {
for (var entry : blocks) {
var g = entry.getKey();
BlockData d;
TileData tile = null;
try {
d = getBlocks().get(g);
tile = getStates().get(g);
d = entry.getValue();
tile = states.get(g);
} catch (Throwable e) {
Iris.reportError(e);
Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (cme)");
@@ -1028,12 +1052,12 @@ public class IrisObject extends IrisRegistrant {
if (stilting) {
readLock.lock();
IrisStiltSettings settings = config.getStiltSettings();
for (BlockVector g : getBlocks().keySet()) {
for (BlockVector g : blocks.keys()) {
BlockData d;
if (settings == null || settings.getPalette() == null) {
try {
d = getBlocks().get(g);
d = blocks.get(g);
} catch (Throwable e) {
Iris.reportError(e);
Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (stilt cme)");
@@ -1140,59 +1164,60 @@ public class IrisObject extends IrisRegistrant {
}
public void rotate(IrisObjectRotation r, int spinx, int spiny, int spinz) {
KMap<BlockVector, BlockData> d = new KMap<>();
writeLock.lock();
VectorMap<BlockData> d = new VectorMap<>();
for (BlockVector i : getBlocks().keySet()) {
d.put(r.rotate(i.clone(), spinx, spiny, spinz), r.rotate(getBlocks().get(i).clone(),
spinx, spiny, spinz));
for (var entry : blocks) {
d.put(r.rotate(entry.getKey(), spinx, spiny, spinz), r.rotate(entry.getValue(), spinx, spiny, spinz));
}
KMap<BlockVector, TileData> dx = new KMap<>();
VectorMap<TileData> dx = new VectorMap<>();
for (BlockVector i : getStates().keySet()) {
dx.put(r.rotate(i.clone(), spinx, spiny, spinz), getStates().get(i));
for (var entry : states) {
dx.put(r.rotate(entry.getKey(), spinx, spiny, spinz), entry.getValue());
}
blocks = d;
states = dx;
shrinkwrap();
writeLock.unlock();
}
public void place(Location at) {
for (BlockVector i : getBlocks().keySet()) {
readLock.lock();
for (var entry : blocks) {
var i = entry.getKey();
Block b = at.clone().add(0, getCenter().getY(), 0).add(i).getBlock();
b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false);
b.setBlockData(Objects.requireNonNull(entry.getValue()), false);
if (getStates().containsKey(i)) {
if (states.containsKey(i)) {
Iris.info(Objects.requireNonNull(states.get(i)).toString());
Objects.requireNonNull(getStates().get(i)).toBukkitTry(b);
Objects.requireNonNull(states.get(i)).toBukkitTry(b);
}
}
readLock.unlock();
}
public void placeCenterY(Location at) {
for (BlockVector i : getBlocks().keySet()) {
readLock.lock();
for (var entry : blocks) {
var i = entry.getKey();
Block b = at.clone().add(getCenter().getX(), getCenter().getY(), getCenter().getZ()).add(i).getBlock();
b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false);
b.setBlockData(Objects.requireNonNull(entry.getValue()), false);
if (getStates().containsKey(i)) {
Objects.requireNonNull(getStates().get(i)).toBukkitTry(b);
if (states.containsKey(i)) {
Objects.requireNonNull(states.get(i)).toBukkitTry(b);
}
}
}
public synchronized KMap<BlockVector, BlockData> getBlocks() {
return blocks;
}
public synchronized KMap<BlockVector, TileData> getStates() {
return states;
readLock.unlock();
}
public void unplaceCenterY(Location at) {
for (BlockVector i : getBlocks().keySet()) {
readLock.lock();
for (BlockVector i : blocks.keys()) {
at.clone().add(getCenter().getX(), getCenter().getY(), getCenter().getZ()).add(i).getBlock().setBlockData(AIR, false);
}
readLock.unlock();
}
public IrisObject scaled(double scale, IrisObjectPlacementScaleInterpolator interpolation) {
@@ -1204,7 +1229,7 @@ public class IrisObject extends IrisRegistrant {
IrisPosition l1 = getAABB().max();
IrisPosition l2 = getAABB().min();
@SuppressWarnings({"unchecked", "rawtypes"}) HashMap<BlockVector, BlockData> placeBlock = new HashMap();
VectorMap<BlockData> placeBlock = new VectorMap<>();
Vector center = getCenter();
if (getH() == 2) {
@@ -1219,17 +1244,19 @@ public class IrisObject extends IrisRegistrant {
IrisObject oo = new IrisObject((int) Math.ceil((w * scale) + (scale * 2)), (int) Math.ceil((h * scale) + (scale * 2)), (int) Math.ceil((d * scale) + (scale * 2)));
for (Map.Entry<BlockVector, BlockData> entry : blocks.entrySet()) {
readLock.lock();
for (var entry : blocks) {
BlockData bd = entry.getValue();
placeBlock.put(entry.getKey().clone().add(HALF).subtract(center)
.multiply(scale).add(sm1).toBlockVector(), bd);
}
readLock.unlock();
for (Map.Entry<BlockVector, BlockData> entry : placeBlock.entrySet()) {
for (var entry : placeBlock) {
BlockVector v = entry.getKey();
if (scale > 1) {
for (BlockVector vec : blocksBetweenTwoPoints(v.clone().add(center), v.clone().add(center).add(sm1))) {
oo.getBlocks().put(vec, entry.getValue());
oo.blocks.put(vec, entry.getValue());
}
} else {
oo.setUnsigned(v.getBlockX(), v.getBlockY(), v.getBlockZ(), entry.getValue());
@@ -1248,8 +1275,9 @@ public class IrisObject extends IrisRegistrant {
}
public void trilinear(int rad) {
KMap<BlockVector, BlockData> v = getBlocks().copy();
KMap<BlockVector, BlockData> b = new KMap<>();
writeLock.lock();
VectorMap<BlockData> v = blocks;
VectorMap<BlockData> b = new VectorMap<>();
BlockVector min = getAABB().minbv();
BlockVector max = getAABB().maxbv();
@@ -1274,11 +1302,13 @@ public class IrisObject extends IrisRegistrant {
}
blocks = b;
writeLock.unlock();
}
public void tricubic(int rad) {
KMap<BlockVector, BlockData> v = getBlocks().copy();
KMap<BlockVector, BlockData> b = new KMap<>();
writeLock.lock();
VectorMap<BlockData> v = blocks;
VectorMap<BlockData> b = new VectorMap<>();
BlockVector min = getAABB().minbv();
BlockVector max = getAABB().maxbv();
@@ -1303,6 +1333,7 @@ public class IrisObject extends IrisRegistrant {
}
blocks = b;
writeLock.unlock();
}
public void trihermite(int rad) {
@@ -1310,8 +1341,9 @@ public class IrisObject extends IrisRegistrant {
}
public void trihermite(int rad, double tension, double bias) {
KMap<BlockVector, BlockData> v = getBlocks().copy();
KMap<BlockVector, BlockData> b = new KMap<>();
writeLock.lock();
VectorMap<BlockData> v = blocks;
VectorMap<BlockData> b = new VectorMap<>();
BlockVector min = getAABB().minbv();
BlockVector max = getAABB().maxbv();
@@ -1336,11 +1368,13 @@ public class IrisObject extends IrisRegistrant {
}
blocks = b;
writeLock.unlock();
}
private BlockData nearestBlockData(int x, int y, int z) {
BlockVector vv = new BlockVector(x, y, z);
BlockData r = getBlocks().get(vv);
readLock.lock();
BlockData r = blocks.get(vv);
if (r != null && !r.getMaterial().isAir()) {
return r;
@@ -1348,7 +1382,7 @@ public class IrisObject extends IrisRegistrant {
double d = Double.MAX_VALUE;
for (Map.Entry<BlockVector, BlockData> entry : blocks.entrySet()) {
for (var entry : blocks) {
BlockData dat = entry.getValue();
if (dat.getMaterial().isAir()) {
@@ -1362,6 +1396,7 @@ public class IrisObject extends IrisRegistrant {
r = dat;
}
}
readLock.unlock();
return r;
}
@@ -1383,4 +1418,10 @@ public class IrisObject extends IrisRegistrant {
@Override
public void scanForErrors(JSONObject p, VolmitSender sender) {
}
private static class HeaderException extends IOException {
public HeaderException() {
super("Invalid Header");
}
}
}
@@ -28,13 +28,13 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.bukkit.Axis;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.*;
import org.bukkit.block.data.type.RedstoneWire;
import org.bukkit.block.data.type.Wall;
import org.bukkit.block.structure.StructureRotation;
import org.bukkit.util.BlockVector;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -101,15 +101,15 @@ public class IrisObjectRotation {
return e.rotateCopy(this);
}
public IrisJigsawPiece rotateCopy(IrisJigsawPiece v) {
public IrisJigsawPiece rotateCopy(IrisJigsawPiece v, IrisPosition offset) {
IrisJigsawPiece piece = v.copy();
for (IrisJigsawPieceConnector i : piece.getConnectors()) {
i.setPosition(rotate(i.getPosition()));
i.setPosition(rotate(i.getPosition()).add(offset));
i.setDirection(rotate(i.getDirection()));
}
try {
var translate = piece.getPlacementOptions().getTranslate();
var pos = rotate(new IrisPosition(translate.getX(), translate.getY(), translate.getZ()));
var pos = rotate(new IrisPosition(translate.getX(), translate.getY(), translate.getZ())).add(offset);
translate.setX(pos.getX()).setY(pos.getY()).setZ(pos.getZ());
} catch (NullPointerException ignored) {}
@@ -259,14 +259,14 @@ public class IrisObjectRotation {
g.setRotation(face);
} else if (d instanceof Orientable) {
BlockFace f = getFace(((Orientable) d).getAxis());
} else if (d instanceof Orientable g) {
BlockFace f = getFace(g.getAxis());
BlockVector bv = new BlockVector(f.getModX(), f.getModY(), f.getModZ());
bv = rotate(bv.clone(), spinx, spiny, spinz);
Axis a = getAxis(bv);
if (!a.equals(((Orientable) d).getAxis()) && ((Orientable) d).getAxes().contains(a)) {
((Orientable) d).setAxis(a);
if (!a.equals(g.getAxis()) && g.getAxes().contains(a)) {
g.setAxis(a);
}
} else if (d instanceof MultipleFacing g) {
List<BlockFace> faces = new KList<>();
@@ -304,14 +304,22 @@ public class IrisObjectRotation {
for (BlockFace i : WALL_FACES) {
wall.setHeight(i, faces.getOrDefault(i, Wall.Height.NONE));
}
} else if (d.getMaterial().equals(Material.NETHER_PORTAL) && d instanceof Orientable g) {
//TODO: Fucks up logs
BlockFace f = faceForAxis(g.getAxis());
BlockVector bv = new BlockVector(f.getModX(), f.getModY(), f.getModZ());
bv = rotate(bv.clone(), spinx, spiny, spinz);
BlockFace t = getFace(bv);
Axis a = !g.getAxes().contains(Axis.Y) ? axisFor(t) : axisFor2D(t);
((Orientable) d).setAxis(a);
} else if (d instanceof RedstoneWire wire) {
Map<BlockFace, RedstoneWire.Connection> faces = new HashMap<>();
var allowed = wire.getAllowedFaces();
for (BlockFace i : allowed) {
RedstoneWire.Connection connection = wire.getFace(i);
BlockVector bv = new BlockVector(i.getModX(), i.getModY(), i.getModZ());
bv = rotate(bv.clone(), spinx, spiny, spinz);
BlockFace r = getFace(bv);
if (allowed.contains(r))
faces.put(r, connection);
}
for (BlockFace i : allowed) {
wire.setFace(i, faces.getOrDefault(i, RedstoneWire.Connection.NONE));
}
}
} catch (Throwable e) {
Iris.reportError(e);
@@ -18,7 +18,7 @@ public class IrisPreProcessors {
private String type = "dimension";
@Required
@Desc("The preprocessor scripts")
@Desc("The preprocessor scripts\nFile extension: .proc.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> scripts = new KList<>();
@@ -20,7 +20,7 @@ package com.volmit.iris.engine.object;
import com.volmit.iris.engine.object.annotations.Desc;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.Block;
import org.bukkit.block.data.Waterlogged;
@Desc("The type of surface entities should spawn on")
@@ -47,8 +47,8 @@ public enum IrisSurface {
* @param state The blockstate
* @return True if it matches
*/
public boolean matches(BlockData state) {
Material type = state.getMaterial();
public boolean matches(Block state) {
Material type = state.getType();
if (type.isSolid()) {
return this == LAND || this == OVERWORLD || (this == ANIMAL
&& (type == Material.GRASS_BLOCK || type == Material.DIRT
@@ -1,10 +1,10 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.scheduling.J;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
@@ -80,7 +80,7 @@ public class LegacyTileData extends TileData {
@Override
public void toBukkit(Block block) {
Iris.platform.getRegionScheduler().run(block.getLocation(), () -> handler.toBukkit(block));
J.s(() -> handler.toBukkit(block));
}
@Override
@@ -38,11 +38,10 @@ import com.volmit.iris.util.data.IrisBiomeStorage;
import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder;
import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder;
import com.volmit.iris.util.io.ReactiveFolder;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Looper;
import de.crazydev22.platformutils.scheduler.IRegionExecutor;
import io.papermc.lib.PaperLib;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Setter;
@@ -143,7 +142,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
@Override
public Location getFixedSpawnLocation(@NotNull World world, @NotNull Random random) {
Location location = new Location(world, 0, 64, 0);
Iris.platform.getChunkAtAsync(location)
PaperLib.getChunkAtAsync(location)
.thenAccept(c -> {
World w = c.getWorld();
if (!w.getSpawnLocation().equals(location))
@@ -167,6 +166,8 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
return targetCache.aquire(() -> {
IrisData data = IrisData.get(dataLocation);
data.dump();
data.clearLists();
IrisDimension dimension = data.getDimensionLoader().load(dimensionKey);
if (dimension == null) {
@@ -196,17 +197,17 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
}
@Override
public void injectChunkReplacement(World world, int x, int z, IRegionExecutor executor) {
public void injectChunkReplacement(World world, int x, int z, Executor syncExecutor) {
try {
loadLock.acquire();
IrisBiomeStorage st = new IrisBiomeStorage();
TerrainChunk tc = TerrainChunk.createUnsafe(world, st);
generateNoise(world, RNG.r, x, z, tc);
this.world.bind(world);
getEngine().generate(x << 4, z << 4, tc, IrisSettings.get().getGenerator().useMulticore);
Chunk c = Iris.platform.getChunkAtAsync(world, x, z)
Chunk c = PaperLib.getChunkAtAsync(world, x, z)
.thenApply(d -> {
if (d == null) throw new IllegalStateException("Chunk is null!");
d.addPluginChunkTicket(Iris.instance);
Iris.tickets.addTicket(d);
for (Entity ee : d.getEntities()) {
if (ee instanceof Player) {
@@ -216,7 +217,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
ee.remove();
}
engine.getWorldManager().onChunkLoad(d, false);
return d;
}).get();
@@ -224,7 +224,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
KList<CompletableFuture<?>> futures = new KList<>(1 + getEngine().getHeight() >> 4);
for (int i = getEngine().getHeight() >> 4; i >= 0; i--) {
int finalI = i << 4;
futures.add(executor.queue(world, x, z, () -> {
futures.add(CompletableFuture.runAsync(() -> {
for (int xx = 0; xx < 16; xx++) {
for (int yy = 0; yy < 16; yy++) {
for (int zz = 0; zz < 16; zz++) {
@@ -236,15 +236,15 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
}
}
}
}));
}, syncExecutor));
}
futures.add(CompletableFuture.runAsync(() -> INMS.get().placeStructures(c), syncExecutor));
CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new))
.thenCompose($ -> executor.queue(world, x, z, () -> INMS.get().placeStructures(c)))
.thenCompose($ -> executor.queue(world, x, z, () -> {
c.removePluginChunkTicket(Iris.instance);
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenRunAsync(() -> {
Iris.tickets.removeTicket(c);
engine.getWorldManager().onChunkLoad(c, true);
}))
}, syncExecutor)
.get();
Iris.debug("Regenerated " + x + " " + z);
@@ -255,6 +255,14 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
e.printStackTrace();
Iris.reportErrorChunk(x, z, e, "CHUNK");
Iris.error("======================================");
ChunkData d = Bukkit.createChunkData(world);
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData());
}
}
}
}
@@ -23,12 +23,12 @@ import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineTarget;
import com.volmit.iris.engine.framework.Hotloadable;
import com.volmit.iris.util.data.DataProvider;
import de.crazydev22.platformutils.scheduler.IRegionExecutor;
import org.bukkit.World;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
public interface PlatformChunkGenerator extends Hotloadable, DataProvider {
@Nullable
@@ -42,7 +42,7 @@ public interface PlatformChunkGenerator extends Hotloadable, DataProvider {
@NotNull
EngineTarget getTarget();
void injectChunkReplacement(World world, int x, int z, IRegionExecutor executor);
void injectChunkReplacement(World world, int x, int z, Executor syncExecutor);
void close();
@@ -18,11 +18,10 @@
package com.volmit.iris.util.board;
import com.volmit.iris.Iris;
import de.crazydev22.platformutils.scheduler.task.Task;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import java.util.Collections;
import java.util.Map;
@@ -35,7 +34,7 @@ public class BoardManager {
private final JavaPlugin plugin;
private final Map<UUID, Board> scoreboards;
private final Task updateTask;
private final BukkitTask updateTask;
private BoardSettings boardSettings;
@@ -43,7 +42,7 @@ public class BoardManager {
this.plugin = plugin;
this.boardSettings = boardSettings;
this.scoreboards = new ConcurrentHashMap<>();
this.updateTask = Iris.platform.getGlobalScheduler().runAtFixedRate(new BoardUpdateTask(this), 2L, 20L);
this.updateTask = new BoardUpdateTask(this).runTaskTimer(plugin, 2L, 20L);
plugin.getServer().getOnlinePlayers().forEach(this::setup);
}

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