9
0
mirror of https://github.com/VolmitSoftware/Iris.git synced 2025-12-27 11:09:06 +00:00

Compare commits

...

112 Commits

Author SHA1 Message Date
Julian Krings
6d3edff459 make studio tools work on folia 2025-09-21 20:54:13 +02:00
Julian Krings
e06724fcf6 Merge branch 'refs/heads/dev' into feat/folia
# Conflicts:
#	core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java
#	core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java
#	core/src/main/java/com/volmit/iris/engine/framework/Engine.java
2025-09-21 20:41:11 +02:00
Julian Krings
7e7933858b suppress json syntax exceptions from being reported to sentry 2025-09-21 15:47:29 +02:00
Julian Krings
9c073ecbcb fix infinite loop due to writing the gradle.kts 2025-09-21 14:01:59 +02:00
Julian Krings
f4617c1996 add tabcompletion for mythic mobs mob stacks 2025-09-21 12:51:59 +02:00
Julian Krings
21a2e4feef fix hotloading when changing kts 2025-09-21 12:13:57 +02:00
Julian Krings
258d0d3aaa make sure that the pack is installed correctly 2025-09-21 00:15:34 +02:00
Julian Krings
27b2fd0823 show other packs data again 2025-09-20 23:31:33 +02:00
Julian Krings
0524adb0df fix compile 2025-09-20 23:05:24 +02:00
Julian Krings
3981b0976d cleanup command framework and fix random locator fails 2025-09-20 23:05:16 +02:00
Julian Krings
b5811cae08 cleanup IrisData usage 2025-09-20 23:04:11 +02:00
Julian Krings
c998fd1fd9 move additional build data in its own constants class 2025-09-20 17:25:20 +02:00
Julian Krings
a7d874d37f use scheduled thread pool for scoreboard svc to prevent freezes 2025-09-20 15:27:49 +02:00
Julian Krings
7c41f86fb3 add slope condition for slabs 2025-09-20 14:28:33 +02:00
Julian Krings
e5e0561d5a cleanup world creator 2025-09-17 18:02:45 +02:00
Julian Krings
d50cdfec3e cleanup pack installation 2025-09-17 18:02:20 +02:00
Julian Krings
00997c1902 return if missing datapack entries were found 2025-09-17 17:36:18 +02:00
Julian Krings
3095a92522 add experimental setting to force place custom blocks as early as possible 2025-09-10 23:06:46 +02:00
Julian Krings
fca309dec7 move the loading block data message into debug 2025-09-10 17:02:51 +02:00
Julian Krings
2793ed1035 send block update after placing itemsadder blocks 2025-09-10 17:01:29 +02:00
Julian Krings
e5908285af remove old worlds from cache before retrieving 2025-09-10 16:15:01 +02:00
Julian Krings
a8ee321eb8 Allow placing datapack structures in Iris worlds (#1225)
* Allow placing datapack structures in Iris worlds

* command for generating configs for datapack structures

* remove the sub dir from the snippet key
2025-09-07 18:36:08 +02:00
Julian Krings
aa14242b54 another mantle fix 2025-09-07 16:50:23 +02:00
Julian Krings
b8219fac1b Merge branch 'dev' into feat/folia
# Conflicts:
#	core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java
#	core/src/main/java/com/volmit/iris/engine/framework/Engine.java
#	core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java
2025-09-06 18:37:29 +02:00
Julian Krings
f6968269b4 add toggle to offset noise types fixing seeds 2025-09-06 14:35:25 +02:00
Julian Krings
0d0251e2f1 add toggle to change rarity algorithm 2025-09-06 14:21:52 +02:00
Julian Krings
81b8fb02ae replace rarity calculation due to it breaking at more than two values 2025-09-06 14:21:52 +02:00
Julian Krings
77842489e5 add command for checking the effective rarity of regions 2025-09-06 14:21:52 +02:00
Julian Krings
eda1f59d3a fix broken cave floors 2025-09-05 17:02:36 +02:00
Julian Krings
5418868559 fix hotloading mantle components 2025-09-05 16:56:56 +02:00
Julian Krings
1d81daafbb add option to control the noise threshold for cave shapes 2025-09-05 16:06:53 +02:00
Julian Krings
609a3585c1 use flat maven repository for classpath context 2025-09-05 16:04:49 +02:00
Julian Krings
571dde608c add shared class loader support for script dependencies 2025-09-05 12:21:28 +02:00
Julian Krings
3a13f5a7c1 fix dependency resolve failing on new intelij versions 2025-09-04 23:07:37 +02:00
Julian Krings
e5654b74d4 Auto Completion for block properties (#1222) 2025-09-04 18:06:00 +02:00
Julian Krings
a75738dd7a minor noise optimizations 2025-09-04 16:13:41 +02:00
Julian Krings
003be1f88b use mantle chunk for deposit modifier 2025-09-04 13:56:05 +02:00
Julian Krings
1eaafae20d move caffeine cache executors into a virtual thread executor 2025-09-04 13:55:34 +02:00
Julian Krings
79088c0305 fix hyperlock not releasing on exceptions 2025-09-04 13:55:03 +02:00
Julian Krings
9e147774bd revert mantle change to hopefully fix deadlock 2025-09-04 13:54:28 +02:00
Julian Krings
e51b632c8f Merge pull request #1221 from VolmitSoftware/feat/kts
Kotlin script engine
2025-09-04 13:43:08 +02:00
Julian Krings
1aa64c9a02 add hook for custom engine modes 2025-09-03 17:02:39 +02:00
Julian Krings
1e148d8fcd minor code cleanup 2025-09-03 13:32:08 +02:00
Julian Krings
f63cabd8b8 fix mantle flag serialization 2025-09-03 12:56:02 +02:00
Julian Krings
176d3a5f9f remove old system property 2025-09-02 22:14:59 +02:00
Julian Krings
eb184983de fix json property description on vscode 2025-09-02 22:09:32 +02:00
Julian Krings
d1c307865d properly generate gradle wrapper for kts tab completion 2025-09-02 22:05:11 +02:00
Julian Krings
4a26b8b34f fix compile 2025-09-02 21:57:34 +02:00
Julian Krings
33fd01c3ac Merge branch 'dev' into feat/kts
# Conflicts:
#	core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java
#	core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java
#	core/src/main/java/com/volmit/iris/engine/mantle/components/MantleJigsawComponent.java
#	core/src/main/java/com/volmit/iris/util/mantle/Mantle.java
#	core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java
2025-09-02 12:47:23 +02:00
Julian Krings
34874080e7 cleanup some array types for json schema generation 2025-09-02 12:28:54 +02:00
Julian Krings
43131ed8f6 make jar scanner also load child classes 2025-09-02 12:27:26 +02:00
Julian Krings
9ea425aee4 isolate io stuff in its own MultiBurst 2025-09-02 12:27:01 +02:00
Julian Krings
2885a39299 cleanup script engine 2025-08-09 00:00:31 +02:00
Julian Krings
768e569400 Merge branch 'dev' into feat/kts
# Conflicts:
#	core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java
#	gradle/libs.versions.toml
2025-08-02 23:32:08 +02:00
Julian Krings
bddc061f46 make chunk retrieval to teleport async 2025-08-02 23:31:17 +02:00
Julian Krings
bf6af9a58d Merge branch 'dev' into feat/folia 2025-08-02 23:26:34 +02:00
Julian Krings
aaf2f2f8a6 fix teleport after world creation 2025-08-02 23:15:57 +02:00
Julian Krings
dc8cf0ad38 remove last usages of the bukkit scheduler 2025-08-02 23:15:21 +02:00
Julian Krings
bd07f5d325 add link for Worlds to bring back world creation on folia 2025-08-02 22:23:05 +02:00
Julian Krings
bd722fdacb Merge branch 'dev' into feat/folia
# Conflicts:
#	core/build.gradle.kts
#	core/src/main/java/com/volmit/iris/Iris.java
#	core/src/main/java/com/volmit/iris/core/commands/CommandIris.java
#	gradle/libs.versions.toml
2025-08-02 21:25:40 +02:00
Julian Krings
a82882c1c1 move local maven repo into iris directory 2025-08-01 12:35:08 +02:00
Julian Krings
05193bd0d9 make depencency resolvers more predictable 2025-08-01 04:51:58 +02:00
Julian Krings
96efc15c36 fix local dependencies not resolving properly 2025-07-31 17:08:50 +02:00
Julian Krings
67f456cf53 cleanup script engine 2025-07-31 00:16:23 +02:00
Julian Krings
8ddc8abdb9 fix resolving dependencies in scripts 2025-07-30 16:54:19 +02:00
Julian Krings
12c2c71739 Merge branch 'refs/heads/dev' into feat/kts
# Conflicts:
#	core/build.gradle.kts
#	core/src/main/java/com/volmit/iris/Iris.java
#	core/src/main/java/com/volmit/iris/core/link/data/MythicMobsDataProvider.java
#	core/src/main/java/com/volmit/iris/util/misc/SlimJar.java
#	gradle/libs.versions.toml
2025-07-29 13:34:25 +02:00
Julian Krings
d5ec6a18a4 fix loot not being applied 2025-07-26 12:31:24 +02:00
Julian Krings
2f16c0cfb7 Merge branch 'dev' into feat/folia 2025-07-25 22:34:17 +02:00
Julian Krings
f7ac827692 don't relocate platform utils for now 2025-07-25 22:34:05 +02:00
Julian Krings
bddc62f385 fix object saving 2025-07-20 00:50:11 +02:00
Julian Krings
68a214edb5 move platform utils to the version catalog 2025-07-19 23:02:49 +02:00
Julian Krings
49d2392c80 use platform utils for regen 2025-07-19 22:55:25 +02:00
Julian Krings
fcbbd2135b apply folia modification to 1.21.7 nms 2025-07-19 22:53:06 +02:00
Julian Krings
c3442ab2ce Merge branch 'dev' into feat/folia
# Conflicts:
#	build.gradle.kts
#	core/build.gradle.kts
#	core/src/main/java/com/volmit/iris/Iris.java
#	core/src/main/java/com/volmit/iris/core/commands/CommandIris.java
#	core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java
#	core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java
#	core/src/main/resources/plugin.yml
#	nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java
#	nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java
#	nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java
#	nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java
#	nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java
#	nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java
#	nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java
#	settings.gradle.kts
2025-07-19 22:50:48 +02:00
Julian Krings
3d2392843a update maven core to fix dependency resolution issues 2025-07-12 14:18:35 +02:00
Julian Krings
8f5f44bc96 open vscode after studio world was created 2025-07-10 18:24:50 +02:00
Julian Krings
6964b99744 fix reading custom mantle flags from json 2025-07-10 16:41:46 +02:00
Julian Krings
11cfd85f6a allow creation of custom mantle flags for custom mantle components 2025-07-10 16:11:02 +02:00
Julian Krings
c5416f54fa add script hook for custom noise 2025-07-09 23:40:04 +02:00
Julian Krings
1bc6192c8b merge kts engine into this codebase 2025-07-09 15:16:11 +02:00
Julian Krings
4b0766c097 remove bfs 2025-07-09 14:24:24 +02:00
Julian Krings
ec5cb2d646 Merge branch 'dev' into feat/kts
# Conflicts:
#	core/build.gradle.kts
#	core/src/main/java/com/volmit/iris/Iris.java
#	core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java
2025-07-09 14:23:53 +02:00
Julian Krings
0a30881f87 add jaxen to runtime dependencies 2025-07-08 16:08:30 +02:00
Julian Krings
c01a7def5d add iris data setup hook 2025-07-08 15:37:14 +02:00
Julian Krings
50db1d11a7 move script engine libraries into the iris plugin folder 2025-07-08 12:30:21 +02:00
Julian Krings
badf108d56 Merge branch 'dev' into feat/kts
# Conflicts:
#	core/build.gradle.kts
#	core/src/main/java/com/volmit/iris/Iris.java
#	core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java
#	core/src/main/java/com/volmit/iris/util/io/IO.java
#	core/src/main/resources/plugin.yml
2025-07-08 00:36:30 +02:00
Julian Krings
c35c858eee add scripts for engine setup 2025-07-07 21:06:36 +02:00
Julian Krings
fd3971018b update platform utils 2025-06-23 16:16:25 +02:00
Julian Krings
b440d0257d fix iris what commands 2025-06-19 19:50:08 +02:00
Julian Krings
42a26a1de2 fix spawning empty particles and improve message for invalid tile states 2025-06-19 19:43:53 +02:00
Julian Krings
c8eab22427 fix a few sync teleports 2025-06-19 18:28:46 +02:00
Julian Krings
fa3e35f702 fix pregen save chunk failing 2025-06-19 18:28:22 +02:00
Julian Krings
cf0bc81778 replace scheduler and paperlib with platform utils 2025-06-19 17:46:08 +02:00
Julian Krings
bef99f18c3 fix effects 2025-06-18 12:00:55 +02:00
Julian Krings
96a384c09c fix modern tile states not applying 2025-06-18 11:51:09 +02:00
Julian Krings
d61b2205c0 handle failing restart command better 2025-06-18 11:25:41 +02:00
Julian Krings
ebdfb94392 Merge branch 'dev' into feat/folia 2025-06-17 21:28:29 +02:00
Julian Krings
2929a1f0a7 update Script Engine to e08b6f893e 2025-06-16 22:44:15 +02:00
Julian Krings
b6f9f68b9f add global preprocessor setting 2025-06-16 22:43:26 +02:00
Julian Krings
73787e21d2 Merge branch 'dev' into feat/kts
# Conflicts:
#	build.gradle
#	core/src/main/java/com/volmit/iris/Iris.java
#	core/src/main/java/com/volmit/iris/util/io/IO.java
2025-06-15 22:54:56 +02:00
Julian Krings
1c5fe016cb handle failing world creation 2025-06-15 12:36:53 +02:00
Julian Krings
0957b9baf2 Merge branch 'dev' into feat/folia
# Conflicts:
#	core/src/main/java/com/volmit/iris/Iris.java
2025-06-15 12:24:18 +02:00
Julian Krings
7570064b1a fix locate command not teleporting 2025-06-14 19:36:32 +02:00
Julian Krings
e461c1e199 fix updater and mob spawning instantly failing 2025-06-14 19:35:28 +02:00
Julian Krings
35b879f0df get iris to load on folia, but it will not load worlds as this is currently not possible 2025-06-13 21:44:02 +02:00
Julian Krings
ba6fac5422 more helper methods 2025-06-13 21:05:11 +02:00
Julian Krings
2577344ac0 implement platform specific schedulers 2025-06-13 19:48:42 +02:00
Julian Krings
5958bcb22e update Script Engine to 41396a77d5 2025-04-28 21:40:44 +02:00
Julian Krings
8eb35aa8be update Script Engine to b5e2cc6e 2025-04-28 21:24:54 +02:00
Julian Krings
e72abc8c39 generate json schemas for intelij 2025-04-24 16:00:23 +02:00
Julian Krings
0a2f35dd8d update the scripting engine and fix cached file extension 2025-04-23 21:24:14 +02:00
Julian Krings
c597c55c2c replace rhino scripting engine with kotlin scripting 2025-04-23 14:21:09 +02:00
215 changed files with 6787 additions and 2678 deletions

View File

@@ -2,6 +2,7 @@ import com.volmit.nmstools.NMSToolsExtension
import com.volmit.nmstools.NMSToolsPlugin
import de.undercouch.gradle.tasks.download.Download
import xyz.jpenilla.runpaper.task.RunServer
import xyz.jpenilla.runtask.service.DownloadsAPIService
import kotlin.system.exitProcess
/*
@@ -62,7 +63,7 @@ val serverMinHeap = "2G"
val serverMaxHeap = "8G"
//Valid values are: none, truecolor, indexed256, indexed16, indexed8
val color = "truecolor"
val errorReporting = false
val errorReporting = findProperty("errorReporting") as Boolean? ?: false
val nmsBindings = mapOf(
"v1_21_R5" to "1.21.7-R0.1-SNAPSHOT",
@@ -94,6 +95,9 @@ nmsBindings.forEach { key, value ->
compileOnly(project(":core"))
compileOnly(rootProject.libs.annotations)
compileOnly(rootProject.libs.byteBuddy.core)
compileOnly(rootProject.libs.platformUtils) {
isTransitive = false
}
}
}
@@ -111,6 +115,22 @@ nmsBindings.forEach { key, value ->
systemProperty("iris.suppressReporting", !errorReporting)
jvmArgs("-javaagent:${project(":core:agent").tasks.jar.flatMap { it.archiveFile }.get().asFile.absolutePath}")
}
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}")
}
}
tasks {
@@ -195,6 +215,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
}
dependencies {

View File

@@ -28,6 +28,8 @@ plugins {
alias(libs.plugins.sentry)
alias(libs.plugins.slimjar)
alias(libs.plugins.grgit)
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.lombok)
}
val apiVersion = "1.19"
@@ -65,22 +67,28 @@ dependencies {
isTransitive = false
}
compileOnly(libs.multiverseCore)
compileOnly(libs.worlds)
// 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)
slim(libs.commons.io)
slim(libs.commons.lang)
slim(libs.commons.lang3)
slim(libs.commons.math3)
slim(libs.oshi)
slim(libs.lz4)
slim(libs.fastutil)
@@ -88,11 +96,28 @@ dependencies {
slim(libs.zip)
slim(libs.gson)
slim(libs.asm)
slim(libs.bsf)
slim(libs.rhino)
slim(libs.caffeine)
slim(libs.byteBuddy.core)
slim(libs.byteBuddy.agent)
slim(libs.dom4j)
slim(libs.jaxen)
// Script Engine
slim(libs.kotlin.stdlib)
slim(libs.kotlin.coroutines)
slim(libs.kotlin.scripting.common)
slim(libs.kotlin.scripting.jvm)
slim(libs.kotlin.scripting.jvm.host)
slim(libs.kotlin.scripting.dependencies.maven) {
constraints {
slim(libs.mavenCore)
}
}
constraints {
slim(libs.gson)
compileOnly(libs.gson)
}
}
java {
@@ -116,10 +141,16 @@ slimJar {
))
relocate("com.dfsek.paralithic", "$lib.paralithic")
relocate("io.papermc.lib", "$lib.paper")
relocate("net.kyori", "$lib.kyori")
relocate("net.kyori.audience", "$lib.audience")
relocate("org.bstats", "$lib.metrics")
relocate("io.sentry", "$lib.sentry")
relocate("org.apache.maven", "$lib.maven")
relocate("org.codehaus.plexus", "$lib.plexus")
relocate("org.eclipse.sisu", "$lib.sisu")
relocate("org.eclipse.aether", "$lib.aether")
relocate("com.google.inject", "$lib.guice")
relocate("org.dom4j", "$lib.dom4j")
relocate("org.jaxen", "$lib.jaxen")
}
tasks {
@@ -140,15 +171,6 @@ tasks {
"version" to rootProject.version,
"apiVersion" to apiVersion,
"main" to main,
"environment" to if (project.hasProperty("release")) "production" else "development",
"commit" to provider {
val res = runCatching { project.extensions.getByType<Grgit>().head().id }
res.getOrDefault("")
.takeIf { it.length == 40 } ?: {
logger.error("Git commit hash not found", res.exceptionOrNull())
"unknown"
}()
},
)
filesMatching("**/plugin.yml") {
expand(inputs.properties)
@@ -163,9 +185,35 @@ tasks {
}
}
/**
* Gradle is weird sometimes, we need to delete the plugin yml from the build folder to actually filter properly.
*/
afterEvaluate {
layout.buildDirectory.file("resources/main/plugin.yml").get().asFile.delete()
val templateSource = file("src/main/templates")
val templateDest = layout.buildDirectory.dir("generated/sources/templates")
val generateTemplates = tasks.register<Copy>("generateTemplates") {
inputs.properties(
"environment" to if (project.hasProperty("release")) "production" else "development",
"commit" to provider {
val res = runCatching { project.extensions.getByType<Grgit>().head().id }
res.getOrDefault("")
.takeIf { it.length == 40 } ?: {
logger.error("Git commit hash not found", res.exceptionOrNull())
"unknown"
}()
},
)
from(templateSource)
into(templateDest)
rename { "com/volmit/iris/$it" }
expand(inputs.properties)
}
tasks.generateSentryBundleIdJava {
dependsOn(generateTemplates)
}
rootProject.tasks.named("prepareKotlinBuildScriptModel") {
dependsOn(generateTemplates)
}
sourceSets.main {
java.srcDir(generateTemplates.map { it.outputs })
}

View File

@@ -62,6 +62,8 @@ 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;
@@ -79,6 +81,7 @@ 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;
@@ -95,6 +98,7 @@ public class Iris extends VolmitPlugin implements Listener {
public static MultiverseCoreLink linkMultiverseCore;
public static IrisCompat compat;
public static FileWatcher configWatcher;
public static Platform platform;
private static VolmitSender sender;
private static Thread shutdownHook;
@@ -313,15 +317,14 @@ public class Iris extends VolmitPlugin implements Listener {
@SuppressWarnings("deprecation")
public static void later(NastyRunnable object) {
try {
Bukkit.getScheduler().scheduleAsyncDelayedTask(instance, () ->
{
platform.getAsyncScheduler().runDelayed(task -> {
try {
object.run();
} catch (Throwable e) {
e.printStackTrace();
Iris.reportError(e);
}
}, RNG.r.i(100, 1200));
}, RNG.r.i(5, 60), TimeUnit.SECONDS);
} catch (IllegalPluginAccessException ignored) {
}
@@ -441,6 +444,7 @@ 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));
@@ -456,7 +460,7 @@ public class Iris extends VolmitPlugin implements Listener {
services.values().forEach(this::registerListener);
addShutdownHook();
J.s(() -> {
J.a(IrisSafeguard::suggestPaper);
//J.a(IrisSafeguard::suggestPaper); //TODO reimplement this
J.a(() -> IO.delete(getTemp()));
J.a(LazyPregenerator::loadLazyGenerators, 100);
J.a(this::bstats);
@@ -485,6 +489,7 @@ public class Iris extends VolmitPlugin implements Listener {
.forEach(PlatformChunkGenerator::close);
MultiBurst.burst.close();
MultiBurst.ioBurst.close();
services.clear();
});
Runtime.getRuntime().addShutdownHook(shutdownHook);
@@ -505,8 +510,13 @@ public class Iris extends VolmitPlugin implements Listener {
WorldCreator c = new WorldCreator(s)
.generator(gen)
.environment(dim.getEnvironment());
INMS.get().createWorld(c);
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
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;
});
} catch (Throwable e) {
Iris.error("Failed to load world " + s + "!");
e.printStackTrace();
@@ -527,7 +537,7 @@ public class Iris extends VolmitPlugin implements Listener {
J.s(() -> {
for (Player i : getServer().getOnlinePlayers()) {
i.setGameMode(GameMode.SPECTATOR);
i.teleport(new Location(w, 0, 200, 0));
platform.teleportAsync(i, new Location(w, 0, 200, 0));
}
});
});
@@ -561,12 +571,11 @@ public class Iris extends VolmitPlugin implements Listener {
public void onDisable() {
services.values().forEach(IrisService::onDisable);
Bukkit.getScheduler().cancelTasks(this);
HandlerList.unregisterAll((Plugin) this);
postShutdown.forEach(Runnable::run);
super.onDisable();
J.attempt(new JarScanner(instance.getJarFile(), "", false)::scan);
J.attempt(new JarScanner(instance.getJarFile(), "", false)::scanAll);
}
private void setupPapi() {
@@ -706,7 +715,11 @@ public class Iris extends VolmitPlugin implements Listener {
Iris.debug("Generator Config: " + w.toString());
File ff = new File(w.worldFolder(), "iris/pack");
if (!ff.exists() || ff.listFiles().length == 0) {
var files = ff.listFiles();
if (files == null || files.length == 0)
IO.delete(ff);
if (!ff.exists()) {
ff.mkdirs();
service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w.worldFolder());
}
@@ -716,13 +729,13 @@ public class Iris extends VolmitPlugin implements Listener {
@Nullable
public static IrisDimension loadDimension(@NonNull String worldName, @NonNull String id) {
var data = IrisData.get(new File(Bukkit.getWorldContainer(), String.join(File.separator, worldName, "iris", "pack")));
var dimension = data.getDimensionLoader().load(id);
if (dimension == null) dimension = IrisData.loadAnyDimension(id);
File pack = new File(Bukkit.getWorldContainer(), String.join(File.separator, worldName, "iris", "pack"));
var dimension = pack.isDirectory() ? IrisData.get(pack).getDimensionLoader().load(id) : null;
if (dimension == null) dimension = IrisData.loadAnyDimension(id, null);
if (dimension == null) {
Iris.warn("Unable to find dimension type " + id + " Looking for online packs...");
Iris.service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, false);
dimension = IrisData.loadAnyDimension(id);
dimension = IrisData.loadAnyDimension(id, null);
if (dimension != null) {
Iris.info("Resolved missing dimension, proceeding.");
@@ -741,7 +754,7 @@ public class Iris extends VolmitPlugin implements Listener {
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()};
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()};

View File

@@ -49,11 +49,10 @@ public class IrisSettings {
private IrisSettingsSentry sentry = new IrisSettingsSentry();
public static int getThreadCount(int c) {
return switch (c) {
return Math.max(switch (c) {
case -1, -2, -4 -> Runtime.getRuntime().availableProcessors() / -c;
case 0, 1, 2 -> 1;
default -> Math.max(c, 2);
};
}, 1);
}
public static IrisSettings get() {
@@ -138,6 +137,7 @@ public class IrisSettings {
@Data
public static class IrisSettingsConcurrency {
public int parallelism = -1;
public int ioParallelism = -2;
public int worldGenParallelism = -1;
public int getWorldGenThreads() {
@@ -243,6 +243,8 @@ public class IrisSettings {
public int maxBiomeChildDepth = 4;
public boolean preventLeafDecay = true;
public boolean useMulticore = false;
public boolean offsetNoiseTypes = false;
public boolean earlyCustomBlocks = false;
}
@Data

View File

@@ -66,6 +66,7 @@ public class IrisWorlds {
}
public KMap<String, String> getWorlds() {
clean();
return readBukkitWorlds().put(worlds);
}
@@ -76,8 +77,7 @@ public class IrisWorlds {
}
public Stream<IrisDimension> getDimensions() {
return readBukkitWorlds()
.put(worlds)
return getWorlds()
.entrySet()
.stream()
.map(entry -> Iris.loadDimension(entry.getKey(), entry.getValue()))

View File

@@ -103,14 +103,14 @@ public class ServerConfigurator {
return worlds;
}
public static void installDataPacks(boolean fullInstall) {
installDataPacks(DataVersion.getDefault(), fullInstall);
public static boolean installDataPacks(boolean fullInstall) {
return installDataPacks(DataVersion.getDefault(), fullInstall);
}
public static void installDataPacks(IDataFixer fixer, boolean fullInstall) {
public static boolean installDataPacks(IDataFixer fixer, boolean fullInstall) {
if (fixer == null) {
Iris.error("Unable to install datapacks, fixer is null!");
return;
return false;
}
Iris.info("Checking Data Packs...");
DimensionHeight height = new DimensionHeight(fixer);
@@ -129,11 +129,10 @@ public class ServerConfigurator {
IrisDimension.writeShared(folders, height);
Iris.info("Data Packs Setup!");
if (fullInstall)
verifyDataPacksPost(IrisSettings.get().getAutoConfiguration().isAutoRestartOnCustomBiomeInstall());
return fullInstall && verifyDataPacksPost(IrisSettings.get().getAutoConfiguration().isAutoRestartOnCustomBiomeInstall());
}
private static void verifyDataPacksPost(boolean allowRestarting) {
private static boolean verifyDataPacksPost(boolean allowRestarting) {
try (Stream<IrisData> stream = allPacks()) {
boolean bad = stream
.map(data -> {
@@ -148,7 +147,7 @@ public class ServerConfigurator {
})
.toList()
.contains(true);
if (!bad) return;
if (!bad) return false;
}
@@ -172,6 +171,7 @@ public class ServerConfigurator {
J.sleep(3000);
}
return true;
}
public static void restart() {
@@ -179,11 +179,14 @@ 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");
});
}

View File

@@ -18,19 +18,29 @@
package com.volmit.iris.core.commands;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.volmit.iris.Iris;
import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.core.service.IrisEngineSVC;
import com.volmit.iris.core.tools.IrisPackBenchmarking;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.decree.specialhandlers.NullableDimensionHandler;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.CountingDataInputStream;
@@ -42,6 +52,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 lombok.SneakyThrows;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import net.jpountz.lz4.LZ4FrameInputStream;
@@ -59,6 +70,7 @@ import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@@ -143,6 +155,130 @@ public class CommandDeveloper implements DecreeExecutor {
}
}
@SneakyThrows
@Decree(description = "Generate Iris structures for all loaded datapack structures")
public void generateStructures(
@Param(description = "The pack to add the generated structures to", aliases = "pack", defaultValue = "null", customHandler = NullableDimensionHandler.class)
IrisDimension dimension,
@Param(description = "Ignore existing structures", defaultValue = "false")
boolean force
) {
var map = INMS.get().collectStructures();
if (map.isEmpty()) {
sender().sendMessage(C.IRIS + "No structures found");
return;
}
sender().sendMessage(C.IRIS + "Found " + map.size() + " structures");
final File dataDir;
final IrisData data;
final Set<String> existingStructures;
final Map<String, Set<String>> snippets;
final File dimensionFile;
final File structuresFolder;
final File snippetsFolder;
var dimensionObj = new JsonObject();
if (dimension == null) {
dataDir = Iris.instance.getDataFolder("structures");
IO.delete(dataDir);
data = IrisData.get(dataDir);
existingStructures = Set.of();
snippets = Map.of();
dimensionFile = new File(dataDir, "structures.json");
} else {
data = dimension.getLoader();
dataDir = data.getDataFolder();
existingStructures = new KSet<>(data.getJigsawStructureLoader().getPossibleKeys());
dimensionObj = data.getGson().fromJson(IO.readAll(dimension.getLoadFile()), JsonObject.class);
snippets = Optional.ofNullable(dimensionObj.getAsJsonArray("jigsawStructures"))
.map(array -> array.asList()
.stream()
.filter(JsonElement::isJsonPrimitive)
.collect(Collectors.toMap(element -> data.getGson()
.fromJson(element, IrisJigsawStructurePlacement.class)
.getStructure(),
element -> Set.of(element.getAsString()),
KSet::merge)))
.orElse(Map.of());
dimensionFile = dimension.getLoadFile();
}
structuresFolder = new File(dataDir, "jigsaw-structures");
snippetsFolder = new File(dataDir, "snippet" + "/" + IrisJigsawStructurePlacement.class.getAnnotation(Snippet.class).value());
var gson = data.getGson();
var jigsawStructures = Optional.ofNullable(dimensionObj.getAsJsonArray("jigsawStructures"))
.orElse(new JsonArray(map.size()));
map.forEach((key, placement) -> {
String loadKey = "datapack/" + key.namespace() + "/" + key.key();
if (existingStructures.contains(loadKey) && !force)
return;
var structures = placement.structures();
var obj = placement.toJson(loadKey);
if (obj == null || structures.isEmpty()) {
sender().sendMessage(C.RED + "Failed to generate hook for " + key);
return;
}
File snippetFile = new File(snippetsFolder, loadKey + ".json");
try {
IO.writeAll(snippetFile, gson.toJson(obj));
} catch (IOException e) {
sender().sendMessage(C.RED + "Failed to generate snippet for " + key);
e.printStackTrace();
return;
}
Set<String> loadKeys = snippets.getOrDefault(loadKey, Set.of(loadKey));
jigsawStructures.asList().removeIf(e -> loadKeys.contains((e.isJsonObject() ? e.getAsJsonObject().get("structure") : e).getAsString()));
jigsawStructures.add("snippet/" + loadKey);
String structureKey;
if (structures.size() > 1) {
KList<String> common = new KList<>();
for (int i = 0; i < structures.size(); i++) {
var tags = structures.get(i).tags();
if (i == 0) common.addAll(tags);
else common.removeIf(tag -> !tags.contains(tag));
}
structureKey = common.isNotEmpty() ? "#" + common.getFirst() : structures.getFirst().key();
} else structureKey = structures.getFirst().key();
JsonArray array = new JsonArray();
if (structures.size() > 1) {
structures.stream()
.flatMap(structure -> {
String[] arr = new String[structure.weight()];
Arrays.fill(arr, structure.key());
return Arrays.stream(arr);
})
.forEach(array::add);
} else array.add(structureKey);
obj = new JsonObject();
obj.addProperty("structureKey", structureKey);
obj.add("datapackStructures", array);
File out = new File(structuresFolder, loadKey + ".json");
out.getParentFile().mkdirs();
try {
IO.writeAll(out, gson.toJson(obj));
} catch (IOException e) {
e.printStackTrace();
}
});
dimensionObj.add("jigsawStructures", jigsawStructures);
IO.writeAll(dimensionFile, gson.toJson(dimensionObj));
data.hotloaded();
}
@Decree(description = "Test")
public void packBenchmark(
@Param(description = "The pack to bench", aliases = {"pack"}, defaultValue = "overworld")

View File

@@ -42,7 +42,6 @@ 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;
@@ -158,13 +157,8 @@ public class CommandIris implements DecreeExecutor {
return;
}
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);
Iris.platform.teleportAsync(target, world.getSpawnLocation()).thenRun(() ->
new VolmitSender(target).sendMessage(C.GREEN + "You have been teleported to " + world.getName() + "."));
}
@Decree(description = "Print version information")

View File

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

View File

@@ -128,7 +128,7 @@ public class CommandObject implements DecreeExecutor {
public Engine getEngine() {
return null;
}
};
}.sync(world);
}
@Decree(description = "Check the composition of an object")
@@ -136,7 +136,7 @@ public class CommandObject implements DecreeExecutor {
@Param(description = "The object to analyze", customHandler = ObjectHandler.class)
String object
) {
IrisObject o = IrisData.loadAnyObject(object);
IrisObject o = IrisData.loadAnyObject(object, data());
sender().sendMessage("Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD() + "");
sender().sendMessage("Blocks Used: " + NumberFormat.getIntegerInstance().format(o.getBlocks().size()));
@@ -201,7 +201,7 @@ public class CommandObject implements DecreeExecutor {
@Decree(description = "Shrink an object to its minimum size")
public void shrink(@Param(description = "The object to shrink", customHandler = ObjectHandler.class) String object) {
IrisObject o = IrisData.loadAnyObject(object);
IrisObject o = IrisData.loadAnyObject(object, data());
sender().sendMessage("Current Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD());
o.shrinkwrap();
sender().sendMessage("New Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD());
@@ -325,7 +325,7 @@ public class CommandObject implements DecreeExecutor {
// @Param(description = "The scale interpolator to use", defaultValue = "none")
// IrisObjectPlacementScaleInterpolator interpolator
) {
IrisObject o = IrisData.loadAnyObject(object);
IrisObject o = IrisData.loadAnyObject(object, data());
double maxScale = Double.max(10 - o.getBlocks().size() / 10000d, 1);
if (scale > maxScale) {
sender().sendMessage(C.YELLOW + "Indicated scale exceeds maximum. Downscaled to maximum: " + maxScale);

View File

@@ -47,21 +47,16 @@ 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.mantle.MantleFlag;
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.math.*;
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 io.papermc.lib.PaperLib;
import de.crazydev22.platformutils.scheduler.task.Task;
import org.bukkit.*;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.util.BlockVector;
@@ -78,6 +73,7 @@ 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.atomic.AtomicInteger;
import java.util.function.Supplier;
@@ -172,10 +168,10 @@ public class CommandStudio implements DecreeExecutor {
var loc = player().getLocation().clone();
J.a(() -> {
DecreeContext.touch(sender);
PlatformChunkGenerator plat = IrisToolbelt.access(world);
Engine engine = plat.getEngine();
try (SyncExecutor executor = new SyncExecutor(20)) {
DecreeContext.touch(sender);
try (var executor = Iris.platform.createRegionExecutor(20)) {
int x = loc.getBlockX() >> 4;
int z = loc.getBlockZ() >> 4;
@@ -233,9 +229,7 @@ public class CommandStudio implements DecreeExecutor {
chunkMap.forEach((pos, chunk) -> {
var c = mantle.getChunk(pos.getX(), pos.getZ()).use();
try {
for (MantleFlag flag : MantleFlag.values()) {
c.flag(flag, chunk.isFlagged(flag));
}
c.copyFlags(chunk);
c.clear();
for (int y = 0; y < sections; y++) {
var slice = chunk.get(y);
@@ -250,6 +244,8 @@ public class CommandStudio implements DecreeExecutor {
} catch (Throwable e) {
sender().sendMessage("Error while regenerating chunks");
e.printStackTrace();
} finally {
DecreeContext.remove();
}
});
}
@@ -336,29 +332,63 @@ 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);
O<Integer> ta = new O<>();
ta.set(-1);
scheduler.runAtFixedRate(refresh -> {
if (!player.getOpenInventory().getType().equals(InventoryType.CHEST)) {
refresh.cancel();
return;
}
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();
}
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);
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);
}
@Decree(description = "Calculate the chance for each region to generate", origin = DecreeOrigin.PLAYER)
public void regions(@Param(description = "The radius in chunks", defaultValue = "500") int radius) {
var engine = engine();
if (engine == null) {
sender().sendMessage(C.RED + "Only works in an Iris world!");
return;
}
var sender = sender();
var player = player();
Thread.ofVirtual()
.start(() -> {
int d = radius * 2;
KMap<String, AtomicInteger> data = new KMap<>();
engine.getDimension().getRegions().forEach(key -> data.put(key, new AtomicInteger(0)));
var multiBurst = new MultiBurst("Region Sampler");
var executor = multiBurst.burst(radius * radius);
sender.sendMessage(C.GRAY + "Generating data...");
var loc = player.getLocation();
int totalTasks = d * d;
AtomicInteger completedTasks = new AtomicInteger(0);
Task c = J.ar(() -> sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding regions"), 0);
new Spiraler(d, d, (x, z) -> executor.queue(() -> {
var region = engine.getRegion((x << 4) + 8, (z << 4) + 8);
data.computeIfAbsent(region.getLoadKey(), (k) -> new AtomicInteger(0))
.incrementAndGet();
completedTasks.incrementAndGet();
})).setOffset(loc.getBlockX(), loc.getBlockZ()).drain();
executor.complete();
multiBurst.close();
c.cancel();
sender.sendMessage(C.GREEN + "Done!");
var loader = engine.getData().getRegionLoader();
data.forEach((k, v) -> sender.sendMessage(C.GREEN + k + ": " + loader.load(k).getRarity() + " / " + Form.f((double) v.get() / totalTasks * 100, 2) + "%"));
});
}
@Decree(description = "Get all structures in a radius of chunks", aliases = "dist", origin = DecreeOrigin.PLAYER)
public void distances(@Param(description = "The radius in chunks") int radius) {
@@ -370,16 +400,14 @@ public class CommandStudio implements DecreeExecutor {
var sender = sender();
int d = radius * 2;
KMap<String, KList<Position2>> data = new KMap<>();
var multiBurst = new MultiBurst("Distance Sampler", Thread.MIN_PRIORITY);
var multiBurst = new MultiBurst("Distance Sampler");
var executor = multiBurst.burst(radius * radius);
sender.sendMessage(C.GRAY + "Generating data...");
var loc = player().getLocation();
int totalTasks = d * d;
AtomicInteger completedTasks = new AtomicInteger(0);
int c = J.ar(() -> {
sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding structures");
}, 0);
var 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);
@@ -391,7 +419,7 @@ public class CommandStudio implements DecreeExecutor {
executor.complete();
multiBurst.close();
J.car(c);
if (c != null) c.cancel();
for (var key : data.keySet()) {
var list = data.get(key);
@@ -669,8 +697,9 @@ public class CommandStudio implements DecreeExecutor {
}
sender().sendMessage(C.GREEN + "Sending you to the studio world!");
player().teleport(Iris.service(StudioSVC.class).getActiveProject().getActiveProvider().getTarget().getWorld().spawnLocation());
player().setGameMode(GameMode.SPECTATOR);
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);
}
@Decree(description = "Update your dimension projects VSCode workspace")
@@ -686,7 +715,7 @@ public class CommandStudio implements DecreeExecutor {
}
}
@Decree(aliases = "find-objects", description = "Get information about nearby structures")
@Decree(aliases = "find-objects", description = "Get information about nearby structures", origin = DecreeOrigin.PLAYER)
public void objects() {
if (!IrisToolbelt.isIrisWorld(player().getWorld())) {
sender().sendMessage(C.RED + "You must be in an Iris world");
@@ -699,21 +728,29 @@ public class CommandStudio implements DecreeExecutor {
sender().sendMessage("You must be in an iris world.");
return;
}
KList<Chunk> chunks = new KList<>();
int bx = player().getLocation().getChunk().getX();
int bz = player().getLocation().getChunk().getZ();
KMap<Position2, CompletableFuture<Chunk>> chunks = new KMap<>();
var location = player().getLocation();
int bx = location.getBlockX() >> 4;
int bz = location.getBlockZ() >> 4;
Spiraled spiraled = (x, z) -> chunks.putIfAbsent(new Position2(x, z), Iris.platform.getChunkAtAsync(world, x, z));
try {
Location l = player().getTargetBlockExact(48, FluidCollisionMode.NEVER).getLocation();
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();
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();
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();
} catch (Throwable e) {
Iris.reportError(e);
}
new Spiraler(3, 3, (x, z) -> chunks.addIfMissing(world.getChunkAt(x + bx, z + bz))).drain();
new Spiraler(3, 3, (x, z) -> spiraled.on(x + bx, z + bz)).drain();
sender().sendMessage("Capturing IGenData from " + chunks.size() + " nearby chunks.");
try {
File ff = Iris.instance.getDataFile("reports/" + M.ms() + ".txt");
@@ -723,11 +760,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!"));
//pw.println("PaperSpigot: " + (PaperLib.isPaper() ? "Yup!" : "Nope!")); //TODO update this
pw.println("Report Captured At: " + new Date());
pw.println("Chunks: (" + chunks.size() + "): ");
for (Chunk i : chunks) {
for (Position2 i : chunks.keySet()) {
pw.println("- [" + i.getX() + ", " + i.getZ() + "]");
}
@@ -752,25 +789,31 @@ public class CommandStudio implements DecreeExecutor {
Iris.reportError(e);
}
KList<String> biomes = new KList<>();
KList<String> caveBiomes = new KList<>();
KMap<String, KMap<String, KList<String>>> objects = new KMap<>();
KSet<String> biomes = new KSet<>();
KSet<String> caveBiomes = new KSet<>();
KMap<String, KMap<String, KSet<String>>> objects = new KMap<>();
for (Chunk i : chunks) {
for (int j = 0; j < 16; j += 3) {
var engine = engine();
assert engine != null;
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);
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);
}
}
}
}));
}
CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).join();
regions = Objects.requireNonNull(new File(world.getWorldFolder().getPath() + "/region").list()).length;
@@ -790,6 +833,13 @@ 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 ==");
@@ -815,8 +865,8 @@ public class CommandStudio implements DecreeExecutor {
}
}
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() + ")";
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() + ")";
int m = 0;
KSet<String> stop = new KSet<>();
for (IrisObjectPlacement f : bb.getObjects()) {
@@ -841,7 +891,7 @@ public class CommandStudio implements DecreeExecutor {
String n3 = nn3;
objects.computeIfAbsent(n1, (k1) -> new KMap<>())
.computeIfAbsent(n2, (k) -> new KList<>()).addIfMissing(n3);
.computeIfAbsent(n2, (k) -> new KSet<>()).add(n3);
}
}
}

View File

@@ -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());
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);
}
}
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)) + ")");
});
}
}
@Decree(description = "What region am i in?", origin = DecreeOrigin.PLAYER)
public void region() {
try {
Chunk chunk = world().getChunkAt(player().getLocation().getBlockZ() / 16, player().getLocation().getBlockZ() / 16);
IrisRegion r = engine().getRegion(chunk);
var loc = player().getLocation();
IrisRegion r = engine().getRegion(loc);
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)
@Decree(description = "What block am i looking at?", origin = DecreeOrigin.PLAYER, sync = true)
public void block() {
BlockData bd;
try {

View File

@@ -18,9 +18,10 @@
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;
@@ -79,7 +80,7 @@ public class BlockSignal {
e.setTicksLived(1);
e.setVelocity(new Vector(0, 0, 0));
new SR(20) {
new AR(20) {
@Override
public void run() {
if (e.isDead()) {
@@ -87,9 +88,10 @@ public class BlockSignal {
return;
}
e.setTicksLived(1);
e.teleport(tg.clone());
e.setVelocity(new Vector(0, 0, 0));
Iris.platform.teleportAsync(e, tg.clone()).thenAccept(b -> {
e.setTicksLived(1);
e.setVelocity(new Vector(0, 0, 0));
}).join();
}
};

View File

@@ -30,6 +30,7 @@ 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;
@@ -55,7 +56,7 @@ public class JigsawEditor implements Listener {
private final IrisJigsawPiece piece;
private final Location origin;
private final Cuboid cuboid;
private final int ticker;
private final Task ticker;
private final KMap<IrisPosition, Runnable> falling = new KMap<>();
private final ChronoLatch cl = new ChronoLatch(100);
private Location target;
@@ -106,21 +107,26 @@ public class JigsawEditor implements Listener {
}
public Location toLocation(IrisPosition i) {
return origin.clone()
return toBlock(origin.clone()
.add(new Vector(i.getX(), i.getY(), i.getZ()))
.add(object.getCenter())
.getBlock()
.getLocation();
.add(object.getCenter()));
}
public IrisPosition toPosition(Location l) {
return new IrisPosition(l.clone().getBlock().getLocation()
return new IrisPosition(l.clone()
.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)) {
@@ -197,7 +203,7 @@ public class JigsawEditor implements Listener {
}
public void exit() {
J.car(ticker);
if (ticker != null) ticker.cancel();
Iris.instance.unregisterListener(this);
try {
J.sfut(() -> {

View File

@@ -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);
player.teleport(new Location(player.getWorld(), xx, h, zz));
Iris.platform.teleportAsync(player, new Location(player.getWorld(), xx, h, zz));
notify("Teleporting to " + xx + ", " + h + ", " + zz);
} else {
notify("No player in world, can't teleport.");

View File

@@ -1,6 +1,8 @@
package com.volmit.iris.core.link;
import com.volmit.iris.core.link.data.DataType;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
@@ -22,7 +24,9 @@ import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
@Getter
@@ -66,6 +70,18 @@ public abstract class ExternalDataProvider implements Listener {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
/**
* Retrieves a list of all {@link BlockProperty} objects associated with the specified block identifier.
*
* @param blockId The identifier of the block whose properties are to be retrieved. Must not be null.
* @return A list of {@link BlockProperty} objects representing the properties of the block.
* @throws MissingResourceException If the specified block identifier is invalid or cannot be found.
*/
@NotNull
public List<BlockProperty> getBlockProperties(@NotNull Identifier blockId) throws MissingResourceException {
return List.of();
}
/**
* @see ExternalDataProvider#getItemStack(Identifier)
*/
@@ -137,4 +153,18 @@ public abstract class ExternalDataProvider implements Listener {
return new Pair<>(yaw, face);
}
protected static List<BlockProperty> YAW_FACE_BIOME_PROPERTIES = List.of(
BlockProperty.ofEnum(BiomeColor.class, "matchBiome", null),
BlockProperty.ofBoolean("randomYaw", false),
BlockProperty.ofFloat("yaw", 0, 0, 360f, false, true),
BlockProperty.ofBoolean("randomFace", true),
new BlockProperty(
"face",
BlockFace.class,
BlockFace.NORTH,
Arrays.asList(BlockFace.values()).subList(0, BlockFace.values().length - 1),
BlockFace::name
)
);
}

View File

@@ -0,0 +1,68 @@
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();
}
}

View File

@@ -62,7 +62,10 @@ public class ItemAdderDataProvider extends ExternalDataProvider {
@Override
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
CustomBlock.place(blockId.toString(), block.getLocation());
CustomBlock custom;
if ((custom = CustomBlock.place(blockId.toString(), block.getLocation())) == null)
return;
block.setBlockData(custom.getBaseBlockData(), false);
}
@Override

View File

@@ -23,6 +23,7 @@ import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap;
@@ -41,6 +42,7 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException;
import java.util.Optional;
@@ -77,6 +79,19 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@Override
public @NotNull List<BlockProperty> getBlockProperties(@NotNull Identifier blockId) throws MissingResourceException {
CrucibleItem crucibleItem = this.itemManager.getItem(blockId.key())
.orElseThrow(() -> new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()));
if (crucibleItem.getFurnitureData() != null) {
return YAW_FACE_BIOME_PROPERTIES;
} else if (crucibleItem.getBlockData() != null) {
return List.of();
}
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@NotNull
@Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {

View File

@@ -5,10 +5,14 @@ import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.tools.IrisToolbelt;
import io.lumine.mythic.api.adapters.AbstractLocation;
import io.lumine.mythic.api.config.MythicLineConfig;
import io.lumine.mythic.api.mobs.entities.SpawnReason;
import io.lumine.mythic.api.skills.conditions.ILocationCondition;
import io.lumine.mythic.bukkit.BukkitAdapter;
import io.lumine.mythic.bukkit.MythicBukkit;
import io.lumine.mythic.bukkit.adapters.BukkitWorld;
import io.lumine.mythic.bukkit.events.MythicConditionLoadEvent;
import io.lumine.mythic.core.mobs.ActiveMob;
import io.lumine.mythic.core.mobs.MobStack;
import io.lumine.mythic.core.skills.SkillCondition;
import io.lumine.mythic.core.utils.annotations.MythicCondition;
import io.lumine.mythic.core.utils.annotations.MythicField;
@@ -20,6 +24,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
public class MythicMobsDataProvider extends ExternalDataProvider {
public MythicMobsDataProvider() {
@@ -32,18 +37,31 @@ public class MythicMobsDataProvider extends ExternalDataProvider {
@Override
public @Nullable Entity spawnMob(@NotNull Location location, @NotNull Identifier entityId) throws MissingResourceException {
var mm = MythicBukkit.inst().getMobManager().spawnMob(entityId.key(), location);
if (mm == null) throw new MissingResourceException("Failed to find mob!", entityId.namespace(), entityId.key());
return mm.getEntity().getBukkitEntity();
var mm = spawnMob(BukkitAdapter.adapt(location), entityId);
return mm == null ? null : mm.getEntity().getBukkitEntity();
}
private ActiveMob spawnMob(AbstractLocation location, Identifier entityId) throws MissingResourceException {
var manager = MythicBukkit.inst().getMobManager();
var mm = manager.getMythicMob(entityId.key()).orElse(null);
if (mm == null) {
var stack = manager.getMythicMobStack(entityId.key());
if (stack == null) throw new MissingResourceException("Failed to find Mob!", entityId.namespace(), entityId.key());
return stack.spawn(location, 1d, SpawnReason.OTHER, null);
}
return mm.spawn(location, 1d, SpawnReason.OTHER, null, null);
}
@Override
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
if (dataType != DataType.ENTITY) return List.of();
return MythicBukkit.inst()
.getMobManager()
.getMobNames()
.stream()
var manager = MythicBukkit.inst().getMobManager();
return Stream.concat(manager.getMobNames().stream(),
manager.getMobStacks()
.stream()
.map(MobStack::getName)
)
.distinct()
.map(name -> new Identifier("mythicmobs", name))
.toList();
}

View File

@@ -8,6 +8,7 @@ import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap;
@@ -56,6 +57,15 @@ public class NexoDataProvider extends ExternalDataProvider {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@Override
public @NotNull List<BlockProperty> getBlockProperties(@NotNull Identifier blockId) throws MissingResourceException {
if (!NexoItems.exists(blockId.key())) {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
return NexoFurniture.isFurniture(blockId.key()) ? YAW_FACE_BIOME_PROPERTIES : List.of();
}
@NotNull
@Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
@@ -63,7 +73,12 @@ public class NexoDataProvider extends ExternalDataProvider {
if (builder == null) {
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
}
return builder.build();
try {
return builder.build();
} catch (Exception e) {
e.printStackTrace();
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
}
}
@Override

View File

@@ -24,6 +24,7 @@ import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import com.volmit.iris.Iris;
import com.volmit.iris.core.scripting.environment.PackEnvironment;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.*;
@@ -33,6 +34,8 @@ import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.mantle.flag.MantleFlagAdapter;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
@@ -40,6 +43,7 @@ import com.volmit.iris.util.reflect.KeyedType;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import lombok.Data;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileReader;
@@ -47,13 +51,14 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.function.Function;
import java.util.Optional;
@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 ResourceLoader<IrisBiome> biomeLoader;
private ResourceLoader<IrisLootTable> lootLoader;
@@ -87,6 +92,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
this.engine = null;
this.dataFolder = dataFolder;
this.id = RNG.r.imax();
this.environment = PackEnvironment.create(this);
hotloaded();
}
@@ -94,6 +100,10 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
return dataLoaders.computeIfAbsent(dataFolder, IrisData::new);
}
public static Optional<IrisData> getLoaded(File dataFolder) {
return Optional.ofNullable(dataLoaders.get(dataFolder));
}
public static void dereference() {
dataLoaders.v().forEach(IrisData::cleanupEngine);
}
@@ -113,92 +123,100 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
Iris.warn(" " + rl.getResourceTypeName() + " @ /" + rl.getFolderName() + ": Cache=" + rl.getLoadCache().getSize() + " Folders=" + rl.getFolders().size());
}
public static IrisObject loadAnyObject(String key) {
return loadAny(key, (dm) -> dm.getObjectLoader().load(key, false));
public static IrisObject loadAnyObject(String key, @Nullable IrisData nearest) {
return loadAny(IrisObject.class, key, nearest);
}
public static IrisMatterObject loadAnyMatter(String key) {
return loadAny(key, (dm) -> dm.getMatterLoader().load(key, false));
public static IrisMatterObject loadAnyMatter(String key, @Nullable IrisData nearest) {
return loadAny(IrisMatterObject.class, key, nearest);
}
public static IrisBiome loadAnyBiome(String key) {
return loadAny(key, (dm) -> dm.getBiomeLoader().load(key, false));
public static IrisBiome loadAnyBiome(String key, @Nullable IrisData nearest) {
return loadAny(IrisBiome.class, key, nearest);
}
public static IrisExpression loadAnyExpression(String key) {
return loadAny(key, (dm) -> dm.getExpressionLoader().load(key, false));
public static IrisExpression loadAnyExpression(String key, @Nullable IrisData nearest) {
return loadAny(IrisExpression.class, key, nearest);
}
public static IrisMod loadAnyMod(String key) {
return loadAny(key, (dm) -> dm.getModLoader().load(key, false));
public static IrisMod loadAnyMod(String key, @Nullable IrisData nearest) {
return loadAny(IrisMod.class, key, nearest);
}
public static IrisJigsawPiece loadAnyJigsawPiece(String key) {
return loadAny(key, (dm) -> dm.getJigsawPieceLoader().load(key, false));
public static IrisJigsawPiece loadAnyJigsawPiece(String key, @Nullable IrisData nearest) {
return loadAny(IrisJigsawPiece.class, key, nearest);
}
public static IrisJigsawPool loadAnyJigsawPool(String key) {
return loadAny(key, (dm) -> dm.getJigsawPoolLoader().load(key, false));
public static IrisJigsawPool loadAnyJigsawPool(String key, @Nullable IrisData nearest) {
return loadAny(IrisJigsawPool.class, key, nearest);
}
public static IrisEntity loadAnyEntity(String key) {
return loadAny(key, (dm) -> dm.getEntityLoader().load(key, false));
public static IrisEntity loadAnyEntity(String key, @Nullable IrisData nearest) {
return loadAny(IrisEntity.class, key, nearest);
}
public static IrisLootTable loadAnyLootTable(String key) {
return loadAny(key, (dm) -> dm.getLootLoader().load(key, false));
public static IrisLootTable loadAnyLootTable(String key, @Nullable IrisData nearest) {
return loadAny(IrisLootTable.class, key, nearest);
}
public static IrisBlockData loadAnyBlock(String key) {
return loadAny(key, (dm) -> dm.getBlockLoader().load(key, false));
public static IrisBlockData loadAnyBlock(String key, @Nullable IrisData nearest) {
return loadAny(IrisBlockData.class, key, nearest);
}
public static IrisSpawner loadAnySpaner(String key) {
return loadAny(key, (dm) -> dm.getSpawnerLoader().load(key, false));
public static IrisSpawner loadAnySpaner(String key, @Nullable IrisData nearest) {
return loadAny(IrisSpawner.class, key, nearest);
}
public static IrisScript loadAnyScript(String key) {
return loadAny(key, (dm) -> dm.getScriptLoader().load(key, false));
public static IrisScript loadAnyScript(String key, @Nullable IrisData nearest) {
return loadAny(IrisScript.class, key, nearest);
}
public static IrisRavine loadAnyRavine(String key) {
return loadAny(key, (dm) -> dm.getRavineLoader().load(key, false));
public static IrisRavine loadAnyRavine(String key, @Nullable IrisData nearest) {
return loadAny(IrisRavine.class, key, nearest);
}
public static IrisRegion loadAnyRegion(String key) {
return loadAny(key, (dm) -> dm.getRegionLoader().load(key, false));
public static IrisRegion loadAnyRegion(String key, @Nullable IrisData nearest) {
return loadAny(IrisRegion.class, key, nearest);
}
public static IrisMarker loadAnyMarker(String key) {
return loadAny(key, (dm) -> dm.getMarkerLoader().load(key, false));
public static IrisMarker loadAnyMarker(String key, @Nullable IrisData nearest) {
return loadAny(IrisMarker.class, key, nearest);
}
public static IrisCave loadAnyCave(String key) {
return loadAny(key, (dm) -> dm.getCaveLoader().load(key, false));
public static IrisCave loadAnyCave(String key, @Nullable IrisData nearest) {
return loadAny(IrisCave.class, key, nearest);
}
public static IrisImage loadAnyImage(String key) {
return loadAny(key, (dm) -> dm.getImageLoader().load(key, false));
public static IrisImage loadAnyImage(String key, @Nullable IrisData nearest) {
return loadAny(IrisImage.class, key, nearest);
}
public static IrisDimension loadAnyDimension(String key) {
return loadAny(key, (dm) -> dm.getDimensionLoader().load(key, false));
public static IrisDimension loadAnyDimension(String key, @Nullable IrisData nearest) {
return loadAny(IrisDimension.class, key, nearest);
}
public static IrisJigsawStructure loadAnyJigsawStructure(String key) {
return loadAny(key, (dm) -> dm.getJigsawStructureLoader().load(key, false));
public static IrisJigsawStructure loadAnyJigsawStructure(String key, @Nullable IrisData nearest) {
return loadAny(IrisJigsawStructure.class, key, nearest);
}
public static IrisGenerator loadAnyGenerator(String key) {
return loadAny(key, (dm) -> dm.getGeneratorLoader().load(key, false));
public static IrisGenerator loadAnyGenerator(String key, @Nullable IrisData nearest) {
return loadAny(IrisGenerator.class, key, nearest);
}
public static <T extends IrisRegistrant> T loadAny(String key, Function<IrisData, T> v) {
public static <T extends IrisRegistrant> T loadAny(Class<T> type, String key, @Nullable IrisData nearest) {
try {
if (nearest != null) {
T t = nearest.load(type, key, false);
if (t != null) {
return t;
}
}
for (File i : Objects.requireNonNull(Iris.instance.getDataFolder("packs").listFiles())) {
if (i.isDirectory()) {
IrisData dm = get(i);
T t = v.apply(dm);
if (dm == nearest) continue;
T t = dm.load(type, key, false);
if (t != null) {
return t;
@@ -213,6 +231,17 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
return null;
}
public <T extends IrisRegistrant> T load(Class<T> type, String key, boolean warn) {
var loader = getLoader(type);
if (loader == null) return null;
return loader.load(key, warn);
}
@SuppressWarnings("unchecked")
public <T extends IrisRegistrant> ResourceLoader<T> getLoader(Class<T> type) {
return (ResourceLoader<T>) loaders.get(type);
}
public ResourceLoader<?> getTypedLoaderFor(File f) {
String[] k = f.getPath().split("\\Q" + File.separator + "\\E");
@@ -252,12 +281,20 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
}
}
if (engine != null && t.getPreprocessors().isNotEmpty()) {
if (engine == null) return;
var global = engine.getDimension().getPreProcessors(t.getFolderName());
var local = t.getPreprocessors();
if ((global != null && global.isNotEmpty()) || local.isNotEmpty()) {
synchronized (this) {
engine.getExecution().getAPI().setPreprocessorObject(t);
if (global != null) {
for (String i : global) {
engine.getExecution().preprocessObject(i, t);
Iris.debug("Loader<" + C.GREEN + t.getTypeName() + C.LIGHT_PURPLE + "> iprocess " + C.YELLOW + t.getLoadKey() + C.LIGHT_PURPLE + " in <rainbow>" + i);
}
}
for (String i : t.getPreprocessors()) {
engine.getExecution().execute(i);
for (String i : local) {
engine.getExecution().preprocessObject(i, t);
Iris.debug("Loader<" + C.GREEN + t.getTypeName() + C.LIGHT_PURPLE + "> iprocess " + C.YELLOW + t.getLoadKey() + C.LIGHT_PURPLE + " in <rainbow>" + i);
}
}
@@ -271,6 +308,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
public void close() {
closed = true;
dump();
dataLoaders.remove(dataFolder);
}
public IrisData copy() {
@@ -311,12 +349,15 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
}
public synchronized void hotloaded() {
closed = false;
environment.close();
possibleSnippets = new KMap<>();
builder = new GsonBuilder()
.addDeserializationExclusionStrategy(this)
.addSerializationExclusionStrategy(this)
.setLenient()
.registerTypeAdapterFactory(this)
.registerTypeAdapter(MantleFlag.class, new MantleFlagAdapter())
.setPrettyPrinting();
loaders.clear();
File packs = dataFolder;
@@ -344,6 +385,10 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
builder.registerTypeAdapterFactory(KeyedType::createTypeAdapter);
gson = builder.create();
dimensionLoader.streamAll()
.map(IrisDimension::getDataScripts)
.flatMap(KList::stream)
.forEach(environment::execute);
}
public void dump() {
@@ -405,6 +450,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
}
String snippetType = typeToken.getRawType().getDeclaredAnnotation(Snippet.class).value();
String snippedBase = "snippet/" + snippetType + "/";
return new TypeAdapter<>() {
@Override
@@ -418,19 +464,20 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
if (reader.peek().equals(JsonToken.STRING)) {
String r = reader.nextString();
if (!r.startsWith("snippet/"))
return null;
if (!r.startsWith(snippedBase))
r = snippedBase + r.substring(8);
if (r.startsWith("snippet/" + snippetType + "/")) {
File f = new File(getDataFolder(), r + ".json");
if (f.exists()) {
try (JsonReader snippetReader = new JsonReader(new FileReader(f))){
return adapter.read(snippetReader);
} catch (Throwable e) {
Iris.error("Couldn't read snippet " + r + " in " + reader.getPath() + " (" + e.getMessage() + ")");
}
} else {
Iris.error("Couldn't find snippet " + r + " in " + reader.getPath());
File f = new File(getDataFolder(), r + ".json");
if (f.exists()) {
try (JsonReader snippetReader = new JsonReader(new FileReader(f))){
return adapter.read(snippetReader);
} catch (Throwable e) {
Iris.error("Couldn't read snippet " + r + " in " + reader.getPath() + " (" + e.getMessage() + ")");
}
} else {
Iris.error("Couldn't find snippet " + r + " in " + reader.getPath());
}
return null;
@@ -468,7 +515,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
.map(s -> s.substring(absPath.length() + 1))
.map(s -> s.replace("\\", "/"))
.map(s -> s.split("\\Q.\\E")[0])
.forEach(s -> l.add("snippet/" + f + "/" + s));
.forEach(s -> l.add("snippet/" + s));
} catch (Throwable e) {
e.printStackTrace();
}
@@ -482,7 +529,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
}
public void savePrefetch(Engine engine) {
BurstExecutor b = MultiBurst.burst.burst(loaders.size());
BurstExecutor b = MultiBurst.ioBurst.burst(loaders.size());
for (ResourceLoader<?> i : loaders.values()) {
b.queue(() -> {
@@ -499,7 +546,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
}
public void loadPrefetch(Engine engine) {
BurstExecutor b = MultiBurst.burst.burst(loaders.size());
BurstExecutor b = MultiBurst.ioBurst.burst(loaders.size());
for (ResourceLoader<?> i : loaders.values()) {
b.queue(() -> {

View File

@@ -28,6 +28,7 @@ import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.plugin.VolmitSender;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.awt.*;
import java.io.File;
@@ -39,6 +40,7 @@ public abstract class IrisRegistrant {
@ArrayType(min = 1, type = String.class)
private KList<String> preprocessors = new KList<>();
@EqualsAndHashCode.Exclude
private transient IrisData loader;
private transient String loadKey;

View File

@@ -45,6 +45,7 @@ import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.*;
import java.util.Arrays;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@@ -215,6 +216,10 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
return j;
}
public Stream<T> streamAll() {
return streamAll(Arrays.stream(getPossibleKeys()));
}
public Stream<T> streamAll(Stream<String> s) {
return s.map(this::load);
}
@@ -235,7 +240,7 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
public KList<T> loadAllParallel(KList<String> s) {
KList<T> m = new KList<>();
BurstExecutor burst = MultiBurst.burst.burst(s.size());
BurstExecutor burst = MultiBurst.ioBurst.burst(s.size());
for (String i : s) {
burst.queue(() -> {

View File

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

View File

@@ -18,7 +18,13 @@
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;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
@@ -36,9 +42,10 @@ import org.bukkit.entity.EntityType;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.awt.Color;
import java.util.concurrent.CompletableFuture;
import java.util.List;
public interface INMSBinding {
boolean hasTile(Material material);
@@ -96,6 +103,15 @@ 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);
@@ -133,4 +149,10 @@ public interface INMSBinding {
default boolean injectBukkit() {
return true;
}
KMap<Material, List<BlockProperty>> getBlockProperties();
void placeStructures(Chunk chunk);
KMap<Identifier, StructurePlacement> collectStructures();
}

View File

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

View File

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

View File

@@ -19,9 +19,13 @@
package com.volmit.iris.core.nms.v1X;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.INMSBinding;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.nms.container.StructurePlacement;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
@@ -40,6 +44,7 @@ import org.bukkit.generator.structure.Structure;
import org.bukkit.inventory.ItemStack;
import java.awt.Color;
import java.util.List;
import java.util.stream.StreamSupport;
public class NMSBinding1X implements INMSBinding {
@@ -124,6 +129,25 @@ public class NMSBinding1X implements INMSBinding {
return false;
}
@Override
public KMap<Material, List<BlockProperty>> getBlockProperties() {
KMap<Material, List<BlockProperty>> map = new KMap<>();
for (Material m : Material.values()) {
if (m.isBlock()) map.put(m, List.of());
}
return map;
}
@Override
public void placeStructures(Chunk chunk) {
}
@Override
public KMap<Identifier, StructurePlacement> collectStructures() {
return new KMap<>();
}
@Override
public CompoundTag serializeEntity(Entity location) {
return null;

View File

@@ -8,13 +8,12 @@ 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.MantleFlag;
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.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;
@@ -223,7 +222,7 @@ public class ChunkUpdater {
for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) {
if (!PaperLib.isChunkGenerated(world, x + dx, z + dz)) {
if (!Iris.platform.isChunkGenerated(world, x + dx, z + dz)) {
return false;
}
}
@@ -239,7 +238,7 @@ public class ChunkUpdater {
try {
Chunk c;
try {
c = PaperLib.getChunkAtAsync(world, xx, zz, false, true)
c = Iris.platform.getChunkAtAsync(world, xx, zz, false, true)
.thenApply(chunk -> {
if (chunk != null)
chunk.addPluginChunkTicket(Iris.instance);
@@ -260,7 +259,7 @@ public class ChunkUpdater {
if (future != null) future.join();
}
if (!PaperLib.isChunkGenerated(c.getWorld(), xx, zz))
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)));

View File

@@ -22,7 +22,6 @@ 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;
@@ -235,16 +234,13 @@ public class DeepSearchPregenerator extends Thread implements Listener {
}
save();
jobs.remove(world.getName());
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.");
J.a(() -> {
while (deepFile.exists()) {
deepFile.delete();
J.sleep(1000);
}
}.runTaskLater(Iris.instance, 20L);
Iris.info("DeepSearch: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
}, 10);
} catch (Exception e) {
Iris.error("Failed to shutdown DeepSearch for " + world.getName());
e.printStackTrace();

View File

@@ -11,7 +11,6 @@ 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;
@@ -19,7 +18,6 @@ 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;
@@ -149,23 +147,9 @@ public class LazyPregenerator extends Thread implements Listener {
private void tickGenerate(Position2 chunk) {
executorService.submit(() -> {
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) {}
Iris.platform.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true).thenAccept((i) -> {
Iris.verbose("Generated Async " + chunk);
}).join();
lazyGeneratedChunks.addAndGet(1);
});
}
@@ -238,16 +222,13 @@ public class LazyPregenerator extends Thread implements Listener {
}
save();
jobs.remove(world.getName());
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.");
J.a(() -> {
while (lazyFile.exists()){
lazyFile.delete();
J.sleep(1000);
}
}.runTaskLater(Iris.instance, 20L);
Iris.info("LazyGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
}, 20);
} catch (Exception e) {
Iris.error("Failed to shutdown Lazygen for " + world.getName());
e.printStackTrace();

View File

@@ -17,7 +17,6 @@ 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;
@@ -26,7 +25,6 @@ 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;
@@ -227,7 +225,7 @@ public class TurboPregenerator extends Thread implements Listener {
private void tickGenerate(Position2 chunk) {
executorService.submit(() -> {
CountDownLatch latch = new CountDownLatch(1);
PaperLib.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true)
Iris.platform.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true)
.thenAccept((i) -> {
latch.countDown();
});
@@ -302,16 +300,13 @@ public class TurboPregenerator extends Thread implements Listener {
}
save();
jobs.remove(world.getName());
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.");
J.a(() -> {
while (turboFile.exists()) {
turboFile.delete();
J.sleep(1000);
}
}.runTaskLater(Iris.instance, 20L);
Iris.info("turboGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
}, 20);
} catch (Exception e) {
Iris.error("Failed to shutdown turbogen for " + world.getName());
e.printStackTrace();

View File

@@ -3,7 +3,9 @@ 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;
@@ -14,12 +16,10 @@ import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import org.jetbrains.annotations.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import java.io.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
@NotThreadSafe
@RequiredArgsConstructor
class PregenCacheImpl implements PregenCache {
private static final int SIZE = 32;
@@ -27,6 +27,8 @@ class PregenCacheImpl implements PregenCache {
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)

View File

@@ -1,73 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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();
}
}

View File

@@ -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,11 +48,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
private final boolean urgent;
private final Map<Chunk, Long> lastUse;
public AsyncPregenMethod(World world, int unusedThreads) {
if (!PaperLib.isPaper()) {
throw new UnsupportedOperationException("Cannot use PaperAsync on non paper!");
}
public AsyncPregenMethod(World world) {
this.world = world;
this.executor = IrisSettings.get().getPregen().isUseTicketQueue() ? new TicketExecutor() : new ServiceExecutor();
this.threads = IrisSettings.get().getPregen().getMaxConcurrency();
@@ -63,26 +59,28 @@ public class AsyncPregenMethod implements PregeneratorMethod {
private void unloadAndSaveAllChunks() {
try {
J.sfut(() -> {
if (world == null) {
Iris.warn("World was null somehow...");
return;
}
if (world == null) {
Iris.warn("World was null somehow...");
return;
}
long minTime = M.ms() - 10_000;
lastUse.entrySet().removeIf(i -> {
final Chunk chunk = i.getKey();
final Long lastUseTime = i.getValue();
if (!chunk.isLoaded() || lastUseTime == null)
return true;
if (lastUseTime < minTime) {
chunk.unload();
return true;
}
return false;
});
world.save();
}).get();
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;
}
return false;
});
futures.add(Iris.platform.getRegionScheduler().run(world, 0, 0, world::save).getResult());
CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).join();
} catch (Throwable e) {
e.printStackTrace();
}
@@ -192,12 +190,12 @@ public class AsyncPregenMethod implements PregeneratorMethod {
private class ServiceExecutor implements Executor {
private final ExecutorService service = IrisSettings.get().getPregen().isUseVirtualThreads() ?
Executors.newVirtualThreadPerTaskExecutor() :
new MultiBurst("Iris Async Pregen", Thread.MIN_PRIORITY);
new MultiBurst("Iris Async Pregen");
public void generate(int x, int z, PregenListener listener) {
service.submit(() -> {
try {
PaperLib.getChunkAtAsync(world, x, z, true, urgent).thenAccept((i) -> {
Iris.platform.getChunkAtAsync(world, x, z, true, urgent).thenAccept((i) -> {
listener.onChunkGenerated(x, z);
listener.onChunkCleaned(x, z);
if (i == null) return;
@@ -222,7 +220,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
private class TicketExecutor implements Executor {
@Override
public void generate(int x, int z, PregenListener listener) {
PaperLib.getChunkAtAsync(world, x, z, true, urgent)
Iris.platform.getChunkAtAsync(world, x, z, true, urgent)
.exceptionally(e -> {
Iris.reportError(e);
e.printStackTrace();

View File

@@ -1,74 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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();
}
}

View File

@@ -1,138 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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;
}
}

View File

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

View File

@@ -24,6 +24,7 @@ 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;
@@ -49,6 +50,8 @@ import lombok.Data;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.World;
import org.dom4j.Document;
import org.dom4j.Element;
import org.zeroturnaround.zip.ZipUtil;
import java.awt.*;
@@ -156,7 +159,7 @@ public class IrisProject {
public void openVSCode(VolmitSender sender) {
IrisDimension d = IrisData.loadAnyDimension(getName());
IrisDimension d = IrisData.loadAnyDimension(getName(), null);
J.attemptAsync(() ->
{
try {
@@ -217,24 +220,15 @@ public class IrisProject {
close();
}
boolean hasError = false;
if (hasError) {
return;
}
IrisDimension d = IrisData.loadAnyDimension(getName());
if (d == null) {
sender.sendMessage("Can't find dimension: " + getName());
return;
} else if (sender.isPlayer()) {
sender.player().setGameMode(GameMode.SPECTATOR);
}
openVSCode(sender);
J.a(() -> {
IrisDimension d = IrisData.loadAnyDimension(getName(), null);
if (d == null) {
sender.sendMessage("Can't find dimension: " + getName());
return;
} else if (sender.isPlayer()) {
sender.player().setGameMode(GameMode.SPECTATOR);
}
try {
activeProvider = (PlatformChunkGenerator) IrisToolbelt.createWorld()
.seed(seed)
@@ -247,6 +241,8 @@ public class IrisProject {
} catch (IrisException e) {
e.printStackTrace();
}
openVSCode(sender);
});
}
@@ -359,6 +355,74 @@ public class IrisProject {
settings.put("json.schemas", schemas);
ws.put("settings", settings);
dm.getEnvironment().configureProject();
File schemasFile = new File(path, ".idea" + File.separator + "jsonSchemas.xml");
Document doc = IO.read(schemasFile);
Element mappings = (Element) doc.selectSingleNode("//component[@name='JsonSchemaMappingsProjectConfiguration']");
if (mappings == null) {
mappings = doc.getRootElement()
.addElement("component")
.addAttribute("name", "JsonSchemaMappingsProjectConfiguration");
}
Element state = (Element) mappings.selectSingleNode("state");
if (state == null) state = mappings.addElement("state");
Element map = (Element) state.selectSingleNode("map");
if (map == null) map = state.addElement("map");
var schemaMap = new KMap<String, String>();
schemas.forEach(element -> {
if (!(element instanceof JSONObject obj))
return;
String url = obj.getString("url");
String dir = obj.getJSONArray("fileMatch").getString(0);
schemaMap.put(url, dir.substring(1, dir.indexOf("/*")));
});
map.selectNodes("entry/value/SchemaInfo/option[@name='relativePathToSchema']")
.stream()
.map(node -> node.valueOf("@value"))
.forEach(schemaMap::remove);
var ideaSchemas = map;
schemaMap.forEach((url, dir) -> {
var genName = UUID.randomUUID().toString();
var info = ideaSchemas.addElement("entry")
.addAttribute("key", genName)
.addElement("value")
.addElement("SchemaInfo");
info.addElement("option")
.addAttribute("name", "generatedName")
.addAttribute("value", genName);
info.addElement("option")
.addAttribute("name", "name")
.addAttribute("value", dir);
info.addElement("option")
.addAttribute("name", "relativePathToSchema")
.addAttribute("value", url);
var item = info.addElement("option")
.addAttribute("name", "patterns")
.addElement("list")
.addElement("Item");
item.addElement("option")
.addAttribute("name", "directory")
.addAttribute("value", "true");
item.addElement("option")
.addAttribute("name", "path")
.addAttribute("value", dir);
item.addElement("option")
.addAttribute("name", "mappingKind")
.addAttribute("value", "Directory");
});
if (!schemaMap.isEmpty()) {
IO.write(schemasFile, doc);
}
Gradle.wrapper(path);
return ws;
}

View File

@@ -110,9 +110,12 @@ public class SchemaBuilder {
private JSONObject buildProperties(Class<?> c) {
JSONObject o = new JSONObject();
JSONObject properties = new JSONObject();
o.put("description", getDescription(c));
String desc = getDescription(c);
o.put("description", desc);
o.put("x-intellij-html-description", desc.replace("\n", "<br>"));
o.put("type", getType(c));
JSONArray required = new JSONArray();
JSONArray extended = new JSONArray();
if (c.isAssignableFrom(IrisRegistrant.class) || IrisRegistrant.class.isAssignableFrom(c)) {
for (Field k : IrisRegistrant.class.getDeclaredFields()) {
@@ -124,11 +127,15 @@ public class SchemaBuilder {
JSONObject property = buildProperty(k, c);
if (property.getBoolean("!required")) {
if (Boolean.TRUE == property.remove("!required")) {
required.put(k.getName());
}
property.remove("!required");
if (Boolean.TRUE == property.remove("!top")) {
extended.put(property);
continue;
}
properties.put(k.getName(), property);
}
}
@@ -142,15 +149,24 @@ public class SchemaBuilder {
JSONObject property = buildProperty(k, c);
if (property.getBoolean("!required"))
if (Boolean.TRUE == property.remove("!required")) {
required.put(k.getName());
property.remove("!required");
}
if (Boolean.TRUE == property.remove("!top")) {
extended.put(property);
continue;
}
properties.put(k.getName(), property);
}
if (required.length() > 0) {
o.put("required", required);
}
if (extended.length() > 0) {
o.put("allOf", extended);
}
o.put("properties", properties);
@@ -343,13 +359,63 @@ public class SchemaBuilder {
}
}
case "object" -> {
fancyType = k.getType().getSimpleName().replaceAll("\\QIris\\E", "") + " (Object)";
String key = "obj-" + k.getType().getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase();
if (!definitions.containsKey(key)) {
definitions.put(key, new JSONObject());
definitions.put(key, buildProperties(k.getType()));
//TODO add back descriptions
if (k.isAnnotationPresent(RegistryMapBlockState.class)) {
String blockType = k.getDeclaredAnnotation(RegistryMapBlockState.class).value();
fancyType = "Block State";
prop.put("!top", true);
JSONArray any = new JSONArray();
prop.put("anyOf", any);
B.getBlockStates().forEach((blocks, properties) -> {
if (blocks.isEmpty()) return;
String raw = blocks.getFirst().replace(':', '_');
String enumKey = "enum-block-state-" + raw;
String propertiesKey = "obj-block-state-" + raw;
any.put(new JSONObject()
.put("if", new JSONObject()
.put("properties", new JSONObject()
.put(blockType, new JSONObject()
.put("type", "string")
.put("$ref", "#/definitions/" + enumKey))))
.put("then", new JSONObject()
.put("properties", new JSONObject()
.put(k.getName(), new JSONObject()
.put("type", "object")
.put("$ref", "#/definitions/" + propertiesKey))))
.put("else", false));
if (!definitions.containsKey(enumKey)) {
JSONArray filters = new JSONArray();
blocks.forEach(filters::put);
definitions.put(enumKey, new JSONObject()
.put("type", "string")
.put("enum", filters));
}
if (!definitions.containsKey(propertiesKey)) {
JSONObject props = new JSONObject();
properties.forEach(property -> {
props.put(property.name(), property.buildJson());
});
definitions.put(propertiesKey, new JSONObject()
.put("type", "object")
.put("properties", props));
}
});
} else {
fancyType = k.getType().getSimpleName().replaceAll("\\QIris\\E", "") + " (Object)";
String key = "obj-" + k.getType().getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase();
if (!definitions.containsKey(key)) {
definitions.put(key, new JSONObject());
definitions.put(key, buildProperties(k.getType()));
}
prop.put("$ref", "#/definitions/" + key);
}
prop.put("$ref", "#/definitions/" + key);
}
case "array" -> {
fancyType = "List of Something...?";
@@ -520,11 +586,12 @@ public class SchemaBuilder {
}
KList<String> d = new KList<>();
d.add(k.getName());
d.add(getFieldDescription(k));
d.add(" ");
d.add(fancyType);
d.add(getDescription(k.getType()));
d.add("<h>" + k.getName() + "</h>");
d.add(getFieldDescription(k) + "<hr></hr>");
d.add("<h>" + fancyType + "</h>");
String typeDesc = getDescription(k.getType());
boolean present = !typeDesc.isBlank();
if (present) d.add(typeDesc);
Snippet snippet = k.getType().getDeclaredAnnotation(Snippet.class);
if (snippet == null) {
@@ -536,8 +603,9 @@ public class SchemaBuilder {
if (snippet != null) {
String sm = snippet.value();
d.add(" ");
if (present) d.add(" ");
d.add("You can instead specify \"snippet/" + sm + "/some-name.json\" to use a snippet file instead of specifying it here.");
present = false;
}
try {
@@ -545,15 +613,13 @@ public class SchemaBuilder {
Object value = k.get(cl.newInstance());
if (value != null) {
if (present) d.add(" ");
if (value instanceof List) {
d.add(" ");
d.add("* Default Value is an empty 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)) {
d.add(" ");
d.add("* Default Value is a default object (create this object to see default properties)");
d.add(SYMBOL_LIMIT__N + " Default Value is a default object (create this object to see default properties)");
} else {
d.add(" ");
d.add("* Default Value is " + value);
d.add(SYMBOL_LIMIT__N + " Default Value is " + value);
}
}
} catch (Throwable ignored) {
@@ -561,8 +627,14 @@ public class SchemaBuilder {
}
description.forEach((g) -> d.add(g.trim()));
String desc = d.toString("\n")
.replace("<hr></hr>", "\n")
.replace("<h>", "")
.replace("</h>", "");
String hDesc = d.toString("<br>");
prop.put("type", type);
prop.put("description", d.toString("\n"));
prop.put("description", desc);
prop.put("x-intellij-html-description", hDesc);
return buildSnippet(prop, k.getType());
}
@@ -588,8 +660,10 @@ public class SchemaBuilder {
arr.put(prop);
arr.put(str);
str.put("description", prop.getString("description"));
str.put("x-intellij-html-description", prop.getString("x-intellij-html-description"));
anyOf.put("anyOf", arr);
anyOf.put("description", prop.getString("description"));
anyOf.put("x-intellij-html-description", prop.getString("x-intellij-html-description"));
anyOf.put("!required", type.isAnnotationPresent(Required.class));
return anyOf;
@@ -615,7 +689,9 @@ public class SchemaBuilder {
String name = function.apply(gg);
j.put("const", name);
Desc dd = type.getField(name).getAnnotation(Desc.class);
j.put("description", dd == null ? ("No Description for " + name) : dd.value());
String desc = dd == null ? ("No Description for " + name) : dd.value();
j.put("description", desc);
j.put("x-intellij-html-description", desc.replace("\n", "<br>"));
a.put(j);
} catch (Throwable e) {
Iris.reportError(e);

View File

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

View File

@@ -0,0 +1,19 @@
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.util.math.RNG;
import lombok.NonNull;
import org.jetbrains.annotations.Nullable;
public interface PackEnvironment extends SimpleEnvironment {
static PackEnvironment create(@NonNull IrisData data) {
return new IrisPackExecutionEnvironment(data);
}
@NonNull
IrisData getData();
@Nullable
Object createNoise(@NonNull String script, @NonNull RNG rng);
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,7 +24,6 @@ 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;
@@ -38,7 +37,7 @@ public class EditSVC implements IrisService {
@Override
public void onEnable() {
this.editors = new KMap<>();
Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::update, 1000, 1000);
Iris.platform.getGlobalScheduler().runAtFixedRate(this::update, 1000, 1000);
}
@Override

View File

@@ -21,6 +21,7 @@ package com.volmit.iris.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.*;
import com.volmit.iris.core.link.data.DataType;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
@@ -107,6 +108,18 @@ public class ExternalDataSVC implements IrisService {
}
}
public Optional<List<BlockProperty>> getBlockProperties(final Identifier key) {
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(key, DataType.BLOCK)).findFirst();
if (provider.isEmpty())
return Optional.empty();
try {
return Optional.of(provider.get().getBlockProperties(key));
} catch (MissingResourceException e) {
Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]");
return Optional.empty();
}
}
public Optional<ItemStack> getItemStack(Identifier key, KMap<String, Object> customNbt) {
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(key, DataType.ITEM)).findFirst();
if (provider.isEmpty()) {
@@ -150,6 +163,14 @@ public class ExternalDataSVC implements IrisService {
.toList();
}
public Collection<Pair<Identifier, List<BlockProperty>>> getAllBlockProperties() {
return activeProviders.stream()
.flatMap(p -> p.getTypes(DataType.BLOCK)
.stream()
.map(id -> new Pair<>(id, p.getBlockProperties(id))))
.toList();
}
public static Pair<Identifier, KMap<String, String>> parseState(Identifier key) {
if (!key.key().contains("[") || !key.key().contains("]")) {
return new Pair<>(key, new KMap<>());

View File

@@ -2,9 +2,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.util.collection.KMap;
import com.volmit.iris.util.data.KCache;
import com.volmit.iris.util.plugin.IrisService;
import lombok.NonNull;
import org.bukkit.Bukkit;
@@ -20,7 +22,11 @@ import java.io.File;
import java.util.function.Function;
public class GlobalCacheSVC implements IrisService {
private static final Cache<String, PregenCache> REFERENCE_CACHE = Caffeine.newBuilder().weakValues().build();
private static final Cache<String, PregenCache> REFERENCE_CACHE = Caffeine.newBuilder()
.executor(KCache.EXECUTOR)
.scheduler(Scheduler.systemScheduler())
.weakValues()
.build();
private final KMap<String, PregenCache> globalCache = new KMap<>();
private transient boolean lastState;
private static boolean disabled = true;

View File

@@ -22,7 +22,6 @@ 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;
@@ -71,21 +70,18 @@ public class ObjectSVC implements IrisService {
*/
private void revert(Map<Block, BlockData> blocks) {
Iterator<Map.Entry<Block, BlockData>> it = blocks.entrySet().iterator();
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);
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();
it.remove();
scheduler.run(block.getLocation(), () -> block.setBlockData(data, false));
}
amount++;
if (amount > 200) {
J.s(() -> revert(blocks), 1);
}
}
});
if (it.hasNext()) {
J.s(() -> revert(blocks), 1);
}
}
}

View File

@@ -43,10 +43,6 @@ public class PreservationSVC implements IrisService {
threads.add(t);
}
public void register(MultiBurst burst) {
}
public void register(ExecutorService service) {
services.add(service);
}

View File

@@ -88,16 +88,18 @@ public class StudioSVC implements IrisService {
}
public IrisDimension installIntoWorld(VolmitSender sender, String type, File folder) {
return installInto(sender, type, new File(folder, "iris/pack"));
}
public IrisDimension installInto(VolmitSender sender, String type, File folder) {
sender.sendMessage("Looking for Package: " + type);
File iris = new File(folder, "iris");
File irispack = new File(folder, "iris/pack");
IrisDimension dim = IrisData.loadAnyDimension(type);
IrisDimension dim = IrisData.loadAnyDimension(type, null);
if (dim == null) {
for (File i : getWorkspaceFolder().listFiles()) {
if (i.isFile() && i.getName().equals(type + ".iris")) {
sender.sendMessage("Found " + type + ".iris in " + WORKSPACE_NAME + " folder");
ZipUtil.unpack(i, irispack);
ZipUtil.unpack(i, folder);
break;
}
}
@@ -106,29 +108,29 @@ public class StudioSVC implements IrisService {
File f = new IrisProject(new File(getWorkspaceFolder(), type)).getPath();
try {
FileUtils.copyDirectory(f, irispack);
FileUtils.copyDirectory(f, folder);
} catch (IOException e) {
Iris.reportError(e);
}
}
File dimf = new File(irispack, "dimensions/" + type + ".json");
File dimensionFile = new File(folder, "dimensions/" + type + ".json");
if (!dimf.exists() || !dimf.isFile()) {
if (!dimensionFile.exists() || !dimensionFile.isFile()) {
downloadSearch(sender, type, false);
File downloaded = getWorkspaceFolder(type);
for (File i : downloaded.listFiles()) {
if (i.isFile()) {
try {
FileUtils.copyFile(i, new File(irispack, i.getName()));
FileUtils.copyFile(i, new File(folder, i.getName()));
} catch (IOException e) {
e.printStackTrace();
Iris.reportError(e);
}
} else {
try {
FileUtils.copyDirectory(i, new File(irispack, i.getName()));
FileUtils.copyDirectory(i, new File(folder, i.getName()));
} catch (IOException e) {
e.printStackTrace();
Iris.reportError(e);
@@ -139,12 +141,13 @@ public class StudioSVC implements IrisService {
IO.delete(downloaded);
}
if (!dimf.exists() || !dimf.isFile()) {
sender.sendMessage("Can't find the " + dimf.getName() + " in the dimensions folder of this pack! Failed!");
if (!dimensionFile.exists() || !dimensionFile.isFile()) {
sender.sendMessage("Can't find the " + dimensionFile.getName() + " in the dimensions folder of this pack! Failed!");
return null;
}
IrisData dm = IrisData.get(irispack);
IrisData dm = IrisData.get(folder);
dm.hotloaded();
dim = dm.getDimensionLoader().load(type);
if (dim == null) {
@@ -261,6 +264,7 @@ public class StudioSVC implements IrisService {
}
IrisDimension d = data.getDimensionLoader().load(dimensions[0]);
data.close();
if (d == null) {
sender.sendMessage("Invalid dimension (folder) in dimensions folder");
@@ -275,7 +279,7 @@ public class StudioSVC implements IrisService {
IO.delete(packEntry);
}
if (IrisData.loadAnyDimension(key) != null) {
if (IrisData.loadAnyDimension(key, null) != null) {
sender.sendMessage("Another dimension in the packs folder is already using the key " + key + " IMPORT FAILED!");
return;
}
@@ -294,6 +298,8 @@ public class StudioSVC implements IrisService {
packEntry.mkdirs();
ZipUtil.unpack(cp, packEntry);
}
IrisData.getLoaded(packEntry)
.ifPresent(IrisData::hotloaded);
sender.sendMessage("Successfully Aquired " + d.getName());
ServerConfigurator.installDataPacks(true);

View File

@@ -142,9 +142,10 @@ 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());
else state.setBlockData(d);
Iris.service(ExternalDataSVC.class).processUpdate(engine, b, data.getCustom());
} else state.setBlockData(d);
blockStateList.add(b.getState());
dataCache.put(new Location(event.getWorld(), x, y, z), d);
}
@@ -207,8 +208,7 @@ public class TreeSVC implements IrisService {
event.setCancelled(true);
J.s(() -> {
Iris.platform.getRegionScheduler().run(event.getLocation(), () -> {
StructureGrowEvent iGrow = new StructureGrowEvent(event.getLocation(), event.getSpecies(), event.isFromBonemeal(), event.getPlayer(), blockStateList);
block = true;
Bukkit.getServer().getPluginManager().callEvent(iGrow);

View File

@@ -35,6 +35,7 @@ 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;
@@ -86,80 +87,10 @@ public class WandSVC implements IrisService {
Cuboid c = new Cuboid(f[0], f[1]);
IrisObject s = new IrisObject(c.getSizeX(), c.getSizeY(), c.getSizeZ());
var it = c.chunkedIterator();
int total = c.getSizeX() * c.getSizeY() * c.getSizeZ();
var latch = new CountDownLatch(1);
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) {
chunk.removePluginChunkTicket(Iris.instance);
chunk = null;
}
cancel();
latch.countDown();
return;
}
try {
var b = it.next();
var bChunk = b.getChunk();
if (chunk == null) {
chunk = bChunk;
chunk.addPluginChunkTicket(Iris.instance);
} else if (chunk != bChunk) {
chunk.removePluginChunkTicket(Iris.instance);
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) {}
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, () -> {});
return s;
} catch (Throwable e) {

View File

@@ -11,6 +11,7 @@ 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;
@@ -58,7 +59,7 @@ public class IrisConverter {
int objW = ((ShortTag) compound.get("Width")).getValue();
int objH = ((ShortTag) compound.get("Height")).getValue();
int objD = ((ShortTag) compound.get("Length")).getValue();
int i = -1;
Task i = null;
int mv = objW * objH * objD;
AtomicInteger v = new AtomicInteger(0);
if (mv > 500_000) {
@@ -66,9 +67,7 @@ public class IrisConverter {
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);
}
}
@@ -97,7 +96,7 @@ public class IrisConverter {
}
}
}
if (i != -1) J.car(i);
if (i != null) i.cancel();
try {
object.shrinkwrap();
object.write(new File(folder, schem.getName().replace(".schem", ".iob")));

View File

@@ -32,7 +32,6 @@ 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.*;
@@ -41,10 +40,11 @@ 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.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import java.util.function.Function;
import java.util.function.IntSupplier;
import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML;
@@ -128,41 +128,37 @@ public class IrisCreator {
Iris.service(StudioSVC.class).installIntoWorld(sender, d.getLoadKey(), new File(Bukkit.getWorldContainer(), name()));
}
PlatformChunkGenerator access;
AtomicReference<World> world = new AtomicReference<>();
AtomicDouble pp = new AtomicDouble(0);
O<Boolean> done = new O<>();
done.set(false);
WorldCreator wc = new IrisWorldCreator()
.dimension(dimension)
.name(name)
.seed(seed)
.studio(studio)
.create();
ServerConfigurator.installDataPacks(false);
if (ServerConfigurator.installDataPacks(true)) {
throw new IrisException("Datapacks were missing!");
}
access = (PlatformChunkGenerator) wc.generator();
PlatformChunkGenerator finalAccess1 = access;
PlatformChunkGenerator access = (PlatformChunkGenerator) wc.generator();
if (access == null) throw new IrisException("Access is null. Something bad happened.");
J.a(() ->
{
Supplier<Integer> g = () -> {
if (finalAccess1 == null || finalAccess1.getEngine() == null) {
AtomicBoolean done = new AtomicBoolean(false);
J.a(() -> {
IntSupplier g = () -> {
if (access.getEngine() == null) {
return 0;
}
return finalAccess1.getEngine().getGenerated();
return access.getEngine().getGenerated();
};
if(!benchmark) {
if (finalAccess1 == null) return;
int req = finalAccess1.getSpawnChunks().join();
while (g.get() < req) {
double v = (double) g.get() / (double) req;
int req = access.getSpawnChunks().join();
for (int c = 0; c < req && !done.get(); c = g.getAsInt()) {
double v = (double) c / req;
if (sender.isPlayer()) {
sender.sendProgress(v, "Generating");
J.sleep(16);
} else {
sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - g.get()) + " Left)")));
sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - c) + " Left)")));
J.sleep(1000);
}
}
@@ -170,39 +166,43 @@ public class IrisCreator {
});
final World world;
try {
J.sfut(() -> {
world.set(INMS.get().createWorld(wc));
}).get();
world = J.sfut(() -> INMS.get().createWorldAsync(wc))
.thenCompose(Function.identity())
.get();
} catch (Throwable e) {
e.printStackTrace();
}
if (access == null) {
throw new IrisException("Access is null. Something bad happened.");
done.set(true);
throw new IrisException("Failed to create world!", e);
}
done.set(true);
if (sender.isPlayer() && !benchmark) {
J.s(() -> {
sender.player().teleport(new Location(world.get(), 0, world.get().getHighestBlockYAt(0, 0), 0));
});
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;
});
}
if (studio || benchmark) {
J.s(() -> {
Iris.linkMultiverseCore.removeFromConfig(world.get());
Iris.linkMultiverseCore.removeFromConfig(world);
if (IrisSettings.get().getStudio().isDisableTimeAndWeather()) {
world.get().setGameRule(GameRule.DO_WEATHER_CYCLE, false);
world.get().setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
world.get().setTime(6000);
world.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
world.setTime(6000);
}
});
} else {
addToBukkitYml();
J.s(() -> Iris.linkMultiverseCore.updateWorld(world.get(), dimension));
J.s(() -> Iris.linkMultiverseCore.updateWorld(world, dimension));
}
if (pregen != null) {
@@ -233,7 +233,7 @@ public class IrisCreator {
e.printStackTrace();
}
}
return world.get();
return world;
}
private void addToBukkitYml() {

View File

@@ -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;
@@ -165,8 +165,7 @@ public class IrisToolbelt {
* @return the pregenerator job (already started)
*/
public static PregeneratorJob pregenerate(PregenTask task, PlatformChunkGenerator gen) {
return pregenerate(task, new HybridPregenMethod(gen.getEngine().getWorld().realWorld(),
IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())), gen.getEngine());
return pregenerate(task, new AsyncPregenMethod(gen.getEngine().getWorld().realWorld()), gen.getEngine());
}
/**
@@ -182,7 +181,7 @@ public class IrisToolbelt {
return pregenerate(task, access(world));
}
return pregenerate(task, new HybridPregenMethod(world, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())), null);
return pregenerate(task, new AsyncPregenMethod(world), null);
}
/**
@@ -196,7 +195,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.");
j.teleport(i.getSpawnLocation());
Iris.platform.teleportAsync(j, i.getSpawnLocation());
}
return true;
@@ -218,7 +217,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);
j.teleport(i.getSpawnLocation());
Iris.platform.teleportAsync(j, i.getSpawnLocation());
}
return true;
}

View File

@@ -64,7 +64,7 @@ public class IrisWorldCreator {
}
public WorldCreator create() {
IrisDimension dim = IrisData.loadAnyDimension(dimensionName);
IrisDimension dim = IrisData.loadAnyDimension(dimensionName, null);
IrisWorld w = IrisWorld.builder()
.name(name)
@@ -80,13 +80,13 @@ public class IrisWorldCreator {
return new WorldCreator(name)
.environment(findEnvironment())
.environment(w.environment())
.generateStructures(true)
.generator(g).seed(seed);
}
private World.Environment findEnvironment() {
IrisDimension dim = IrisData.loadAnyDimension(dimensionName);
IrisDimension dim = IrisData.loadAnyDimension(dimensionName, null);
if (dim == null || dim.getEnvironment() == null) {
return World.Environment.NORMAL;
} else {

View File

@@ -25,8 +25,6 @@ import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.interpolation.IrisInterpolation.NoiseKey;
@@ -43,7 +41,7 @@ import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import java.io.File;
import java.util.UUID;
import java.util.*;
@Data
@EqualsAndHashCode(exclude = "data")
@@ -53,7 +51,7 @@ public class IrisComplex implements DataProvider {
private RNG rng;
private double fluidHeight;
private IrisData data;
private KMap<IrisInterpolator, KSet<IrisGenerator>> generators;
private Map<IrisInterpolator, Set<IrisGenerator>> generators;
private ProceduralStream<IrisRegion> regionStream;
private ProceduralStream<Double> regionStyleStream;
private ProceduralStream<Double> regionIdentityStream;
@@ -98,10 +96,10 @@ public class IrisComplex implements DataProvider {
this.data = engine.getData();
double height = engine.getMaxHeight();
fluidHeight = engine.getDimension().getFluidHeight();
generators = new KMap<>();
generators = new HashMap<>();
focusBiome = engine.getFocus();
focusRegion = engine.getFocusRegion();
KMap<InferredType, ProceduralStream<IrisBiome>> inferredStreams = new KMap<>();
Map<InferredType, ProceduralStream<IrisBiome>> inferredStreams = new HashMap<>();
if (focusBiome != null) {
focusBiome.setInferredType(InferredType.LAND);
@@ -118,6 +116,7 @@ public class IrisComplex implements DataProvider {
.getAllBiomes(this)
.forEach(this::registerGenerators));
}
boolean legacy = engine.getDimension().isLegacyRarity();
overlayStream = ProceduralStream.ofDouble((x, z) -> 0.0D).waste("Overlay Stream");
engine.getDimension().getOverlayNoise().forEach(i -> overlayStream = overlayStream.add((x, z) -> i.get(rng, getData(), x, z)));
rockStream = engine.getDimension().getRockPalette().getLayerGenerator(rng.nextParallelRNG(45), data).stream()
@@ -131,7 +130,7 @@ public class IrisComplex implements DataProvider {
ProceduralStream.of((x, z) -> focusRegion,
Interpolated.of(a -> 0D, a -> focusRegion))
: regionStyleStream
.selectRarity(data.getRegionLoader().loadAll(engine.getDimension().getRegions()))
.selectRarity(data.getRegionLoader().loadAll(engine.getDimension().getRegions()), legacy)
.cache2D("regionStream", engine, cacheSize).waste("Region Stream");
regionIDStream = regionIdentityStream.convertCached((i) -> new UUID(Double.doubleToLongBits(i),
String.valueOf(i * 38445).hashCode() * 3245556666L)).waste("Region ID Stream");
@@ -140,7 +139,7 @@ public class IrisComplex implements DataProvider {
-> engine.getDimension().getCaveBiomeStyle().create(rng.nextParallelRNG(InferredType.CAVE.ordinal()), getData()).stream()
.zoom(engine.getDimension().getBiomeZoom())
.zoom(r.getCaveBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getCaveBiomes()))
.selectRarity(data.getBiomeLoader().loadAll(r.getCaveBiomes()), legacy)
.onNull(emptyBiome)
).convertAware2D(ProceduralStream::get).cache2D("caveBiomeStream", engine, cacheSize).waste("Cave Biome Stream");
inferredStreams.put(InferredType.CAVE, caveBiomeStream);
@@ -150,7 +149,7 @@ public class IrisComplex implements DataProvider {
.zoom(engine.getDimension().getBiomeZoom())
.zoom(engine.getDimension().getLandZoom())
.zoom(r.getLandBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getLandBiomes(), (t) -> t.setInferredType(InferredType.LAND)))
.selectRarity(data.getBiomeLoader().loadAll(r.getLandBiomes(), (t) -> t.setInferredType(InferredType.LAND)), legacy)
).convertAware2D(ProceduralStream::get)
.cache2D("landBiomeStream", engine, cacheSize).waste("Land Biome Stream");
inferredStreams.put(InferredType.LAND, landBiomeStream);
@@ -160,7 +159,7 @@ public class IrisComplex implements DataProvider {
.zoom(engine.getDimension().getBiomeZoom())
.zoom(engine.getDimension().getSeaZoom())
.zoom(r.getSeaBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getSeaBiomes(), (t) -> t.setInferredType(InferredType.SEA)))
.selectRarity(data.getBiomeLoader().loadAll(r.getSeaBiomes(), (t) -> t.setInferredType(InferredType.SEA)), legacy)
).convertAware2D(ProceduralStream::get)
.cache2D("seaBiomeStream", engine, cacheSize).waste("Sea Biome Stream");
inferredStreams.put(InferredType.SEA, seaBiomeStream);
@@ -169,7 +168,7 @@ public class IrisComplex implements DataProvider {
-> engine.getDimension().getShoreBiomeStyle().create(rng.nextParallelRNG(InferredType.SHORE.ordinal()), getData()).stream()
.zoom(engine.getDimension().getBiomeZoom())
.zoom(r.getShoreBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getShoreBiomes(), (t) -> t.setInferredType(InferredType.SHORE)))
.selectRarity(data.getBiomeLoader().loadAll(r.getShoreBiomes(), (t) -> t.setInferredType(InferredType.SHORE)), legacy)
).convertAware2D(ProceduralStream::get).cache2D("shoreBiomeStream", engine, cacheSize).waste("Shore Biome Stream");
inferredStreams.put(InferredType.SHORE, shoreBiomeStream);
bridgeStream = focusBiome != null ? ProceduralStream.of((x, z) -> focusBiome.getInferredType(),
@@ -302,12 +301,12 @@ public class IrisComplex implements DataProvider {
return biome;
}
private double interpolateGenerators(Engine engine, IrisInterpolator interpolator, KSet<IrisGenerator> generators, double x, double z, long seed) {
private double interpolateGenerators(Engine engine, IrisInterpolator interpolator, Set<IrisGenerator> generators, double x, double z, long seed) {
if (generators.isEmpty()) {
return 0;
}
KMap<NoiseKey, IrisBiome> cache = new KMap<>();
HashMap<NoiseKey, IrisBiome> cache = new HashMap<>(64);
double hi = interpolator.interpolate(x, z, (xx, zz) -> {
try {
IrisBiome bx = baseBiomeStream.get(xx, zz);
@@ -379,7 +378,7 @@ public class IrisComplex implements DataProvider {
}
private void registerGenerator(IrisGenerator cachedGenerator) {
generators.computeIfAbsent(cachedGenerator.getInterpolator(), (k) -> new KSet<>()).add(cachedGenerator);
generators.computeIfAbsent(cachedGenerator.getInterpolator(), (k) -> new HashSet<>()).add(cachedGenerator);
}
private IrisBiome implode(IrisBiome b, Double x, Double z) {

View File

@@ -28,12 +28,12 @@ import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.core.nms.container.BlockPos;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.project.IrisProject;
import com.volmit.iris.core.scripting.environment.EngineEnvironment;
import com.volmit.iris.core.service.PreservationSVC;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.*;
import com.volmit.iris.engine.mantle.EngineMantle;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
import com.volmit.iris.util.atomics.AtomicRollingSequence;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.ChunkContext;
@@ -43,7 +43,7 @@ import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.MatterStructurePOI;
@@ -51,6 +51,7 @@ import com.volmit.iris.util.matter.slices.container.JigsawStructureContainer;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import de.crazydev22.platformutils.scheduler.task.Task;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@@ -86,7 +87,7 @@ public class IrisEngine implements Engine {
private final EngineMetrics metrics;
private final boolean studio;
private final AtomicRollingSequence wallClock;
private final int art;
private final Task art;
private final AtomicCache<IrisEngineData> engineData = new AtomicCache<>();
private final AtomicBoolean cleaning;
private final ChronoLatch cleanLatch;
@@ -94,7 +95,7 @@ public class IrisEngine implements Engine {
private CompletableFuture<Long> hash32;
private EngineMode mode;
private EngineEffects effects;
private EngineExecutionEnvironment execution;
private EngineEnvironment execution;
private EngineWorldManager worldManager;
private volatile int parallelism;
private boolean failing;
@@ -170,10 +171,12 @@ public class IrisEngine implements Engine {
cacheId = RNG.r.nextInt();
worldManager = new IrisWorldManager(this);
complex = new IrisComplex(this);
execution = new IrisExecutionEnvironment(this);
execution = EngineEnvironment.create(this);
effects = new IrisEngineEffects(this);
hash32 = new CompletableFuture<>();
mantle.hotload();
setupMode();
getDimension().getEngineScripts().forEach(execution::execute);
J.a(this::computeBiomeMaxes);
J.a(() -> {
File[] roots = getData().getLoaders()
@@ -199,7 +202,7 @@ public class IrisEngine implements Engine {
mode.close();
}
mode = getDimension().getMode().getType().create(this);
mode = getDimension().getMode().create(this);
}
@Override
@@ -425,7 +428,7 @@ public class IrisEngine implements Engine {
public void close() {
PregeneratorJob.shutdownInstance();
closed = true;
J.car(art);
art.cancel();
getWorldManager().close();
getTarget().close();
saveEngineData();

View File

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

View File

@@ -1,84 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisScript;
import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
import com.volmit.iris.engine.scripting.IrisScriptingAPI;
import com.volmit.iris.util.format.C;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.apache.bsf.BSFException;
import org.apache.bsf.BSFManager;
import org.apache.bsf.engines.javascript.JavaScriptEngine;
@Data
@EqualsAndHashCode(exclude = "engine")
@ToString(exclude = "engine")
public class IrisExecutionEnvironment implements EngineExecutionEnvironment {
private final BSFManager manager;
private final Engine engine;
private final IrisScriptingAPI api;
private JavaScriptEngine javaScriptEngine;
public IrisExecutionEnvironment(Engine engine) {
this.engine = engine;
this.api = new IrisScriptingAPI(engine);
this.manager = new BSFManager();
this.manager.setClassLoader(Iris.class.getClassLoader());
try {
this.manager.declareBean("Iris", api, api.getClass());
this.javaScriptEngine = (JavaScriptEngine) this.manager.loadScriptingEngine("javascript");
} catch (Throwable e) {
e.printStackTrace();
}
}
@Override
public IrisScriptingAPI getAPI() {
return api;
}
public void execute(String script) {
execute(getEngine().getData().getScriptLoader().load(script));
}
public void execute(IrisScript script) {
Iris.debug("Execute Script (void) " + C.DARK_GREEN + script.getLoadKey());
try {
javaScriptEngine.exec("", 0, 0, script);
} catch (BSFException e) {
e.printStackTrace();
}
}
public Object evaluate(String script) {
Iris.debug("Execute Script (for result) " + C.DARK_GREEN + script);
try {
return javaScriptEngine.eval("", 0, 0, getEngine().getData().getScriptLoader().load(script));
} catch (BSFException e) {
e.printStackTrace();
}
return null;
}
}

View File

@@ -20,7 +20,9 @@ package com.volmit.iris.engine;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineAssignedWorldManager;
import com.volmit.iris.engine.object.*;
@@ -29,7 +31,7 @@ import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.MantleFlag;
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.RNG;
@@ -41,7 +43,6 @@ 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;
@@ -59,10 +60,7 @@ import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -188,32 +186,54 @@ 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(i.getLocation().getChunk()).flag(MantleFlag.DISCOVERED, true);
mantle.getChunk(cX + x, cZ + z).flag(MantleFlag.DISCOVERED, true);
}
}
}
}
private void updateChunks() {
for (Player i : getEngine().getWorld().realWorld().getPlayers()) {
int r = 1;
int radius = 1;
int diameter = radius * 2 + 1;
int count = (diameter * diameter) + 1;
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)) {
var players = new KList<>(getEngine().getWorld().realWorld().getPlayers());
var latch = new CountDownLatch(count * players.size());
if (IrisSettings.get().getWorld().isPostLoadBlockUpdates()) {
getEngine().updateChunk(c.getWorld().getChunkAt(c.getX() + x, c.getZ() + z));
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;
}
if (IrisSettings.get().getWorld().isPostLoadBlockUpdates()) {
Chunk cx = c.getWorld().getChunkAt(cX, cZ);
J.a(() -> {
getEngine().updateChunk(cx);
latch.countDown();
});
} else latch.countDown();
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
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,
Chunk cx = getEngine().getWorld().realWorld().getChunkAt(cX, cZ);
J.a(() -> getMantle().raiseFlag(cX, cZ, MantleFlag.INITIAL_SPAWNED_MARKER,
() -> {
J.a(() -> spawnIn(cx, true), RNG.r.i(5, 200));
getSpawnersFromMarkers(cx).forEach((blockf, spawners) -> {
@@ -229,8 +249,17 @@ 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() {
@@ -424,18 +453,35 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
}
var ref = new WeakReference<>(e.getWorld());
int x = e.getX(), z = e.getZ();
int cX = e.getX(), cZ = e.getZ();
J.s(() -> {
World world = ref.get();
if (world == null || !world.isChunkLoaded(x, z))
if (world == null || !world.isChunkLoaded(cX, cZ))
return;
energy += 0.3;
fixEnergy();
getEngine().cleanupMantleChunk(x, z);
getEngine().cleanupMantleChunk(cX, cZ);
}, IrisSettings.get().getPerformance().mantleCleanupDelay);
if (generated) {
//INMS.get().injectBiomesFromMantle(e, getMantle());
if (!IrisSettings.get().getGenerator().earlyCustomBlocks) return;
e.addPluginChunkTicket(Iris.instance);
J.s(() -> {
var chunk = getMantle().getChunk(e).use();
int minY = getTarget().getWorld().minHeight();
try {
chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, () -> {
chunk.iterate(Identifier.class, (x, y, z, v) -> {
Iris.service(ExternalDataSVC.class).processUpdate(getEngine(), e.getBlock(x & 15, y + minY, z & 15), v);
});
});
} finally {
chunk.release();
e.removePluginChunkTicket(Iris.instance);
}
}, RNG.r.i(20, 60));
}
}
@@ -474,8 +520,8 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
e.setCancelled(true);
warmupAreaAsync(e.getPlayer(), e.getTo(), () -> J.s(() -> {
ignoreTP.set(true);
e.getPlayer().teleport(e.getTo(), e.getCause());
ignoreTP.set(false);
Iris.platform.teleportAsync(e.getPlayer(), e.getTo(), e.getCause())
.thenRun(() -> ignoreTP.set(false));
}));
}
}
@@ -495,7 +541,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
}
futures.add(MultiBurst.burst.completeValue(()
-> PaperLib.getChunkAtAsync(to.getWorld(),
-> Iris.platform.getChunkAtAsync(to.getWorld(),
(to.getBlockX() >> 4) + finalI,
(to.getBlockZ() >> 4) + finalJ,
true, IrisSettings.get().getWorld().getAsyncTeleport().isUrgent()).get()));
@@ -532,19 +578,17 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
IrisPosition pos = new IrisPosition((c.getX() << 4) + x, y, (c.getZ() << 4) + z);
if (mark.isEmptyAbove()) {
AtomicBoolean remove = new AtomicBoolean(false);
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();
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()) {
if (remove == Boolean.TRUE) {
b.add(pos);
return;
}

View File

@@ -29,13 +29,13 @@ import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.nms.container.BlockPos;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.pregenerator.ChunkUpdater;
import com.volmit.iris.core.scripting.environment.EngineEnvironment;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.IrisComplex;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.data.chunk.TerrainChunk;
import com.volmit.iris.engine.mantle.EngineMantle;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.ChunkContext;
@@ -48,7 +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.MantleFlag;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
@@ -64,7 +64,6 @@ 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;
@@ -110,7 +109,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
IrisContext getContext();
EngineExecutionEnvironment getExecution();
EngineEnvironment getExecution();
double getMaxBiomeObjectDensity();
@@ -296,20 +295,20 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
try {
Semaphore semaphore = new Semaphore(3);
chunk.raiseFlag(MantleFlag.ETCHED, () -> {
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> {
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());
});
}, 0));
chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> {
}, c, 1));
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);
});
}, 0));
}, c, 1));
chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> {
chunk.raiseFlagUnchecked(MantleFlag.UPDATE, run(semaphore, () -> {
PrecisionStopwatch p = PrecisionStopwatch.start();
int[][] grid = new int[16][16];
for (int x = 0; x < 16; x++) {
@@ -352,7 +351,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
});
chunk.deleteSlices(MatterUpdate.class);
getMetrics().getUpdates().put(p.getMilliseconds());
}, RNG.r.i(1, 20))); //Why is there a random delay here?
}, c, RNG.r.i(2, 20))); //Why is there a random delay here?
});
try {
@@ -363,12 +362,12 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
}
}
private static Runnable run(Semaphore semaphore, Runnable runnable, int delay) {
private static Runnable run(Semaphore semaphore, Runnable runnable, Chunk chunk, int delay) {
return () -> {
if (!semaphore.tryAcquire())
return;
J.s(() -> {
Iris.platform.getRegionScheduler().runDelayed(chunk.getWorld(), chunk.getX(), chunk.getZ(), () -> {
try {
runnable.run();
} finally {
@@ -527,8 +526,9 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
if (IrisLootEvent.callLootEvent(items, inv, world, x, y, z))
return;
if (PaperLib.isPaper() && getWorld().hasRealWorld()) {
PaperLib.getChunkAtAsync(getWorld().realWorld(), x >> 4, z >> 4).thenAccept((c) -> {
if (world != null) {
final int cX = x >> 4, cZ = z >> 4;
Iris.platform.getChunkAtAsync(world, cX, cZ, true, false).thenAccept((c) -> {
Runnable r = () -> {
for (ItemStack i : items) {
inv.addItem(i);
@@ -537,10 +537,10 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
scramble(inv, rng);
};
if (Bukkit.isPrimaryThread()) {
if (Iris.platform.isOwnedByCurrentRegion(world, cX, cZ)) {
r.run();
} else {
J.s(r);
Iris.platform.getRegionScheduler().run(world, cX, cZ, r);
}
});
} else {
@@ -863,7 +863,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
default void gotoBiome(IrisBiome biome, Player player, boolean teleport) {
Set<String> regionKeys = getDimension()
.getAllRegions(this).stream()
.filter((i) -> i.getAllBiomes(this).contains(biome))
.filter((i) -> i.getAllBiomeIds().contains(biome.getLoadKey()))
.map(IrisRegistrant::getLoadKey)
.collect(Collectors.toSet());
Locator<IrisBiome> lb = Locator.surfaceBiome(biome.getLoadKey());
@@ -885,7 +885,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());
J.s(() -> player.teleport(ll));
Iris.platform.teleportAsync(player, ll);
}
return;
@@ -959,7 +959,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
}
default void gotoRegion(IrisRegion r, Player player, boolean teleport) {
if (!getDimension().getAllRegions(this).contains(r)) {
if (!getDimension().getRegions().contains(r.getLoadKey())) {
player.sendMessage(C.RED + r.getName() + " is not defined in the dimension!");
return;
}

View File

@@ -20,39 +20,34 @@ 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.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 int taskId;
private final Task task;
protected AtomicBoolean ignoreTP = new AtomicBoolean(false);
public EngineAssignedWorldManager() {
super(null, null);
taskId = -1;
task = null;
}
public EngineAssignedWorldManager(Engine engine) {
super(engine, "World");
Iris.instance.registerListener(this);
taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::onTick, 0, 0);
task = Iris.platform.getGlobalScheduler().runAtFixedRate(this::onTick, 1, 1);
}
@EventHandler
@@ -129,6 +124,6 @@ public abstract class EngineAssignedWorldManager extends EngineAssignedComponent
public void close() {
super.close();
Iris.instance.unregisterListener(this);
Bukkit.getScheduler().cancelTask(taskId);
if (task != null) task.cancel();
}
}

View File

@@ -18,6 +18,7 @@
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;
@@ -36,7 +37,6 @@ 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) {
J.s(() -> player.teleport(location));
Iris.platform.teleportAsync(player, location);
} else {
player.sendMessage(C.GREEN + message + " at: " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ());
}

View File

@@ -22,8 +22,7 @@ import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisObjectPlacement;
import lombok.AllArgsConstructor;
import lombok.Data;
import javax.annotation.Nullable;
import org.jetbrains.annotations.Nullable;
@Data
@AllArgsConstructor

View File

@@ -0,0 +1,111 @@
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();
}
}

View File

@@ -160,8 +160,9 @@ public class PlannedStructure {
}, null, getData().getEngine() != null ? getData() : eng.getData()) != -1;
}
//TODO properly fix for folia
public void place(WorldObjectPlacer placer, Consumer<Boolean> consumer) {
J.s(() -> consumer.accept(place(placer, placer.getMantle().getMantle(), placer.getEngine())));
Iris.platform.getRegionScheduler().run(placer.getWorld(), position.getX() >> 4, position.getZ() >> 4, () -> consumer.accept(place(placer, placer.getMantle().getMantle(), placer.getEngine())));
}
private void generateOutwards() {

View File

@@ -1,6 +1,6 @@
package com.volmit.iris.engine.mantle;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.mantle.flag.ReservedFlag;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -10,5 +10,5 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentFlag {
MantleFlag value();
ReservedFlag value();
}

View File

@@ -37,13 +37,16 @@ import com.volmit.iris.util.documentation.ChunkCoordinates;
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.MantleFlag;
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;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.UnmodifiableView;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static com.volmit.iris.util.parallel.StreamUtils.forEach;
@@ -60,12 +63,19 @@ public interface EngineMantle {
int getRealRadius();
KList<Pair<KList<MantleComponent>, Integer>> getComponents();
@UnmodifiableView
List<Pair<List<MantleComponent>, Integer>> getComponents();
void registerComponent(MantleComponent c);
@UnmodifiableView
Map<MantleFlag, MantleComponent> getRegisteredComponents();
boolean registerComponent(MantleComponent c);
@UnmodifiableView
KList<MantleFlag> getComponentFlags();
void hotload();
default int getHighest(int x, int z) {
return getHighest(x, z, getData());
}
@@ -185,6 +195,7 @@ public interface EngineMantle {
forEach(streamRadius(x, z, radius),
pos -> pair.getA()
.stream()
.filter(MantleComponent::isEnabled)
.map(c -> new Pair<>(c, pos)),
p -> {
MantleComponent c = p.getA();

View File

@@ -18,7 +18,7 @@
package com.volmit.iris.engine.mantle;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@@ -30,5 +30,32 @@ public abstract class IrisMantleComponent implements MantleComponent {
private final EngineMantle engineMantle;
private final MantleFlag flag;
private final int priority;
private volatile int radius = -1;
private final Object lock = new Object();
private boolean enabled = true;
protected abstract int computeRadius();
@Override
public void hotload() {
synchronized (lock) {
radius = -1;
}
}
@Override
public final int getRadius() {
int r = radius;
if(r != -1) return r;
synchronized (lock) {
if((r = radius) != -1) {
return r;
}
r = computeRadius();
if(r < 0) r = 0;
return radius = r;
}
}
}

View File

@@ -24,7 +24,7 @@ import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.parallel.BurstExecutor;
import org.jetbrains.annotations.NotNull;
@@ -65,6 +65,8 @@ public interface MantleComponent extends Comparable<MantleComponent> {
void setEnabled(boolean b);
void hotload();
@ChunkCoordinates
void generateLayer(MantleWriter writer, int x, int z, ChunkContext context);

View File

@@ -28,17 +28,13 @@ import com.volmit.iris.engine.object.IrisCarving;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.mantle.flag.ReservedFlag;
import com.volmit.iris.util.math.RNG;
import lombok.Getter;
@Getter
@ComponentFlag(MantleFlag.CARVED)
@ComponentFlag(ReservedFlag.CARVED)
public class MantleCarvingComponent extends IrisMantleComponent {
private final int radius = computeRadius();
public MantleCarvingComponent(EngineMantle engineMantle) {
super(engineMantle, MantleFlag.CARVED, 0);
super(engineMantle, ReservedFlag.CARVED, 0);
}
@Override
@@ -63,7 +59,7 @@ public class MantleCarvingComponent extends IrisMantleComponent {
carving.doCarving(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4, 0);
}
private int computeRadius() {
protected int computeRadius() {
var dimension = getDimension();
int max = 0;

View File

@@ -28,17 +28,13 @@ import com.volmit.iris.engine.object.IrisFluidBodies;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.mantle.flag.ReservedFlag;
import com.volmit.iris.util.math.RNG;
import lombok.Getter;
@Getter
@ComponentFlag(MantleFlag.FLUID_BODIES)
@ComponentFlag(ReservedFlag.FLUID_BODIES)
public class MantleFluidBodyComponent extends IrisMantleComponent {
private final int radius = computeRadius();
public MantleFluidBodyComponent(EngineMantle engineMantle) {
super(engineMantle, MantleFlag.FLUID_BODIES, 0);
super(engineMantle, ReservedFlag.FLUID_BODIES, 0);
}
@Override
@@ -63,7 +59,7 @@ public class MantleFluidBodyComponent extends IrisMantleComponent {
bodies.generate(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4);
}
private int computeRadius() {
protected int computeRadius() {
int max = 0;
max = Math.max(max, getDimension().getFluidBodies().getMaxRange(getData()));

View File

@@ -30,7 +30,7 @@ import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.mantle.flag.ReservedFlag;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer;
@@ -40,14 +40,12 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
@ComponentFlag(MantleFlag.JIGSAW)
@ComponentFlag(ReservedFlag.JIGSAW)
public class MantleJigsawComponent extends IrisMantleComponent {
@Getter
private final int radius = computeRadius();
private final CNG cng;
public MantleJigsawComponent(EngineMantle engineMantle) {
super(engineMantle, MantleFlag.JIGSAW, 2);
super(engineMantle, ReservedFlag.JIGSAW, 2);
cng = NoiseStyle.STATIC.create(new RNG(jigsaw()));
}
@@ -169,6 +167,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
@BlockCoordinates
private boolean place(MantleWriter writer, IrisPosition position, IrisJigsawStructure structure, RNG rng, boolean forcePlace) {
if (structure == null || structure.getDatapackStructures().isNotEmpty()) return false;
return new PlannedStructure(structure, position, rng, forcePlace).place(writer, getMantle(), writer.getEngine());
}
@@ -176,7 +175,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
return getEngineMantle().getEngine().getSeedManager().getJigsaw();
}
private int computeRadius() {
protected int computeRadius() {
var dimension = getDimension();
KSet<String> structures = new KSet<>();

View File

@@ -33,13 +33,12 @@ import com.volmit.iris.util.data.B;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.mantle.flag.ReservedFlag;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.MatterStructurePOI;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.noise.NoiseType;
import com.volmit.iris.util.parallel.BurstExecutor;
import lombok.Getter;
import org.bukkit.util.BlockVector;
import java.io.IOException;
@@ -47,13 +46,11 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
@Getter
@ComponentFlag(MantleFlag.OBJECT)
@ComponentFlag(ReservedFlag.OBJECT)
public class MantleObjectComponent extends IrisMantleComponent {
private final int radius = computeRadius();
public MantleObjectComponent(EngineMantle engineMantle) {
super(engineMantle, MantleFlag.OBJECT, 1);
super(engineMantle, ReservedFlag.OBJECT, 1);
}
@Override
@@ -157,7 +154,7 @@ public class MantleObjectComponent extends IrisMantleComponent {
return v;
}
private int computeRadius() {
protected int computeRadius() {
var dimension = getDimension();
AtomicInteger xg = new AtomicInteger();

View File

@@ -219,16 +219,21 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
if (!blocks.hasIndex(i)) {
break;
}
int y = zone.floor - i - 1;
if (!B.isSolid(output.get(rx, zone.floor - i - 1, rz))) {
BlockData b = blocks.get(i);
BlockData down = output.get(rx, y, rz);
if (!B.isSolid(down)) {
continue;
}
if (B.isOre(output.get(rx, zone.floor - i - 1, rz))) {
if (B.isOre(down)) {
output.set(rx, y, rz, B.toDeepSlateOre(down, b));
continue;
}
output.set(rx, zone.floor - i - 1, rz, blocks.get(i));
output.set(rx, y, rz, blocks.get(i));
}
blocks = biome.generateCeilingLayers(getDimension(), xx, zz, rng, 3, zone.ceiling, getData(), getComplex());

View File

@@ -5,7 +5,7 @@ import com.volmit.iris.engine.framework.EngineAssignedModifier;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import org.bukkit.block.data.BlockData;

View File

@@ -25,7 +25,9 @@ import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.HeightMap;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.MatterCavern;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.bukkit.Material;
@@ -54,28 +56,30 @@ public class IrisDepositModifier extends EngineAssignedModifier<BlockData> {
long seed = x * 341873128712L + z * 132897987541L;
long mask = 0;
MantleChunk chunk = getEngine().getMantle().getMantle().getChunk(x, z).use();
for (IrisDepositGenerator k : getDimension().getDeposits()) {
long finalSeed = seed * ++mask;
burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context));
burst.queue(() -> generate(k, chunk, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context));
}
for (IrisDepositGenerator k : region.getDeposits()) {
long finalSeed = seed * ++mask;
burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context));
burst.queue(() -> generate(k, chunk, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context));
}
for (IrisDepositGenerator k : biome.getDeposits()) {
long finalSeed = seed * ++mask;
burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context));
burst.queue(() -> generate(k, chunk, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context));
}
burst.complete();
chunk.release();
}
public void generate(IrisDepositGenerator k, Hunk<BlockData> data, RNG rng, int cx, int cz, boolean safe, ChunkContext context) {
generate(k, data, rng, cx, cz, safe, null, context);
public void generate(IrisDepositGenerator k, MantleChunk chunk, Hunk<BlockData> data, RNG rng, int cx, int cz, boolean safe, ChunkContext context) {
generate(k, chunk, data, rng, cx, cz, safe, null, context);
}
public void generate(IrisDepositGenerator k, Hunk<BlockData> data, RNG rng, int cx, int cz, boolean safe, HeightMap he, ChunkContext context) {
public void generate(IrisDepositGenerator k, MantleChunk chunk, Hunk<BlockData> data, RNG rng, int cx, int cz, boolean safe, HeightMap he, ChunkContext context) {
if (k.getSpawnChance() < rng.d())
return;
@@ -127,7 +131,7 @@ public class IrisDepositModifier extends EngineAssignedModifier<BlockData> {
continue;
}
if (!getEngine().getMantle().isCarved((cx << 4) + nx, ny, (cz << 4) + nz)) {
if (chunk.get(nx, ny, nz, MatterCavern.class) == null) {
data.set(nx, ny, nz, B.toDeepSlateOre(data.get(nx, ny, nz), clump.getBlocks().get(j)));
}
}

View File

@@ -21,6 +21,7 @@ package com.volmit.iris.engine.modifier;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineAssignedModifier;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisSlopeClip;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.hunk.Hunk;
@@ -174,7 +175,8 @@ public class IrisPostModifier extends EngineAssignedModifier<BlockData> {
|| (hd == h + 1 && isSolidNonSlab(x, hd, z - 1, currentPostX, currentPostZ, currentData)))
//@done
{
BlockData d = biome.getSlab().get(rng, x, h, z, getData());
IrisSlopeClip sc = biome.getSlab().getSlopeCondition();
BlockData d = sc.isValid(getComplex().getSlopeStream().get(x, z)) ? biome.getSlab().get(rng, x, h, z, getData()) : null;
if (d != null) {
boolean cancel = B.isAir(d);

View File

@@ -18,9 +18,12 @@
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 org.bukkit.block.TileState;
import com.volmit.iris.engine.framework.placer.SafeObjectPlacer;
import de.crazydev22.platformutils.Type;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
public interface IObjectPlacer {
@@ -47,4 +50,10 @@ public interface IObjectPlacer {
void setTile(int xx, int yy, int zz, TileData tile);
Engine getEngine();
default IObjectPlacer sync(World world) {
if (Iris.platform.getType() == Type.FOLIA)
return new SafeObjectPlacer(world, this);
return this;
}
}

View File

@@ -25,9 +25,9 @@ import com.volmit.iris.util.stream.interpolation.Interpolated;
import java.util.List;
public interface IRare {
static <T extends IRare> ProceduralStream<T> stream(ProceduralStream<Double> noise, List<T> possibilities) {
return ProceduralStream.of((x, z) -> pick(possibilities, noise.get(x, z)),
(x, y, z) -> pick(possibilities, noise.get(x, y, z)),
static <T extends IRare> ProceduralStream<T> stream(ProceduralStream<Double> noise, List<T> possibilities, boolean legacyRarity) {
return ProceduralStream.of(legacyRarity ? (x, z) -> pickLegacy(possibilities, noise.get(x, z)) : (x, z) -> pick(possibilities, noise.get(x, z)),
legacyRarity ? (x, y, z) -> pickLegacy(possibilities, noise.get(x, y, z)) : (x, y, z) -> pick(possibilities, noise.get(x, y, z)),
new Interpolated<T>() {
@Override
public double toDouble(T t) {
@@ -69,6 +69,32 @@ public interface IRare {
return null;
}
if (possibilities.size() == 1) {
return possibilities.getFirst();
}
double total = 0;
for (T i : possibilities) {
total += 1d / i.getRarity();
}
double threshold = total * noiseValue;
double buffer = 0;
for (T i : possibilities) {
buffer += 1d / i.getRarity();
if (buffer >= threshold) {
return i;
}
}
return possibilities.getLast();
}
static <T extends IRare> T pickLegacy(List<T> possibilities, double noiseValue) {
if (possibilities.isEmpty()) {
return null;
}
if (possibilities.size() == 1) {
return possibilities.get(0);
}

View File

@@ -143,14 +143,14 @@ public class IrisBiome extends IrisRegistrant implements IRare {
@Desc("The default wall if iris decides to place a wall higher than 2 blocks (steep hills or possibly cliffs)")
private IrisBiomePaletteLayer wall = new IrisBiomePaletteLayer().zero();
@Required
@ArrayType(min = 1, type = IrisBiomePaletteLayer.class)
@ArrayType(type = IrisBiomePaletteLayer.class)
@Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.")
private KList<IrisBiomePaletteLayer> layers = new KList<IrisBiomePaletteLayer>().qadd(new IrisBiomePaletteLayer());
@Required
@ArrayType(min = 1, type = IrisBiomePaletteLayer.class)
@ArrayType(type = IrisBiomePaletteLayer.class)
@Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.")
private KList<IrisBiomePaletteLayer> caveCeilingLayers = new KList<IrisBiomePaletteLayer>().qadd(new IrisBiomePaletteLayer());
@ArrayType(min = 1, type = IrisBiomePaletteLayer.class)
@ArrayType(type = IrisBiomePaletteLayer.class)
@Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.")
private KList<IrisBiomePaletteLayer> seaLayers = new KList<>();
@ArrayType(min = 1, type = IrisDecorator.class)

View File

@@ -61,6 +61,7 @@ public class IrisBlockData extends IrisRegistrant {
private int weight = 1;
@Desc("If the block cannot be created on this version, Iris will attempt to use this backup block data instead.")
private IrisBlockData backup = null;
@RegistryMapBlockState("block")
@Desc("Optional properties for this block data such as 'waterlogged': true")
private KMap<String, Object> data = new KMap<>();
@Desc("Optional tile data for this block data")

View File

@@ -104,7 +104,7 @@ public class IrisCave extends IrisRegistrant {
CNG cng = shape.getNoise(base.nextParallelRNG(8131545), engine);
KSet<IrisPosition> mask = shape.getMasked(rng, engine);
writer.setNoiseMasked(points,
girth, cng.noise(x, y, z), cng, mask, true,
girth, shape.getNoiseThreshold() < 0 ? cng.noise(x, y, z) : shape.getNoiseThreshold(), cng, mask, true,
(xf, yf, zf) -> yf <= h ? w : c);
}

View File

@@ -1,9 +1,7 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.RegistryListResource;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.math.M;
@@ -25,6 +23,11 @@ public class IrisCaveShape {
@Desc("Noise used for the shape of the cave")
private IrisGeneratorStyle noise = new IrisGeneratorStyle();
@MinNumber(0)
@MaxNumber(1)
@Desc("The threshold for noise mask")
private double noiseThreshold = -1;
@RegistryListResource(IrisObject.class)
@Desc("Object used as mask for the shape of the cave")
private String object = null;

View File

@@ -21,6 +21,7 @@ package com.volmit.iris.engine.object;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.object.annotations.ArrayType;
import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.Required;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KList;
import lombok.Data;
@@ -37,6 +38,7 @@ import org.bukkit.World;
@Data
public class IrisCommand {
@Required
@ArrayType(min = 1, type = String.class)
@Desc("List of commands. Iris replaces {x} {y} and {z} with the location of the entity spawn")
private KList<String> commands = new KList<>();
@@ -65,6 +67,7 @@ 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()))
@@ -72,9 +75,9 @@ public class IrisCommand {
.replaceAll("\\Q{z}\\E", String.valueOf(at.getBlockZ()));
final String finalCommand = command;
if (repeat) {
Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), delay, repeatDelay);
scheduler.runAtFixedRate(() -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), Math.max(delay, 1), Math.max(repeatDelay, 1));
} else {
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), delay);
scheduler.runDelayed(() -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), Math.max(delay, 1));
}
}
}

View File

@@ -33,6 +33,7 @@ import org.bukkit.entity.Player;
@Desc("Represents a casting location for a command")
@Data
public class IrisCommandRegistry {
@Required
@ArrayType(min = 1, type = IrisCommand.class)
@Desc("Run commands, at the exact location of the player")
private KList<IrisCommand> rawCommands = new KList<>();

View File

@@ -30,11 +30,12 @@ import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.engine.object.annotations.functions.ComponentFlagFunction;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG;
@@ -68,6 +69,7 @@ public class IrisDimension extends IrisRegistrant {
private final transient AtomicCache<Double> rad = new AtomicCache<>();
private final transient AtomicCache<Boolean> featuresUsed = new AtomicCache<>();
private final transient AtomicCache<KList<Position2>> strongholdsCache = new AtomicCache<>();
private final transient AtomicCache<KMap<String, KList<String>>> cachedPreProcessors = new AtomicCache<>();
@MinNumber(2)
@Required
@Desc("The human readable name of this dimension")
@@ -241,9 +243,22 @@ public class IrisDimension extends IrisRegistrant {
@Desc("The Subterrain Fluid Layer Height")
private int caveLavaHeight = 8;
@RegistryListFunction(ComponentFlagFunction.class)
@ArrayType(type = MantleFlag.class)
@ArrayType(type = String.class)
@Desc("Collection of disabled components")
private KList<MantleFlag> disabledComponents = new KList<>();
@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")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> engineScripts = new KList<>();
@Desc("A list of scripts executed on data setup")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> dataScripts = new KList<>();
@Desc("Use legacy rarity instead of modern one\nWARNING: Changing this may break expressions and image maps")
private boolean legacyRarity = true;
public int getMaxHeight() {
return (int) getDimensionHeight().getMax();
@@ -340,7 +355,7 @@ public class IrisDimension extends IrisRegistrant {
KList<IrisRegion> r = new KList<>();
for (String i : getRegions()) {
r.add(IrisData.loadAnyRegion(i));
r.add(IrisData.loadAnyRegion(i, getLoader()));
}
return r;
@@ -364,6 +379,17 @@ public class IrisDimension extends IrisRegistrant {
return r;
}
public KList<String> getPreProcessors(String type) {
return cachedPreProcessors.aquire(() -> {
KMap<String, KList<String>> preProcessors = new KMap<>();
for (var entry : globalPreProcessors) {
preProcessors.computeIfAbsent(entry.getType(), k -> new KList<>())
.addAll(entry.getScripts());
}
return preProcessors;
}).get(type);
}
public IrisGeneratorStyle getBiomeStyle(InferredType type) {
switch (type) {
case CAVE:

View File

@@ -18,7 +18,10 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineMode;
import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.RegistryListResource;
import com.volmit.iris.engine.object.annotations.Snippet;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -35,4 +38,19 @@ public class IrisDimensionMode {
@Desc("The dimension type")
private IrisDimensionModeType type = IrisDimensionModeType.OVERWORLD;
@RegistryListResource(IrisScript.class)
@Desc("The script to create the dimension mode instead of using provided types")
private String script;
public EngineMode create(Engine engine) {
if (script == null) {
return type.create(engine);
}
Object result = engine.getExecution().evaluate(script);
if (result instanceof EngineMode) {
return (EngineMode) result;
}
throw new IllegalStateException("The script '" + script + "' did not return an engine mode!");
}
}

View File

@@ -24,7 +24,6 @@ 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;
@@ -146,7 +145,6 @@ public class IrisEffect {
@MinNumber(1)
@Desc("The chance is 1 in CHANCE per interval")
private int chance = 50;
@ArrayType(min = 1, type = IrisCommandRegistry.class)
@Desc("Run commands, with configurable location parameters")
private IrisCommandRegistry commandRegistry = null;
@@ -195,7 +193,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));
J.s(() -> p.playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch)));
schedule(p, () -> p.playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch)));
}
if (particleEffect != null) {
@@ -205,7 +203,7 @@ public class IrisEffect {
part.add(RNG.r.d(), 0, RNG.r.d());
int offset = p.getWorld().getMinHeight();
if (extra != 0) {
J.s(() -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset),
schedule(p, () -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset),
part.getZ(),
particleCount,
randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX,
@@ -213,7 +211,7 @@ public class IrisEffect {
randomAltZ ? RNG.r.d(-particleAltZ, particleAltZ) : particleAltZ,
extra));
} else {
J.s(() -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(),
schedule(p, () -> 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,
@@ -232,10 +230,10 @@ public class IrisEffect {
return;
}
J.s(() -> p.removePotionEffect(getRealType()));
schedule(p, () -> p.removePotionEffect(getRealType()));
}
J.s(() -> p.addPotionEffect(new PotionEffect(getRealType(),
schedule(p, () -> p.addPotionEffect(new PotionEffect(getRealType(),
RNG.r.i(Math.min(potionTicksMax, potionTicksMin),
Math.max(potionTicksMax, potionTicksMin)),
getPotionStrength(),
@@ -255,7 +253,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));
J.s(() -> p.getWorld().playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch)));
schedule(p, () -> p.getWorld().playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch)));
}
if (particleEffect != null) {
@@ -263,7 +261,7 @@ public class IrisEffect {
part.add(RNG.r.d(), 0, RNG.r.d());
int offset = p.getWorld().getMinHeight();
if (extra != 0) {
J.s(() -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset),
schedule(p, () -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset),
part.getZ(),
particleCount,
randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX,
@@ -271,7 +269,7 @@ public class IrisEffect {
randomAltZ ? RNG.r.d(-particleAltZ, particleAltZ) : particleAltZ,
extra));
} else {
J.s(() -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(),
schedule(p, () -> 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,
@@ -279,4 +277,8 @@ public class IrisEffect {
}
}
}
private void schedule(Entity entity, Runnable task) {
Iris.platform.getEntityScheduler(entity).run(task, null);
}
}

View File

@@ -33,8 +33,6 @@ 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;
@@ -50,13 +48,11 @@ 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.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import static com.volmit.iris.util.data.registry.Particles.ITEM;
@@ -183,39 +179,34 @@ public class IrisEntity extends IrisRegistrant {
return spawn(gen, at, new RNG(at.hashCode()));
}
public Entity spawn(Engine gen, Location at, RNG rng) {
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;
}
}
if (!Chunks.isSafe(at)) {
return null;
}
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();
if (isSpawnEffectRiseOutOfGround() && Chunks.hasPlayersNearby(at)) {
at.add(0, -5, 0);
}
Entity ee = doSpawn(at);
if (ee == null && !Chunks.isSafe(at)) {
if (ee == null) {
return null;
}
if (!spawnerScript.isEmpty() && ee == null) {
synchronized (this) {
gen.getExecution().getAPI().setLocation(at);
try {
ee = (Entity) gen.getExecution().evaluate(spawnerScript);
ee = (Entity) gen.getExecution().spawnMob(spawnerScript, at.clone());
} catch (Throwable ex) {
Iris.error("You must return an Entity in your scripts to use entity scripts!");
ex.printStackTrace();
@@ -242,111 +233,96 @@ public class IrisEntity extends IrisRegistrant {
int gg = 0;
for (IrisEntity i : passengers) {
Entity passenger = i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++));
if (!Bukkit.isPrimaryThread()) {
J.s(() -> e.addPassenger(passenger));
}
e.addPassenger(i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++)));
}
if (e instanceof Attributable) {
Attributable a = (Attributable) e;
if (e instanceof Attributable attributable) {
for (IrisAttributeModifier i : getAttributes()) {
i.apply(rng, a);
i.apply(rng, attributable);
}
}
if (e instanceof Lootable) {
Lootable l = (Lootable) e;
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 (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, at.getWorld(), at.getBlockX(), at.getBlockY(), at.getBlockZ()));
}
@Override
public Collection<ItemStack> populateLoot(Random random, LootContext context) {
KList<ItemStack> items = new KList<>();
return items;
}
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);
}
@Override
public void fillInventory(Inventory inventory, Random random, LootContext context) {
for (ItemStack i : populateLoot(random, context)) {
inventory.addItem(i);
}
gen.scramble(inventory, rng);
}
});
}
gen.scramble(inventory, rng);
}
});
}
if (e instanceof LivingEntity) {
LivingEntity l = (LivingEntity) e;
l.setAI(isAi());
l.setCanPickupItems(isPickupItems());
if (e instanceof LivingEntity living) {
living.setAI(isAi());
living.setCanPickupItems(isPickupItems());
if (getLeashHolder() != null) {
l.setLeashHolder(getLeashHolder().spawn(gen, at, rng.nextParallelRNG(234548)));
living.setLeashHolder(getLeashHolder().spawn(gen, at, rng.nextParallelRNG(234548)));
}
l.setRemoveWhenFarAway(isRemovable());
living.setRemoveWhenFarAway(isRemovable());
if (getHelmet() != null && rng.i(1, getHelmet().getRarity()) == 1) {
l.getEquipment().setHelmet(getHelmet().get(gen.isStudio(), rng));
living.getEquipment().setHelmet(getHelmet().get(gen.isStudio(), rng));
}
if (getChestplate() != null && rng.i(1, getChestplate().getRarity()) == 1) {
l.getEquipment().setChestplate(getChestplate().get(gen.isStudio(), rng));
living.getEquipment().setChestplate(getChestplate().get(gen.isStudio(), rng));
}
if (getLeggings() != null && rng.i(1, getLeggings().getRarity()) == 1) {
l.getEquipment().setLeggings(getLeggings().get(gen.isStudio(), rng));
living.getEquipment().setLeggings(getLeggings().get(gen.isStudio(), rng));
}
if (getBoots() != null && rng.i(1, getBoots().getRarity()) == 1) {
l.getEquipment().setBoots(getBoots().get(gen.isStudio(), rng));
living.getEquipment().setBoots(getBoots().get(gen.isStudio(), rng));
}
if (getMainHand() != null && rng.i(1, getMainHand().getRarity()) == 1) {
l.getEquipment().setItemInMainHand(getMainHand().get(gen.isStudio(), rng));
living.getEquipment().setItemInMainHand(getMainHand().get(gen.isStudio(), rng));
}
if (getOffHand() != null && rng.i(1, getOffHand().getRarity()) == 1) {
l.getEquipment().setItemInOffHand(getOffHand().get(gen.isStudio(), rng));
living.getEquipment().setItemInOffHand(getOffHand().get(gen.isStudio(), rng));
}
}
if (e instanceof Ageable && isBaby()) {
((Ageable) e).setBaby();
if (e instanceof Ageable ageable && isBaby()) {
ageable.setBaby();
}
if (e instanceof Panda) {
((Panda) e).setMainGene(getPandaMainGene());
((Panda) e).setMainGene(getPandaHiddenGene());
if (e instanceof Panda panda) {
panda.setMainGene(getPandaMainGene());
panda.setMainGene(getPandaHiddenGene());
}
if (e instanceof Villager) {
Villager villager = (Villager) e;
if (e instanceof Villager villager) {
villager.setRemoveWhenFarAway(false);
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> {
villager.setPersistent(true);
}, 1);
villager.setPersistent(true);
}
if (e instanceof Mob) {
Mob m = (Mob) e;
m.setAware(isAware());
if (e instanceof Mob mob) {
mob.setAware(isAware());
}
if (spawnEffect != null) {
@@ -355,11 +331,8 @@ public class IrisEntity extends IrisRegistrant {
if (postSpawnScripts.isNotEmpty()) {
synchronized (this) {
gen.getExecution().getAPI().setLocation(at);
gen.getExecution().getAPI().setEntity(ee);
for (String i : postSpawnScripts) {
gen.getExecution().execute(i);
gen.getExecution().postSpawnMob(i, at, ee);
}
}
}
@@ -369,41 +342,35 @@ public class IrisEntity extends IrisRegistrant {
rawCommands.forEach(r -> r.run(fat));
}
Location finalAt1 = at;
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;
}
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;
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);
}
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));
}
});
} else {
task.cancel();
living.setNoDamageTicks(0);
living.setCollidable(true);
living.setAI(true);
e.setInvulnerable(false);
}
}, 1, 1);
}
return e;
@@ -433,29 +400,6 @@ 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));
}

View File

@@ -36,8 +36,14 @@ 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
@@ -164,8 +170,15 @@ public class IrisEntitySpawn implements IRare {
return null;
}
if (!ignoreSurfaces && !irisEntity.getSurface().matches(at.clone().subtract(0, 1, 0).getBlock())) {
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;
}
}
Vector3d boundingBox = INMS.get().getBoundingbox(irisEntity.getType());
@@ -199,15 +212,22 @@ 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++) {
if (world.getBlockAt(x, y, z).getType() != Material.AIR) {
return false;
}
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);
}
}
}
return true;
lock.acquireUninterruptibly(Integer.MAX_VALUE);
return bool.get();
}
}

View File

@@ -18,6 +18,7 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.*;
@@ -25,6 +26,7 @@ import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.noise.ExpressionNoise;
import com.volmit.iris.util.noise.ImageNoise;
import com.volmit.iris.util.noise.NoiseGenerator;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -56,6 +58,9 @@ 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.")
@RegistryListResource(IrisScript.class)
private String script = null;
@MinNumber(0.00001)
@Desc("The Output multiplier. Only used if parent is fracture.")
private double multiplier = 1;
@@ -93,40 +98,27 @@ public class IrisGeneratorStyle {
public CNG createNoCache(RNG rng, IrisData data, boolean actuallyCached) {
String cacheKey = hash() + "";
CNG cng = null;
if (getExpression() != null) {
IrisExpression e = data.getExpressionLoader().load(getExpression());
if (e != null) {
CNG cng = new CNG(rng, new ExpressionNoise(rng, e), 1D, 1)
.bake().scale(1D / zoom).pow(exponent).bake();
cng.setTrueFracturing(axialFracturing);
if (fracture != null) {
cng.fractureWith(fracture.create(rng.nextParallelRNG(2934), data), fracture.getMultiplier());
}
if (cellularFrequency > 0) {
return cng.cellularize(rng.nextParallelRNG(884466), cellularFrequency).scale(1D / cellularZoom).bake();
}
return cng;
cng = new CNG(rng, new ExpressionNoise(rng, e), 1D, 1).bake();
}
} else if (getImageMap() != null) {
CNG cng = new CNG(rng, new ImageNoise(data, getImageMap()), 1D, 1).bake().scale(1D / zoom).pow(exponent).bake();
cng.setTrueFracturing(axialFracturing);
if (fracture != null) {
cng.fractureWith(fracture.create(rng.nextParallelRNG(2934), data), fracture.getMultiplier());
cng = new CNG(rng, new ImageNoise(data, getImageMap()), 1D, 1).bake();
} else if (getScript() != null) {
Object result = data.getEnvironment().createNoise(getScript(), rng);
if (result == null) Iris.warn("Failed to create noise from script: " + getScript());
if (result instanceof NoiseGenerator generator) {
cng = new CNG(rng, generator, 1D, 1).bake();
}
if (cellularFrequency > 0) {
return cng.cellularize(rng.nextParallelRNG(884466), cellularFrequency).scale(1D / cellularZoom).bake();
}
return cng;
}
CNG cng = style.create(rng).bake().scale(1D / zoom).pow(exponent).bake();
if (cng == null) {
cng = style.create(rng).bake();
}
cng = cng.scale(1D / zoom).pow(exponent).bake();
cng.setTrueFracturing(axialFracturing);
if (fracture != null) {

View File

@@ -50,8 +50,7 @@ public class IrisJigsawPiece extends IrisRegistrant {
@Desc("The object this piece represents")
private String object = "";
@Required
@ArrayType(type = IrisJigsawPieceConnector.class, min = 1)
@ArrayType(type = IrisJigsawPieceConnector.class)
@Desc("The connectors this object contains")
private KList<IrisJigsawPieceConnector> connectors = new KList<>();

View File

@@ -1,43 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine.object;
import com.volmit.iris.engine.object.annotations.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Snippet("jigsaw-placer")
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Desc("Represents a jigsaw placement")
@Data
public class IrisJigsawPlacement {
@RegistryListResource(IrisJigsawStructure.class)
@Required
@Desc("The jigsaw structure to use")
private String structure = "";
@Required
@MinNumber(1)
@Desc("The rarity for this jigsaw structure to place on a per chunk basis")
private int rarity = 29;
}

View File

@@ -23,6 +23,7 @@ import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.engine.object.annotations.functions.StructureKeyFunction;
import com.volmit.iris.engine.object.annotations.functions.StructureKeyOrTagFunction;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.plugin.VolmitSender;
@@ -40,6 +41,11 @@ import lombok.experimental.Accessors;
@Data
@EqualsAndHashCode(callSuper = false)
public class IrisJigsawStructure extends IrisRegistrant {
@RegistryListFunction(StructureKeyFunction.class)
@ArrayType(min = 1, type = String.class)
@Desc("The datapack structures. Randomply chooses a structure to place\nIgnores every other setting")
private KList<String> datapackStructures = new KList<>();
@RegistryListResource(IrisJigsawPiece.class)
@Required
@ArrayType(min = 1, type = String.class)
@@ -70,7 +76,7 @@ public class IrisJigsawStructure extends IrisRegistrant {
@Desc("Set to true to prevent rotating the initial structure piece")
private boolean disableInitialRotation = false;
@RegistryListFunction(StructureKeyFunction.class)
@RegistryListFunction(StructureKeyOrTagFunction.class)
@Desc("The minecraft key to use when creating treasure maps")
private String structureKey = null;
@@ -117,6 +123,10 @@ public class IrisJigsawStructure extends IrisRegistrant {
public int getMaxDimension() {
return maxDimension.aquire(() -> {
if (datapackStructures.isNotEmpty()) {
return 0;
}
if (useMaxPieceSizeForParallaxRadius) {
int max = 0;
KList<String> pools = new KList<>();

View File

@@ -0,0 +1,25 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.engine.object.annotations.functions.ResourceLoadersFunction;
import com.volmit.iris.util.collection.KList;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Desc("Represents global preprocessors")
public class IrisPreProcessors {
@Required
@Desc("The preprocessor type")
@RegistryListFunction(ResourceLoadersFunction.class)
private String type = "dimension";
@Required
@Desc("The preprocessor scripts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> scripts = new KList<>();
}

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