9
0
mirror of https://github.com/VolmitSoftware/Iris.git synced 2025-12-19 15:09:18 +00:00

Compare commits

...

64 Commits

Author SHA1 Message Date
Aidan Aeternum
93ca26e368 v+ 2025-12-17 12:12:25 -05:00
Aidan Aeternum
8c1db1c223 Merge pull request #1231 from VolmitSoftware/dev
3.8.0
2025-12-17 12:11:28 -05:00
Julian Krings
123708601f improve pregen cache 2025-12-01 16:01:54 +01:00
Julian Krings
b5ab4968ba fix compile 2025-11-30 15:36:36 +01:00
Julian Krings
93ae6037bd whoops forgot to disable craftbukkit relocations on <=1.20.4 2025-11-29 11:49:15 +01:00
Julian Krings
dd8e487a3b fix tile entity serialization on paper 1.21.6+ servers 2025-11-29 11:13:30 +01:00
Julian Krings
d3c8377a12 allow switching between buildtools and userdev 2025-11-29 11:12:16 +01:00
Julian Krings
84f3687c0c update compat for iron bars 2025-11-27 16:09:31 +01:00
Julian Krings
ed1e1f1181 whoops forgot those providers 2025-11-26 21:33:03 +01:00
Julian Krings
528c97f367 replace IrisCustomData class with a proxy to keep full access to the base BlockData 2025-11-26 21:32:13 +01:00
Julian Krings
f7a459f3bc initial 1.21.9/10 bindings 2025-11-26 21:25:05 +01:00
Julian Krings
cd179b4321 reintroduce native threads for the updater as a setting and cleanup 2025-11-26 20:55:48 +01:00
Julian Krings
6373dbb1b8 potential optimization for the noise cache 2025-11-21 16:21:54 +01:00
Julian Krings
0b0797f876 minor optimization for chunk updater 2025-11-21 16:21:31 +01:00
Julian Krings
446acefc91 minor optimization for the mantle writer 2025-11-21 16:21:02 +01:00
Julian Krings
7a44e555b2 rename noise cache size setting and decrease default value 2025-11-21 16:20:32 +01:00
Julian Krings
57d4c2935c add cache sizes to engine status 2025-11-21 16:16:15 +01:00
Julian Krings
234fb1b0c4 also include parent class for schema generation 2025-11-08 00:58:12 +01:00
Julian Krings
0882b5acc4 use parent shared classloader to reflect intelij behavior 2025-11-06 22:32:28 +01:00
Julian Krings
18da26e1fa minor performance improvement 2025-11-06 22:27:14 +01:00
Julian Krings
65aa95f2a5 fix wrong radius when marking mantle chunks as completed 2025-11-06 22:25:37 +01:00
Julian Krings
5330ddc4ec fix deleting object ids with mantle cleanup 2025-11-06 22:20:30 +01:00
Julian Krings
a7fdd37569 fix studio loot command 2025-11-06 22:16:27 +01:00
Julian Krings
a226fea9e2 fix regen command 2025-11-06 16:22:02 +01:00
Julian Krings
8cea165a29 even more performance improvements 2025-11-06 15:29:03 +01:00
Julian Krings
1d7cba184c fix linear palette not growing correctly 2025-11-06 14:41:39 +01:00
Julian Krings
4ca7ea3911 minor speed improvements 2025-11-01 22:36:25 +01:00
Julian Krings
ea5919def2 stop writing first access each time the engine is opened 2025-10-30 16:40:35 +01:00
Julian Krings
be35e49302 use coroutines for mantle generation 2025-10-30 16:40:08 +01:00
Julian Krings
aadd03990a optimize data palette for mantle slices 2025-10-27 19:53:47 +01:00
Julian Krings
38a579453d optimize noise cache 2025-10-26 13:49:03 +01:00
Julian Krings
0bf5da2ca1 optimize object maps 2025-10-26 13:48:11 +01:00
Julian Krings
317848692e improve regen speed 2025-10-06 14:12:01 +02:00
Julian Krings
22118de9e9 fix object smart bore 2025-10-06 14:10:37 +02:00
Julian Krings
d7039d120b fix place commands causing unwanted block updates 2025-10-06 13:00:00 +02:00
Julian Krings
979ee4e7d8 switch hashing algorithm for objects once more 2025-10-05 21:46:12 +02:00
Julian Krings
f68d45bd30 dynamically resolve snippet classes 2025-10-05 00:21:38 +02:00
Julian Krings
b86d7f303e restructure the shared kts classloader to be more consistent 2025-10-05 00:20:55 +02:00
Julian Krings
c573843314 fix kts dependency resolver 2025-10-05 00:17:57 +02:00
Julian Krings
51a7bef18e whoops forgot escaping the path 2025-10-04 17:19:11 +02:00
Julian Krings
0e237aa1ad fix generated build.gradle.kts on external dives on windows 2025-10-04 13:41:48 +02:00
Julian Krings
b46c413f6b make gradle setup print to console on failure 2025-10-04 13:40:47 +02:00
Julian Krings
f3ef1ca2ae fix typo in preprocessors description 2025-10-04 13:40:07 +02:00
Julian Krings
703e61dd54 fix preprocessors not applying reliably 2025-10-04 13:39:33 +02:00
Aidan Aeternum
e1ec6b7827 v+ 2025-10-03 16:08:05 -04:00
Aidan Aeternum
f94292fdac Merge pull request #1228 from VolmitSoftware/dev
3.7.11
2025-10-03 16:07:47 -04:00
Julian Krings
7d153bf985 optimize objects to avoid hash collision 2025-10-02 15:25:37 +02:00
Julian Krings
f85f15ed02 fix converter for complex schematic 2025-10-02 11:43:16 +02:00
Julian Krings
867686eced fix deserialisation of unversioned mantle plates 2025-10-01 12:57:38 +02:00
Aidan Aeternum
9d796bd2a0 v+ 2025-09-27 07:34:58 -04:00
Aidan Aeternum
1a9a5d80ad Merge pull request #1223 from VolmitSoftware/dev
3.7.10
2025-09-27 07:34:31 -04:00
Julian Krings
c5c7f9bdc5 fix minor issue with nms tools 2025-09-22 18:10:34 +02:00
Julian Krings
01a421b732 add file extensions to the script property descriptions 2025-09-21 22:35:34 +02:00
Julian Krings
ae92bcf194 add kts hook for chunk updates 2025-09-21 22:30:48 +02:00
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
129 changed files with 4663 additions and 2521 deletions

View File

@@ -1,5 +1,3 @@
import com.volmit.nmstools.NMSToolsExtension
import com.volmit.nmstools.NMSToolsPlugin
import de.undercouch.gradle.tasks.download.Download
import xyz.jpenilla.runpaper.task.RunServer
import kotlin.system.exitProcess
@@ -24,19 +22,18 @@ import kotlin.system.exitProcess
buildscript {
repositories.maven("https://jitpack.io")
dependencies.classpath("com.github.VolmitSoftware:NMSTools:c5cbc46ce6")
dependencies.classpath("com.github.VolmitSoftware:NMSTools:c88961416f")
}
plugins {
java
`java-library`
alias(libs.plugins.shadow)
alias(libs.plugins.download)
alias(libs.plugins.runPaper)
}
group = "com.volmit"
version = "3.7.2-1.20.1-1.21.8"
version = "3.8.0-1.20.1-1.21.10"
apply<ApiGenerator>()
@@ -58,14 +55,16 @@ registerCustomOutputTaskUnix("PixelMac", "/Users/test/Desktop/mcserver/plugins")
registerCustomOutputTaskUnix("CrazyDev22LT", "/home/julian/Desktop/server/plugins")
// ==============================================================
val serverMinHeap = "2G"
val serverMaxHeap = "8G"
val serverMinHeap = "10G"
val serverMaxHeap = "10G"
val additionalFlags = "-XX:+AlwaysPreTouch"
//Valid values are: none, truecolor, indexed256, indexed16, indexed8
val color = "truecolor"
val errorReporting = findProperty("errorReporting") as Boolean? ?: false
val nmsBindings = mapOf(
"v1_21_R5" to "1.21.7-R0.1-SNAPSHOT",
"v1_21_R6" to "1.21.10-R0.1-SNAPSHOT",
"v1_21_R5" to "1.21.8-R0.1-SNAPSHOT",
"v1_21_R4" to "1.21.5-R0.1-SNAPSHOT",
"v1_21_R3" to "1.21.4-R0.1-SNAPSHOT",
"v1_21_R2" to "1.21.3-R0.1-SNAPSHOT",
@@ -76,18 +75,14 @@ val nmsBindings = mapOf(
"v1_20_R1" to "1.20.1-R0.1-SNAPSHOT",
)
val jvmVersion = mapOf<String, Int>()
nmsBindings.forEach { key, value ->
nmsBindings.forEach { (key, value) ->
project(":nms:$key") {
apply<JavaPlugin>()
apply<NMSToolsPlugin>()
repositories {
maven("https://libraries.minecraft.net")
}
extensions.configure(NMSToolsExtension::class) {
nmsBinding {
jvm = jvmVersion.getOrDefault(key, 21)
version = value
type = NMSBinding.Type.DIRECT
}
dependencies {
@@ -110,17 +105,23 @@ nmsBindings.forEach { key, value ->
systemProperty("com.mojang.eula.agree", true)
systemProperty("iris.suppressReporting", !errorReporting)
jvmArgs("-javaagent:${project(":core:agent").tasks.jar.flatMap { it.archiveFile }.get().asFile.absolutePath}")
jvmArgs(additionalFlags.split(' '))
}
}
val jarJar: Configuration by configurations.creating
dependencies {
for (key in nmsBindings.keys) {
implementation(project(":nms:$key", "reobf"))
}
implementation(project(":core", "shadow"))
jarJar(project(":core:agent"))
}
tasks {
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
nmsBindings.forEach { key, _ ->
from(project(":nms:$key").tasks.named("remap").map { zipTree(it.outputs.files.singleFile) })
}
from(project(":core").tasks.shadowJar.flatMap { it.archiveFile }.map { zipTree(it) })
from(project(":core:agent").tasks.jar.flatMap { it.archiveFile })
from(jarJar, configurations.runtimeClasspath.map { it.resolve().map(::zipTree) })
archiveFileName.set("Iris-${project.version}.jar")
}

View File

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

View File

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

View File

@@ -142,6 +142,7 @@ slimJar {
relocate("com.google.inject", "$lib.guice")
relocate("org.dom4j", "$lib.dom4j")
relocate("org.jaxen", "$lib.jaxen")
relocate("com.github.benmanes.caffeine", "$lib.caffeine")
}
tasks {
@@ -162,15 +163,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)
@@ -185,9 +177,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

@@ -58,6 +58,7 @@ import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitPlugin;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.plugin.chunk.ChunkTickets;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Queue;
import com.volmit.iris.util.scheduling.ShurikenQueue;
@@ -95,6 +96,7 @@ public class Iris extends VolmitPlugin implements Listener {
public static MultiverseCoreLink linkMultiverseCore;
public static IrisCompat compat;
public static FileWatcher configWatcher;
public static ChunkTickets tickets;
private static VolmitSender sender;
private static Thread shutdownHook;
@@ -450,6 +452,7 @@ public class Iris extends VolmitPlugin implements Listener {
IrisSafeguard.IrisSafeguardSystem();
getSender().setTag(getTag());
IrisSafeguard.splash(true);
tickets = new ChunkTickets();
linkMultiverseCore = new MultiverseCoreLink();
configWatcher = new FileWatcher(getDataFile("settings.json"));
services.values().forEach(IrisService::onEnable);
@@ -707,7 +710,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());
}
@@ -717,13 +724,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.");

View File

@@ -159,7 +159,7 @@ public class IrisSettings {
private IrisSettingsEngineSVC engineSVC = new IrisSettingsEngineSVC();
public boolean trimMantleInStudio = false;
public int mantleKeepAlive = 30;
public int cacheSize = 4_096;
public int noiseCacheSize = 1_024;
public int resourceLoaderCacheSize = 1_024;
public int objectLoaderCacheSize = 4_096;
public int scriptLoaderCacheSize = 512;
@@ -177,6 +177,9 @@ public class IrisSettings {
@Data
public static class IrisSettingsUpdater {
public int maxConcurrency = 256;
public boolean nativeThreads = false;
public double threadMultiplier = 2;
public double chunkLoadSensitivity = 0.7;
public MsRange emptyMsRange = new MsRange(80, 100);
public MsRange defaultMsRange = new MsRange(20, 40);
@@ -185,6 +188,10 @@ public class IrisSettings {
return Math.max(Math.abs(maxConcurrency), 1);
}
public double getThreadMultiplier() {
return Math.min(Math.abs(threadMultiplier), 0.1);
}
public double getChunkLoadSensitivity() {
return Math.min(chunkLoadSensitivity, 0.9);
}
@@ -243,6 +250,7 @@ public class IrisSettings {
public int maxBiomeChildDepth = 4;
public boolean preventLeafDecay = true;
public boolean useMulticore = false;
public boolean useMulticoreMantle = false;
public boolean offsetNoiseTypes = false;
public boolean earlyCustomBlocks = false;
}

View File

@@ -71,7 +71,6 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@@ -159,7 +158,7 @@ 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 = "---", customHandler = NullableDimensionHandler.class)
@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

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

@@ -38,7 +38,6 @@ import com.volmit.iris.util.decree.specialhandlers.ObjectHandler;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.Direction;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.Queue;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
@@ -79,9 +78,9 @@ public class CommandObject implements DecreeExecutor {
futureBlockChanges.put(block, block.getBlockData());
if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase());
block.setBlockData(data.getBase(), false);
Iris.warn("Tried to place custom block at " + x + ", " + y + ", " + z + " which is not supported!");
} else block.setBlockData(d);
} else block.setBlockData(d, false);
}
@Override
@@ -124,6 +123,16 @@ public class CommandObject implements DecreeExecutor {
tile.toBukkitTry(world.getBlockAt(xx, yy, zz));
}
@Override
public <T> void setData(int xx, int yy, int zz, T data) {
}
@Override
public <T> T getData(int xx, int yy, int zz, Class<T> t) {
return null;
}
@Override
public Engine getEngine() {
return null;
@@ -136,11 +145,11 @@ 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()));
Queue<BlockData> queue = o.getBlocks().enqueueValues();
var queue = o.getBlocks().values();
Map<Material, Set<BlockData>> unsorted = new HashMap<>();
Map<BlockData, Integer> amounts = new HashMap<>();
Map<Material, Integer> materials = new HashMap<>();
@@ -201,7 +210,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 +334,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

@@ -58,7 +58,7 @@ 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 com.volmit.iris.util.scheduling.jobs.ParallelRadiusJob;
import io.papermc.lib.PaperLib;
import org.bukkit.*;
import org.bukkit.event.inventory.InventoryType;
@@ -78,6 +78,7 @@ import java.util.Arrays;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
@@ -171,59 +172,52 @@ 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 (SyncExecutor executor = new SyncExecutor(20);
var service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())
) {
int x = loc.getBlockX() >> 4;
int z = loc.getBlockZ() >> 4;
int rad = engine.getMantle().getRadius();
var mantle = engine.getMantle().getMantle();
var chunkMap = new KMap<Position2, MantleChunk>();
ParallelQueueJob<Position2> prep = new ParallelQueueJob<>() {
ParallelRadiusJob prep = new ParallelRadiusJob(Integer.MAX_VALUE, service) {
@Override
public void execute(Position2 pos) {
var cpos = pos.add(x, z);
if (Math.abs(pos.getX()) <= radius && Math.abs(pos.getZ()) <= radius) {
mantle.deleteChunk(cpos.getX(), cpos.getZ());
protected void execute(int rX, int rZ) {
if (Math.abs(rX) <= radius && Math.abs(rZ) <= radius) {
mantle.deleteChunk(rX + x, rZ + z);
return;
}
chunkMap.put(cpos, mantle.getChunk(cpos.getX(), cpos.getZ()));
mantle.deleteChunk(cpos.getX(), cpos.getZ());
rX += x;
rZ += z;
chunkMap.put(new Position2(rX, rZ), mantle.getChunk(rX, rZ));
mantle.deleteChunk(rX, rZ);
}
@Override
public String getName() {
return "Preparing Mantle";
}
};
for (int xx = -(radius + rad); xx <= radius + rad; xx++) {
for (int zz = -(radius + rad); zz <= radius + rad; zz++) {
prep.queue(new Position2(xx, zz));
}
}
}.retarget(radius + rad, 0, 0);
CountDownLatch pLatch = new CountDownLatch(1);
prep.execute(sender(), pLatch::countDown);
pLatch.await();
ParallelQueueJob<Position2> job = new ParallelQueueJob<>() {
ParallelRadiusJob job = new ParallelRadiusJob(Integer.MAX_VALUE, service) {
@Override
public void execute(Position2 p) {
plat.injectChunkReplacement(world, p.getX(), p.getZ(), executor);
protected void execute(int x, int z) {
plat.injectChunkReplacement(world, x, z, executor);
}
@Override
public String getName() {
return "Regenerating";
}
};
for (int i = -radius; i <= radius; i++) {
for (int j = -radius; j <= radius; j++) {
job.queue(new Position2(i + x, j + z));
}
}
}.retarget(radius, x, z);
CountDownLatch latch = new CountDownLatch(1);
job.execute(sender(), latch::countDown);
latch.await();
@@ -247,6 +241,8 @@ public class CommandStudio implements DecreeExecutor {
} catch (Throwable e) {
sender().sendMessage("Error while regenerating chunks");
e.printStackTrace();
} finally {
DecreeContext.remove();
}
});
}
@@ -337,11 +333,15 @@ public class CommandStudio implements DecreeExecutor {
O<Integer> ta = new O<>();
ta.set(-1);
var sender = sender();
var player = player();
var engine = engine();
ta.set(Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () ->
{
if (!player().getOpenInventory().getType().equals(InventoryType.CHEST)) {
if (!player.getOpenInventory().getType().equals(InventoryType.CHEST)) {
Bukkit.getScheduler().cancelTask(ta.get());
sender().sendMessage(C.GREEN + "Opened inventory!");
sender.sendMessage(C.GREEN + "Opened inventory!");
return;
}
@@ -349,7 +349,7 @@ public class CommandStudio implements DecreeExecutor {
inv.clear();
}
engine().addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player().getWorld(), player().getLocation().getBlockX(), player().getLocation().getBlockY(), player().getLocation().getBlockZ(), 1);
engine.addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player.getWorld(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ(), 1);
}, 0, fast ? 5 : 35));
sender().sendMessage(C.GREEN + "Opening inventory now!");

View File

@@ -67,7 +67,7 @@ public class HMCLeavesDataProvider extends ExternalDataProvider {
BlockData blockData = Bukkit.createBlockData(material);
if (IrisSettings.get().getGenerator().preventLeafDecay && blockData instanceof Leaves leaves)
leaves.setPersistent(true);
return new IrisCustomData(blockData, ExternalDataSVC.buildState(blockId, state));
return IrisCustomData.of(blockData, ExternalDataSVC.buildState(blockId, state));
}
@NotNull

View File

@@ -47,7 +47,7 @@ public class ItemAdderDataProvider extends ExternalDataProvider {
if (block == null) {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
return new IrisCustomData(block.getBaseBlockData(), blockId);
return IrisCustomData.of(block.getBaseBlockData(), blockId);
}
@NotNull

View File

@@ -33,7 +33,7 @@ public class KGeneratorsDataProvider extends ExternalDataProvider {
@Override
public @NotNull BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
if (Main.getGenerators().get(blockId.key()) == null) throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
return new IrisCustomData(Material.STRUCTURE_VOID.createBlockData(), ExternalDataSVC.buildState(blockId, state));
return IrisCustomData.of(Material.STRUCTURE_VOID.createBlockData(), ExternalDataSVC.buildState(blockId, state));
}
@Override

View File

@@ -72,7 +72,7 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider {
CustomBlockItemContext blockItemContext = crucibleItem.getBlockData();
FurnitureItemContext furnitureItemContext = crucibleItem.getFurnitureData();
if (furnitureItemContext != null) {
return new IrisCustomData(B.getAir(), ExternalDataSVC.buildState(blockId, state));
return IrisCustomData.of(B.getAir(), ExternalDataSVC.buildState(blockId, state));
} else if (blockItemContext != null) {
return blockItemContext.getBlockData();
}

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;
@@ -17,10 +21,10 @@ import org.bukkit.entity.Entity;
import org.bukkit.event.EventHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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() {
@@ -33,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

@@ -49,9 +49,9 @@ public class NexoDataProvider extends ExternalDataProvider {
BlockData data = NexoBlocks.blockData(blockId.key());
if (data == null)
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
return new IrisCustomData(data, blockState);
return IrisCustomData.of(data, blockState);
} else if (NexoFurniture.isFurniture(blockId.key())) {
return new IrisCustomData(B.getAir(), blockState);
return IrisCustomData.of(B.getAir(), blockState);
}
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());

View File

@@ -43,22 +43,22 @@ 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;
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.*;
@Data
public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
private static final KMap<File, IrisData> dataLoaders = new KMap<>();
private final File dataFolder;
private final int id;
private final PackEnvironment environment;
private boolean closed = false;
private PackEnvironment environment;
private ResourceLoader<IrisBiome> biomeLoader;
private ResourceLoader<IrisLootTable> lootLoader;
private ResourceLoader<IrisRegion> regionLoader;
@@ -91,7 +91,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
this.engine = null;
this.dataFolder = dataFolder;
this.id = RNG.r.imax();
this.environment = PackEnvironment.create(this);
hotloaded();
}
@@ -99,6 +98,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);
}
@@ -118,92 +121,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;
@@ -218,6 +229,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");
@@ -325,7 +347,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
}
public synchronized void hotloaded() {
environment.close();
closed = false;
possibleSnippets = new KMap<>();
builder = new GsonBuilder()
.addDeserializationExclusionStrategy(this)
@@ -357,6 +379,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
this.imageLoader = registerLoader(IrisImage.class);
this.scriptLoader = registerLoader(IrisScript.class);
this.matterObjectLoader = registerLoader(IrisMatterObject.class);
this.environment = PackEnvironment.create(this);
builder.registerTypeAdapterFactory(KeyedType::createTypeAdapter);
gson = builder.create();
@@ -364,6 +387,10 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
.map(IrisDimension::getDataScripts)
.flatMap(KList::stream)
.forEach(environment::execute);
if (engine != null) {
engine.hotload();
}
}
public void dump() {
@@ -379,6 +406,33 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
possibleSnippets.clear();
}
public Set<Class<?>> resolveSnippets() {
var result = new HashSet<Class<?>>();
var processed = new HashSet<Class<?>>();
var excluder = gson.excluder();
var queue = new LinkedList<Class<?>>(loaders.keySet());
while (!queue.isEmpty()) {
var type = queue.poll();
if (excluder.excludeClass(type, false) || !processed.add(type))
continue;
if (type.isAnnotationPresent(Snippet.class))
result.add(type);
try {
for (var field : type.getDeclaredFields()) {
if (excluder.excludeField(field, false))
continue;
queue.add(field.getType());
}
} catch (Throwable ignored) {
}
}
return result;
}
public String toLoadKey(File f) {
if (f.getPath().startsWith(getDataFolder().getPath())) {
String[] full = f.getPath().split("\\Q" + File.separator + "\\E");

View File

@@ -35,7 +35,7 @@ import java.io.File;
@Data
public abstract class IrisRegistrant {
@Desc("Preprocess this object in-memory when it's loaded, run scripts using the variable 'Iris.getPreprocessorObject()' and modify properties about this object before it's used.")
@Desc("Preprocess this object in-memory when it's loaded, run scripts using the variable 'object' and modify properties about this object before it's used.\nFile extension: .proc.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(min = 1, type = String.class)
private KList<String> preprocessors = new KList<>();

View File

@@ -46,6 +46,7 @@ import lombok.ToString;
import java.io.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@@ -170,7 +171,6 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
return possibleKeys;
}
KSet<String> m = new KSet<>();
KList<File> files = getFolders();
if (files == null) {
@@ -178,6 +178,7 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
return possibleKeys;
}
HashSet<String> m = new HashSet<>();
for (File i : files) {
for (File j : matchAllFiles(i, (f) -> f.getName().endsWith(".json"))) {
m.add(i.toURI().relativize(j.toURI()).getPath().replaceAll("\\Q.json\\E", ""));
@@ -319,7 +320,8 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
return null;
}
firstAccess.add(name);
var set = firstAccess;
if (set != null) firstAccess.add(name);
return loadCache.get(name);
}
@@ -342,21 +344,24 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
}
din.close();
file.deleteOnExit();
Iris.info("Loading " + s.size() + " prefetch " + getFolderName());
firstAccess = null;
loadAllParallel(s);
}
public void saveFirstAccess(Engine engine) throws IOException {
if (firstAccess == null) return;
String id = "DIM" + Math.abs(engine.getSeedManager().getSeed() + engine.getDimension().getVersion() + engine.getDimension().getLoadKey().hashCode());
File file = Iris.instance.getDataFile("prefetch/" + id + "/" + Math.abs(getFolderName().hashCode()) + ".ipfch");
file.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(file);
GZIPOutputStream gzo = new CustomOutputStream(fos, 9);
DataOutputStream dos = new DataOutputStream(gzo);
dos.writeInt(firstAccess.size());
var set = firstAccess;
firstAccess = null;
dos.writeInt(set.size());
for (String i : firstAccess) {
for (String i : set) {
dos.writeUTF(i);
}

View File

@@ -28,9 +28,10 @@ import java.util.List;
public class INMS {
private static final Version CURRENT = Boolean.getBoolean("iris.no-version-limit") ?
new Version(Integer.MAX_VALUE, Integer.MAX_VALUE, null) :
new Version(21, 8, null);
new Version(21, 10, null);
private static final List<Version> REVISION = List.of(
new Version(21, 9, "v1_21_R6"),
new Version(21, 6, "v1_21_R5"),
new Version(21, 5, "v1_21_R4"),
new Version(21, 4, "v1_21_R3"),

View File

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

View File

@@ -24,9 +24,11 @@ public interface PregenCache {
void write();
void trim(long unloadDuration);
static PregenCache create(File directory) {
if (directory == null) return EMPTY;
return new PregenCacheImpl(directory);
return new PregenCacheImpl(directory, 16);
}
default PregenCache sync() {
@@ -51,19 +53,16 @@ public interface PregenCache {
}
@Override
public void cacheChunk(int x, int z) {
}
public void cacheChunk(int x, int z) {}
@Override
public void cacheRegion(int x, int z) {
}
public void cacheRegion(int x, int z) {}
@Override
public void write() {
public void write() {}
}
@Override
public void trim(long unloadDuration) {}
};

View File

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

View File

@@ -1,11 +1,6 @@
package com.volmit.iris.core.pregenerator.cache;
import lombok.AllArgsConstructor;
@AllArgsConstructor
class SynchronizedCache implements PregenCache {
private final PregenCache cache;
record SynchronizedCache(PregenCache cache) implements PregenCache {
@Override
public boolean isThreadSafe() {
return true;
@@ -45,4 +40,11 @@ class SynchronizedCache implements PregenCache {
cache.write();
}
}
@Override
public void trim(long unloadDuration) {
synchronized (cache) {
cache.trim(unloadDuration);
}
}
}

View File

@@ -9,9 +9,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Optional;
import java.util.Scanner;
import java.util.*;
public class Gradle {
private static final boolean WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
@@ -38,10 +36,15 @@ public class Gradle {
cmd[0] = gradle.getAbsolutePath();
System.arraycopy(args, 0, cmd, 1, args.length);
var process = Runtime.getRuntime().exec(cmd, ENVIRONMENT, projectDir);
attach(process.getInputStream());
attach(process.getErrorStream());
var lines = Collections.synchronizedList(new ArrayList<String>());
attach(process.getInputStream(), lines);
attach(process.getErrorStream(), lines);
var code = process.waitFor();
if (code == 0) return;
if (code == 0) {
lines.forEach(Iris::debug);
return;
}
lines.forEach(Iris::error);
throw new RuntimeException("Gradle exited with code " + code);
}
@@ -91,12 +94,12 @@ public class Gradle {
.orElseThrow(() -> new RuntimeException("Failed to find java home, please set java.home system property"));
}
private static void attach(InputStream stream) {
Thread.ofVirtual().start(() -> {
private static void attach(InputStream stream, List<String> list) {
Thread.ofPlatform().start(() -> {
try (var in = new Scanner(stream)) {
while (in.hasNextLine()) {
String line = in.nextLine();
Iris.debug("[GRADLE] " + line);
list.add(line);
}
}
});

View File

@@ -24,7 +24,6 @@ import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.core.scripting.environment.SimpleEnvironment;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.object.annotations.Snippet;
@@ -159,7 +158,7 @@ public class IrisProject {
public void openVSCode(VolmitSender sender) {
IrisDimension d = IrisData.loadAnyDimension(getName());
IrisDimension d = IrisData.loadAnyDimension(getName(), null);
J.attemptAsync(() ->
{
try {
@@ -221,7 +220,7 @@ public class IrisProject {
}
J.a(() -> {
IrisDimension d = IrisData.loadAnyDimension(getName());
IrisDimension d = IrisData.loadAnyDimension(getName(), null);
if (d == null) {
sender.sendMessage("Can't find dimension: " + getName());
return;
@@ -326,7 +325,7 @@ public class IrisProject {
}
}
for (Class<?> i : Iris.getClasses("com.volmit.iris.engine.object.", Snippet.class)) {
for (Class<?> i : dm.resolveSnippets()) {
try {
String snipType = i.getDeclaredAnnotation(Snippet.class).value();
JSONObject o = new JSONObject();

View File

@@ -38,6 +38,7 @@ import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.lang.reflect.Field;
import java.lang.reflect.InaccessibleObjectException;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
@@ -117,49 +118,13 @@ public class SchemaBuilder {
JSONArray required = new JSONArray();
JSONArray extended = new JSONArray();
if (c.isAssignableFrom(IrisRegistrant.class) || IrisRegistrant.class.isAssignableFrom(c)) {
for (Field k : IrisRegistrant.class.getDeclaredFields()) {
k.setAccessible(true);
if (Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
continue;
}
JSONObject property = buildProperty(k, c);
if (Boolean.TRUE == property.remove("!required")) {
required.put(k.getName());
}
if (Boolean.TRUE == property.remove("!top")) {
extended.put(property);
continue;
}
properties.put(k.getName(), property);
}
var parent = c.getSuperclass();
while (parent != null && IrisRegistrant.class.isAssignableFrom(parent)) {
buildProperties(properties, required, extended, parent);
parent = parent.getSuperclass();
}
for (Field k : c.getDeclaredFields()) {
k.setAccessible(true);
if (Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
continue;
}
JSONObject property = buildProperty(k, c);
if (Boolean.TRUE == property.remove("!required")) {
required.put(k.getName());
}
if (Boolean.TRUE == property.remove("!top")) {
extended.put(property);
continue;
}
properties.put(k.getName(), property);
}
buildProperties(properties, required, extended, c);
if (required.length() > 0) {
o.put("required", required);
@@ -174,6 +139,33 @@ public class SchemaBuilder {
return buildSnippet(o, c);
}
private void buildProperties(JSONObject properties, JSONArray required, JSONArray extended, Class<?> c) {
for (Field k : c.getDeclaredFields()) {
if (Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
continue;
}
try {
k.setAccessible(true);
} catch (InaccessibleObjectException e) {
continue;
}
JSONObject property = buildProperty(k, c);
if (Boolean.TRUE == property.remove("!top")) {
extended.put(property);
continue;
}
if (Boolean.TRUE == property.remove("!required")) {
required.put(k.getName());
}
properties.put(k.getName(), property);
}
}
private JSONObject buildProperty(Field k, Class<?> cl) {
JSONObject prop = new JSONObject();
String type = getType(k.getType());
@@ -616,7 +608,7 @@ public class SchemaBuilder {
if (present) d.add(" ");
if (value instanceof List) {
d.add(SYMBOL_LIMIT__N + " Default Value is an empty list");
} else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum()) && !KeyedType.isKeyed(cl)) {
} else if (!k.getType().isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(value instanceof Enum<?>) && !KeyedType.isKeyed(k.getType())) {
d.add(SYMBOL_LIMIT__N + " Default Value is a default object (create this object to see default properties)");
} else {
d.add(SYMBOL_LIMIT__N + " Default Value is " + value);

View File

@@ -1,9 +1,12 @@
package com.volmit.iris.core.scripting.environment;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.scripting.func.UpdateExecutor;
import com.volmit.iris.core.scripting.kotlin.environment.IrisExecutionEnvironment;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.mantle.MantleChunk;
import lombok.NonNull;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.Nullable;
@@ -22,4 +25,6 @@ public interface EngineEnvironment extends PackEnvironment {
void postSpawnMob(@NonNull String script, @NonNull Location location, @NonNull Entity mob);
void preprocessObject(@NonNull String script, @NonNull IrisRegistrant object);
void updateChunk(@NonNull String script, @NonNull MantleChunk mantleChunk, @NonNull Chunk chunk, @NonNull UpdateExecutor executor);
}

View File

@@ -2,6 +2,7 @@ package com.volmit.iris.core.scripting.environment;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.scripting.kotlin.environment.IrisPackExecutionEnvironment;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.math.RNG;
import lombok.NonNull;
import org.jetbrains.annotations.Nullable;
@@ -16,4 +17,6 @@ public interface PackEnvironment extends SimpleEnvironment {
@Nullable
Object createNoise(@NonNull String script, @NonNull RNG rng);
EngineEnvironment with(@NonNull Engine engine);
}

View File

@@ -27,8 +27,4 @@ public interface SimpleEnvironment {
@Nullable
Object evaluate(@NonNull String script, @NonNull Class<?> type, @Nullable Map<@NonNull String, Object> vars);
default void close() {
}
}

View File

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

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

@@ -1,13 +1,11 @@
package com.volmit.iris.core.service;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Scheduler;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.cache.PregenCache;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.KCache;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.Looper;
import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.World;
@@ -19,21 +17,33 @@ import org.bukkit.event.world.WorldUnloadEvent;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.function.Function;
public class GlobalCacheSVC implements IrisService {
private static final Cache<String, PregenCache> REFERENCE_CACHE = Caffeine.newBuilder()
.executor(KCache.EXECUTOR)
.scheduler(Scheduler.systemScheduler())
.weakValues()
.build();
private static final KMap<String, Reference<PregenCache>> REFERENCE_CACHE = new KMap<>();
private final KMap<String, PregenCache> globalCache = new KMap<>();
private transient boolean lastState;
private static boolean disabled = true;
private Looper trimmer;
@Override
public void onEnable() {
disabled = false;
trimmer = new Looper() {
@Override
protected long loop() {
var it = REFERENCE_CACHE.values().iterator();
while (it.hasNext()) {
var cache = it.next().get();
if (cache == null) it.remove();
else cache.trim(10_000);
}
return disabled ? -1 : 2_000;
}
};
trimmer.start();
lastState = !IrisSettings.get().getWorld().isGlobalPregenCache();
if (lastState) return;
Bukkit.getWorlds().forEach(this::createCache);
@@ -42,6 +52,9 @@ public class GlobalCacheSVC implements IrisService {
@Override
public void onDisable() {
disabled = true;
try {
trimmer.join();
} catch (InterruptedException ignored) {}
globalCache.qclear((world, cache) -> cache.write());
}
@@ -76,6 +89,7 @@ public class GlobalCacheSVC implements IrisService {
}
private void createCache(World world) {
if (!IrisToolbelt.isIrisWorld(world)) return;
globalCache.computeIfAbsent(world.getName(), GlobalCacheSVC::createDefault);
}
@@ -99,7 +113,15 @@ public class GlobalCacheSVC implements IrisService {
@NonNull
public static PregenCache createCache(@NonNull String worldName, @NonNull Function<String, PregenCache> provider) {
return REFERENCE_CACHE.get(worldName, provider);
PregenCache[] holder = new PregenCache[1];
REFERENCE_CACHE.compute(worldName, (name, ref) -> {
if (ref != null) {
if ((holder[0] = ref.get()) != null)
return ref;
}
return new WeakReference<>(holder[0] = provider.apply(worldName));
});
return holder[0];
}
@NonNull

View File

@@ -3,7 +3,7 @@ package com.volmit.iris.core.service;
import com.google.common.util.concurrent.AtomicDouble;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
@@ -14,6 +14,8 @@ import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.Looper;
import com.volmit.iris.util.stream.utility.CachedStream2D;
import com.volmit.iris.util.stream.utility.CachedStream3D;
import lombok.Synchronized;
import org.bukkit.Bukkit;
import org.bukkit.World;
@@ -27,6 +29,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
public class IrisEngineSVC implements IrisService {
private static final int TRIM_PERIOD = 2_000;
private final AtomicInteger tectonicLimit = new AtomicInteger(30);
private final AtomicInteger tectonicPlates = new AtomicInteger();
private final AtomicInteger queuedTectonicPlates = new AtomicInteger();
@@ -64,10 +67,26 @@ public class IrisEngineSVC implements IrisService {
}
public void engineStatus(VolmitSender sender) {
long[] sizes = new long[4];
long[] count = new long[4];
for (var cache : Iris.service(PreservationSVC.class).getCaches()) {
var type = switch (cache) {
case ResourceLoader<?> ignored -> 0;
case CachedStream2D<?> ignored -> 1;
case CachedStream3D<?> ignored -> 2;
default -> 3;
};
sizes[type] += cache.getSize();
count[type]++;
}
sender.sendMessage(C.DARK_PURPLE + "-------------------------");
sender.sendMessage(C.DARK_PURPLE + "Status:");
sender.sendMessage(C.DARK_PURPLE + "- Service: " + C.LIGHT_PURPLE + (service.isShutdown() ? "Shutdown" : "Running"));
sender.sendMessage(C.DARK_PURPLE + "- Updater: " + C.LIGHT_PURPLE + (updateTicker.isAlive() ? "Running" : "Stopped"));
sender.sendMessage(C.DARK_PURPLE + "- Period: " + C.LIGHT_PURPLE + Form.duration(TRIM_PERIOD));
sender.sendMessage(C.DARK_PURPLE + "- Trimmers: " + C.LIGHT_PURPLE + trimmerAlive.get());
sender.sendMessage(C.DARK_PURPLE + "- Unloaders: " + C.LIGHT_PURPLE + unloaderAlive.get());
sender.sendMessage(C.DARK_PURPLE + "Tectonic Plates:");
@@ -76,10 +95,14 @@ public class IrisEngineSVC implements IrisService {
sender.sendMessage(C.DARK_PURPLE + "- Queued: " + C.LIGHT_PURPLE + queuedTectonicPlates.get());
sender.sendMessage(C.DARK_PURPLE + "- Max Idle Duration: " + C.LIGHT_PURPLE + Form.duration(maxIdleDuration.get(), 2));
sender.sendMessage(C.DARK_PURPLE + "- Min Idle Duration: " + C.LIGHT_PURPLE + Form.duration(minIdleDuration.get(), 2));
sender.sendMessage(C.DARK_PURPLE + "Caches:");
sender.sendMessage(C.DARK_PURPLE + "- Resource: " + C.LIGHT_PURPLE + sizes[0] + " (" + count[0] + ")");
sender.sendMessage(C.DARK_PURPLE + "- 2D Stream: " + C.LIGHT_PURPLE + sizes[1] + " (" + count[1] + ")");
sender.sendMessage(C.DARK_PURPLE + "- 3D Stream: " + C.LIGHT_PURPLE + sizes[2] + " (" + count[2] + ")");
sender.sendMessage(C.DARK_PURPLE + "- Other: " + C.LIGHT_PURPLE + sizes[3] + " (" + count[3] + ")");
sender.sendMessage(C.DARK_PURPLE + "Other:");
sender.sendMessage(C.DARK_PURPLE + "- Iris Worlds: " + C.LIGHT_PURPLE + totalWorlds.get());
sender.sendMessage(C.DARK_PURPLE + "- Loaded Chunks: " + C.LIGHT_PURPLE + loadedChunks.get());
sender.sendMessage(C.DARK_PURPLE + "- Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize()));
sender.sendMessage(C.DARK_PURPLE + "-------------------------");
}
@@ -113,12 +136,12 @@ public class IrisEngineSVC implements IrisService {
@Override
protected long loop() {
try {
queuedTectonicPlates.set(0);
tectonicPlates.set(0);
loadedChunks.set(0);
unloaderAlive.set(0);
trimmerAlive.set(0);
totalWorlds.set(0);
int queuedPlates = 0;
int totalPlates = 0;
long chunks = 0;
int unloaders = 0;
int trimmers = 0;
int iris = 0;
double maxDuration = Long.MIN_VALUE;
double minDuration = Long.MAX_VALUE;
@@ -126,23 +149,30 @@ public class IrisEngineSVC implements IrisService {
var registered = entry.getValue();
if (registered.closed) continue;
totalWorlds.incrementAndGet();
unloaderAlive.addAndGet(registered.unloaderAlive() ? 1 : 0);
trimmerAlive.addAndGet(registered.trimmerAlive() ? 1 : 0);
iris++;
if (registered.unloaderAlive()) unloaders++;
if (registered.trimmerAlive()) trimmers++;
var engine = registered.getEngine();
if (engine == null) continue;
queuedTectonicPlates.addAndGet((int) engine.getMantle().getUnloadRegionCount());
tectonicPlates.addAndGet(engine.getMantle().getLoadedRegionCount());
loadedChunks.addAndGet(entry.getKey().getLoadedChunks().length);
queuedPlates += engine.getMantle().getUnloadRegionCount();
totalPlates += engine.getMantle().getLoadedRegionCount();
chunks += entry.getKey().getLoadedChunks().length;
double duration = engine.getMantle().getAdjustedIdleDuration();
if (duration > maxDuration) maxDuration = duration;
if (duration < minDuration) minDuration = duration;
}
trimmerAlive.set(trimmers);
unloaderAlive.set(unloaders);
tectonicPlates.set(totalPlates);
queuedTectonicPlates.set(queuedPlates);
maxIdleDuration.set(maxDuration);
minIdleDuration.set(minDuration);
loadedChunks.set(chunks);
totalWorlds.set(iris);
worlds.values().forEach(Registered::update);
} catch (Throwable e) {
@@ -157,7 +187,7 @@ public class IrisEngineSVC implements IrisService {
private final class Registered {
private final String name;
private final PlatformChunkGenerator access;
private final int offset = RNG.r.nextInt(1000);
private final int offset = RNG.r.nextInt(TRIM_PERIOD);
private transient ScheduledFuture<?> trimmer;
private transient ScheduledFuture<?> unloader;
private transient boolean closed;
@@ -194,7 +224,7 @@ public class IrisEngineSVC implements IrisService {
Iris.error("EngineSVC: Failed to trim for " + name);
e.printStackTrace();
}
}, offset, 2000, TimeUnit.MILLISECONDS);
}, offset, TRIM_PERIOD, TimeUnit.MILLISECONDS);
}
if (unloader == null || unloader.isDone() || unloader.isCancelled()) {
@@ -214,7 +244,7 @@ public class IrisEngineSVC implements IrisService {
Iris.error("EngineSVC: Failed to unload for " + name);
e.printStackTrace();
}
}, offset + 1000, 2000, TimeUnit.MILLISECONDS);
}, offset + TRIM_PERIOD / 2, TRIM_PERIOD, TimeUnit.MILLISECONDS);
}
}

View File

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

View File

@@ -93,7 +93,7 @@ public class StudioSVC implements IrisService {
public IrisDimension installInto(VolmitSender sender, String type, File folder) {
sender.sendMessage("Looking for Package: " + type);
IrisDimension dim = IrisData.loadAnyDimension(type);
IrisDimension dim = IrisData.loadAnyDimension(type, null);
if (dim == null) {
for (File i : getWorkspaceFolder().listFiles()) {
@@ -147,8 +147,7 @@ public class StudioSVC implements IrisService {
}
IrisData dm = IrisData.get(folder);
dm.dump();
dm.clearLists();
dm.hotloaded();
dim = dm.getDimensionLoader().load(type);
if (dim == null) {
@@ -265,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");
@@ -279,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;
}
@@ -298,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

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

View File

@@ -90,6 +90,7 @@ public class WandSVC implements IrisService {
int total = c.getSizeX() * c.getSizeY() * c.getSizeZ();
var latch = new CountDownLatch(1);
var holder = Iris.tickets.getHolder(p.getWorld());
new Job() {
private int i;
private Chunk chunk;
@@ -108,7 +109,7 @@ public class WandSVC implements IrisService {
while (time > M.ms()) {
if (!it.hasNext()) {
if (chunk != null) {
chunk.removePluginChunkTicket(Iris.instance);
holder.removeTicket(chunk);
chunk = null;
}
@@ -122,9 +123,10 @@ public class WandSVC implements IrisService {
var bChunk = b.getChunk();
if (chunk == null) {
chunk = bChunk;
chunk.addPluginChunkTicket(Iris.instance);
holder.addTicket(chunk);
} else if (chunk != bChunk) {
chunk.removePluginChunkTicket(Iris.instance);
holder.removeTicket(chunk);
holder.addTicket(bChunk);
chunk = bChunk;
}

View File

@@ -89,7 +89,7 @@ public class IrisConverter {
for (int h = 0; h < objH; h++) {
for (int d = 0; d < objD; d++) {
for (int w = 0; w < objW; w++) {
BlockData bd = blockmap.get((int) originalBlockArray[v.get()]);
BlockData bd = blockmap.get(Byte.toUnsignedInt(originalBlockArray[v.get()]));
if (!bd.getMaterial().isAir()) {
object.setUnsigned(w, h, d, bd);
}

View File

@@ -34,6 +34,7 @@ import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import java.io.File;
import java.io.IOException;
@@ -45,6 +46,7 @@ import java.util.Map;
* Hope you packed snacks & road sodas.
*/
public class IrisToolbelt {
@ApiStatus.Internal
public static Map<String, Boolean> toolbeltConfiguration = new HashMap<>();
/**
@@ -232,7 +234,11 @@ public class IrisToolbelt {
}
public static void retainMantleDataForSlice(String className) {
toolbeltConfiguration.put("retain.mantle." + className, true);
toolbeltConfiguration.put("retain.mantle." + className, Boolean.TRUE);
}
public static boolean isRetainingMantleDataForSlice(String className) {
return !toolbeltConfiguration.isEmpty() && toolbeltConfiguration.get("retain.mantle." + className) == Boolean.TRUE;
}
public static <T> T getMantleData(World world, int x, int y, int z, Class<T> of) {

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)
@@ -86,7 +86,7 @@ public class IrisWorldCreator {
}
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

@@ -89,7 +89,7 @@ public class IrisComplex implements DataProvider {
}
public IrisComplex(Engine engine, boolean simple) {
int cacheSize = IrisSettings.get().getPerformance().getCacheSize();
int cacheSize = IrisSettings.get().getPerformance().getNoiseCacheSize();
IrisBiome emptyBiome = new IrisBiome();
UUID focusUUID = UUID.nameUUIDFromBytes("focus".getBytes());
this.rng = new RNG(engine.getSeedManager().getComplex());

File diff suppressed because it is too large Load Diff

View File

@@ -86,11 +86,13 @@ public class IrisEngineMantle implements EngineMantle {
.map(components::get)
.map(components -> {
int radius = components.stream()
.filter(MantleComponent::isEnabled)
.mapToInt(MantleComponent::getRadius)
.max()
.orElse(0);
return new Pair<>(List.copyOf(components), radius);
})
.filter(pair -> !pair.getA().isEmpty())
.toList();
int radius = 0;

View File

@@ -440,7 +440,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
//INMS.get().injectBiomesFromMantle(e, getMantle());
if (!IrisSettings.get().getGenerator().earlyCustomBlocks) return;
e.addPluginChunkTicket(Iris.instance);
Iris.tickets.addTicket(e);
J.s(() -> {
var chunk = getMantle().getChunk(e).use();
int minY = getTarget().getWorld().minHeight();
@@ -452,7 +452,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
});
} finally {
chunk.release();
e.removePluginChunkTicket(Iris.instance);
Iris.tickets.removeTicket(e);
}
}, RNG.r.i(20, 60));
}

View File

@@ -18,6 +18,7 @@
package com.volmit.iris.engine.framework;
import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.math.RNG;
import org.bukkit.Chunk;
import org.bukkit.block.data.BlockData;
@@ -28,5 +29,5 @@ public interface BlockUpdater {
void updateChunk(Chunk c);
void update(int x, int y, int z, Chunk c, RNG rf);
void update(int x, int y, int z, Chunk c, MantleChunk mc, RNG rf);
}

View File

@@ -48,6 +48,7 @@ import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.function.Function2;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.M;
@@ -294,8 +295,8 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
var chunk = mantle.getChunk(c).use();
try {
Semaphore semaphore = new Semaphore(3);
chunk.raiseFlag(MantleFlag.ETCHED, () -> {
Semaphore semaphore = new Semaphore(1024);
chunk.raiseFlagUnchecked(MantleFlag.ETCHED, () -> {
chunk.raiseFlagUnchecked(MantleFlag.TILE, run(semaphore, () -> {
chunk.iterate(TileWrapper.class, (x, y, z, v) -> {
Block block = c.getBlock(x & 15, y + getWorld().minHeight(), z & 15);
@@ -340,14 +341,14 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
for (int z = 0; z < 16; z++) {
if (grid[x][z] == Integer.MIN_VALUE)
continue;
update(x, grid[x][z], z, c, rng);
update(x, grid[x][z], z, c, chunk, rng);
}
}
chunk.iterate(MatterUpdate.class, (x, yf, z, v) -> {
int y = yf + getWorld().minHeight();
if (v != null && v.isUpdate()) {
update(x, y, z, c, rng);
update(x, y, z, c, chunk, rng);
}
});
chunk.deleteSlices(MatterUpdate.class);
@@ -355,8 +356,18 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
}, RNG.r.i(1, 20))); //Why is there a random delay here?
});
chunk.raiseFlagUnchecked(MantleFlag.SCRIPT, () -> {
var scripts = getDimension().getChunkUpdateScripts();
if (scripts == null || scripts.isEmpty())
return;
for (var script : scripts) {
getExecution().updateChunk(script, chunk, c, (delay, task) -> run(semaphore, task, delay));
}
});
try {
semaphore.acquire(3);
semaphore.acquire(1024);
} catch (InterruptedException ignored) {}
} finally {
chunk.release();
@@ -365,8 +376,11 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
private static Runnable run(Semaphore semaphore, Runnable runnable, int delay) {
return () -> {
if (!semaphore.tryAcquire())
return;
try {
semaphore.acquire();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
J.s(() -> {
try {
@@ -381,7 +395,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
@BlockCoordinates
@Override
default void update(int x, int y, int z, Chunk c, RNG rf) {
default void update(int x, int y, int z, Chunk c, MantleChunk mc, RNG rf) {
Block block = c.getBlock(x, y, z);
BlockData data = block.getBlockData();
blockUpdatedMetric();
@@ -394,17 +408,11 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
}
if (slot != null) {
KList<IrisLootTable> tables = getLootTables(rx, block);
KList<IrisLootTable> tables = getLootTables(rx, block, mc);
try {
Bukkit.getPluginManager().callEvent(new IrisLootEvent(this, block, slot, tables));
if (!tables.isEmpty()){
Iris.debug("IrisLootEvent has been accessed");
}
if (tables.isEmpty())
return;
if (tables.isEmpty()) return;
InventoryHolder m = (InventoryHolder) block.getState();
addItems(false, m.getInventory(), rx, tables, slot, c.getWorld(), x, y, z, 15);
@@ -470,13 +478,23 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
@BlockCoordinates
@Override
default KList<IrisLootTable> getLootTables(RNG rng, Block b) {
MantleChunk mc = getMantle().getMantle().getChunk(b.getChunk()).use();
try {
return getLootTables(rng, b, mc);
} finally {
mc.release();
}
}
@BlockCoordinates
default KList<IrisLootTable> getLootTables(RNG rng, Block b, MantleChunk mc) {
int rx = b.getX();
int rz = b.getZ();
int ry = b.getY() - getWorld().minHeight();
double he = getComplex().getHeightStream().get(rx, rz);
KList<IrisLootTable> tables = new KList<>();
PlacedObject po = getObjectPlacement(rx, ry, rz);
PlacedObject po = getObjectPlacement(rx, ry, rz, mc);
if (po != null && po.getPlacement() != null) {
if (B.isStorageChest(b.getBlockData())) {
IrisLootTable table = po.getPlacement().getTable(b.getBlockData(), getData());
@@ -799,7 +817,16 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
}
default PlacedObject getObjectPlacement(int x, int y, int z) {
String objectAt = getMantle().getMantle().get(x, y, z, String.class);
MantleChunk chunk = getMantle().getMantle().getChunk(x >> 4, z >> 4).use();
try {
return getObjectPlacement(x, y, z, chunk);
} finally {
chunk.release();
}
}
default PlacedObject getObjectPlacement(int x, int y, int z, MantleChunk chunk) {
String objectAt = chunk.get(x & 15, y, z & 15, String.class);
if (objectAt == null || objectAt.isEmpty()) {
return null;
}
@@ -809,7 +836,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
int id = Integer.parseInt(v[1]);
JigsawPieceContainer container = getMantle().getMantle().get(x, y, z, JigsawPieceContainer.class);
JigsawPieceContainer container = chunk.get(x & 15, y, z & 15, JigsawPieceContainer.class);
if (container != null) {
IrisJigsawPiece piece = container.load(getData());
if (piece.getObject().equals(object))
@@ -863,7 +890,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());
@@ -959,7 +986,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

@@ -24,7 +24,6 @@ import com.volmit.iris.engine.object.IObjectPlacer;
import com.volmit.iris.engine.object.IrisObjectPlacement;
import com.volmit.iris.engine.object.TileData;
import com.volmit.iris.util.math.RNG;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData;
public class HeightmapObjectPlacer implements IObjectPlacer {
@@ -83,6 +82,16 @@ public class HeightmapObjectPlacer implements IObjectPlacer {
oplacer.setTile(param1Int1, param1Int2, param1Int3, param1TileData);
}
@Override
public <T> void setData(int xx, int yy, int zz, T data) {
oplacer.setData(xx, yy, zz, data);
}
@Override
public <T> T getData(int xx, int yy, int zz, Class<T> t) {
return oplacer.getData(xx, yy, zz, t);
}
@Override
public Engine getEngine() {
return null;

View File

@@ -59,6 +59,11 @@ public class WorldObjectPlacer implements IObjectPlacer {
slot = InventorySlotType.STORAGE;
}
if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase(), false);
Iris.warn("Tried to place custom block at " + x + ", " + y + ", " + z + " which is not supported!");
} else block.setBlockData(d, false);
if (slot != null) {
RNG rx = new RNG(Cache.key(x, z));
KList<IrisLootTable> tables = engine.getLootTables(rx, block);
@@ -78,12 +83,6 @@ public class WorldObjectPlacer implements IObjectPlacer {
Iris.reportError(e);
}
}
if (d instanceof IrisCustomData data) {
block.setBlockData(data.getBase());
Iris.warn("Tried to place custom block at " + x + ", " + y + ", " + z + " which is not supported!");
} else block.setBlockData(d);
}
@Override
@@ -125,4 +124,13 @@ public class WorldObjectPlacer implements IObjectPlacer {
public void setTile(int xx, int yy, int zz, TileData tile) {
tile.toBukkitTry(world.getBlockAt(xx, yy + world.getMinHeight(), zz));
}
@Override
public <T> void setData(int xx, int yy, int zz, T data) {
}
@Override
public <T> T getData(int xx, int yy, int zz, Class<T> t) {
return null;
}
}

View File

@@ -154,9 +154,9 @@ public class PlannedStructure {
JigsawStructureContainer structure = JigsawStructureContainer.toContainer(getStructure());
i.setRealPositions(xx, height, zz, placer);
return v.place(xx, height, zz, placer, options, rng, (b, data) -> {
e.set(b.getX(), b.getY(), b.getZ(), v.getLoadKey() + "@" + id);
e.set(b.getX(), b.getY(), b.getZ(), structure);
e.set(b.getX(), b.getY(), b.getZ(), piece);
placer.setData(b.getX(), b.getY(), b.getZ(), v.getLoadKey() + "@" + id);
placer.setData(b.getX(), b.getY(), b.getZ(), structure);
placer.setData(b.getX(), b.getY(), b.getZ(), piece);
}, null, getData().getEngine() != null ? getData() : eng.getData()) != -1;
}

View File

@@ -29,8 +29,6 @@ import com.volmit.iris.engine.mantle.components.MantleObjectComponent;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisPosition;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates;
@@ -38,7 +36,6 @@ import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.matter.*;
import com.volmit.iris.util.matter.slices.UpdateMatter;
import com.volmit.iris.util.parallel.MultiBurst;
@@ -49,10 +46,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static com.volmit.iris.util.parallel.StreamUtils.forEach;
import static com.volmit.iris.util.parallel.StreamUtils.streamRadius;
public interface EngineMantle {
public interface EngineMantle extends MatterGenerator {
BlockData AIR = B.get("AIR");
Mantle getMantle();
@@ -180,49 +174,6 @@ public interface EngineMantle {
return getEngine().burst();
}
@ChunkCoordinates
default void generateMatter(int x, int z, boolean multicore, ChunkContext context) {
if (!getEngine().getDimension().isUseMantle() || getMantle().hasFlag(x, z, MantleFlag.PLANNED)) {
return;
}
try (MantleWriter writer = getMantle().write(this, x, z, getRadius() * 2)) {
var iterator = getComponents().iterator();
while (iterator.hasNext()) {
var pair = iterator.next();
int radius = pair.getB();
boolean last = !iterator.hasNext();
forEach(streamRadius(x, z, radius),
pos -> pair.getA()
.stream()
.filter(MantleComponent::isEnabled)
.map(c -> new Pair<>(c, pos)),
p -> {
MantleComponent c = p.getA();
Position2 pos = p.getB();
int xx = pos.getX();
int zz = pos.getZ();
IrisContext.getOr(getEngine()).setChunkContext(context);
generateMantleComponent(writer, xx, zz, c, writer.acquireChunk(xx, zz), context);
},
multicore ? burst() : null
);
if (!last) continue;
forEach(streamRadius(x, z, radius),
p -> writer.acquireChunk(x, z).flag(MantleFlag.PLANNED, true),
multicore ? burst() : null
);
}
}
}
default void generateMantleComponent(MantleWriter writer, int x, int z, MantleComponent c, MantleChunk mc, ChunkContext context) {
mc.raiseFlag(MantleFlag.PLANNED, c.getFlag(), () -> {
if (c.isEnabled()) c.generateLayer(writer, x, z, context);
});
}
@ChunkCoordinates
default <T> void insertMatter(int x, int z, Class<T> t, Hunk<T> blocks, boolean multicore) {
if (!getEngine().getDimension().isUseMantle()) {
@@ -262,9 +213,6 @@ public interface EngineMantle {
default int getLoadedRegionCount() {
return getMantle().getLoadedRegionCount();
}
default long getLastUseMapMemoryUsage(){
return getMantle().LastUseMapMemoryUsage();
}
MantleJigsawComponent getJigsawComponent();
@@ -290,7 +238,7 @@ public interface EngineMantle {
if (!isCovered(x, z)) return;
MantleChunk chunk = getMantle().getChunk(x, z).use();
try {
chunk.raiseFlag(MantleFlag.CLEANED, () -> {
chunk.raiseFlagUnchecked(MantleFlag.CLEANED, () -> {
chunk.deleteSlices(BlockData.class);
chunk.deleteSlices(String.class);
chunk.deleteSlices(MatterCavern.class);
@@ -301,7 +249,7 @@ public interface EngineMantle {
}
}
default long getUnloadRegionCount() {
default int getUnloadRegionCount() {
return getMantle().getUnloadRegionCount();
}

View File

@@ -44,9 +44,7 @@ import lombok.Data;
import org.bukkit.block.data.BlockData;
import org.bukkit.util.Vector;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import static com.volmit.iris.engine.mantle.EngineMantle.AIR;
@@ -54,20 +52,21 @@ import static com.volmit.iris.engine.mantle.EngineMantle.AIR;
public class MantleWriter implements IObjectPlacer, AutoCloseable {
private final EngineMantle engineMantle;
private final Mantle mantle;
private final KMap<Long, MantleChunk> cachedChunks;
private final Map<Long, MantleChunk> cachedChunks;
private final int radius;
private final int x;
private final int z;
public MantleWriter(EngineMantle engineMantle, Mantle mantle, int x, int z, int radius) {
public MantleWriter(EngineMantle engineMantle, Mantle mantle, int x, int z, int radius, boolean multicore) {
this.engineMantle = engineMantle;
this.mantle = mantle;
this.cachedChunks = new KMap<>();
this.radius = radius;
this.radius = radius * 2;
int d = this.radius + 1;
this.cachedChunks = multicore ? new KMap<>(d * d, 0.75f, Math.max(32, Runtime.getRuntime().availableProcessors() * 4)) : new HashMap<>(d * d);
this.x = x;
this.z = z;
int r = radius / 4;
int r = radius / 2;
for (int i = -r; i <= r; i++) {
for (int j = -r; j <= r; j++) {
cachedChunks.put(Cache.key(i + x, j + z), mantle.getChunk(i + x, j + z).use());
@@ -182,8 +181,13 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
Iris.error("Mantle Writer Accessed chunk out of bounds" + cx + "," + cz);
return null;
}
MantleChunk chunk = cachedChunks.computeIfAbsent(Cache.key(cx, cz), k -> mantle.getChunk(cx, cz).use());
if (chunk == null) Iris.error("Mantle Writer Accessed " + cx + "," + cz + " and came up null (and yet within bounds!)");
final Long key = Cache.key(cx, cz);
MantleChunk chunk = cachedChunks.get(key);
if (chunk == null) {
chunk = mantle.getChunk(cx, cz).use();
var old = cachedChunks.put(key, chunk);
if (old != null) old.release();
}
return chunk;
}

View File

@@ -35,7 +35,6 @@ import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer;
import com.volmit.iris.util.noise.CNG;
import lombok.Getter;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -45,7 +44,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
private final CNG cng;
public MantleJigsawComponent(EngineMantle engineMantle) {
super(engineMantle, ReservedFlag.JIGSAW, 2);
super(engineMantle, ReservedFlag.JIGSAW, 1);
cng = NoiseStyle.STATIC.create(new RNG(jigsaw()));
}

View File

@@ -119,7 +119,7 @@ public class IrisDepositModifier extends EngineAssignedModifier<BlockData> {
if (y > k.getMaxHeight() || y < k.getMinHeight() || y > height - 2)
continue;
for (BlockVector j : clump.getBlocks().keySet()) {
for (BlockVector j : clump.getBlocks().keys()) {
int nx = j.getBlockX() + x;
int ny = j.getBlockY() + y;
int nz = j.getBlockZ() + z;

View File

@@ -20,8 +20,8 @@ package com.volmit.iris.engine.object;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.framework.Engine;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.Nullable;
public interface IObjectPlacer {
int getHighest(int x, int z, IrisData data);
@@ -46,5 +46,9 @@ public interface IObjectPlacer {
void setTile(int xx, int yy, int zz, TileData tile);
<T> void setData(int xx, int yy, int zz, T data);
<T> @Nullable T getData(int xx, int yy, int zz, Class<T> t);
Engine getEngine();
}

View File

@@ -122,6 +122,10 @@ public class IrisCompat {
private static KList<IrisCompatabilityBlockFilter> getDefaultBlockCompatabilityFilters() {
KList<IrisCompatabilityBlockFilter> filters = new KList<>();
filters.add(new IrisCompatabilityBlockFilter("CHAIN", "IRON_CHAIN"));
filters.add(new IrisCompatabilityBlockFilter("GRASS", "SHORT_GRASS"));
filters.add(new IrisCompatabilityBlockFilter("SHORT_GRASS", "GRASS"));
// Below 1.16
filters.add(new IrisCompatabilityBlockFilter("WEEPING_VINES", "NETHER_FENCE"));
filters.add(new IrisCompatabilityBlockFilter("WEEPING_VINES_PLANT", "NETHER_FENCE"));
@@ -160,7 +164,7 @@ public class IrisCompat {
filters.add(new IrisCompatabilityBlockFilter("CRACKED_NETHER_BRICKS", "NETHER_BRICKS"));
filters.add(new IrisCompatabilityBlockFilter("CHISELED_NETHER_BRICKS", "NETHER_BRICKS"));
filters.add(new IrisCompatabilityBlockFilter("NETHER_FENCE", "LEGACY_NETHER_FENCE"));
filters.add(new IrisCompatabilityBlockFilter("CHAIN", "IRON_BARS"));
filters.add(new IrisCompatabilityBlockFilter("IRON_CHAIN", "IRON_BARS"));
filters.add(new IrisCompatabilityBlockFilter("NETHERITE_BLOCK", "QUARTZ_BLOCK"));
filters.add(new IrisCompatabilityBlockFilter("BLACKSTONE", "COBBLESTONE"));
filters.add(new IrisCompatabilityBlockFilter("BASALT", "STONE"));
@@ -254,7 +258,6 @@ public class IrisCompat {
filters.add(new IrisCompatabilityBlockFilter("BAMBOO", "BIRCH_FENCE"));
filters.add(new IrisCompatabilityBlockFilter("BAMBOO_SAPLING", "BIRCH_SAPLING"));
filters.add(new IrisCompatabilityBlockFilter("POTTED_BAMBOO", "POTTED_BIRCH_SAPLING"));
filters.add(new IrisCompatabilityBlockFilter("GRASS", "SHORT_GRASS"));
return filters;
}

View File

@@ -249,14 +249,18 @@ public class IrisDimension extends IrisRegistrant {
@Desc("A list of globally applied pre-processors")
@ArrayType(type = IrisPreProcessors.class)
private KList<IrisPreProcessors> globalPreProcessors = new KList<>();
@Desc("A list of scripts executed on engine setup")
@Desc("A list of scripts executed on engine setup\nFile extension: .engine.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> engineScripts = new KList<>();
@Desc("A list of scripts executed on data setup")
@Desc("A list of scripts executed on data setup\nFile extension: .data.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> dataScripts = new KList<>();
@Desc("A list of scripts executed on chunk update\nFile extension: .update.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> chunkUpdateScripts = new KList<>();
@Desc("Use legacy rarity instead of modern one\nWARNING: Changing this may break expressions and image maps")
private boolean legacyRarity = true;
@@ -355,7 +359,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;

View File

@@ -39,7 +39,7 @@ public class IrisDimensionMode {
private IrisDimensionModeType type = IrisDimensionModeType.OVERWORLD;
@RegistryListResource(IrisScript.class)
@Desc("The script to create the dimension mode instead of using provided types")
@Desc("The script to create the dimension mode instead of using provided types\nFile extension: .engine.kts")
private String script;
public EngineMode create(Engine engine) {

View File

@@ -166,12 +166,12 @@ public class IrisEntity extends IrisRegistrant {
@Desc("Set to true if you want to apply all of the settings here to the mob, even though an external plugin has already done so. Scripts are always applied.")
private boolean applySettingsToCustomMobAnyways = false;
@Desc("Set the entity type to UNKNOWN, then define a script here which ends with the entity variable (the result). You can use Iris.getLocation() to find the target location. You can spawn any entity this way.")
@Desc("Set the entity type to UNKNOWN, then define a script here which ends with the entity variable (the result). You can use location to find the target location. You can spawn any entity this way.\nFile extension: .spawn.kts")
@RegistryListResource(IrisScript.class)
private String spawnerScript = "";
@ArrayType(min = 1, type = String.class)
@Desc("Set the entity type to UNKNOWN, then define a script here. You can use Iris.getLocation() to find the target location. You can spawn any entity this way.")
@Desc("Executed post spawn you can modify the entity however you want with it\nFile extension: .postspawn.kts")
@RegistryListResource(IrisScript.class)
private KList<String> postSpawnScripts = new KList<>();

View File

@@ -58,7 +58,7 @@ public class IrisGeneratorStyle {
private String expression = null;
@Desc("Use an Image map instead of a generated value")
private IrisImageMap imageMap = null;
@Desc("Instead of using the style property, use a custom noise generator to represent this style.")
@Desc("Instead of using the style property, use a custom noise generator to represent this style.\nFile extension: .noise.kts")
@RegistryListResource(IrisScript.class)
private String script = null;
@MinNumber(0.00001)

View File

@@ -30,18 +30,15 @@ import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.data.VectorMap;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.interpolation.IrisInterpolation;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.math.AxisAlignedBB;
import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.math.*;
import com.volmit.iris.util.matter.MatterMarker;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.IrisLock;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.scheduling.jobs.Job;
import com.volmit.iris.util.stream.ProceduralStream;
@@ -65,7 +62,10 @@ import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.BiConsumer;
import java.util.stream.StreamSupport;
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@@ -75,17 +75,17 @@ public class IrisObject extends IrisRegistrant {
protected static final BlockData VAIR = B.get("VOID_AIR");
protected static final BlockData VAIR_DEBUG = B.get("COBWEB");
protected static final BlockData[] SNOW_LAYERS = new BlockData[]{B.get("minecraft:snow[layers=1]"), B.get("minecraft:snow[layers=2]"), B.get("minecraft:snow[layers=3]"), B.get("minecraft:snow[layers=4]"), B.get("minecraft:snow[layers=5]"), B.get("minecraft:snow[layers=6]"), B.get("minecraft:snow[layers=7]"), B.get("minecraft:snow[layers=8]")};
protected transient final IrisLock readLock = new IrisLock("read-conclock");
protected transient final Lock readLock;
protected transient final Lock writeLock;
@Getter
@Setter
protected transient volatile boolean smartBored = false;
@Getter
@Setter
protected transient IrisLock lock = new IrisLock("Preloadcache");
@Setter
protected transient AtomicCache<AxisAlignedBB> aabb = new AtomicCache<>();
private KMap<BlockVector, BlockData> blocks;
private KMap<BlockVector, TileData> states;
@Getter
private VectorMap<BlockData> blocks;
@Getter
private VectorMap<TileData> states;
@Getter
@Setter
private int w;
@@ -97,15 +97,18 @@ public class IrisObject extends IrisRegistrant {
private int h;
@Getter
@Setter
private transient BlockVector center;
private transient Vector3i center;
public IrisObject(int w, int h, int d) {
blocks = new KMap<>();
states = new KMap<>();
blocks = new VectorMap<>();
states = new VectorMap<>();
this.w = w;
this.h = h;
this.d = d;
center = new BlockVector(w / 2, h / 2, d / 2);
center = new Vector3i(w / 2, h / 2, d / 2);
var lock = new ReentrantReadWriteLock();
readLock = lock.readLock();
writeLock = lock.writeLock();
}
public IrisObject() {
@@ -161,10 +164,10 @@ public class IrisObject extends IrisRegistrant {
PrecisionStopwatch p = PrecisionStopwatch.start();
BlockData vair = debug ? VAIR_DEBUG : VAIR;
lock.lock();
writeLock.lock();
AtomicInteger applied = new AtomicInteger();
if (getBlocks().isEmpty()) {
lock.unlock();
if (blocks.isEmpty()) {
writeLock.unlock();
Iris.warn("Cannot Smart Bore " + getLoadKey() + " because it has 0 blocks in it.");
smartBored = true;
return;
@@ -173,7 +176,7 @@ public class IrisObject extends IrisRegistrant {
BlockVector max = new BlockVector(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE);
BlockVector min = new BlockVector(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
for (BlockVector i : getBlocks().keySet()) {
for (BlockVector i : blocks.keys()) {
max.setX(Math.max(i.getX(), max.getX()));
min.setX(Math.min(i.getX(), min.getX()));
max.setY(Math.max(i.getY(), max.getY()));
@@ -193,7 +196,7 @@ public class IrisObject extends IrisRegistrant {
int end = Integer.MIN_VALUE;
for (int ray = min.getBlockX(); ray <= max.getBlockX(); ray++) {
if (getBlocks().containsKey(new BlockVector(ray, finalRayY, rayZ))) {
if (blocks.containsKey(new Vector3i(ray, finalRayY, rayZ))) {
start = Math.min(ray, start);
end = Math.max(ray, end);
}
@@ -201,10 +204,10 @@ public class IrisObject extends IrisRegistrant {
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
for (int i = start; i <= end; i++) {
BlockVector v = new BlockVector(i, finalRayY, rayZ);
Vector3i v = new Vector3i(i, finalRayY, rayZ);
if (!B.isAir(getBlocks().get(v))) {
getBlocks().computeIfAbsent(v, (vv) -> vair);
if (!vair.equals(blocks.get(v))) {
blocks.computeIfAbsent(v, (vv) -> vair);
applied.getAndIncrement();
}
}
@@ -222,7 +225,7 @@ public class IrisObject extends IrisRegistrant {
int end = Integer.MIN_VALUE;
for (int ray = min.getBlockY(); ray <= max.getBlockY(); ray++) {
if (getBlocks().containsKey(new BlockVector(finalRayX, ray, rayZ))) {
if (blocks.containsKey(new Vector3i(finalRayX, ray, rayZ))) {
start = Math.min(ray, start);
end = Math.max(ray, end);
}
@@ -230,10 +233,10 @@ public class IrisObject extends IrisRegistrant {
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
for (int i = start; i <= end; i++) {
BlockVector v = new BlockVector(finalRayX, i, rayZ);
Vector3i v = new Vector3i(finalRayX, i, rayZ);
if (!B.isAir(getBlocks().get(v))) {
getBlocks().computeIfAbsent(v, (vv) -> vair);
if (!vair.equals(blocks.get(v))) {
blocks.computeIfAbsent(v, (vv) -> vair);
applied.getAndIncrement();
}
}
@@ -251,7 +254,7 @@ public class IrisObject extends IrisRegistrant {
int end = Integer.MIN_VALUE;
for (int ray = min.getBlockZ(); ray <= max.getBlockZ(); ray++) {
if (getBlocks().containsKey(new BlockVector(finalRayX, rayY, ray))) {
if (blocks.containsKey(new Vector3i(finalRayX, rayY, ray))) {
start = Math.min(ray, start);
end = Math.max(ray, end);
}
@@ -259,10 +262,10 @@ public class IrisObject extends IrisRegistrant {
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
for (int i = start; i <= end; i++) {
BlockVector v = new BlockVector(finalRayX, rayY, i);
Vector3i v = new Vector3i(finalRayX, rayY, i);
if (!B.isAir(getBlocks().get(v))) {
getBlocks().computeIfAbsent(v, (vv) -> vair);
if (!vair.equals(blocks.get(v))) {
blocks.computeIfAbsent(v, (vv) -> vair);
applied.getAndIncrement();
}
}
@@ -273,7 +276,7 @@ public class IrisObject extends IrisRegistrant {
burst.complete();
smartBored = true;
lock.unlock();
writeLock.unlock();
Iris.debug("Smart Bore: " + getLoadKey() + " in " + Form.duration(p.getMilliseconds(), 2) + " (" + Form.f(applied.get()) + ")");
}
@@ -284,13 +287,8 @@ public class IrisObject extends IrisRegistrant {
o.setLoadFile(getLoadFile());
o.setCenter(getCenter().clone());
for (BlockVector i : getBlocks().keySet()) {
o.getBlocks().put(i.clone(), Objects.requireNonNull(getBlocks().get(i)).clone());
}
for (BlockVector i : getStates().keySet()) {
o.getStates().put(i.clone(), Objects.requireNonNull(getStates().get(i)).clone());
}
blocks.forEach((i, v) -> o.blocks.put(i.clone(), v.clone()));
states.forEach((i, v) -> o.states.put(i.clone(), v.clone()));
return o;
}
@@ -300,18 +298,18 @@ public class IrisObject extends IrisRegistrant {
this.w = din.readInt();
this.h = din.readInt();
this.d = din.readInt();
center = new BlockVector(w / 2, h / 2, d / 2);
center = new Vector3i(w / 2, h / 2, d / 2);
int s = din.readInt();
for (int i = 0; i < s; i++) {
getBlocks().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), B.get(din.readUTF()));
blocks.put(new Vector3i(din.readShort(), din.readShort(), din.readShort()), B.get(din.readUTF()));
}
try {
int size = din.readInt();
for (int i = 0; i < size; i++) {
getStates().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), TileData.read(din));
states.put(new Vector3i(din.readShort(), din.readShort(), din.readShort()), TileData.read(din));
}
} catch (Throwable e) {
Iris.reportError(e);
@@ -327,7 +325,7 @@ public class IrisObject extends IrisRegistrant {
if (!din.readUTF().equals("Iris V2 IOB;")) {
return;
}
center = new BlockVector(w / 2, h / 2, d / 2);
center = new Vector3i(w / 2, h / 2, d / 2);
int s = din.readShort();
int i;
KList<String> palette = new KList<>();
@@ -339,13 +337,13 @@ public class IrisObject extends IrisRegistrant {
s = din.readInt();
for (i = 0; i < s; i++) {
getBlocks().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), B.get(palette.get(din.readShort())));
blocks.put(new Vector3i(din.readShort(), din.readShort(), din.readShort()), B.get(palette.get(din.readShort())));
}
s = din.readInt();
for (i = 0; i < s; i++) {
getStates().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), TileData.read(din));
states.put(new Vector3i(din.readShort(), din.readShort(), din.readShort()), TileData.read(din));
}
}
@@ -357,7 +355,7 @@ public class IrisObject extends IrisRegistrant {
dos.writeUTF("Iris V2 IOB;");
KList<String> palette = new KList<>();
for (BlockData i : getBlocks().values()) {
for (BlockData i : blocks.values()) {
palette.addIfMissing(i.getAsString());
}
@@ -367,21 +365,23 @@ public class IrisObject extends IrisRegistrant {
dos.writeUTF(i);
}
dos.writeInt(getBlocks().size());
dos.writeInt(blocks.size());
for (BlockVector i : getBlocks().keySet()) {
for (var entry : blocks) {
var i = entry.getKey();
dos.writeShort(i.getBlockX());
dos.writeShort(i.getBlockY());
dos.writeShort(i.getBlockZ());
dos.writeShort(palette.indexOf(getBlocks().get(i).getAsString()));
dos.writeShort(palette.indexOf(entry.getValue().getAsString()));
}
dos.writeInt(getStates().size());
for (BlockVector i : getStates().keySet()) {
dos.writeInt(states.size());
for (var entry : states) {
var i = entry.getKey();
dos.writeShort(i.getBlockX());
dos.writeShort(i.getBlockY());
dos.writeShort(i.getBlockZ());
getStates().get(i).toBinary(dos);
entry.getValue().toBinary(dos);
}
}
@@ -389,7 +389,7 @@ public class IrisObject extends IrisRegistrant {
AtomicReference<IOException> ref = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(1);
new Job() {
private int total = getBlocks().size() * 3 + getStates().size();
private int total = blocks.size() * 3 + states.size();
private int c = 0;
@Override
@@ -408,11 +408,11 @@ public class IrisObject extends IrisRegistrant {
KList<String> palette = new KList<>();
for (BlockData i : getBlocks().values()) {
for (BlockData i : blocks.values()) {
palette.addIfMissing(i.getAsString());
++c;
}
total -= getBlocks().size() - palette.size();
total -= blocks.size() - palette.size();
dos.writeShort(palette.size());
@@ -421,22 +421,24 @@ public class IrisObject extends IrisRegistrant {
++c;
}
dos.writeInt(getBlocks().size());
dos.writeInt(blocks.size());
for (BlockVector i : getBlocks().keySet()) {
for (var entry : blocks) {
var i = entry.getKey();
dos.writeShort(i.getBlockX());
dos.writeShort(i.getBlockY());
dos.writeShort(i.getBlockZ());
dos.writeShort(palette.indexOf(getBlocks().get(i).getAsString()));
dos.writeShort(palette.indexOf(entry.getValue().getAsString()));
++c;
}
dos.writeInt(getStates().size());
for (BlockVector i : getStates().keySet()) {
dos.writeInt(states.size());
for (var entry : states) {
var i = entry.getKey();
dos.writeShort(i.getBlockX());
dos.writeShort(i.getBlockY());
dos.writeShort(i.getBlockZ());
getStates().get(i).toBinary(dos);
entry.getValue().toBinary(dos);
++c;
}
} catch (IOException e) {
@@ -505,7 +507,7 @@ public class IrisObject extends IrisRegistrant {
BlockVector min = new BlockVector();
BlockVector max = new BlockVector();
for (BlockVector i : getBlocks().keySet()) {
for (BlockVector i : blocks.keys()) {
min.setX(Math.min(min.getX(), i.getX()));
min.setY(Math.min(min.getY(), i.getY()));
min.setZ(Math.min(min.getZ(), i.getZ()));
@@ -517,62 +519,52 @@ public class IrisObject extends IrisRegistrant {
w = max.getBlockX() - min.getBlockX() + 1;
h = max.getBlockY() - min.getBlockY() + 1;
d = max.getBlockZ() - min.getBlockZ() + 1;
center = new BlockVector(w / 2, h / 2, d / 2);
center = new Vector3i(w / 2, h / 2, d / 2);
}
public void clean() {
KMap<BlockVector, BlockData> d = new KMap<>();
VectorMap<BlockData> d = new VectorMap<>();
d.putAll(blocks);
for (BlockVector i : getBlocks().keySet()) {
d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i)));
}
KMap<BlockVector, TileData> dx = new KMap<>();
for (BlockVector i : getBlocks().keySet()) {
d.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getBlocks().get(i)));
}
for (BlockVector i : getStates().keySet()) {
dx.put(new BlockVector(i.getBlockX(), i.getBlockY(), i.getBlockZ()), Objects.requireNonNull(getStates().get(i)));
}
VectorMap<TileData> dx = new VectorMap<>();
dx.putAll(states);
blocks = d;
states = dx;
}
public BlockVector getSigned(int x, int y, int z) {
public Vector3i getSigned(int x, int y, int z) {
if (x >= w || y >= h || z >= d) {
throw new RuntimeException(x + " " + y + " " + z + " exceeds limit of " + w + " " + h + " " + d);
}
return new BlockVector(x, y, z).subtract(center).toBlockVector();
return (Vector3i) new Vector3i(x, y, z).subtract(center);
}
public void setUnsigned(int x, int y, int z, BlockData block) {
BlockVector v = getSigned(x, y, z);
Vector3i v = getSigned(x, y, z);
if (block == null) {
getBlocks().remove(v);
getStates().remove(v);
blocks.remove(v);
states.remove(v);
} else {
getBlocks().put(v, block);
blocks.put(v, block);
}
}
public void setUnsigned(int x, int y, int z, Block block, boolean legacy) {
BlockVector v = getSigned(x, y, z);
Vector3i v = getSigned(x, y, z);
if (block == null) {
getBlocks().remove(v);
getStates().remove(v);
blocks.remove(v);
states.remove(v);
} else {
BlockData data = block.getBlockData();
getBlocks().put(v, data);
blocks.put(v, data);
TileData state = TileData.getTileState(block, legacy);
if (state != null) {
Iris.debug("Saved State " + v);
getStates().put(v, state);
states.put(v, state);
}
}
}
@@ -869,6 +861,9 @@ public class IrisObject extends IrisRegistrant {
try {
if (config.getMarkers().isNotEmpty() && placer.getEngine() != null) {
markers = new KMap<>();
var list = StreamSupport.stream(blocks.keys().spliterator(), false)
.collect(KList.collector());
for (IrisObjectMarker j : config.getMarkers()) {
IrisMarker marker = getLoader().getMarkerLoader().load(j.getMarker());
@@ -877,13 +872,12 @@ public class IrisObject extends IrisRegistrant {
}
int max = j.getMaximumMarkers();
for (BlockVector i : getBlocks().k().shuffle()) {
for (BlockVector i : list.shuffle()) {
if (max <= 0) {
break;
}
BlockData data = getBlocks().get(i);
BlockData data = blocks.get(i);
for (BlockData k : j.getMark(rdata)) {
if (max <= 0) {
@@ -891,8 +885,8 @@ public class IrisObject extends IrisRegistrant {
}
if (j.isExact() ? k.matches(data) : k.getMaterial().equals(data.getMaterial())) {
boolean a = !blocks.containsKey(new BlockVector(i.clone().add(new BlockVector(0, 1, 0))));
boolean fff = !blocks.containsKey(new BlockVector(i.clone().add(new BlockVector(0, 2, 0))));
boolean a = !blocks.containsKey((BlockVector) i.clone().add(new BlockVector(0, 1, 0)));
boolean fff = !blocks.containsKey((BlockVector) i.clone().add(new BlockVector(0, 2, 0)));
if (!marker.isEmptyAbove() || (a && fff)) {
markers.put(i, j.getMarker());
@@ -904,13 +898,14 @@ public class IrisObject extends IrisRegistrant {
}
}
for (BlockVector g : getBlocks().keySet()) {
for (var entry : blocks) {
var g = entry.getKey();
BlockData d;
TileData tile = null;
try {
d = getBlocks().get(g);
tile = getStates().get(g);
d = entry.getValue();
tile = states.get(g);
} catch (Throwable e) {
Iris.reportError(e);
Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (cme)");
@@ -1028,12 +1023,12 @@ public class IrisObject extends IrisRegistrant {
if (stilting) {
readLock.lock();
IrisStiltSettings settings = config.getStiltSettings();
for (BlockVector g : getBlocks().keySet()) {
for (BlockVector g : blocks.keys()) {
BlockData d;
if (settings == null || settings.getPalette() == null) {
try {
d = getBlocks().get(g);
d = blocks.get(g);
} catch (Throwable e) {
Iris.reportError(e);
Iris.warn("Failed to read block node " + g.getBlockX() + "," + g.getBlockY() + "," + g.getBlockZ() + " in object " + getLoadKey() + " (stilt cme)");
@@ -1140,59 +1135,60 @@ public class IrisObject extends IrisRegistrant {
}
public void rotate(IrisObjectRotation r, int spinx, int spiny, int spinz) {
KMap<BlockVector, BlockData> d = new KMap<>();
writeLock.lock();
VectorMap<BlockData> d = new VectorMap<>();
for (BlockVector i : getBlocks().keySet()) {
d.put(r.rotate(i.clone(), spinx, spiny, spinz), r.rotate(getBlocks().get(i).clone(),
spinx, spiny, spinz));
for (var entry : blocks) {
d.put(r.rotate(entry.getKey(), spinx, spiny, spinz), r.rotate(entry.getValue(), spinx, spiny, spinz));
}
KMap<BlockVector, TileData> dx = new KMap<>();
VectorMap<TileData> dx = new VectorMap<>();
for (BlockVector i : getStates().keySet()) {
dx.put(r.rotate(i.clone(), spinx, spiny, spinz), getStates().get(i));
for (var entry : states) {
dx.put(r.rotate(entry.getKey(), spinx, spiny, spinz), entry.getValue());
}
blocks = d;
states = dx;
writeLock.unlock();
shrinkwrap();
}
public void place(Location at) {
for (BlockVector i : getBlocks().keySet()) {
readLock.lock();
for (var entry : blocks) {
var i = entry.getKey();
Block b = at.clone().add(0, getCenter().getY(), 0).add(i).getBlock();
b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false);
b.setBlockData(Objects.requireNonNull(entry.getValue()), false);
if (getStates().containsKey(i)) {
if (states.containsKey(i)) {
Iris.info(Objects.requireNonNull(states.get(i)).toString());
Objects.requireNonNull(getStates().get(i)).toBukkitTry(b);
Objects.requireNonNull(states.get(i)).toBukkitTry(b);
}
}
readLock.unlock();
}
public void placeCenterY(Location at) {
for (BlockVector i : getBlocks().keySet()) {
readLock.lock();
for (var entry : blocks) {
var i = entry.getKey();
Block b = at.clone().add(getCenter().getX(), getCenter().getY(), getCenter().getZ()).add(i).getBlock();
b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false);
b.setBlockData(Objects.requireNonNull(entry.getValue()), false);
if (getStates().containsKey(i)) {
Objects.requireNonNull(getStates().get(i)).toBukkitTry(b);
if (states.containsKey(i)) {
Objects.requireNonNull(states.get(i)).toBukkitTry(b);
}
}
}
public synchronized KMap<BlockVector, BlockData> getBlocks() {
return blocks;
}
public synchronized KMap<BlockVector, TileData> getStates() {
return states;
readLock.unlock();
}
public void unplaceCenterY(Location at) {
for (BlockVector i : getBlocks().keySet()) {
readLock.lock();
for (BlockVector i : blocks.keys()) {
at.clone().add(getCenter().getX(), getCenter().getY(), getCenter().getZ()).add(i).getBlock().setBlockData(AIR, false);
}
readLock.unlock();
}
public IrisObject scaled(double scale, IrisObjectPlacementScaleInterpolator interpolation) {
@@ -1204,7 +1200,7 @@ public class IrisObject extends IrisRegistrant {
IrisPosition l1 = getAABB().max();
IrisPosition l2 = getAABB().min();
@SuppressWarnings({"unchecked", "rawtypes"}) HashMap<BlockVector, BlockData> placeBlock = new HashMap();
VectorMap<BlockData> placeBlock = new VectorMap<>();
Vector center = getCenter();
if (getH() == 2) {
@@ -1219,17 +1215,19 @@ public class IrisObject extends IrisRegistrant {
IrisObject oo = new IrisObject((int) Math.ceil((w * scale) + (scale * 2)), (int) Math.ceil((h * scale) + (scale * 2)), (int) Math.ceil((d * scale) + (scale * 2)));
for (Map.Entry<BlockVector, BlockData> entry : blocks.entrySet()) {
readLock.lock();
for (var entry : blocks) {
BlockData bd = entry.getValue();
placeBlock.put(entry.getKey().clone().add(HALF).subtract(center)
.multiply(scale).add(sm1).toBlockVector(), bd);
}
readLock.unlock();
for (Map.Entry<BlockVector, BlockData> entry : placeBlock.entrySet()) {
for (var entry : placeBlock) {
BlockVector v = entry.getKey();
if (scale > 1) {
for (BlockVector vec : blocksBetweenTwoPoints(v.clone().add(center), v.clone().add(center).add(sm1))) {
oo.getBlocks().put(vec, entry.getValue());
oo.blocks.put(vec, entry.getValue());
}
} else {
oo.setUnsigned(v.getBlockX(), v.getBlockY(), v.getBlockZ(), entry.getValue());
@@ -1248,8 +1246,9 @@ public class IrisObject extends IrisRegistrant {
}
public void trilinear(int rad) {
KMap<BlockVector, BlockData> v = getBlocks().copy();
KMap<BlockVector, BlockData> b = new KMap<>();
writeLock.lock();
VectorMap<BlockData> v = blocks;
VectorMap<BlockData> b = new VectorMap<>();
BlockVector min = getAABB().minbv();
BlockVector max = getAABB().maxbv();
@@ -1274,11 +1273,13 @@ public class IrisObject extends IrisRegistrant {
}
blocks = b;
writeLock.unlock();
}
public void tricubic(int rad) {
KMap<BlockVector, BlockData> v = getBlocks().copy();
KMap<BlockVector, BlockData> b = new KMap<>();
writeLock.lock();
VectorMap<BlockData> v = blocks;
VectorMap<BlockData> b = new VectorMap<>();
BlockVector min = getAABB().minbv();
BlockVector max = getAABB().maxbv();
@@ -1303,6 +1304,7 @@ public class IrisObject extends IrisRegistrant {
}
blocks = b;
writeLock.unlock();
}
public void trihermite(int rad) {
@@ -1310,8 +1312,9 @@ public class IrisObject extends IrisRegistrant {
}
public void trihermite(int rad, double tension, double bias) {
KMap<BlockVector, BlockData> v = getBlocks().copy();
KMap<BlockVector, BlockData> b = new KMap<>();
writeLock.lock();
VectorMap<BlockData> v = blocks;
VectorMap<BlockData> b = new VectorMap<>();
BlockVector min = getAABB().minbv();
BlockVector max = getAABB().maxbv();
@@ -1336,11 +1339,13 @@ public class IrisObject extends IrisRegistrant {
}
blocks = b;
writeLock.unlock();
}
private BlockData nearestBlockData(int x, int y, int z) {
BlockVector vv = new BlockVector(x, y, z);
BlockData r = getBlocks().get(vv);
readLock.lock();
BlockData r = blocks.get(vv);
if (r != null && !r.getMaterial().isAir()) {
return r;
@@ -1348,7 +1353,7 @@ public class IrisObject extends IrisRegistrant {
double d = Double.MAX_VALUE;
for (Map.Entry<BlockVector, BlockData> entry : blocks.entrySet()) {
for (var entry : blocks) {
BlockData dat = entry.getValue();
if (dat.getMaterial().isAir()) {
@@ -1362,6 +1367,7 @@ public class IrisObject extends IrisRegistrant {
r = dat;
}
}
readLock.unlock();
return r;
}

View File

@@ -18,7 +18,7 @@ public class IrisPreProcessors {
private String type = "dimension";
@Required
@Desc("The preprocessor scripts")
@Desc("The preprocessor scripts\nFile extension: .proc.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> scripts = new KList<>();

View File

@@ -346,7 +346,7 @@ public class IrisRegion extends IrisRegistrant implements IRare {
continue;
}
IrisBiome biome = IrisData.loadAnyBiome(i);
IrisBiome biome = IrisData.loadAnyBiome(i, getLoader());
names.remove(i);
if (biome == null) {

View File

@@ -166,11 +166,13 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
return targetCache.aquire(() -> {
IrisData data = IrisData.get(dataLocation);
data.dump();
data.clearLists();
IrisDimension dimension = data.getDimensionLoader().load(dimensionKey);
if (dimension == null) {
Iris.error("Oh No! There's no pack in " + data.getDataFolder().getPath() + " or... there's no dimension for the key " + dimensionKey);
IrisDimension test = IrisData.loadAnyDimension(dimensionKey);
IrisDimension test = IrisData.loadAnyDimension(dimensionKey, null);
if (test != null) {
Iris.warn("Looks like " + dimensionKey + " exists in " + test.getLoadFile().getPath() + " ");
@@ -205,7 +207,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
Chunk c = PaperLib.getChunkAtAsync(world, x, z)
.thenApply(d -> {
d.addPluginChunkTicket(Iris.instance);
Iris.tickets.addTicket(d);
for (Entity ee : d.getEntities()) {
if (ee instanceof Player) {
@@ -215,7 +217,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
ee.remove();
}
engine.getWorldManager().onChunkLoad(d, false);
return d;
}).get();
@@ -241,8 +242,8 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenRunAsync(() -> {
c.removePluginChunkTicket(Iris.instance);
c.unload();
Iris.tickets.removeTicket(c);
engine.getWorldManager().onChunkLoad(c, true);
}, syncExecutor)
.get();
Iris.debug("Regenerated " + x + " " + z);
@@ -354,16 +355,16 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
@Override
public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) {
try {
getEngine(world);
Engine engine = getEngine(world);
computeStudioGenerator();
TerrainChunk tc = TerrainChunk.create(d, new IrisBiomeStorage());
this.world.bind(world);
if (studioGenerator != null) {
studioGenerator.generateChunk(getEngine(), tc, x, z);
studioGenerator.generateChunk(engine, tc, x, z);
} else {
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight());
getEngine().generate(x << 4, z << 4, blocks, biomes, IrisSettings.get().getGenerator().useMulticore);
engine.generate(x << 4, z << 4, blocks, biomes, IrisSettings.get().getGenerator().useMulticore);
blocks.apply();
biomes.apply();
}

View File

@@ -2,24 +2,55 @@ package com.volmit.iris.util.cache;
import com.volmit.iris.util.function.Function2;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
public class ChunkCache2D<T> {
private final AtomicReferenceArray<T> cache;
private static final boolean FAST = Boolean.getBoolean("iris.cache.fast");
private static final boolean DYNAMIC = Boolean.getBoolean("iris.cache.dynamic");
private static final VarHandle AA = MethodHandles.arrayElementVarHandle(Entry[].class);
private final Entry<T>[] cache;
@SuppressWarnings({"unchecked"})
public ChunkCache2D() {
this.cache = new AtomicReferenceArray<>(256);
this.cache = new Entry[256];
if (DYNAMIC) return;
for (int i = 0; i < cache.length; i++) {
cache[i] = FAST ? new FastEntry<>() : new Entry<>();
}
}
@SuppressWarnings({"unchecked"})
public T get(int x, int z, Function2<Integer, Integer, T> resolver) {
int key = ((z & 15) * 16) + (x & 15);
T t = cache.get(key);
if (t == null) {
t = resolver.apply(x, z);
cache.set(key, t);
var entry = cache[key];
if (entry == null) {
entry = FAST ? new FastEntry<>() : new Entry<>();
if (!AA.compareAndSet(cache, key, null, entry)) {
entry = (Entry<T>) AA.getVolatile(cache, key);
}
}
return entry.compute(x, z, resolver);
}
return t;
private static class Entry<T> {
protected volatile T t;
protected T compute(int x, int z, Function2<Integer, Integer, T> resolver) {
if (t != null) return t;
synchronized (this) {
if (t == null) t = resolver.apply(x, z);
return t;
}
}
}
private static class FastEntry<T> extends Entry<T> {
@Override
protected T compute(int x, int z, Function2<Integer, Integer, T> resolver) {
if (t != null) return t;
return t = resolver.apply(x, z);
}
}
}

View File

@@ -1,24 +1,32 @@
package com.volmit.iris.util.cache;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.util.data.KCache;
import com.volmit.iris.util.function.Function2;
public class WorldCache2D<T> {
private final KCache<Long, ChunkCache2D<T>> chunks;
private final ConcurrentLinkedHashMap<Long, ChunkCache2D<T>> chunks;
private final Function2<Integer, Integer, T> resolver;
public WorldCache2D(Function2<Integer, Integer, T> resolver) {
public WorldCache2D(Function2<Integer, Integer, T> resolver, int size) {
this.resolver = resolver;
chunks = new KCache<>((x) -> new ChunkCache2D<>(), 1024);
chunks = new ConcurrentLinkedHashMap.Builder<Long, ChunkCache2D<T>>()
.initialCapacity(size)
.maximumWeightedCapacity(size)
.concurrencyLevel(Math.max(32, Runtime.getRuntime().availableProcessors() * 4))
.build();
}
public T get(int x, int z) {
ChunkCache2D<T> chunk = chunks.get(Cache.key(x >> 4, z >> 4));
ChunkCache2D<T> chunk = chunks.computeIfAbsent(Cache.key(x >> 4, z >> 4), $ -> new ChunkCache2D<>());
return chunk.get(x, z, resolver);
}
public long getSize() {
return chunks.getSize() * 256L;
return chunks.size() * 256L;
}
public long getMaxSize() {
return chunks.capacity() * 256L;
}
}

View File

@@ -33,7 +33,15 @@ public class KMap<K, V> extends ConcurrentHashMap<K, V> {
private static final long serialVersionUID = 7288942695300448163L;
public KMap() {
super();
this(16);
}
public KMap(int initialCapacity) {
this(initialCapacity, 0.75f, 1);
}
public KMap(int initialCapacity, float loadFactor, int concurrencyLevel) {
super(initialCapacity, loadFactor, concurrencyLevel);
}
public KMap(Map<K, V> gMap) {

View File

@@ -1,51 +0,0 @@
package com.volmit.iris.util.context;
import com.volmit.iris.engine.IrisComplex;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import lombok.Data;
import org.bukkit.block.data.BlockData;
@Data
public class ChunkContext {
private final int x;
private final int z;
private ChunkedDataCache<Double> height;
private ChunkedDataCache<IrisBiome> biome;
private ChunkedDataCache<IrisBiome> cave;
private ChunkedDataCache<BlockData> rock;
private ChunkedDataCache<BlockData> fluid;
private ChunkedDataCache<IrisRegion> region;
@BlockCoordinates
public ChunkContext(int x, int z, IrisComplex c) {
this(x, z, c, true);
}
@BlockCoordinates
public ChunkContext(int x, int z, IrisComplex c, boolean cache) {
this.x = x;
this.z = z;
if (cache) {
BurstExecutor b = MultiBurst.burst.burst();
height = new ChunkedDataCache<>(b, c.getHeightStream(), x, z);
biome = new ChunkedDataCache<>(b, c.getTrueBiomeStream(), x, z);
cave = new ChunkedDataCache<>(b, c.getCaveBiomeStream(), x, z);
rock = new ChunkedDataCache<>(b, c.getRockStream(), x, z);
fluid = new ChunkedDataCache<>(b, c.getFluidStream(), x, z);
region = new ChunkedDataCache<>(b, c.getRegionStream(), x, z);
b.complete();
} else {
height = new ChunkedDataCache<>(null, c.getHeightStream(), x, z, false);
biome = new ChunkedDataCache<>(null, c.getTrueBiomeStream(), x, z, false);
cave = new ChunkedDataCache<>(null, c.getCaveBiomeStream(), x, z, false);
rock = new ChunkedDataCache<>(null, c.getRockStream(), x, z, false);
fluid = new ChunkedDataCache<>(null, c.getFluidStream(), x, z, false);
region = new ChunkedDataCache<>(null, c.getRegionStream(), x, z, false);
}
}
}

View File

@@ -1,60 +0,0 @@
package com.volmit.iris.util.context;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.stream.ProceduralStream;
import lombok.Data;
@Data
public class ChunkedDataCache<T> {
private final int x;
private final int z;
private final KSet<T> uniques;
private final Object[] data;
private final boolean cache;
private final ProceduralStream<T> stream;
@BlockCoordinates
public ChunkedDataCache(BurstExecutor burst, ProceduralStream<T> stream, int x, int z) {
this(burst, stream, x, z, true);
}
@BlockCoordinates
public ChunkedDataCache(BurstExecutor burst, ProceduralStream<T> stream, int x, int z, boolean cache) {
this.stream = stream;
this.cache = cache;
this.x = x;
this.z = z;
this.uniques = cache ? new KSet<>() : null;
if (cache) {
data = new Object[256];
int i, j;
for (i = 0; i < 16; i++) {
int finalI = i;
for (j = 0; j < 16; j++) {
int finalJ = j;
burst.queue(() -> {
T t = stream.get(x + finalI, z + finalJ);
data[(finalJ * 16) + finalI] = t;
uniques.add(t);
});
}
}
} else {
data = new Object[0];
}
}
@SuppressWarnings("unchecked")
@BlockCoordinates
public T get(int x, int z) {
if (!cache) {
return stream.get(this.x + x, this.z + z);
}
T t = (T) data[(z * 16) + x];
return t == null ? stream.get(this.x + x, this.z + z) : t;
}
}

View File

@@ -1,127 +1,77 @@
package com.volmit.iris.util.data;
import com.volmit.iris.core.link.Identifier;
import lombok.Data;
import com.volmit.iris.util.collection.KMap;
import lombok.NonNull;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.SoundGroup;
import org.bukkit.block.*;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.structure.Mirror;
import org.bukkit.block.structure.StructureRotation;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@Data
public class IrisCustomData implements BlockData {
private final @NonNull BlockData base;
private final @NotNull Identifier custom;
import java.lang.reflect.Proxy;
import java.util.*;
@NotNull
@Override
public Material getMaterial() {
return base.getMaterial();
public interface IrisCustomData extends BlockData {
@NonNull BlockData getBase();
@NonNull Identifier getCustom();
static IrisCustomData of(@NotNull BlockData base, @NotNull Identifier custom) {
var clazz = base.getClass();
var loader = clazz.getClassLoader();
return (IrisCustomData) Proxy.newProxyInstance(loader, Internal.getInterfaces(loader, clazz), (proxy, method, args) ->
switch (method.getName()) {
case "getBase" -> base;
case "getCustom" -> custom;
case "merge" -> of(base.merge((BlockData) args[0]), custom);
case "clone" -> of(base.clone(), custom);
case "hashCode" -> Objects.hash(base, custom);
case "matches" -> {
if (!(args[0] instanceof IrisCustomData store))
yield false;
yield base.matches(store.getBase()) && custom.equals(store.getCustom());
}
case "equals" -> {
if (!(args[0] instanceof IrisCustomData store))
yield false;
yield store.getBase().equals(base) && store.getCustom().equals(custom);
}
default -> method.invoke(base, args);
});
}
@NotNull
@Override
public String getAsString() {
return base.getAsString();
}
@ApiStatus.Internal
abstract class Internal {
private static final KMap<Class<?>, Class<?>[]> cache = new KMap<>();
@NotNull
@Override
public String getAsString(boolean b) {
return base.getAsString(b);
}
private static Class<?>[] getInterfaces(ClassLoader loader, Class<?> base) {
return cache.computeIfAbsent(base, k -> {
Queue<Class<?>> queue = new LinkedList<>();
Set<Class<?>> set = new HashSet<>();
@NotNull
@Override
public BlockData merge(@NotNull BlockData blockData) {
return new IrisCustomData(base.merge(blockData), custom);
}
queue.add(k);
while (!queue.isEmpty()) {
Class<?> i = queue.poll();
@Override
public boolean matches(@Nullable BlockData blockData) {
if (blockData instanceof IrisCustomData b)
return custom.equals(b.custom) && base.matches(b.base);
return base.matches(blockData);
}
if (!BlockData.class.isAssignableFrom(i))
continue;
@NotNull
@Override
public BlockData clone() {
return new IrisCustomData(base.clone(), custom);
}
for (Class<?> j : i.getInterfaces()) {
if (j.isSealed() || j.isHidden())
continue;
@NotNull
@Override
public SoundGroup getSoundGroup() {
return base.getSoundGroup();
}
try {
Class.forName(j.getName(), false, loader);
set.add(j);
} catch (ClassNotFoundException ignored) {}
}
@Override
public int getLightEmission() {
return base.getLightEmission();
}
var parent = i.getSuperclass();
if (parent != null)
queue.add(parent);
}
@Override
public boolean isOccluding() {
return base.isOccluding();
}
@Override
public boolean requiresCorrectToolForDrops() {
return base.requiresCorrectToolForDrops();
}
@Override
public boolean isPreferredTool(@NotNull ItemStack itemStack) {
return base.isPreferredTool(itemStack);
}
@NotNull
@Override
public PistonMoveReaction getPistonMoveReaction() {
return base.getPistonMoveReaction();
}
@Override
public boolean isSupported(@NotNull Block block) {
return base.isSupported(block);
}
@Override
public boolean isSupported(@NotNull Location location) {
return base.isSupported(location);
}
@Override
public boolean isFaceSturdy(@NotNull BlockFace blockFace, @NotNull BlockSupport blockSupport) {
return base.isFaceSturdy(blockFace, blockSupport);
}
@NotNull
@Override
public Material getPlacementMaterial() {
return base.getPlacementMaterial();
}
@Override
public void rotate(@NotNull StructureRotation structureRotation) {
base.rotate(structureRotation);
}
@Override
public void mirror(@NotNull Mirror mirror) {
base.mirror(mirror);
}
@NotNull
@Override
public BlockState createBlockState() {
return base.createBlockState();
set.add(IrisCustomData.class);
return set.toArray(Class<?>[]::new);
});
}
}
}

View File

@@ -0,0 +1,220 @@
package com.volmit.iris.util.data;
import com.volmit.iris.util.collection.KMap;
import lombok.NonNull;
import org.bukkit.util.BlockVector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Iterator;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
public class VectorMap<T> implements Iterable<Map.Entry<BlockVector, T>> {
private final Map<Key, Map<Key, T>> map = new KMap<>();
public int size() {
return map.values().stream().mapToInt(Map::size).sum();
}
public boolean isEmpty() {
return map.values().stream().allMatch(Map::isEmpty);
}
public boolean containsKey(@NonNull BlockVector vector) {
var chunk = map.get(chunk(vector));
return chunk != null && chunk.containsKey(relative(vector));
}
public boolean containsValue(@NonNull T value) {
return map.values().stream().anyMatch(m -> m.containsValue(value));
}
public @Nullable T get(@NonNull BlockVector vector) {
var chunk = map.get(chunk(vector));
return chunk == null ? null : chunk.get(relative(vector));
}
public @Nullable T put(@NonNull BlockVector vector, @NonNull T value) {
return map.computeIfAbsent(chunk(vector), k -> new KMap<>())
.put(relative(vector), value);
}
public @Nullable T computeIfAbsent(@NonNull BlockVector vector, @NonNull Function<@NonNull BlockVector, @NonNull T> mappingFunction) {
return map.computeIfAbsent(chunk(vector), k -> new KMap<>())
.computeIfAbsent(relative(vector), $ -> mappingFunction.apply(vector));
}
public @Nullable T remove(@NonNull BlockVector vector) {
var chunk = map.get(chunk(vector));
return chunk == null ? null : chunk.remove(relative(vector));
}
public void putAll(@NonNull VectorMap<T> map) {
map.forEach(this::put);
}
public void clear() {
map.clear();
}
public void forEach(@NonNull BiConsumer<@NonNull BlockVector, @NonNull T> consumer) {
map.forEach((chunk, values) -> {
int rX = chunk.x << 10;
int rY = chunk.y << 10;
int rZ = chunk.z << 10;
values.forEach((relative, value) -> consumer.accept(
relative.resolve(rX, rY, rZ),
value
));
});
}
private static Key chunk(BlockVector vector) {
return new Key(vector.getBlockX() >> 10, vector.getBlockY() >> 10, vector.getBlockZ() >> 10);
}
private static Key relative(BlockVector vector) {
return new Key(vector.getBlockX() & 0x3FF, vector.getBlockY() & 0x3FF, vector.getBlockZ() & 0x3FF);
}
@Override
public @NotNull EntryIterator iterator() {
return new EntryIterator();
}
public @NotNull KeyIterator keys() {
return new KeyIterator();
}
public @NotNull ValueIterator values() {
return new ValueIterator();
}
public class EntryIterator implements Iterator<Map.Entry<BlockVector, T>> {
private final Iterator<Map.Entry<Key, Map<Key, T>>> chunkIterator = map.entrySet().iterator();
private Iterator<Map.Entry<Key, T>> relativeIterator;
private int rX, rY, rZ;
@Override
public boolean hasNext() {
return relativeIterator != null && relativeIterator.hasNext() || chunkIterator.hasNext();
}
@Override
public Map.Entry<BlockVector, T> next() {
if (relativeIterator == null || !relativeIterator.hasNext()) {
if (!chunkIterator.hasNext()) throw new IllegalStateException("No more elements");
var chunk = chunkIterator.next();
rX = chunk.getKey().x << 10;
rY = chunk.getKey().y << 10;
rZ = chunk.getKey().z << 10;
relativeIterator = chunk.getValue().entrySet().iterator();
}
var entry = relativeIterator.next();
return Map.entry(entry.getKey().resolve(rX, rY, rZ), entry.getValue());
}
@Override
public void remove() {
if (relativeIterator == null) throw new IllegalStateException("No element to remove");
relativeIterator.remove();
}
}
public class KeyIterator implements Iterator<BlockVector>, Iterable<BlockVector> {
private final Iterator<Map.Entry<Key, Map<Key, T>>> chunkIterator = map.entrySet().iterator();
private Iterator<Key> relativeIterator;
private int rX, rY, rZ;
@Override
public boolean hasNext() {
return relativeIterator != null && relativeIterator.hasNext() || chunkIterator.hasNext();
}
@Override
public BlockVector next() {
if (relativeIterator == null || !relativeIterator.hasNext()) {
var chunk = chunkIterator.next();
rX = chunk.getKey().x << 10;
rY = chunk.getKey().y << 10;
rZ = chunk.getKey().z << 10;
relativeIterator = chunk.getValue().keySet().iterator();
}
return relativeIterator.next().resolve(rX, rY, rZ);
}
@Override
public void remove() {
if (relativeIterator == null) throw new IllegalStateException("No element to remove");
relativeIterator.remove();
}
@Override
public @NotNull Iterator<BlockVector> iterator() {
return this;
}
}
public class ValueIterator implements Iterator<T>, Iterable<T> {
private final Iterator<Map<Key, T>> chunkIterator = map.values().iterator();
private Iterator<T> relativeIterator;
@Override
public boolean hasNext() {
return relativeIterator != null && relativeIterator.hasNext() || chunkIterator.hasNext();
}
@Override
public T next() {
if (relativeIterator == null || !relativeIterator.hasNext()) {
relativeIterator = chunkIterator.next().values().iterator();
}
return relativeIterator.next();
}
@Override
public void remove() {
if (relativeIterator == null) throw new IllegalStateException("No element to remove");
relativeIterator.remove();
}
@Override
public @NotNull Iterator<T> iterator() {
return this;
}
}
private static final class Key {
private final int x;
private final int y;
private final int z;
private final int hashCode;
private Key(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
this.hashCode = (x << 20) | (y << 10) | z;
}
private BlockVector resolve(int rX, int rY, int rZ) {
return new BlockVector(rX + x, rY + y, rZ + z);
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Key key)) return false;
return x == key.x && y == key.y && z == key.z;
}
}
}

View File

@@ -18,29 +18,20 @@
package com.volmit.iris.util.decree;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.ChronoLatch;
public class DecreeContext {
private static final ChronoLatch cl = new ChronoLatch(60000);
private static final KMap<Thread, VolmitSender> context = new KMap<>();
private static final ThreadLocal<VolmitSender> context = new ThreadLocal<>();
public static VolmitSender get() {
return context.get(Thread.currentThread());
return context.get();
}
public static void touch(VolmitSender c) {
synchronized (context) {
context.put(Thread.currentThread(), c);
context.set(c);
}
if (cl.flip()) {
for (Thread i : context.k()) {
if (!i.isAlive()) {
context.remove(i);
}
}
}
}
public static void remove() {
context.remove();
}
}

View File

@@ -18,6 +18,7 @@
package com.volmit.iris.util.decree;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
@@ -34,6 +35,14 @@ public interface DecreeExecutor {
return sender().player();
}
default IrisData data() {
var access = access();
if (access != null) {
return access.getData();
}
return null;
}
default Engine engine() {
if (sender().isPlayer() && IrisToolbelt.access(sender().player().getWorld()) != null) {
PlatformChunkGenerator gen = IrisToolbelt.access(sender().player().getWorld());

View File

@@ -23,7 +23,7 @@ import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import java.util.concurrent.atomic.AtomicReference;
public interface DecreeParameterHandler<T> {
public interface DecreeParameterHandler<T> extends DecreeExecutor {
/**
* Should return the possible values for this type
*

View File

@@ -133,23 +133,32 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter {
default boolean call(VolmitSender sender, String[] args) {
DecreeContext.touch(sender);
return getRoot().invoke(sender, enhanceArgs(args));
try {
return getRoot().invoke(sender, enhanceArgs(args));
} finally {
DecreeContext.remove();
}
}
@Nullable
@Override
default List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
KList<String> enhanced = new KList<>(args);
KList<String> v = getRoot().tabComplete(enhanced, enhanced.toString(" "));
v.removeDuplicates();
DecreeContext.touch(new VolmitSender(sender));
try {
KList<String> enhanced = new KList<>(args);
KList<String> v = getRoot().tabComplete(enhanced, enhanced.toString(" "));
v.removeDuplicates();
if (sender instanceof Player) {
if (IrisSettings.get().getGeneral().isCommandSounds()) {
((Player) sender).playSound(((Player) sender).getLocation(), Sound.BLOCK_AMETHYST_BLOCK_CHIME, 0.25f, RNG.r.f(0.125f, 1.95f));
if (sender instanceof Player) {
if (IrisSettings.get().getGeneral().isCommandSounds()) {
((Player) sender).playSound(((Player) sender).getLocation(), Sound.BLOCK_AMETHYST_BLOCK_CHIME, 0.25f, RNG.r.f(0.125f, 1.95f));
}
}
}
return v;
return v;
} finally {
DecreeContext.remove();
}
}
@Override

View File

@@ -18,63 +18,12 @@
package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import java.io.File;
import java.util.stream.Collectors;
public class BiomeHandler implements DecreeParameterHandler<IrisBiome> {
@Override
public KList<IrisBiome> getPossibilities() {
KMap<String, IrisBiome> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisBiome j : data.getBiomeLoader().loadAll(data.getBiomeLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisBiome dim) {
return dim.getLoadKey();
}
@Override
public IrisBiome parse(String in, boolean force) throws DecreeParsingException {
if (in.equals("null")) {
return null;
}
KList<IrisBiome> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Biome \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Biome \"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisBiome.class);
public class BiomeHandler extends RegistrantHandler<IrisBiome> {
public BiomeHandler() {
super(IrisBiome.class, true);
}
@Override

View File

@@ -18,62 +18,12 @@
package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisCave;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import java.io.File;
import java.util.stream.Collectors;
public class CaveHandler implements DecreeParameterHandler<IrisCave> {
@Override
public KList<IrisCave> getPossibilities() {
KMap<String, IrisCave> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisCave j : data.getCaveLoader().loadAll(data.getCaveLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisCave dim) {
return dim.getLoadKey();
}
@Override
public IrisCave parse(String in, boolean force) throws DecreeParsingException {
if (in.equals("null")) {
return null;
}
KList<IrisCave> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Cave \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Cave\"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisCave.class);
public class CaveHandler extends RegistrantHandler<IrisCave> {
public CaveHandler() {
super(IrisCave.class, true);
}
@Override

View File

@@ -18,65 +18,22 @@
package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import java.io.File;
public class DimensionHandler implements DecreeParameterHandler<IrisDimension> {
@Override
public KList<IrisDimension> getPossibilities() {
KMap<String, IrisDimension> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisDimension j : data.getDimensionLoader().loadAll(data.getDimensionLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisDimension dim) {
return dim.getLoadKey();
public class DimensionHandler extends RegistrantHandler<IrisDimension> {
public DimensionHandler() {
super(IrisDimension.class, false);
}
@Override
public IrisDimension parse(String in, boolean force) throws DecreeParsingException {
if (in.equalsIgnoreCase("default")) {
return parse(IrisSettings.get().getGenerator().getDefaultWorldType());
}
KList<IrisDimension> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Dimension \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).toList().get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Dimension \"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisDimension.class);
return super.parse(in, force);
}
@Override

View File

@@ -18,84 +18,13 @@
package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisEntity;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import java.io.File;
import java.util.stream.Collectors;
public class EntityHandler extends RegistrantHandler<IrisEntity> {
public class EntityHandler implements DecreeParameterHandler<IrisEntity> {
/**
* Should return the possible values for this type
*
* @return Possibilities for this type.
*/
@Override
public KList<IrisEntity> getPossibilities() {
KMap<String, IrisEntity> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisEntity j : data.getEntityLoader().loadAll(data.getEntityLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
/**
* Converting the type back to a string (inverse of the {@link #parse(String) parse} method)
*
* @param entity The input of the designated type to convert to a String
* @return The resulting string
*/
@Override
public String toString(IrisEntity entity) {
return entity.getLoadKey();
}
/**
* Should parse a String into the designated type
*
* @param in The string to parse
* @return The value extracted from the string, of the designated type
* @throws DecreeParsingException Thrown when the parsing fails (ex: "oop" translated to an integer throws this)
*/
@Override
public IrisEntity parse(String in, boolean force) throws DecreeParsingException {
KList<IrisEntity> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Entity \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Entity \"" + in + "\"");
}
}
/**
* Returns whether a certain type is supported by this handler<br>
*
* @param type The type to check
* @return True if supported, false if not
*/
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisEntity.class);
public EntityHandler() {
super(IrisEntity.class, false);
}
@Override

View File

@@ -18,59 +18,12 @@
package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import java.io.File;
import java.util.stream.Collectors;
public class GeneratorHandler implements DecreeParameterHandler<IrisGenerator> {
@Override
public KList<IrisGenerator> getPossibilities() {
KMap<String, IrisGenerator> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisGenerator j : data.getGeneratorLoader().loadAll(data.getGeneratorLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisGenerator gen) {
return gen.getLoadKey();
}
@Override
public IrisGenerator parse(String in, boolean force) throws DecreeParsingException {
KList<IrisGenerator> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Generator \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Generator \"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisGenerator.class);
public class GeneratorHandler extends RegistrantHandler<IrisGenerator> {
public GeneratorHandler() {
super(IrisGenerator.class, false);
}
@Override

View File

@@ -18,62 +18,12 @@
package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisJigsawPiece;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import java.io.File;
import java.util.stream.Collectors;
public class JigsawPieceHandler implements DecreeParameterHandler<IrisJigsawPiece> {
@Override
public KList<IrisJigsawPiece> getPossibilities() {
KMap<String, IrisJigsawPiece> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisJigsawPiece j : data.getJigsawPieceLoader().loadAll(data.getJigsawPieceLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisJigsawPiece dim) {
return dim.getLoadKey();
}
@Override
public IrisJigsawPiece parse(String in, boolean force) throws DecreeParsingException {
if (in.equals("null")) {
return null;
}
KList<IrisJigsawPiece> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Jigsaw Piece \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Jigsaw Piece \"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisJigsawPiece.class);
public class JigsawPieceHandler extends RegistrantHandler<IrisJigsawPiece> {
public JigsawPieceHandler() {
super(IrisJigsawPiece.class, true);
}
@Override

View File

@@ -18,62 +18,12 @@
package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisJigsawPool;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import java.io.File;
import java.util.stream.Collectors;
public class JigsawPoolHandler implements DecreeParameterHandler<IrisJigsawPool> {
@Override
public KList<IrisJigsawPool> getPossibilities() {
KMap<String, IrisJigsawPool> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisJigsawPool j : data.getJigsawPoolLoader().loadAll(data.getJigsawPoolLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisJigsawPool dim) {
return dim.getLoadKey();
}
@Override
public IrisJigsawPool parse(String in, boolean force) throws DecreeParsingException {
if (in.equals("null")) {
return null;
}
KList<IrisJigsawPool> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Jigsaw Pool \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Jigsaw Pool \"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisJigsawPool.class);
public class JigsawPoolHandler extends RegistrantHandler<IrisJigsawPool> {
public JigsawPoolHandler() {
super(IrisJigsawPool.class, true);
}
@Override

View File

@@ -18,62 +18,12 @@
package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisJigsawStructure;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import java.io.File;
import java.util.stream.Collectors;
public class JigsawStructureHandler implements DecreeParameterHandler<IrisJigsawStructure> {
@Override
public KList<IrisJigsawStructure> getPossibilities() {
KMap<String, IrisJigsawStructure> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisJigsawStructure j : data.getJigsawStructureLoader().loadAll(data.getJigsawStructureLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisJigsawStructure dim) {
return dim.getLoadKey();
}
@Override
public IrisJigsawStructure parse(String in, boolean force) throws DecreeParsingException {
if (in.equals("null")) {
return null;
}
KList<IrisJigsawStructure> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Jigsaw Structure \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Jigsaw Structure \"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisJigsawStructure.class);
public class JigsawStructureHandler extends RegistrantHandler<IrisJigsawStructure> {
public JigsawStructureHandler() {
super(IrisJigsawStructure.class, true);
}
@Override

View File

@@ -18,62 +18,12 @@
package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import java.io.File;
import java.util.stream.Collectors;
public class RegionHandler implements DecreeParameterHandler<IrisRegion> {
@Override
public KList<IrisRegion> getPossibilities() {
KMap<String, IrisRegion> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisRegion j : data.getRegionLoader().loadAll(data.getRegionLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisRegion dim) {
return dim.getLoadKey();
}
@Override
public IrisRegion parse(String in, boolean force) throws DecreeParsingException {
if (in.equals("null")) {
return null;
}
KList<IrisRegion> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Region \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Region \"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisRegion.class);
public class RegionHandler extends RegistrantHandler<IrisRegion> {
public RegionHandler() {
super(IrisRegion.class, true);
}
@Override

View File

@@ -18,59 +18,12 @@
package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisScript;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import java.io.File;
import java.util.stream.Collectors;
public class ScriptHandler implements DecreeParameterHandler<IrisScript> {
@Override
public KList<IrisScript> getPossibilities() {
KMap<String, IrisScript> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisScript j : data.getScriptLoader().loadAll(data.getScriptLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisScript script) {
return script.getLoadKey();
}
@Override
public IrisScript parse(String in, boolean force) throws DecreeParsingException {
KList<IrisScript> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Script \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Script \"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisScript.class);
public class ScriptHandler extends RegistrantHandler<IrisScript> {
public ScriptHandler() {
super(IrisScript.class, false);
}
@Override

View File

@@ -18,67 +18,21 @@
package com.volmit.iris.util.decree.specialhandlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import java.io.File;
public class NullableDimensionHandler implements DecreeParameterHandler<IrisDimension> {
@Override
public KList<IrisDimension> getPossibilities() {
KMap<String, IrisDimension> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisDimension j : data.getDimensionLoader().loadAll(data.getDimensionLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisDimension dim) {
return dim.getLoadKey();
public class NullableDimensionHandler extends RegistrantHandler<IrisDimension> {
public NullableDimensionHandler() {
super(IrisDimension.class, true);
}
@Override
public IrisDimension parse(String in, boolean force) throws DecreeParsingException {
if (in.equalsIgnoreCase("---"))
return null;
if (in.equalsIgnoreCase("default")) {
return parse(IrisSettings.get().getGenerator().getDefaultWorldType());
}
KList<IrisDimension> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Dimension \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).toList().get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Dimension \"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisDimension.class);
return super.parse(in, force);
}
@Override

View File

@@ -31,11 +31,15 @@ public class ObjectHandler implements DecreeParameterHandler<String> {
@Override
public KList<String> getPossibilities() {
KList<String> p = new KList<>();
IrisData data = data();
if (data != null) {
return new KList<>(data.getObjectLoader().getPossibleKeys());
}
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
data = IrisData.get(i);
p.add(data.getObjectLoader().getPossibleKeys());
}
}

View File

@@ -0,0 +1,76 @@
package com.volmit.iris.util.decree.specialhandlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
public abstract class RegistrantHandler<T extends IrisRegistrant> implements DecreeParameterHandler<T> {
private final Class<T> type;
private final String name;
private final boolean nullable;
public RegistrantHandler(Class<T> type, boolean nullable) {
this.type = type;
this.name = type.getSimpleName().replaceFirst("Iris", "");
this.nullable = nullable;
}
@Override
public KList<T> getPossibilities() {
KList<T> p = new KList<>();
Set<String> known = new HashSet<>();
IrisData data = data();
if (data != null) {
for (T j : data.getLoader(type).loadAll(data.getLoader(type).getPossibleKeys())) {
known.add(j.getLoadKey());
p.add(j);
}
}
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
data = IrisData.get(i);
for (T j : data.getLoader(type).loadAll(data.getLoader(type).getPossibleKeys())) {
if (known.add(j.getLoadKey()))
p.add(j);
}
}
}
return p;
}
@Override
public String toString(T t) {
return t != null ? t.getLoadKey() : "null";
}
@Override
public T parse(String in, boolean force) throws DecreeParsingException {
if (in.equals("null") && nullable) {
return null;
}
KList<T> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find " + name + " \"" + in + "\"");
}
return options.stream()
.filter((i) -> toString(i).equalsIgnoreCase(in))
.findFirst()
.orElseThrow(() -> new DecreeParsingException("Unable to filter which " + name + " \"" + in + "\""));
}
@Override
public boolean supports(Class<?> type) {
return type.equals(this.type);
}
}

View File

@@ -478,21 +478,27 @@ public class VirtualDecreeCommand {
}
DecreeContext.touch(sender);
Runnable rx = () -> {
try {
try {
Runnable rx = () -> {
DecreeContext.touch(sender);
getNode().getMethod().setAccessible(true);
getNode().getMethod().invoke(getNode().getInstance(), params);
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException("Failed to execute <INSERT REAL NODE HERE>"); // TODO:
}
};
try {
getNode().getMethod().setAccessible(true);
getNode().getMethod().invoke(getNode().getInstance(), params);
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException("Failed to execute <INSERT REAL NODE HERE>"); // TODO:
} finally {
DecreeContext.remove();
}
};
if (getNode().isSync()) {
J.s(rx);
} else {
rx.run();
if (getNode().isSync()) {
J.s(rx);
} else {
rx.run();
}
} finally {
DecreeContext.remove();
}
return true;

View File

@@ -19,21 +19,30 @@
package com.volmit.iris.util.hunk.bits;
import com.volmit.iris.util.data.Varint;
import lombok.Synchronized;
import it.unimi.dsi.fastutil.ints.*;
import java.io.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class DataContainer<T> {
private static final boolean TRIM = Boolean.getBoolean("iris.trim-palette");
protected static final int INITIAL_BITS = 3;
protected static final int LINEAR_BITS_LIMIT = 4;
protected static final int LINEAR_INITIAL_LENGTH = (int) Math.pow(2, LINEAR_BITS_LIMIT) + 1;
protected static final int LINEAR_INITIAL_LENGTH = (int) Math.pow(2, LINEAR_BITS_LIMIT) + 2;
protected static final int[] BIT = computeBitLimits();
private final Lock read, write;
private volatile Palette<T> palette;
private volatile DataBits data;
private final int length;
private final Writable<T> writer;
public DataContainer(Writable<T> writer, int length) {
var lock = new ReentrantReadWriteLock();
this.read = lock.readLock();
this.write = lock.writeLock();
this.writer = writer;
this.length = length;
this.data = new DataBits(INITIAL_BITS, length);
@@ -41,10 +50,15 @@ public class DataContainer<T> {
}
public DataContainer(DataInputStream din, Writable<T> writer) throws IOException {
var lock = new ReentrantReadWriteLock();
this.read = lock.readLock();
this.write = lock.writeLock();
this.writer = writer;
this.length = Varint.readUnsignedVarInt(din);
this.palette = newPalette(din);
this.data = new DataBits(palette.bits(), length, din);
trim();
}
private static int[] computeBitLimits() {
@@ -86,13 +100,18 @@ public class DataContainer<T> {
writeDos(new DataOutputStream(out));
}
@Synchronized
public void writeDos(DataOutputStream dos) throws IOException {
Varint.writeUnsignedVarInt(length, dos);
Varint.writeUnsignedVarInt(palette.size(), dos);
palette.iterateIO((data, __) -> writer.writeNodeData(dos, data));
data.write(dos);
dos.flush();
write.lock();
try {
trim();
Varint.writeUnsignedVarInt(length, dos);
Varint.writeUnsignedVarInt(palette.size(), dos);
palette.iterateIO((data, __) -> writer.writeNodeData(dos, data));
data.write(dos);
dos.flush();
} finally {
write.unlock();
}
}
private Palette<T> newPalette(DataInputStream din) throws IOException {
@@ -110,25 +129,38 @@ public class DataContainer<T> {
return new HashPalette<>();
}
@Synchronized
public void set(int position, T t) {
int id = palette.id(t);
int id;
if (id == -1) {
id = palette.add(t);
updateBits();
read.lock();
try {
id = palette.id(t);
if (id == -1) {
id = palette.add(t);
if (palette.bits() == data.getBits()) {
data.set(position, id);
return;
}
}
} finally {
read.unlock();
}
data.set(position, id);
write.lock();
try {
updateBits();
data.set(position, id);
} finally {
write.unlock();
}
}
@Synchronized
@SuppressWarnings("NonAtomicOperationOnVolatileField")
private void updateBits() {
if (palette.bits() == data.getBits())
int bits = palette.bits();
if (bits == data.getBits())
return;
int bits = palette.bits();
if (data.getBits() <= LINEAR_BITS_LIMIT != bits <= LINEAR_BITS_LIMIT) {
palette = newPalette(bits).from(palette);
}
@@ -136,18 +168,44 @@ public class DataContainer<T> {
data = data.setBits(bits);
}
@Synchronized
public T get(int position) {
int id = data.get(position);
read.lock();
try {
int id = data.get(position);
if (id <= 0) {
return null;
if (id <= 0) {
return null;
}
return palette.get(id);
} finally {
read.unlock();
}
return palette.get(id);
}
public int size() {
return data.getSize();
}
private void trim() {
var ints = new Int2IntRBTreeMap();
for (int i = 0; i < length; i++) {
int x = data.get(i);
if (x <= 0) continue;
ints.put(x, x);
}
if (ints.size() == palette.size())
return;
int bits = bits(ints.size() + 1);
var trimmed = newPalette(bits);
ints.replaceAll((k, v) -> trimmed.add(palette.get(k)));
var tBits = new DataBits(bits, length);
for (int i = 0; i < length; i++) {
tBits.set(i, ints.get(data.get(i)));
}
data = tBits;
palette = trimmed;
}
}

View File

@@ -27,13 +27,14 @@ import java.util.LinkedHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class HashPalette<T> implements Palette<T> {
private final LinkedHashMap<T, Integer> palette;
private final Object lock = new Object();
private final KMap<T, Integer> palette;
private final KMap<Integer, T> lookup;
private final AtomicInteger size;
public HashPalette() {
this.size = new AtomicInteger(1);
this.palette = new LinkedHashMap<>();
this.palette = new KMap<>();
this.lookup = new KMap<>();
}
@@ -52,13 +53,13 @@ public class HashPalette<T> implements Palette<T> {
return 0;
}
synchronized (palette) {
return palette.computeIfAbsent(t, $ -> {
return palette.computeIfAbsent(t, $ -> {
synchronized (lock) {
int index = size.getAndIncrement();
lookup.put(index, t);
return index;
});
}
}
});
}
@Override
@@ -78,7 +79,7 @@ public class HashPalette<T> implements Palette<T> {
@Override
public void iterate(Consumer2<T, Integer> c) {
synchronized (palette) {
synchronized (lock) {
for (int i = 1; i < size.get(); i++) {
c.accept(lookup.get(i), i);
}

View File

@@ -45,25 +45,23 @@ public class LinearPalette<T> implements Palette<T> {
@Override
public int add(T t) {
if (t == null) {
return 0;
}
int index = size.getAndIncrement();
grow(index + 1);
if (palette.length() <= index)
grow(index);
palette.set(index, t);
return index;
}
private synchronized void grow(int newLength) {
if (newLength > palette.length()) {
AtomicReferenceArray<T> a = new AtomicReferenceArray<>(newLength);
private synchronized void grow(int lastIndex) {
if (palette.length() > lastIndex)
return;
for (int i = 0; i < palette.length(); i++) {
a.set(i, palette.get(i));
}
palette = a;
AtomicReferenceArray<T> a = new AtomicReferenceArray<>(lastIndex + 1);
for (int i = 0; i < palette.length(); i++) {
a.set(i, palette.get(i));
}
palette = a;
}
@Override

View File

@@ -999,7 +999,7 @@ public class IrisInterpolation {
public static double getNoise(InterpolationMethod method, int x, int z, double h, NoiseProvider noise) {
HashMap<NoiseKey, Double> cache = new HashMap<>(64);
NoiseProvider n = (x1, z1) -> cache.computeIfAbsent(new NoiseKey(x1, z1), k -> noise.noise(k.x, k.z));
NoiseProvider n = (x1, z1) -> cache.computeIfAbsent(new NoiseKey(x1 - x, z1 - z), k -> noise.noise(x1, z1));
if (method.equals(InterpolationMethod.BILINEAR)) {
return getBilinearNoise(x, z, h, n);

View File

@@ -179,6 +179,8 @@ public class IO {
JsonElement json;
try (FileReader reader = new FileReader(file)) {
json = JsonParser.parseReader(reader);
} catch (Throwable e) {
throw new IOException("Failed to read json file " + file, e);
}
var queue = new LinkedList<JsonElement>();

View File

@@ -46,8 +46,8 @@ public class ReactiveFolder {
if (checkCycle % 3 == 0 ? fw.checkModified() : fw.checkModifiedFast()) {
for (File i : fw.getCreated()) {
if (i.getName().endsWith(".iob") || i.getName().endsWith(".json") || i.getName().endsWith(".js")) {
if (i.getPath().contains(".iris")) {
if (i.getName().endsWith(".iob") || i.getName().endsWith(".json") || i.getName().endsWith(".kts")) {
if (i.getPath().contains(".iris") || i.getName().endsWith(".gradle.kts")) {
continue;
}
@@ -58,11 +58,11 @@ public class ReactiveFolder {
if (!modified) {
for (File i : fw.getChanged()) {
if (i.getPath().contains(".iris")) {
if (i.getPath().contains(".iris") || i.getName().endsWith(".gradle.kts")) {
continue;
}
if (i.getName().endsWith(".iob") || i.getName().endsWith(".json") || i.getName().endsWith(".js")) {
if (i.getName().endsWith(".iob") || i.getName().endsWith(".json") || i.getName().endsWith(".kts")) {
modified = true;
break;
}
@@ -71,11 +71,11 @@ public class ReactiveFolder {
if (!modified) {
for (File i : fw.getDeleted()) {
if (i.getPath().contains(".iris")) {
if (i.getPath().contains(".iris") || i.getName().endsWith(".gradle.kts")) {
continue;
}
if (i.getName().endsWith(".iob") || i.getName().endsWith(".json") || i.getName().endsWith(".js")) {
if (i.getName().endsWith(".iob") || i.getName().endsWith(".json") || i.getName().endsWith(".kts")) {
modified = true;
break;
}

View File

@@ -176,8 +176,8 @@ public class Mantle {
* @return the writer
*/
@ChunkCoordinates
public MantleWriter write(EngineMantle engineMantle, int x, int z, int radius) {
return new MantleWriter(engineMantle, this, x, z, radius);
public MantleWriter write(EngineMantle engineMantle, int x, int z, int radius, boolean multicore) {
return new MantleWriter(engineMantle, this, x, z, radius, multicore);
}
/**
@@ -406,18 +406,6 @@ public class Mantle {
Iris.debug("The Mantle has Closed " + C.DARK_AQUA + dataFolder.getAbsolutePath());
}
/**
* Estimates the memory usage of the lastUse map.
*
* @return Estimated memory usage in bytes.
*/
public long LastUseMapMemoryUsage() {
long numberOfEntries = lastUse.size();
long bytesPerEntry = Long.BYTES * 2;
return numberOfEntries * bytesPerEntry;
}
/**
* Save & unload regions that have not been used for more than the
* specified amount of milliseconds
@@ -635,7 +623,7 @@ public class Mantle {
}
public void deleteChunkSlice(int x, int z, Class<?> c) {
if (!IrisToolbelt.toolbeltConfiguration.isEmpty() && IrisToolbelt.toolbeltConfiguration.getOrDefault("retain.mantle." + c.getCanonicalName(), false)) {
if (IrisToolbelt.isRetainingMantleDataForSlice(c.getCanonicalName())) {
return;
}

View File

@@ -19,16 +19,14 @@
package com.volmit.iris.util.mantle;
import com.volmit.iris.Iris;
import com.volmit.iris.util.data.Varint;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.documentation.ChunkRelativeBlockCoordinates;
import com.volmit.iris.util.function.Consumer4;
import com.volmit.iris.util.io.CountingDataInputStream;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.matter.IrisMatter;
import com.volmit.iris.util.matter.Matter;
import com.volmit.iris.util.matter.MatterSlice;
import com.volmit.iris.util.parallel.AtomicBooleanArray;
import lombok.Getter;
import lombok.SneakyThrows;
import org.jetbrains.annotations.Nullable;
@@ -44,13 +42,11 @@ import java.util.concurrent.atomic.AtomicReferenceArray;
* Represents a mantle chunk. Mantle chunks contain sections of matter (see matter api)
* Mantle Chunks are fully atomic & thread safe
*/
public class MantleChunk {
public class MantleChunk extends FlaggedChunk {
@Getter
private final int x;
@Getter
private final int z;
private final AtomicBooleanArray flags;
private final Object[] flagLocks;
private final AtomicReferenceArray<Matter> sections;
private final Semaphore ref = new Semaphore(Integer.MAX_VALUE, true);
private final AtomicBoolean closed = new AtomicBoolean(false);
@@ -63,14 +59,8 @@ public class MantleChunk {
@ChunkCoordinates
public MantleChunk(int sectionHeight, int x, int z) {
sections = new AtomicReferenceArray<>(sectionHeight);
flags = new AtomicBooleanArray(MantleFlag.MAX_ORDINAL + 1);
flagLocks = new Object[flags.length()];
this.x = x;
this.z = z;
for (int i = 0; i < flags.length(); i++) {
flagLocks[i] = new Object();
}
}
/**
@@ -84,20 +74,7 @@ public class MantleChunk {
public MantleChunk(int version, int sectionHeight, CountingDataInputStream din) throws IOException {
this(sectionHeight, din.readByte(), din.readByte());
int s = din.readByte();
int l = version < 0 ? MantleFlag.RESERVED_FLAGS : Varint.readUnsignedVarInt(din);
if (version >= 1) {
for (int i = 0; i < l;) {
byte f = din.readByte();
for (int j = 0; j < Byte.SIZE && i < flags.length(); j++, i++) {
flags.set(i, (f & (1 << j)) != 0);
}
}
} else {
for (int i = 0; i < flags.length() && i < l; i++) {
flags.set(i, din.readBoolean());
}
}
readFlags(version, din);
for (int i = 0; i < s; i++) {
Iris.addPanic("read.section", "Section[" + i + "]");
@@ -156,40 +133,10 @@ public class MantleChunk {
public void copyFlags(MantleChunk chunk) {
use();
for (int i = 0; i < flags.length(); i++) {
flags.set(i, chunk.flags.get(i));
}
super.copyFlags(chunk);
release();
}
public void flag(MantleFlag flag, boolean f) {
if (closed.get()) throw new IllegalStateException("Chunk is closed!");
flags.set(flag.ordinal(), f);
}
public void raiseFlag(MantleFlag flag, Runnable r) {
raiseFlag(null, flag, r);
}
public void raiseFlag(@Nullable MantleFlag guard, MantleFlag flag, Runnable r) {
if (closed.get()) throw new IllegalStateException("Chunk is closed!");
if (guard != null && isFlagged(guard)) return;
synchronized (flagLocks[flag.ordinal()]) {
if (flags.compareAndSet(flag.ordinal(), false, true)) {
r.run();
}
}
}
public void raiseFlagUnchecked(MantleFlag flag, Runnable r) {
if (closed.get()) throw new IllegalStateException("Chunk is closed!");
if (flags.compareAndSet(flag.ordinal(), false, true)) r.run();
}
public boolean isFlagged(MantleFlag flag) {
return flags.get(flag.ordinal());
}
/**
* Check if a section exists (same as get(section) != null)
*
@@ -271,16 +218,7 @@ public class MantleChunk {
dos.writeByte(x);
dos.writeByte(z);
dos.writeByte(sections.length());
Varint.writeUnsignedVarInt(flags.length(), dos);
int count = flags.length();
for (int i = 0; i < count;) {
int f = 0;
for (int j = 0; j < Byte.SIZE && i < flags.length(); j++, i++) {
f |= flags.get(i) ? (1 << j) : 0;
}
dos.write(f);
}
writeFlags(dos);
var bytes = new ByteArrayOutputStream(8192);
var sub = new DataOutputStream(bytes);
@@ -333,6 +271,8 @@ public class MantleChunk {
}
public void deleteSlices(Class<?> c) {
if (IrisToolbelt.isRetainingMantleDataForSlice(c.getCanonicalName()))
return;
for (int i = 0; i < sections.length(); i++) {
Matter m = sections.get(i);
if (m != null && m.hasSlice(c)) {
@@ -348,4 +288,9 @@ public class MantleChunk {
}
}
}
@Override
public boolean isClosed() {
return closed.get();
}
}

View File

@@ -40,6 +40,7 @@ public sealed interface MantleFlag permits CustomFlag, ReservedFlag {
MantleFlag CUSTOM = ReservedFlag.CUSTOM;
MantleFlag DISCOVERED = ReservedFlag.DISCOVERED;
MantleFlag CUSTOM_ACTIVE = ReservedFlag.CUSTOM_ACTIVE;
MantleFlag SCRIPT = ReservedFlag.SCRIPT;
int RESERVED_FLAGS = ReservedFlag.values().length;

View File

@@ -16,7 +16,8 @@ public enum ReservedFlag implements MantleFlag {
TILE,
CUSTOM,
DISCOVERED,
CUSTOM_ACTIVE;
CUSTOM_ACTIVE,
SCRIPT;
@Override
public boolean isCustom() {

View File

@@ -0,0 +1,26 @@
package com.volmit.iris.util.math;
import org.bukkit.util.BlockVector;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
public class Vector3i extends BlockVector {
public Vector3i(int x, int y, int z) {
super(x, y, z);
}
public Vector3i(Vector vec) {
super(vec);
}
@NotNull
@Override
public Vector3i clone() {
return (Vector3i) super.clone();
}
@Override
public int hashCode() {
return (int) x ^ ((int) z << 12) ^ ((int) y << 24);
}
}

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