mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-12-19 15:09:18 +00:00
Compare commits
64 Commits
feat/craft
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93ca26e368 | ||
|
|
8c1db1c223 | ||
|
|
123708601f | ||
|
|
b5ab4968ba | ||
|
|
93ae6037bd | ||
|
|
dd8e487a3b | ||
|
|
d3c8377a12 | ||
|
|
84f3687c0c | ||
|
|
ed1e1f1181 | ||
|
|
528c97f367 | ||
|
|
f7a459f3bc | ||
|
|
cd179b4321 | ||
|
|
6373dbb1b8 | ||
|
|
0b0797f876 | ||
|
|
446acefc91 | ||
|
|
7a44e555b2 | ||
|
|
57d4c2935c | ||
|
|
234fb1b0c4 | ||
|
|
0882b5acc4 | ||
|
|
18da26e1fa | ||
|
|
65aa95f2a5 | ||
|
|
5330ddc4ec | ||
|
|
a7fdd37569 | ||
|
|
a226fea9e2 | ||
|
|
8cea165a29 | ||
|
|
1d7cba184c | ||
|
|
4ca7ea3911 | ||
|
|
ea5919def2 | ||
|
|
be35e49302 | ||
|
|
aadd03990a | ||
|
|
38a579453d | ||
|
|
0bf5da2ca1 | ||
|
|
317848692e | ||
|
|
22118de9e9 | ||
|
|
d7039d120b | ||
|
|
979ee4e7d8 | ||
|
|
f68d45bd30 | ||
|
|
b86d7f303e | ||
|
|
c573843314 | ||
|
|
51a7bef18e | ||
|
|
0e237aa1ad | ||
|
|
b46c413f6b | ||
|
|
f3ef1ca2ae | ||
|
|
703e61dd54 | ||
|
|
e1ec6b7827 | ||
|
|
f94292fdac | ||
|
|
7d153bf985 | ||
|
|
f85f15ed02 | ||
|
|
867686eced | ||
|
|
9d796bd2a0 | ||
|
|
1a9a5d80ad | ||
|
|
c5c7f9bdc5 | ||
|
|
01a421b732 | ||
|
|
ae92bcf194 | ||
|
|
7e7933858b | ||
|
|
9c073ecbcb | ||
|
|
f4617c1996 | ||
|
|
21a2e4feef | ||
|
|
258d0d3aaa | ||
|
|
27b2fd0823 | ||
|
|
0524adb0df | ||
|
|
3981b0976d | ||
|
|
b5811cae08 | ||
|
|
c998fd1fd9 |
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
182
buildSrc/src/main/kotlin/NMSBinding.kt
Normal file
182
buildSrc/src/main/kotlin/NMSBinding.kt
Normal 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)
|
||||
@@ -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 })
|
||||
}
|
||||
@@ -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.");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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!");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -33,7 +33,7 @@ public class KGeneratorsDataProvider extends ExternalDataProvider {
|
||||
@Override
|
||||
public @NotNull BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
|
||||
if (Main.getGenerators().get(blockId.key()) == null) throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
|
||||
return new IrisCustomData(Material.STRUCTURE_VOID.createBlockData(), ExternalDataSVC.buildState(blockId, state));
|
||||
return IrisCustomData.of(Material.STRUCTURE_VOID.createBlockData(), ExternalDataSVC.buildState(blockId, state));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -72,7 +72,7 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider {
|
||||
CustomBlockItemContext blockItemContext = crucibleItem.getBlockData();
|
||||
FurnitureItemContext furnitureItemContext = crucibleItem.getFurnitureData();
|
||||
if (furnitureItemContext != null) {
|
||||
return new IrisCustomData(B.getAir(), ExternalDataSVC.buildState(blockId, state));
|
||||
return IrisCustomData.of(B.getAir(), ExternalDataSVC.buildState(blockId, state));
|
||||
} else if (blockItemContext != null) {
|
||||
return blockItemContext.getBlockData();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -35,7 +35,7 @@ import java.io.File;
|
||||
|
||||
@Data
|
||||
public abstract class IrisRegistrant {
|
||||
@Desc("Preprocess this object in-memory when it's loaded, run scripts using the variable 'Iris.getPreprocessorObject()' and modify properties about this object before it's used.")
|
||||
@Desc("Preprocess this object in-memory when it's loaded, run scripts using the variable 'object' and modify properties about this object before it's used.\nFile extension: .proc.kts")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@ArrayType(min = 1, type = String.class)
|
||||
private KList<String> preprocessors = new KList<>();
|
||||
|
||||
@@ -46,6 +46,7 @@ import lombok.ToString;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
@@ -170,7 +171,6 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
|
||||
return possibleKeys;
|
||||
}
|
||||
|
||||
KSet<String> m = new KSet<>();
|
||||
KList<File> files = getFolders();
|
||||
|
||||
if (files == null) {
|
||||
@@ -178,6 +178,7 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
|
||||
return possibleKeys;
|
||||
}
|
||||
|
||||
HashSet<String> m = new HashSet<>();
|
||||
for (File i : files) {
|
||||
for (File j : matchAllFiles(i, (f) -> f.getName().endsWith(".json"))) {
|
||||
m.add(i.toURI().relativize(j.toURI()).getPath().replaceAll("\\Q.json\\E", ""));
|
||||
@@ -319,7 +320,8 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
|
||||
return null;
|
||||
}
|
||||
|
||||
firstAccess.add(name);
|
||||
var set = firstAccess;
|
||||
if (set != null) firstAccess.add(name);
|
||||
return loadCache.get(name);
|
||||
}
|
||||
|
||||
@@ -342,21 +344,24 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
|
||||
}
|
||||
|
||||
din.close();
|
||||
file.deleteOnExit();
|
||||
Iris.info("Loading " + s.size() + " prefetch " + getFolderName());
|
||||
firstAccess = null;
|
||||
loadAllParallel(s);
|
||||
}
|
||||
|
||||
public void saveFirstAccess(Engine engine) throws IOException {
|
||||
if (firstAccess == null) return;
|
||||
String id = "DIM" + Math.abs(engine.getSeedManager().getSeed() + engine.getDimension().getVersion() + engine.getDimension().getLoadKey().hashCode());
|
||||
File file = Iris.instance.getDataFile("prefetch/" + id + "/" + Math.abs(getFolderName().hashCode()) + ".ipfch");
|
||||
file.getParentFile().mkdirs();
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
GZIPOutputStream gzo = new CustomOutputStream(fos, 9);
|
||||
DataOutputStream dos = new DataOutputStream(gzo);
|
||||
dos.writeInt(firstAccess.size());
|
||||
var set = firstAccess;
|
||||
firstAccess = null;
|
||||
dos.writeInt(set.size());
|
||||
|
||||
for (String i : firstAccess) {
|
||||
for (String i : set) {
|
||||
dos.writeUTF(i);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,9 +28,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"),
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -24,9 +24,11 @@ public interface PregenCache {
|
||||
|
||||
void write();
|
||||
|
||||
void trim(long unloadDuration);
|
||||
|
||||
static PregenCache create(File directory) {
|
||||
if (directory == null) return EMPTY;
|
||||
return new PregenCacheImpl(directory);
|
||||
return new PregenCacheImpl(directory, 16);
|
||||
}
|
||||
|
||||
default PregenCache sync() {
|
||||
@@ -51,19 +53,16 @@ public interface PregenCache {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cacheChunk(int x, int z) {
|
||||
|
||||
}
|
||||
public void cacheChunk(int x, int z) {}
|
||||
|
||||
@Override
|
||||
public void cacheRegion(int x, int z) {
|
||||
|
||||
}
|
||||
public void cacheRegion(int x, int z) {}
|
||||
|
||||
@Override
|
||||
public void write() {
|
||||
public void write() {}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void trim(long unloadDuration) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
package com.volmit.iris.core.pregenerator.cache;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.github.benmanes.caffeine.cache.RemovalCause;
|
||||
import com.github.benmanes.caffeine.cache.Scheduler;
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.data.KCache;
|
||||
import com.volmit.iris.util.data.Varint;
|
||||
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.documentation.RegionCoordinates;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.parallel.HyperLock;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
class PregenCacheImpl implements PregenCache {
|
||||
private static final int SIZE = 32;
|
||||
private final File directory;
|
||||
private final HyperLock hyperLock = new HyperLock(SIZE * 2, true);
|
||||
private final LoadingCache<Pos, Plate> cache = Caffeine.newBuilder()
|
||||
.expireAfterAccess(10, TimeUnit.SECONDS)
|
||||
.executor(KCache.EXECUTOR)
|
||||
.scheduler(Scheduler.systemScheduler())
|
||||
.maximumSize(SIZE)
|
||||
.removalListener(this::onRemoval)
|
||||
.evictionListener(this::onRemoval)
|
||||
.build(this::load);
|
||||
|
||||
@ChunkCoordinates
|
||||
public boolean isChunkCached(int x, int z) {
|
||||
var plate = cache.get(new Pos(x >> 10, z >> 10));
|
||||
if (plate == null) return false;
|
||||
return plate.isCached((x >> 5) & 31, (z >> 5) & 31, r -> r.isCached(x & 31, z & 31));
|
||||
}
|
||||
|
||||
@RegionCoordinates
|
||||
public boolean isRegionCached(int x, int z) {
|
||||
var plate = cache.get(new Pos(x >> 5, z >> 5));
|
||||
if (plate == null) return false;
|
||||
return plate.isCached(x & 31, z & 31, Region::isCached);
|
||||
}
|
||||
|
||||
@ChunkCoordinates
|
||||
public void cacheChunk(int x, int z) {
|
||||
var plate = cache.get(new Pos(x >> 10, z >> 10));
|
||||
plate.cache((x >> 5) & 31, (z >> 5) & 31, r -> r.cache(x & 31, z & 31));
|
||||
}
|
||||
|
||||
@RegionCoordinates
|
||||
public void cacheRegion(int x, int z) {
|
||||
var plate = cache.get(new Pos(x >> 5, z >> 5));
|
||||
plate.cache(x & 31, z & 31, Region::cache);
|
||||
}
|
||||
|
||||
public void write() {
|
||||
cache.asMap().values().forEach(this::write);
|
||||
}
|
||||
|
||||
private Plate load(Pos key) {
|
||||
hyperLock.lock(key.x, key.z);
|
||||
try {
|
||||
File file = fileForPlate(key);
|
||||
if (!file.exists()) return new Plate(key);
|
||||
try (var in = new DataInputStream(new LZ4BlockInputStream(new FileInputStream(file)))) {
|
||||
return new Plate(key, in);
|
||||
} catch (IOException e){
|
||||
Iris.error("Failed to read pregen cache " + file);
|
||||
Iris.reportError(e);
|
||||
e.printStackTrace();
|
||||
return new Plate(key);
|
||||
}
|
||||
} finally {
|
||||
hyperLock.unlock(key.x, key.z);
|
||||
}
|
||||
}
|
||||
|
||||
private void write(Plate plate) {
|
||||
hyperLock.lock(plate.pos.x, plate.pos.z);
|
||||
try {
|
||||
File file = fileForPlate(plate.pos);
|
||||
try {
|
||||
IO.write(file, out -> new DataOutputStream(new LZ4BlockOutputStream(out)), plate::write);
|
||||
} catch (IOException e) {
|
||||
Iris.error("Failed to write pregen cache " + file);
|
||||
Iris.reportError(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
hyperLock.unlock(plate.pos.x, plate.pos.z);
|
||||
}
|
||||
}
|
||||
|
||||
private void onRemoval(@Nullable Pos key, @Nullable Plate plate, RemovalCause cause) {
|
||||
if (plate == null) return;
|
||||
write(plate);
|
||||
}
|
||||
|
||||
private File fileForPlate(Pos pos) {
|
||||
if (!directory.exists() && !directory.mkdirs())
|
||||
throw new IllegalStateException("Cannot create directory: " + directory.getAbsolutePath());
|
||||
return new File(directory, "c." + pos.x + "." + pos.z + ".lz4b");
|
||||
}
|
||||
|
||||
private static class Plate {
|
||||
private final Pos pos;
|
||||
private short count;
|
||||
private Region[] regions;
|
||||
|
||||
public Plate(Pos pos) {
|
||||
this.pos = pos;
|
||||
count = 0;
|
||||
regions = new Region[1024];
|
||||
}
|
||||
|
||||
public Plate(Pos pos, DataInput in) throws IOException {
|
||||
this.pos = pos;
|
||||
count = (short) Varint.readSignedVarInt(in);
|
||||
if (count == 1024) return;
|
||||
regions = new Region[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
if (in.readBoolean()) continue;
|
||||
regions[i] = new Region(in);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCached(int x, int z, Predicate<Region> predicate) {
|
||||
if (count == 1024) return true;
|
||||
Region region = regions[x * 32 + z];
|
||||
if (region == null) return false;
|
||||
return predicate.test(region);
|
||||
}
|
||||
|
||||
public void cache(int x, int z, Predicate<Region> predicate) {
|
||||
if (count == 1024) return;
|
||||
Region region = regions[x * 32 + z];
|
||||
if (region == null) regions[x * 32 + z] = region = new Region();
|
||||
if (predicate.test(region)) count++;
|
||||
}
|
||||
|
||||
public void write(DataOutput out) throws IOException {
|
||||
Varint.writeSignedVarInt(count, out);
|
||||
if (count == 1024) return;
|
||||
for (Region region : regions) {
|
||||
out.writeBoolean(region == null);
|
||||
if (region == null) continue;
|
||||
region.write(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Region {
|
||||
private short count;
|
||||
private long[] words;
|
||||
|
||||
public Region() {
|
||||
count = 0;
|
||||
words = new long[64];
|
||||
}
|
||||
|
||||
public Region(DataInput in) throws IOException {
|
||||
count = (short) Varint.readSignedVarInt(in);
|
||||
if (count == 1024) return;
|
||||
words = new long[64];
|
||||
for (int i = 0; i < 64; i++) {
|
||||
words[i] = Varint.readUnsignedVarLong(in);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean cache() {
|
||||
if (count == 1024) return false;
|
||||
count = 1024;
|
||||
words = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean cache(int x, int z) {
|
||||
if (count == 1024) return false;
|
||||
|
||||
int i = x * 32 + z;
|
||||
int w = i >> 6;
|
||||
long b = 1L << (i & 63);
|
||||
|
||||
var cur = (words[w] & b) != 0;
|
||||
if (cur) return false;
|
||||
|
||||
if (++count == 1024) {
|
||||
words = null;
|
||||
return true;
|
||||
} else words[w] |= b;
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isCached() {
|
||||
return count == 1024;
|
||||
}
|
||||
|
||||
public boolean isCached(int x, int z) {
|
||||
int i = x * 32 + z;
|
||||
return count == 1024 || (words[i >> 6] & 1L << (i & 63)) != 0;
|
||||
}
|
||||
|
||||
public void write(DataOutput out) throws IOException {
|
||||
Varint.writeSignedVarInt(count, out);
|
||||
if (isCached()) return;
|
||||
for (long word : words) {
|
||||
Varint.writeUnsignedVarLong(word, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private record Pos(int x, int z) {}
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
package com.volmit.iris.core.pregenerator.cache;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
class SynchronizedCache implements PregenCache {
|
||||
private final PregenCache cache;
|
||||
|
||||
record SynchronizedCache(PregenCache cache) implements PregenCache {
|
||||
@Override
|
||||
public boolean isThreadSafe() {
|
||||
return true;
|
||||
@@ -45,4 +40,11 @@ class SynchronizedCache implements PregenCache {
|
||||
cache.write();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trim(long unloadDuration) {
|
||||
synchronized (cache) {
|
||||
cache.trim(unloadDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.Scanner;
|
||||
import java.util.*;
|
||||
|
||||
public class Gradle {
|
||||
private static final boolean WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
|
||||
@@ -38,10 +36,15 @@ public class Gradle {
|
||||
cmd[0] = gradle.getAbsolutePath();
|
||||
System.arraycopy(args, 0, cmd, 1, args.length);
|
||||
var process = Runtime.getRuntime().exec(cmd, ENVIRONMENT, projectDir);
|
||||
attach(process.getInputStream());
|
||||
attach(process.getErrorStream());
|
||||
var lines = Collections.synchronizedList(new ArrayList<String>());
|
||||
attach(process.getInputStream(), lines);
|
||||
attach(process.getErrorStream(), lines);
|
||||
var code = process.waitFor();
|
||||
if (code == 0) return;
|
||||
if (code == 0) {
|
||||
lines.forEach(Iris::debug);
|
||||
return;
|
||||
}
|
||||
lines.forEach(Iris::error);
|
||||
throw new RuntimeException("Gradle exited with code " + code);
|
||||
}
|
||||
|
||||
@@ -91,12 +94,12 @@ public class Gradle {
|
||||
.orElseThrow(() -> new RuntimeException("Failed to find java home, please set java.home system property"));
|
||||
}
|
||||
|
||||
private static void attach(InputStream stream) {
|
||||
Thread.ofVirtual().start(() -> {
|
||||
private static void attach(InputStream stream, List<String> list) {
|
||||
Thread.ofPlatform().start(() -> {
|
||||
try (var in = new Scanner(stream)) {
|
||||
while (in.hasNextLine()) {
|
||||
String line = in.nextLine();
|
||||
Iris.debug("[GRADLE] " + line);
|
||||
list.add(line);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.core.loader.IrisRegistrant;
|
||||
import com.volmit.iris.core.loader.ResourceLoader;
|
||||
import com.volmit.iris.core.scripting.environment.SimpleEnvironment;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
import com.volmit.iris.engine.object.*;
|
||||
import com.volmit.iris.engine.object.annotations.Snippet;
|
||||
@@ -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();
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InaccessibleObjectException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -117,49 +118,13 @@ public class SchemaBuilder {
|
||||
JSONArray required = new JSONArray();
|
||||
JSONArray extended = new JSONArray();
|
||||
|
||||
if (c.isAssignableFrom(IrisRegistrant.class) || IrisRegistrant.class.isAssignableFrom(c)) {
|
||||
for (Field k : IrisRegistrant.class.getDeclaredFields()) {
|
||||
k.setAccessible(true);
|
||||
|
||||
if (Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JSONObject property = buildProperty(k, c);
|
||||
|
||||
if (Boolean.TRUE == property.remove("!required")) {
|
||||
required.put(k.getName());
|
||||
}
|
||||
|
||||
if (Boolean.TRUE == property.remove("!top")) {
|
||||
extended.put(property);
|
||||
continue;
|
||||
}
|
||||
|
||||
properties.put(k.getName(), property);
|
||||
}
|
||||
var parent = c.getSuperclass();
|
||||
while (parent != null && IrisRegistrant.class.isAssignableFrom(parent)) {
|
||||
buildProperties(properties, required, extended, parent);
|
||||
parent = parent.getSuperclass();
|
||||
}
|
||||
|
||||
for (Field k : c.getDeclaredFields()) {
|
||||
k.setAccessible(true);
|
||||
|
||||
if (Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JSONObject property = buildProperty(k, c);
|
||||
|
||||
if (Boolean.TRUE == property.remove("!required")) {
|
||||
required.put(k.getName());
|
||||
}
|
||||
|
||||
if (Boolean.TRUE == property.remove("!top")) {
|
||||
extended.put(property);
|
||||
continue;
|
||||
}
|
||||
|
||||
properties.put(k.getName(), property);
|
||||
}
|
||||
buildProperties(properties, required, extended, c);
|
||||
|
||||
if (required.length() > 0) {
|
||||
o.put("required", required);
|
||||
@@ -174,6 +139,33 @@ public class SchemaBuilder {
|
||||
return buildSnippet(o, c);
|
||||
}
|
||||
|
||||
private void buildProperties(JSONObject properties, JSONArray required, JSONArray extended, Class<?> c) {
|
||||
for (Field k : c.getDeclaredFields()) {
|
||||
if (Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
k.setAccessible(true);
|
||||
} catch (InaccessibleObjectException e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JSONObject property = buildProperty(k, c);
|
||||
|
||||
if (Boolean.TRUE == property.remove("!top")) {
|
||||
extended.put(property);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Boolean.TRUE == property.remove("!required")) {
|
||||
required.put(k.getName());
|
||||
}
|
||||
|
||||
properties.put(k.getName(), property);
|
||||
}
|
||||
}
|
||||
|
||||
private JSONObject buildProperty(Field k, Class<?> cl) {
|
||||
JSONObject prop = new JSONObject();
|
||||
String type = getType(k.getType());
|
||||
@@ -616,7 +608,7 @@ public class SchemaBuilder {
|
||||
if (present) d.add(" ");
|
||||
if (value instanceof List) {
|
||||
d.add(SYMBOL_LIMIT__N + " Default Value is an empty list");
|
||||
} else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum()) && !KeyedType.isKeyed(cl)) {
|
||||
} else if (!k.getType().isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(value instanceof Enum<?>) && !KeyedType.isKeyed(k.getType())) {
|
||||
d.add(SYMBOL_LIMIT__N + " Default Value is a default object (create this object to see default properties)");
|
||||
} else {
|
||||
d.add(SYMBOL_LIMIT__N + " Default Value is " + value);
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package com.volmit.iris.core.scripting.environment;
|
||||
|
||||
import com.volmit.iris.core.loader.IrisRegistrant;
|
||||
import com.volmit.iris.core.scripting.func.UpdateExecutor;
|
||||
import com.volmit.iris.core.scripting.kotlin.environment.IrisExecutionEnvironment;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.util.mantle.MantleChunk;
|
||||
import lombok.NonNull;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -22,4 +25,6 @@ public interface EngineEnvironment extends PackEnvironment {
|
||||
void postSpawnMob(@NonNull String script, @NonNull Location location, @NonNull Entity mob);
|
||||
|
||||
void preprocessObject(@NonNull String script, @NonNull IrisRegistrant object);
|
||||
|
||||
void updateChunk(@NonNull String script, @NonNull MantleChunk mantleChunk, @NonNull Chunk chunk, @NonNull UpdateExecutor executor);
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.volmit.iris.core.scripting.environment;
|
||||
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.core.scripting.kotlin.environment.IrisPackExecutionEnvironment;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import lombok.NonNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -16,4 +17,6 @@ public interface PackEnvironment extends SimpleEnvironment {
|
||||
|
||||
@Nullable
|
||||
Object createNoise(@NonNull String script, @NonNull RNG rng);
|
||||
|
||||
EngineEnvironment with(@NonNull Engine engine);
|
||||
}
|
||||
@@ -27,8 +27,4 @@ public interface SimpleEnvironment {
|
||||
|
||||
@Nullable
|
||||
Object evaluate(@NonNull String script, @NonNull Class<?> type, @Nullable Map<@NonNull String, Object> vars);
|
||||
|
||||
default void close() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.volmit.iris.core.scripting.func;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface UpdateExecutor {
|
||||
|
||||
@NotNull Runnable wrap(int delay, @NotNull Runnable runnable);
|
||||
|
||||
@NotNull
|
||||
default Runnable wrap(@NotNull Runnable runnable) {
|
||||
return wrap(1, runnable);
|
||||
}
|
||||
|
||||
default void execute(@NotNull Runnable runnable) {
|
||||
execute(1, runnable);
|
||||
}
|
||||
|
||||
default void execute(int delay, @NotNull Runnable runnable) {
|
||||
wrap(delay, runnable).run();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package com.volmit.iris.core.service;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.Scheduler;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.pregenerator.cache.PregenCache;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.data.KCache;
|
||||
import com.volmit.iris.util.plugin.IrisService;
|
||||
import com.volmit.iris.util.scheduling.Looper;
|
||||
import lombok.NonNull;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
@@ -19,21 +17,33 @@ import org.bukkit.event.world.WorldUnloadEvent;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class GlobalCacheSVC implements IrisService {
|
||||
private static final Cache<String, PregenCache> REFERENCE_CACHE = Caffeine.newBuilder()
|
||||
.executor(KCache.EXECUTOR)
|
||||
.scheduler(Scheduler.systemScheduler())
|
||||
.weakValues()
|
||||
.build();
|
||||
private static final KMap<String, Reference<PregenCache>> REFERENCE_CACHE = new KMap<>();
|
||||
private final KMap<String, PregenCache> globalCache = new KMap<>();
|
||||
private transient boolean lastState;
|
||||
private static boolean disabled = true;
|
||||
private Looper trimmer;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
disabled = false;
|
||||
trimmer = new Looper() {
|
||||
@Override
|
||||
protected long loop() {
|
||||
var it = REFERENCE_CACHE.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
var cache = it.next().get();
|
||||
if (cache == null) it.remove();
|
||||
else cache.trim(10_000);
|
||||
}
|
||||
return disabled ? -1 : 2_000;
|
||||
}
|
||||
};
|
||||
trimmer.start();
|
||||
lastState = !IrisSettings.get().getWorld().isGlobalPregenCache();
|
||||
if (lastState) return;
|
||||
Bukkit.getWorlds().forEach(this::createCache);
|
||||
@@ -42,6 +52,9 @@ public class GlobalCacheSVC implements IrisService {
|
||||
@Override
|
||||
public void onDisable() {
|
||||
disabled = true;
|
||||
try {
|
||||
trimmer.join();
|
||||
} catch (InterruptedException ignored) {}
|
||||
globalCache.qclear((world, cache) -> cache.write());
|
||||
}
|
||||
|
||||
@@ -76,6 +89,7 @@ public class GlobalCacheSVC implements IrisService {
|
||||
}
|
||||
|
||||
private void createCache(World world) {
|
||||
if (!IrisToolbelt.isIrisWorld(world)) return;
|
||||
globalCache.computeIfAbsent(world.getName(), GlobalCacheSVC::createDefault);
|
||||
}
|
||||
|
||||
@@ -99,7 +113,15 @@ public class GlobalCacheSVC implements IrisService {
|
||||
|
||||
@NonNull
|
||||
public static PregenCache createCache(@NonNull String worldName, @NonNull Function<String, PregenCache> provider) {
|
||||
return REFERENCE_CACHE.get(worldName, provider);
|
||||
PregenCache[] holder = new PregenCache[1];
|
||||
REFERENCE_CACHE.compute(worldName, (name, ref) -> {
|
||||
if (ref != null) {
|
||||
if ((holder[0] = ref.get()) != null)
|
||||
return ref;
|
||||
}
|
||||
return new WeakReference<>(holder[0] = provider.apply(worldName));
|
||||
});
|
||||
return holder[0];
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.volmit.iris.core.service;
|
||||
import com.google.common.util.concurrent.AtomicDouble;
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.core.loader.ResourceLoader;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
||||
@@ -14,6 +14,8 @@ import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.plugin.IrisService;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.scheduling.Looper;
|
||||
import com.volmit.iris.util.stream.utility.CachedStream2D;
|
||||
import com.volmit.iris.util.stream.utility.CachedStream3D;
|
||||
import lombok.Synchronized;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
@@ -27,6 +29,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class IrisEngineSVC implements IrisService {
|
||||
private static final int TRIM_PERIOD = 2_000;
|
||||
private final AtomicInteger tectonicLimit = new AtomicInteger(30);
|
||||
private final AtomicInteger tectonicPlates = new AtomicInteger();
|
||||
private final AtomicInteger queuedTectonicPlates = new AtomicInteger();
|
||||
@@ -64,10 +67,26 @@ public class IrisEngineSVC implements IrisService {
|
||||
}
|
||||
|
||||
public void engineStatus(VolmitSender sender) {
|
||||
long[] sizes = new long[4];
|
||||
long[] count = new long[4];
|
||||
|
||||
for (var cache : Iris.service(PreservationSVC.class).getCaches()) {
|
||||
var type = switch (cache) {
|
||||
case ResourceLoader<?> ignored -> 0;
|
||||
case CachedStream2D<?> ignored -> 1;
|
||||
case CachedStream3D<?> ignored -> 2;
|
||||
default -> 3;
|
||||
};
|
||||
|
||||
sizes[type] += cache.getSize();
|
||||
count[type]++;
|
||||
}
|
||||
|
||||
sender.sendMessage(C.DARK_PURPLE + "-------------------------");
|
||||
sender.sendMessage(C.DARK_PURPLE + "Status:");
|
||||
sender.sendMessage(C.DARK_PURPLE + "- Service: " + C.LIGHT_PURPLE + (service.isShutdown() ? "Shutdown" : "Running"));
|
||||
sender.sendMessage(C.DARK_PURPLE + "- Updater: " + C.LIGHT_PURPLE + (updateTicker.isAlive() ? "Running" : "Stopped"));
|
||||
sender.sendMessage(C.DARK_PURPLE + "- Period: " + C.LIGHT_PURPLE + Form.duration(TRIM_PERIOD));
|
||||
sender.sendMessage(C.DARK_PURPLE + "- Trimmers: " + C.LIGHT_PURPLE + trimmerAlive.get());
|
||||
sender.sendMessage(C.DARK_PURPLE + "- Unloaders: " + C.LIGHT_PURPLE + unloaderAlive.get());
|
||||
sender.sendMessage(C.DARK_PURPLE + "Tectonic Plates:");
|
||||
@@ -76,10 +95,14 @@ public class IrisEngineSVC implements IrisService {
|
||||
sender.sendMessage(C.DARK_PURPLE + "- Queued: " + C.LIGHT_PURPLE + queuedTectonicPlates.get());
|
||||
sender.sendMessage(C.DARK_PURPLE + "- Max Idle Duration: " + C.LIGHT_PURPLE + Form.duration(maxIdleDuration.get(), 2));
|
||||
sender.sendMessage(C.DARK_PURPLE + "- Min Idle Duration: " + C.LIGHT_PURPLE + Form.duration(minIdleDuration.get(), 2));
|
||||
sender.sendMessage(C.DARK_PURPLE + "Caches:");
|
||||
sender.sendMessage(C.DARK_PURPLE + "- Resource: " + C.LIGHT_PURPLE + sizes[0] + " (" + count[0] + ")");
|
||||
sender.sendMessage(C.DARK_PURPLE + "- 2D Stream: " + C.LIGHT_PURPLE + sizes[1] + " (" + count[1] + ")");
|
||||
sender.sendMessage(C.DARK_PURPLE + "- 3D Stream: " + C.LIGHT_PURPLE + sizes[2] + " (" + count[2] + ")");
|
||||
sender.sendMessage(C.DARK_PURPLE + "- Other: " + C.LIGHT_PURPLE + sizes[3] + " (" + count[3] + ")");
|
||||
sender.sendMessage(C.DARK_PURPLE + "Other:");
|
||||
sender.sendMessage(C.DARK_PURPLE + "- Iris Worlds: " + C.LIGHT_PURPLE + totalWorlds.get());
|
||||
sender.sendMessage(C.DARK_PURPLE + "- Loaded Chunks: " + C.LIGHT_PURPLE + loadedChunks.get());
|
||||
sender.sendMessage(C.DARK_PURPLE + "- Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize()));
|
||||
sender.sendMessage(C.DARK_PURPLE + "-------------------------");
|
||||
}
|
||||
|
||||
@@ -113,12 +136,12 @@ public class IrisEngineSVC implements IrisService {
|
||||
@Override
|
||||
protected long loop() {
|
||||
try {
|
||||
queuedTectonicPlates.set(0);
|
||||
tectonicPlates.set(0);
|
||||
loadedChunks.set(0);
|
||||
unloaderAlive.set(0);
|
||||
trimmerAlive.set(0);
|
||||
totalWorlds.set(0);
|
||||
int queuedPlates = 0;
|
||||
int totalPlates = 0;
|
||||
long chunks = 0;
|
||||
int unloaders = 0;
|
||||
int trimmers = 0;
|
||||
int iris = 0;
|
||||
|
||||
double maxDuration = Long.MIN_VALUE;
|
||||
double minDuration = Long.MAX_VALUE;
|
||||
@@ -126,23 +149,30 @@ public class IrisEngineSVC implements IrisService {
|
||||
var registered = entry.getValue();
|
||||
if (registered.closed) continue;
|
||||
|
||||
totalWorlds.incrementAndGet();
|
||||
unloaderAlive.addAndGet(registered.unloaderAlive() ? 1 : 0);
|
||||
trimmerAlive.addAndGet(registered.trimmerAlive() ? 1 : 0);
|
||||
iris++;
|
||||
if (registered.unloaderAlive()) unloaders++;
|
||||
if (registered.trimmerAlive()) trimmers++;
|
||||
|
||||
var engine = registered.getEngine();
|
||||
if (engine == null) continue;
|
||||
|
||||
queuedTectonicPlates.addAndGet((int) engine.getMantle().getUnloadRegionCount());
|
||||
tectonicPlates.addAndGet(engine.getMantle().getLoadedRegionCount());
|
||||
loadedChunks.addAndGet(entry.getKey().getLoadedChunks().length);
|
||||
queuedPlates += engine.getMantle().getUnloadRegionCount();
|
||||
totalPlates += engine.getMantle().getLoadedRegionCount();
|
||||
chunks += entry.getKey().getLoadedChunks().length;
|
||||
|
||||
double duration = engine.getMantle().getAdjustedIdleDuration();
|
||||
if (duration > maxDuration) maxDuration = duration;
|
||||
if (duration < minDuration) minDuration = duration;
|
||||
}
|
||||
|
||||
trimmerAlive.set(trimmers);
|
||||
unloaderAlive.set(unloaders);
|
||||
tectonicPlates.set(totalPlates);
|
||||
queuedTectonicPlates.set(queuedPlates);
|
||||
maxIdleDuration.set(maxDuration);
|
||||
minIdleDuration.set(minDuration);
|
||||
loadedChunks.set(chunks);
|
||||
totalWorlds.set(iris);
|
||||
|
||||
worlds.values().forEach(Registered::update);
|
||||
} catch (Throwable e) {
|
||||
@@ -157,7 +187,7 @@ public class IrisEngineSVC implements IrisService {
|
||||
private final class Registered {
|
||||
private final String name;
|
||||
private final PlatformChunkGenerator access;
|
||||
private final int offset = RNG.r.nextInt(1000);
|
||||
private final int offset = RNG.r.nextInt(TRIM_PERIOD);
|
||||
private transient ScheduledFuture<?> trimmer;
|
||||
private transient ScheduledFuture<?> unloader;
|
||||
private transient boolean closed;
|
||||
@@ -194,7 +224,7 @@ public class IrisEngineSVC implements IrisService {
|
||||
Iris.error("EngineSVC: Failed to trim for " + name);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, offset, 2000, TimeUnit.MILLISECONDS);
|
||||
}, offset, TRIM_PERIOD, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
if (unloader == null || unloader.isDone() || unloader.isCancelled()) {
|
||||
@@ -214,7 +244,7 @@ public class IrisEngineSVC implements IrisService {
|
||||
Iris.error("EngineSVC: Failed to unload for " + name);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, offset + 1000, 2000, TimeUnit.MILLISECONDS);
|
||||
}, offset + TRIM_PERIOD / 2, TRIM_PERIOD, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -89,7 +89,7 @@ public class IrisComplex implements DataProvider {
|
||||
}
|
||||
|
||||
public IrisComplex(Engine engine, boolean simple) {
|
||||
int cacheSize = IrisSettings.get().getPerformance().getCacheSize();
|
||||
int cacheSize = IrisSettings.get().getPerformance().getNoiseCacheSize();
|
||||
IrisBiome emptyBiome = new IrisBiome();
|
||||
UUID focusUUID = UUID.nameUUIDFromBytes("focus".getBytes());
|
||||
this.rng = new RNG(engine.getSeedManager().getComplex());
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -86,11 +86,13 @@ public class IrisEngineMantle implements EngineMantle {
|
||||
.map(components::get)
|
||||
.map(components -> {
|
||||
int radius = components.stream()
|
||||
.filter(MantleComponent::isEnabled)
|
||||
.mapToInt(MantleComponent::getRadius)
|
||||
.max()
|
||||
.orElse(0);
|
||||
return new Pair<>(List.copyOf(components), radius);
|
||||
})
|
||||
.filter(pair -> !pair.getA().isEmpty())
|
||||
.toList();
|
||||
|
||||
int radius = 0;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
package com.volmit.iris.engine.framework;
|
||||
|
||||
import com.volmit.iris.util.mantle.MantleChunk;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
@@ -28,5 +29,5 @@ public interface BlockUpdater {
|
||||
|
||||
void updateChunk(Chunk c);
|
||||
|
||||
void update(int x, int y, int z, Chunk c, RNG rf);
|
||||
void update(int x, int y, int z, Chunk c, MantleChunk mc, RNG rf);
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.format.C;
|
||||
import com.volmit.iris.util.function.Function2;
|
||||
import com.volmit.iris.util.hunk.Hunk;
|
||||
import com.volmit.iris.util.mantle.MantleChunk;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.BlockPosition;
|
||||
import com.volmit.iris.util.math.M;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer;
|
||||
import com.volmit.iris.util.noise.CNG;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
@@ -45,7 +44,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
|
||||
private final CNG cng;
|
||||
|
||||
public MantleJigsawComponent(EngineMantle engineMantle) {
|
||||
super(engineMantle, ReservedFlag.JIGSAW, 2);
|
||||
super(engineMantle, ReservedFlag.JIGSAW, 1);
|
||||
cng = NoiseStyle.STATIC.create(new RNG(jigsaw()));
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ public class IrisDepositModifier extends EngineAssignedModifier<BlockData> {
|
||||
if (y > k.getMaxHeight() || y < k.getMinHeight() || y > height - 2)
|
||||
continue;
|
||||
|
||||
for (BlockVector j : clump.getBlocks().keySet()) {
|
||||
for (BlockVector j : clump.getBlocks().keys()) {
|
||||
int nx = j.getBlockX() + x;
|
||||
int ny = j.getBlockY() + y;
|
||||
int nz = j.getBlockZ() + z;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -122,6 +122,10 @@ public class IrisCompat {
|
||||
private static KList<IrisCompatabilityBlockFilter> getDefaultBlockCompatabilityFilters() {
|
||||
KList<IrisCompatabilityBlockFilter> filters = new KList<>();
|
||||
|
||||
filters.add(new IrisCompatabilityBlockFilter("CHAIN", "IRON_CHAIN"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("GRASS", "SHORT_GRASS"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("SHORT_GRASS", "GRASS"));
|
||||
|
||||
// Below 1.16
|
||||
filters.add(new IrisCompatabilityBlockFilter("WEEPING_VINES", "NETHER_FENCE"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("WEEPING_VINES_PLANT", "NETHER_FENCE"));
|
||||
@@ -160,7 +164,7 @@ public class IrisCompat {
|
||||
filters.add(new IrisCompatabilityBlockFilter("CRACKED_NETHER_BRICKS", "NETHER_BRICKS"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("CHISELED_NETHER_BRICKS", "NETHER_BRICKS"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("NETHER_FENCE", "LEGACY_NETHER_FENCE"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("CHAIN", "IRON_BARS"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("IRON_CHAIN", "IRON_BARS"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("NETHERITE_BLOCK", "QUARTZ_BLOCK"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("BLACKSTONE", "COBBLESTONE"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("BASALT", "STONE"));
|
||||
@@ -254,7 +258,6 @@ public class IrisCompat {
|
||||
filters.add(new IrisCompatabilityBlockFilter("BAMBOO", "BIRCH_FENCE"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("BAMBOO_SAPLING", "BIRCH_SAPLING"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("POTTED_BAMBOO", "POTTED_BIRCH_SAPLING"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("GRASS", "SHORT_GRASS"));
|
||||
|
||||
return filters;
|
||||
}
|
||||
|
||||
@@ -249,14 +249,18 @@ public class IrisDimension extends IrisRegistrant {
|
||||
@Desc("A list of globally applied pre-processors")
|
||||
@ArrayType(type = IrisPreProcessors.class)
|
||||
private KList<IrisPreProcessors> globalPreProcessors = new KList<>();
|
||||
@Desc("A list of scripts executed on engine setup")
|
||||
@Desc("A list of scripts executed on engine setup\nFile extension: .engine.kts")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@ArrayType(type = String.class, min = 1)
|
||||
private KList<String> engineScripts = new KList<>();
|
||||
@Desc("A list of scripts executed on data setup")
|
||||
@Desc("A list of scripts executed on data setup\nFile extension: .data.kts")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@ArrayType(type = String.class, min = 1)
|
||||
private KList<String> dataScripts = new KList<>();
|
||||
@Desc("A list of scripts executed on chunk update\nFile extension: .update.kts")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@ArrayType(type = String.class, min = 1)
|
||||
private KList<String> chunkUpdateScripts = new KList<>();
|
||||
@Desc("Use legacy rarity instead of modern one\nWARNING: Changing this may break expressions and image maps")
|
||||
private boolean legacyRarity = true;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<>();
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ public class IrisGeneratorStyle {
|
||||
private String expression = null;
|
||||
@Desc("Use an Image map instead of a generated value")
|
||||
private IrisImageMap imageMap = null;
|
||||
@Desc("Instead of using the style property, use a custom noise generator to represent this style.")
|
||||
@Desc("Instead of using the style property, use a custom noise generator to represent this style.\nFile extension: .noise.kts")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
private String script = null;
|
||||
@MinNumber(0.00001)
|
||||
|
||||
@@ -30,18 +30,15 @@ import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.context.IrisContext;
|
||||
import com.volmit.iris.util.data.B;
|
||||
import com.volmit.iris.util.data.IrisCustomData;
|
||||
import com.volmit.iris.util.data.VectorMap;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.interpolation.IrisInterpolation;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.math.AxisAlignedBB;
|
||||
import com.volmit.iris.util.math.BlockPosition;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.math.*;
|
||||
import com.volmit.iris.util.matter.MatterMarker;
|
||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.scheduling.IrisLock;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
import com.volmit.iris.util.scheduling.jobs.Job;
|
||||
import com.volmit.iris.util.stream.ProceduralStream;
|
||||
@@ -65,7 +62,10 @@ import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@@ -75,17 +75,17 @@ public class IrisObject extends IrisRegistrant {
|
||||
protected static final BlockData VAIR = B.get("VOID_AIR");
|
||||
protected static final BlockData VAIR_DEBUG = B.get("COBWEB");
|
||||
protected static final BlockData[] SNOW_LAYERS = new BlockData[]{B.get("minecraft:snow[layers=1]"), B.get("minecraft:snow[layers=2]"), B.get("minecraft:snow[layers=3]"), B.get("minecraft:snow[layers=4]"), B.get("minecraft:snow[layers=5]"), B.get("minecraft:snow[layers=6]"), B.get("minecraft:snow[layers=7]"), B.get("minecraft:snow[layers=8]")};
|
||||
protected transient final IrisLock readLock = new IrisLock("read-conclock");
|
||||
protected transient final Lock readLock;
|
||||
protected transient final Lock writeLock;
|
||||
@Getter
|
||||
@Setter
|
||||
protected transient volatile boolean smartBored = false;
|
||||
@Getter
|
||||
@Setter
|
||||
protected transient IrisLock lock = new IrisLock("Preloadcache");
|
||||
@Setter
|
||||
protected transient AtomicCache<AxisAlignedBB> aabb = new AtomicCache<>();
|
||||
private KMap<BlockVector, BlockData> blocks;
|
||||
private KMap<BlockVector, TileData> states;
|
||||
@Getter
|
||||
private VectorMap<BlockData> blocks;
|
||||
@Getter
|
||||
private VectorMap<TileData> states;
|
||||
@Getter
|
||||
@Setter
|
||||
private int w;
|
||||
@@ -97,15 +97,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;
|
||||
}
|
||||
|
||||
@@ -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<>();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
220
core/src/main/java/com/volmit/iris/util/data/VectorMap.java
Normal file
220
core/src/main/java/com/volmit/iris/util/data/VectorMap.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -16,7 +16,8 @@ public enum ReservedFlag implements MantleFlag {
|
||||
TILE,
|
||||
CUSTOM,
|
||||
DISCOVERED,
|
||||
CUSTOM_ACTIVE;
|
||||
CUSTOM_ACTIVE,
|
||||
SCRIPT;
|
||||
|
||||
@Override
|
||||
public boolean isCustom() {
|
||||
|
||||
26
core/src/main/java/com/volmit/iris/util/math/Vector3i.java
Normal file
26
core/src/main/java/com/volmit/iris/util/math/Vector3i.java
Normal 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
Reference in New Issue
Block a user