mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-07-23 07:10:51 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d3edff459 | |||
| e06724fcf6 | |||
| b8219fac1b | |||
| bddc061f46 | |||
| bf6af9a58d | |||
| aaf2f2f8a6 | |||
| dc8cf0ad38 | |||
| bd07f5d325 | |||
| bd722fdacb | |||
| d5ec6a18a4 | |||
| 2f16c0cfb7 | |||
| f7ac827692 | |||
| bddc62f385 | |||
| 68a214edb5 | |||
| 49d2392c80 | |||
| fcbbd2135b | |||
| c3442ab2ce | |||
| fd3971018b | |||
| b440d0257d | |||
| 42a26a1de2 | |||
| c8eab22427 | |||
| fa3e35f702 | |||
| cf0bc81778 | |||
| bef99f18c3 | |||
| 96a384c09c | |||
| d61b2205c0 | |||
| ebdfb94392 | |||
| 1c5fe016cb | |||
| 0957b9baf2 | |||
| 7570064b1a | |||
| e461c1e199 | |||
| 35b879f0df | |||
| ba6fac5422 | |||
| 2577344ac0 |
+40
-22
@@ -1,5 +1,8 @@
|
||||
import com.volmit.nmstools.NMSToolsExtension
|
||||
import com.volmit.nmstools.NMSToolsPlugin
|
||||
import de.undercouch.gradle.tasks.download.Download
|
||||
import xyz.jpenilla.runpaper.task.RunServer
|
||||
import xyz.jpenilla.runtask.service.DownloadsAPIService
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
/*
|
||||
@@ -22,18 +25,19 @@ import kotlin.system.exitProcess
|
||||
|
||||
buildscript {
|
||||
repositories.maven("https://jitpack.io")
|
||||
dependencies.classpath("com.github.VolmitSoftware:NMSTools:c88961416f")
|
||||
dependencies.classpath("com.github.VolmitSoftware:NMSTools:c5cbc46ce6")
|
||||
}
|
||||
|
||||
plugins {
|
||||
java
|
||||
`java-library`
|
||||
alias(libs.plugins.shadow)
|
||||
alias(libs.plugins.download)
|
||||
alias(libs.plugins.runPaper)
|
||||
}
|
||||
|
||||
group = "com.volmit"
|
||||
version = "3.8.2-1.20.1-1.21.10"
|
||||
version = "3.7.2-1.20.1-1.21.8"
|
||||
|
||||
apply<ApiGenerator>()
|
||||
|
||||
@@ -55,16 +59,14 @@ registerCustomOutputTaskUnix("PixelMac", "/Users/test/Desktop/mcserver/plugins")
|
||||
registerCustomOutputTaskUnix("CrazyDev22LT", "/home/julian/Desktop/server/plugins")
|
||||
// ==============================================================
|
||||
|
||||
val serverMinHeap = "10G"
|
||||
val serverMaxHeap = "10G"
|
||||
val additionalFlags = "-XX:+AlwaysPreTouch"
|
||||
val serverMinHeap = "2G"
|
||||
val serverMaxHeap = "8G"
|
||||
//Valid values are: none, truecolor, indexed256, indexed16, indexed8
|
||||
val color = "truecolor"
|
||||
val errorReporting = "true" == findProperty("errorReporting")
|
||||
val errorReporting = findProperty("errorReporting") as Boolean? ?: false
|
||||
|
||||
val nmsBindings = mapOf(
|
||||
"v1_21_R6" to "1.21.10-R0.1-SNAPSHOT",
|
||||
"v1_21_R5" to "1.21.8-R0.1-SNAPSHOT",
|
||||
"v1_21_R5" to "1.21.7-R0.1-SNAPSHOT",
|
||||
"v1_21_R4" to "1.21.5-R0.1-SNAPSHOT",
|
||||
"v1_21_R3" to "1.21.4-R0.1-SNAPSHOT",
|
||||
"v1_21_R2" to "1.21.3-R0.1-SNAPSHOT",
|
||||
@@ -75,20 +77,27 @@ 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>()
|
||||
|
||||
nmsBinding {
|
||||
repositories {
|
||||
maven("https://libraries.minecraft.net")
|
||||
}
|
||||
|
||||
extensions.configure(NMSToolsExtension::class) {
|
||||
jvm = jvmVersion.getOrDefault(key, 21)
|
||||
version = value
|
||||
type = NMSBinding.Type.DIRECT
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(project(":core"))
|
||||
compileOnly(rootProject.libs.annotations)
|
||||
compileOnly(rootProject.libs.byteBuddy.core)
|
||||
compileOnly(rootProject.libs.platformUtils) {
|
||||
isTransitive = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,25 +114,33 @@ 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 included: Configuration by configurations.creating
|
||||
val jarJar: Configuration by configurations.creating
|
||||
dependencies {
|
||||
for (key in nmsBindings.keys) {
|
||||
included(project(":nms:$key", "reobf"))
|
||||
tasks.register<RunServer>("runFolia-$key") {
|
||||
group = "servers"
|
||||
downloadsApiService = DownloadsAPIService.folia(project)
|
||||
minecraftVersion(value.split("-")[0])
|
||||
minHeapSize = serverMinHeap
|
||||
maxHeapSize = serverMaxHeap
|
||||
pluginJars(tasks.jar.flatMap { it.archiveFile })
|
||||
javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(jvmVersion.getOrDefault(key, 21))}
|
||||
runDirectory.convention(layout.buildDirectory.dir("run/$key"))
|
||||
systemProperty("disable.watchdog", "")
|
||||
systemProperty("net.kyori.ansi.colorLevel", color)
|
||||
systemProperty("com.mojang.eula.agree", true)
|
||||
systemProperty("iris.suppressReporting", !errorReporting)
|
||||
jvmArgs("-javaagent:${project(":core:agent").tasks.jar.flatMap { it.archiveFile }.get().asFile.absolutePath}")
|
||||
}
|
||||
included(project(":core", "shadow"))
|
||||
jarJar(project(":core:agent"))
|
||||
}
|
||||
|
||||
tasks {
|
||||
jar {
|
||||
inputs.files(included)
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
from(jarJar, provider { included.resolve().map(::zipTree) })
|
||||
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 })
|
||||
archiveFileName.set("Iris-${project.version}.jar")
|
||||
}
|
||||
|
||||
@@ -198,6 +215,7 @@ allprojects {
|
||||
maven("https://mvn.lumine.io/repository/maven-public/") // mythic
|
||||
maven("https://nexus.phoenixdevt.fr/repository/maven-public/") //MMOItems
|
||||
maven("https://repo.onarandombox.com/content/groups/public/") //Multiverse Core
|
||||
maven("https://repo.thenextlvl.net/releases") //Worlds
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
plugins {
|
||||
kotlin("jvm") version embeddedKotlinVersion
|
||||
kotlin("jvm") version "2.0.20"
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
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)
|
||||
+18
-18
@@ -67,16 +67,21 @@ dependencies {
|
||||
isTransitive = false
|
||||
}
|
||||
compileOnly(libs.multiverseCore)
|
||||
compileOnly(libs.worlds)
|
||||
|
||||
// Shaded
|
||||
implementation(slimjarHelper("spigot"))
|
||||
implementation(rootProject.libs.platformUtils) {
|
||||
isTransitive = false
|
||||
}
|
||||
|
||||
// Dynamically Loaded
|
||||
slim(libs.paralithic)
|
||||
slim(libs.paperlib)
|
||||
slim(libs.adventure.api)
|
||||
slim(libs.adventure.minimessage)
|
||||
slim(libs.adventure.platform)
|
||||
slim(libs.adventure.gson)
|
||||
slim(libs.adventure.legacy)
|
||||
slim(libs.bstats)
|
||||
slim(libs.sentry)
|
||||
|
||||
@@ -108,6 +113,11 @@ dependencies {
|
||||
slim(libs.mavenCore)
|
||||
}
|
||||
}
|
||||
|
||||
constraints {
|
||||
slim(libs.gson)
|
||||
compileOnly(libs.gson)
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
@@ -115,7 +125,7 @@ java {
|
||||
}
|
||||
|
||||
sentry {
|
||||
url = "http://sentry.volmit.com:8080"
|
||||
url = "http://sentry.volmit.com:8080/"
|
||||
autoInstallation.enabled = false
|
||||
includeSourceContext = true
|
||||
|
||||
@@ -131,8 +141,7 @@ slimJar {
|
||||
))
|
||||
|
||||
relocate("com.dfsek.paralithic", "$lib.paralithic")
|
||||
relocate("io.papermc.lib", "$lib.paper")
|
||||
relocate("net.kyori", "$lib.kyori")
|
||||
relocate("net.kyori.audience", "$lib.audience")
|
||||
relocate("org.bstats", "$lib.metrics")
|
||||
relocate("io.sentry", "$lib.sentry")
|
||||
relocate("org.apache.maven", "$lib.maven")
|
||||
@@ -142,7 +151,6 @@ 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 {
|
||||
@@ -175,28 +183,20 @@ tasks {
|
||||
relocate("io.github.slimjar", "$lib.slimjar")
|
||||
exclude("modules/loader-agent.isolated-jar")
|
||||
}
|
||||
|
||||
sentryCollectSourcesJava {
|
||||
dependsOn(generateTemplates)
|
||||
}
|
||||
}
|
||||
|
||||
val templateSource = file("src/main/templates")
|
||||
val templateDest = layout.buildDirectory.dir("generated/sources/templates")!!
|
||||
val templateDest = layout.buildDirectory.dir("generated/sources/templates")
|
||||
val generateTemplates = tasks.register<Copy>("generateTemplates") {
|
||||
inputs.properties(
|
||||
"environment" to when {
|
||||
project.hasProperty("release") -> "production"
|
||||
project.hasProperty("argghh") -> "Argghh!"
|
||||
else -> "development"
|
||||
},
|
||||
"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 } ?: run {
|
||||
this.logger.error("Git commit hash not found", res.exceptionOrNull())
|
||||
.takeIf { it.length == 40 } ?: {
|
||||
logger.error("Git commit hash not found", res.exceptionOrNull())
|
||||
"unknown"
|
||||
}
|
||||
}()
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.volmit.iris.core.link.IrisPapiExpansion;
|
||||
import com.volmit.iris.core.link.MultiverseCoreLink;
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.core.nms.INMS;
|
||||
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
||||
import com.volmit.iris.core.pregenerator.LazyPregenerator;
|
||||
import com.volmit.iris.core.service.StudioSVC;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
@@ -42,6 +43,7 @@ import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.exceptions.IrisException;
|
||||
import com.volmit.iris.util.format.C;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.function.NastyRunnable;
|
||||
import com.volmit.iris.util.io.FileWatcher;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
@@ -51,15 +53,17 @@ import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.misc.Bindings;
|
||||
import com.volmit.iris.util.misc.SlimJar;
|
||||
import com.volmit.iris.util.misc.getHardware;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import com.volmit.iris.util.plugin.IrisService;
|
||||
import com.volmit.iris.util.plugin.VolmitPlugin;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.plugin.chunk.ChunkTickets;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.Queue;
|
||||
import com.volmit.iris.util.scheduling.ShurikenQueue;
|
||||
import lombok.NonNull;
|
||||
import de.crazydev22.platformutils.Platform;
|
||||
import de.crazydev22.platformutils.PlatformUtils;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.command.Command;
|
||||
@@ -77,10 +81,14 @@ import java.io.*;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
|
||||
import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware;
|
||||
|
||||
@SuppressWarnings("CanBeFinal")
|
||||
public class Iris extends VolmitPlugin implements Listener {
|
||||
private static final Queue<Runnable> syncJobs = new ShurikenQueue<>();
|
||||
@@ -90,7 +98,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
public static MultiverseCoreLink linkMultiverseCore;
|
||||
public static IrisCompat compat;
|
||||
public static FileWatcher configWatcher;
|
||||
public static ChunkTickets tickets;
|
||||
public static Platform platform;
|
||||
private static VolmitSender sender;
|
||||
private static Thread shutdownHook;
|
||||
|
||||
@@ -302,19 +310,21 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
public static void info(String format, Object... args) {
|
||||
msg(C.WHITE + String.format(format, args));
|
||||
}
|
||||
public static void safeguard(String format, Object... args) {
|
||||
msg(C.RESET + String.format(format, args));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void later(NastyRunnable object) {
|
||||
try {
|
||||
Bukkit.getScheduler().scheduleAsyncDelayedTask(instance, () ->
|
||||
{
|
||||
platform.getAsyncScheduler().runDelayed(task -> {
|
||||
try {
|
||||
object.run();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}, RNG.r.i(100, 1200));
|
||||
}, RNG.r.i(5, 60), TimeUnit.SECONDS);
|
||||
} catch (IllegalPluginAccessException ignored) {
|
||||
|
||||
}
|
||||
@@ -411,7 +421,6 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
pw.println();
|
||||
pw.println();
|
||||
}
|
||||
pw.println("[%%__USER__%%,%%__RESOURCE__%%,%%__PRODUCT__%%,%%__BUILTBYBIT__%%]");
|
||||
|
||||
pw.close();
|
||||
Iris.info("DUMPED! See " + fi.getAbsolutePath());
|
||||
@@ -435,22 +444,23 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
|
||||
private void enable() {
|
||||
services = new KMap<>();
|
||||
platform = PlatformUtils.createPlatform(this);
|
||||
setupAudience();
|
||||
Bindings.setupSentry();
|
||||
initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class<? extends IrisService>) i.getClass(), (IrisService) i));
|
||||
IO.delete(new File("iris"));
|
||||
compat = IrisCompat.configured(getDataFile("compat.json"));
|
||||
ServerConfigurator.configure();
|
||||
IrisSafeguard.execute();
|
||||
IrisSafeguard.IrisSafeguardSystem();
|
||||
getSender().setTag(getTag());
|
||||
IrisSafeguard.splash();
|
||||
tickets = new ChunkTickets();
|
||||
IrisSafeguard.splash(true);
|
||||
linkMultiverseCore = new MultiverseCoreLink();
|
||||
configWatcher = new FileWatcher(getDataFile("settings.json"));
|
||||
services.values().forEach(IrisService::onEnable);
|
||||
services.values().forEach(this::registerListener);
|
||||
addShutdownHook();
|
||||
J.s(() -> {
|
||||
//J.a(IrisSafeguard::suggestPaper); //TODO reimplement this
|
||||
J.a(() -> IO.delete(getTemp()));
|
||||
J.a(LazyPregenerator::loadLazyGenerators, 100);
|
||||
J.a(this::bstats);
|
||||
@@ -458,6 +468,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
J.sr(this::tickQueue, 0);
|
||||
J.s(this::setupPapi);
|
||||
J.a(ServerConfigurator::configure, 20);
|
||||
IrisSafeguard.splash(false);
|
||||
|
||||
autoStartStudio();
|
||||
checkForBukkitWorlds(s -> true);
|
||||
@@ -499,8 +510,13 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
WorldCreator c = new WorldCreator(s)
|
||||
.generator(gen)
|
||||
.environment(dim.getEnvironment());
|
||||
INMS.get().createWorld(c);
|
||||
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
|
||||
INMS.get().createWorldAsync(c)
|
||||
.thenAccept(w -> Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"))
|
||||
.exceptionally(e -> {
|
||||
Iris.error("Failed to load world " + s + "!");
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
Iris.error("Failed to load world " + s + "!");
|
||||
e.printStackTrace();
|
||||
@@ -519,10 +535,9 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
Player r = new KList<>(getServer().getOnlinePlayers()).getRandom();
|
||||
Iris.service(StudioSVC.class).open(r != null ? new VolmitSender(r) : getSender(), 1337, IrisSettings.get().getGenerator().getDefaultWorldType(), (w) -> {
|
||||
J.s(() -> {
|
||||
var spawn = w.getSpawnLocation();
|
||||
for (Player i : getServer().getOnlinePlayers()) {
|
||||
i.setGameMode(GameMode.SPECTATOR);
|
||||
i.teleport(spawn);
|
||||
platform.teleportAsync(i, new Location(w, 0, 200, 0));
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -551,12 +566,11 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
enable();
|
||||
super.onEnable();
|
||||
Bukkit.getPluginManager().registerEvents(this, this);
|
||||
setupChecks();
|
||||
}
|
||||
|
||||
public void onDisable() {
|
||||
if (IrisSafeguard.isForceShutdown()) return;
|
||||
services.values().forEach(IrisService::onDisable);
|
||||
Bukkit.getScheduler().cancelTasks(this);
|
||||
HandlerList.unregisterAll((Plugin) this);
|
||||
postShutdown.forEach(Runnable::run);
|
||||
super.onDisable();
|
||||
@@ -582,7 +596,49 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
|
||||
@Override
|
||||
public String getTag(String subTag) {
|
||||
return IrisSafeguard.mode().tag(subTag);
|
||||
if (unstablemode) {
|
||||
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.RED + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
|
||||
}
|
||||
if (warningmode) {
|
||||
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.GOLD + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
|
||||
}
|
||||
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.IRIS + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
|
||||
|
||||
}
|
||||
|
||||
private boolean setupChecks() {
|
||||
boolean passed = true;
|
||||
Iris.info("Version Information: " + instance.getServer().getVersion() + " | " + instance.getServer().getBukkitVersion());
|
||||
if (INMS.get() instanceof NMSBinding1X) {
|
||||
passed = false;
|
||||
Iris.warn("============================================");
|
||||
Iris.warn("=");
|
||||
Iris.warn("=");
|
||||
Iris.warn("=");
|
||||
Iris.warn("Iris is not compatible with this version of Minecraft.");
|
||||
Iris.warn("=");
|
||||
Iris.warn("=");
|
||||
Iris.warn("=");
|
||||
Iris.warn("============================================");
|
||||
}
|
||||
|
||||
try {
|
||||
Class.forName("io.papermc.paper.configuration.PaperConfigurations");
|
||||
} catch (ClassNotFoundException e) {
|
||||
Iris.info(C.RED + "Iris requires paper or above to function properly..");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
Class.forName("org.purpurmc.purpur.PurpurConfig");
|
||||
} catch (ClassNotFoundException e) {
|
||||
Iris.info("We recommend using Purpur for the best experience with Iris.");
|
||||
Iris.info("Purpur is a fork of Paper that is optimized for performance and stability.");
|
||||
Iris.info("Plugins that work on Spigot / Paper work on Purpur.");
|
||||
Iris.info("You can download it here: https://purpurmc.org");
|
||||
return false;
|
||||
}
|
||||
return passed;
|
||||
}
|
||||
|
||||
private void checkConfigHotload() {
|
||||
@@ -690,11 +746,88 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
}
|
||||
|
||||
public void splash() {
|
||||
Iris.info("Server type & version: " + Bukkit.getName() + " v" + Bukkit.getVersion());
|
||||
if (!IrisSettings.get().getGeneral().isSplashLogoStartup()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String padd = Form.repeat(" ", 8);
|
||||
String padd2 = Form.repeat(" ", 4);
|
||||
String[] info = {"", "", "", "", "", padd2 + C.IRIS + " Iris", padd2 + C.GRAY + " by " + "<rainbow>Volmit Software", padd2 + C.GRAY + " v" + C.IRIS + getDescription().getVersion()};
|
||||
if (unstablemode) {
|
||||
info = new String[]{"", "", "", "", "", padd2 + C.RED + " Iris", padd2 + C.GRAY + " by " + C.DARK_RED + "Volmit Software", padd2 + C.GRAY + " v" + C.RED + getDescription().getVersion()};
|
||||
}
|
||||
if (warningmode) {
|
||||
info = new String[]{"", "", "", "", "", padd2 + C.GOLD + " Iris", padd2 + C.GRAY + " by " + C.GOLD + "Volmit Software", padd2 + C.GRAY + " v" + C.GOLD + getDescription().getVersion()};
|
||||
}
|
||||
|
||||
String[] splashstable = {
|
||||
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
|
||||
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.IRIS + " .(((()))). ",
|
||||
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.IRIS + " .((((((())))))). ",
|
||||
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.IRIS + " ((((((((())))))))) " + C.GRAY + " @",
|
||||
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.IRIS + " ((((((((-))))))))) " + C.GRAY + " @@",
|
||||
padd + C.GRAY + "@@@&&" + C.IRIS + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
|
||||
padd + C.GRAY + "@@" + C.IRIS + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
|
||||
padd + C.GRAY + "@" + C.IRIS + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
|
||||
padd + C.GRAY + "" + C.IRIS + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@",
|
||||
padd + C.GRAY + "" + C.IRIS + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
|
||||
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
|
||||
};
|
||||
|
||||
String[] splashunstable = {
|
||||
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
|
||||
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.RED + " .(((()))). ",
|
||||
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.RED + " .((((((())))))). ",
|
||||
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.RED + " ((((((((())))))))) " + C.GRAY + " @",
|
||||
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.RED + " ((((((((-))))))))) " + C.GRAY + " @@",
|
||||
padd + C.GRAY + "@@@&&" + C.RED + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
|
||||
padd + C.GRAY + "@@" + C.RED + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
|
||||
padd + C.GRAY + "@" + C.RED + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
|
||||
padd + C.GRAY + "" + C.RED + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@",
|
||||
padd + C.GRAY + "" + C.RED + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
|
||||
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
|
||||
};
|
||||
String[] splashwarning = {
|
||||
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
|
||||
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.GOLD + " .(((()))). ",
|
||||
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.GOLD + " .((((((())))))). ",
|
||||
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.GOLD + " ((((((((())))))))) " + C.GRAY + " @",
|
||||
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.GOLD + " ((((((((-))))))))) " + C.GRAY + " @@",
|
||||
padd + C.GRAY + "@@@&&" + C.GOLD + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
|
||||
padd + C.GRAY + "@@" + C.GOLD + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
|
||||
padd + C.GRAY + "@" + C.GOLD + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
|
||||
padd + C.GRAY + "" + C.GOLD + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@",
|
||||
padd + C.GRAY + "" + C.GOLD + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
|
||||
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
|
||||
};
|
||||
String[] splash;
|
||||
File freeSpace = new File(Bukkit.getWorldContainer() + ".");
|
||||
if (unstablemode) {
|
||||
splash = splashunstable;
|
||||
} else if (warningmode) {
|
||||
splash = splashwarning;
|
||||
} else {
|
||||
splash = splashstable;
|
||||
}
|
||||
|
||||
if (!passedserversoftware) {
|
||||
Iris.info("Server type & version: " + C.RED + Bukkit.getVersion());
|
||||
} else { Iris.info("Server type & version: " + Bukkit.getVersion()); }
|
||||
Iris.info("Java: " + getJava());
|
||||
if (getHardware.getProcessMemory() < 5999) {
|
||||
Iris.warn("6GB+ Ram is recommended");
|
||||
Iris.warn("Process Memory: " + getHardware.getProcessMemory() + " MB");
|
||||
}
|
||||
Iris.info("Bukkit distro: " + Bukkit.getName());
|
||||
Iris.info("Custom Biomes: " + INMS.get().countCustomBiomes());
|
||||
setupChecks();
|
||||
printPacks();
|
||||
|
||||
IrisSafeguard.mode().trySplash();
|
||||
for (int i = 0; i < info.length; i++) {
|
||||
splash[i] += info[i];
|
||||
}
|
||||
|
||||
Iris.info("\n\n " + new KList<>(splash).toString("\n") + "\n");
|
||||
}
|
||||
|
||||
private void printPacks() {
|
||||
|
||||
@@ -159,7 +159,7 @@ public class IrisSettings {
|
||||
private IrisSettingsEngineSVC engineSVC = new IrisSettingsEngineSVC();
|
||||
public boolean trimMantleInStudio = false;
|
||||
public int mantleKeepAlive = 30;
|
||||
public int noiseCacheSize = 1_024;
|
||||
public int cacheSize = 4_096;
|
||||
public int resourceLoaderCacheSize = 1_024;
|
||||
public int objectLoaderCacheSize = 4_096;
|
||||
public int scriptLoaderCacheSize = 512;
|
||||
@@ -177,9 +177,6 @@ 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);
|
||||
@@ -188,10 +185,6 @@ 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);
|
||||
}
|
||||
@@ -250,7 +243,6 @@ public class IrisSettings {
|
||||
public int maxBiomeChildDepth = 4;
|
||||
public boolean preventLeafDecay = true;
|
||||
public boolean useMulticore = false;
|
||||
public boolean useMulticoreMantle = false;
|
||||
public boolean offsetNoiseTypes = false;
|
||||
public boolean earlyCustomBlocks = false;
|
||||
}
|
||||
|
||||
@@ -179,11 +179,14 @@ public class ServerConfigurator {
|
||||
Iris.warn("New data pack entries have been installed in Iris! Restarting server!");
|
||||
Iris.warn("This will only happen when your pack changes (updates/first time setup)");
|
||||
Iris.warn("(You can disable this auto restart in iris settings)");
|
||||
if (!Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart")) {
|
||||
Iris.warn("Looks like the restart command didn't work. Stopping the server instead!");
|
||||
Bukkit.shutdown();
|
||||
}
|
||||
J.s(() -> {
|
||||
Iris.warn("Looks like the restart command didn't work. Stopping the server instead!");
|
||||
Bukkit.shutdown();
|
||||
}, 100);
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -31,9 +31,7 @@ import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.object.IrisDimension;
|
||||
import com.volmit.iris.engine.object.IrisPosition;
|
||||
import com.volmit.iris.engine.object.annotations.Snippet;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.context.IrisContext;
|
||||
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||
@@ -54,7 +52,6 @@ import com.volmit.iris.util.nbt.mca.MCAFile;
|
||||
import com.volmit.iris.util.nbt.mca.MCAUtil;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.scheduling.jobs.Job;
|
||||
import lombok.SneakyThrows;
|
||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||
@@ -95,124 +92,6 @@ public class CommandDeveloper implements DecreeExecutor {
|
||||
Iris.reportError(new Exception("This is a test"));
|
||||
}
|
||||
|
||||
@Decree(description = "Dev cmd to fix all the broken objects caused by faulty shrinkwarp")
|
||||
public void fixObjects(
|
||||
@Param(aliases = "dimension", description = "The dimension type to create the world with")
|
||||
IrisDimension type
|
||||
) {
|
||||
if (type == null) {
|
||||
sender().sendMessage("Type cant be null?");
|
||||
return;
|
||||
}
|
||||
|
||||
IrisData dm = IrisData.get(Iris.instance.getDataFolder("packs", type.getLoadKey()));
|
||||
var loader = dm.getObjectLoader();
|
||||
var processed = new KMap<String, IrisPosition>();
|
||||
|
||||
var objects = loader.getPossibleKeys();
|
||||
var pieces = dm.getJigsawPieceLoader().getPossibleKeys();
|
||||
var sender = sender();
|
||||
|
||||
sender.sendMessage(C.IRIS + "Found " + objects.length + " objects in " + type.getLoadKey());
|
||||
sender.sendMessage(C.IRIS + "Found " + pieces.length + " jigsaw pieces in " + type.getLoadKey());
|
||||
|
||||
final int total = objects.length;
|
||||
final AtomicInteger completed = new AtomicInteger();
|
||||
final AtomicInteger changed = new AtomicInteger();
|
||||
|
||||
new Job() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Fixing Objects";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
Arrays.stream(pieces).parallel()
|
||||
.map(dm.getJigsawPieceLoader()::load)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(piece -> {
|
||||
var offset = processed.compute(piece.getObject(), (key, o) -> {
|
||||
if (o != null) return o;
|
||||
var obj = loader.load(key);
|
||||
if (obj == null) return new IrisPosition();
|
||||
|
||||
obj.shrinkwrap();
|
||||
try {
|
||||
if (!obj.getShrinkOffset().isZero()) {
|
||||
changed.incrementAndGet();
|
||||
obj.write(obj.getLoadFile());
|
||||
}
|
||||
completeWork();
|
||||
} catch (IOException e) {
|
||||
Iris.error("Failed to write object " + obj.getLoadKey());
|
||||
e.printStackTrace();
|
||||
return new IrisPosition();
|
||||
}
|
||||
|
||||
return new IrisPosition(obj.getShrinkOffset());
|
||||
});
|
||||
if (offset.getX() == 0 && offset.getY() == 0 && offset.getZ() == 0)
|
||||
return;
|
||||
|
||||
piece.getConnectors().forEach(connector -> connector.setPosition(connector.getPosition().add(offset)));
|
||||
|
||||
try {
|
||||
IO.writeAll(piece.getLoadFile(), dm.getGson().toJson(piece));
|
||||
} catch (IOException e) {
|
||||
Iris.error("Failed to write jigsaw piece " + piece.getLoadKey());
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
Arrays.stream(loader.getPossibleKeys()).parallel()
|
||||
.filter(key -> !processed.containsKey(key))
|
||||
.map(loader::load)
|
||||
.forEach(obj -> {
|
||||
if (obj == null) {
|
||||
completeWork();
|
||||
return;
|
||||
}
|
||||
|
||||
obj.shrinkwrap();
|
||||
if (obj.getShrinkOffset().isZero()) {
|
||||
completeWork();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
obj.write(obj.getLoadFile());
|
||||
completeWork();
|
||||
changed.incrementAndGet();
|
||||
} catch (IOException e) {
|
||||
Iris.error("Failed to write object " + obj.getLoadKey());
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeWork() {
|
||||
completed.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalWork() {
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWorkCompleted() {
|
||||
return completed.get();
|
||||
}
|
||||
}.execute(sender, () -> {
|
||||
var failed = total - completed.get();
|
||||
if (failed != 0) sender.sendMessage(C.IRIS + "" + failed + " objects failed!");
|
||||
if (changed.get() != 0) sender.sendMessage(C.IRIS + "" + changed.get() + " objects had their offsets changed!");
|
||||
else sender.sendMessage(C.IRIS + "No objects had their offsets changed!");
|
||||
});
|
||||
}
|
||||
|
||||
@Decree(description = "Test")
|
||||
public void mantle(@Param(defaultValue = "false") boolean plate, @Param(defaultValue = "21474836474") String name) throws Throwable {
|
||||
var base = Iris.instance.getDataFile("dump", "pv." + name + ".ttp.lz4b.bin");
|
||||
|
||||
@@ -46,16 +46,6 @@ public class CommandEdit implements DecreeExecutor {
|
||||
sender().sendMessage(C.RED + "You must be in a studio world!");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GraphicsEnvironment.isHeadless()) {
|
||||
sender().sendMessage(C.RED + "Cannot open files in headless environments!");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Desktop.isDesktopSupported()) {
|
||||
sender().sendMessage(C.RED + "Desktop is not supported by this environment!");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
@@ -158,13 +157,8 @@ public class CommandIris implements DecreeExecutor {
|
||||
return;
|
||||
}
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
target.teleport(world.getSpawnLocation());
|
||||
new VolmitSender(target).sendMessage(C.GREEN + "You have been teleported to " + world.getName() + ".");
|
||||
}
|
||||
}.runTask(Iris.instance);
|
||||
Iris.platform.teleportAsync(target, world.getSpawnLocation()).thenRun(() ->
|
||||
new VolmitSender(target).sendMessage(C.GREEN + "You have been teleported to " + world.getName() + "."));
|
||||
}
|
||||
|
||||
@Decree(description = "Print version information")
|
||||
|
||||
@@ -38,6 +38,7 @@ 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;
|
||||
@@ -78,9 +79,9 @@ public class CommandObject implements DecreeExecutor {
|
||||
futureBlockChanges.put(block, block.getBlockData());
|
||||
|
||||
if (d instanceof IrisCustomData data) {
|
||||
block.setBlockData(data.getBase(), false);
|
||||
block.setBlockData(data.getBase());
|
||||
Iris.warn("Tried to place custom block at " + x + ", " + y + ", " + z + " which is not supported!");
|
||||
} else block.setBlockData(d, false);
|
||||
} else block.setBlockData(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,21 +124,11 @@ public class CommandObject implements DecreeExecutor {
|
||||
tile.toBukkitTry(world.getBlockAt(xx, yy, zz));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void setData(int xx, int yy, int zz, T data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getData(int xx, int yy, int zz, Class<T> t) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Engine getEngine() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}.sync(world);
|
||||
}
|
||||
|
||||
@Decree(description = "Check the composition of an object")
|
||||
@@ -149,7 +140,7 @@ public class CommandObject implements DecreeExecutor {
|
||||
sender().sendMessage("Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD() + "");
|
||||
sender().sendMessage("Blocks Used: " + NumberFormat.getIntegerInstance().format(o.getBlocks().size()));
|
||||
|
||||
var queue = o.getBlocks().values();
|
||||
Queue<BlockData> queue = o.getBlocks().enqueueValues();
|
||||
Map<Material, Set<BlockData>> unsorted = new HashMap<>();
|
||||
Map<BlockData, Integer> amounts = new HashMap<>();
|
||||
Map<Material, Integer> materials = new HashMap<>();
|
||||
|
||||
@@ -47,20 +47,16 @@ import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.json.JSONArray;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.mantle.MantleChunk;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.math.Spiraler;
|
||||
import com.volmit.iris.util.math.*;
|
||||
import com.volmit.iris.util.noise.CNG;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import com.volmit.iris.util.parallel.SyncExecutor;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.O;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
import com.volmit.iris.util.scheduling.jobs.ParallelRadiusJob;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import com.volmit.iris.util.scheduling.jobs.ParallelQueueJob;
|
||||
import de.crazydev22.platformutils.scheduler.task.Task;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.util.BlockVector;
|
||||
@@ -77,8 +73,8 @@ import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -175,55 +171,76 @@ public class CommandStudio implements DecreeExecutor {
|
||||
PlatformChunkGenerator plat = IrisToolbelt.access(world);
|
||||
Engine engine = plat.getEngine();
|
||||
DecreeContext.touch(sender);
|
||||
try (SyncExecutor executor = new SyncExecutor(20);
|
||||
var service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())
|
||||
) {
|
||||
try (var executor = Iris.platform.createRegionExecutor(20)) {
|
||||
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>();
|
||||
ParallelRadiusJob prep = new ParallelRadiusJob(Integer.MAX_VALUE, service) {
|
||||
ParallelQueueJob<Position2> prep = new ParallelQueueJob<>() {
|
||||
@Override
|
||||
protected void execute(int rX, int rZ) {
|
||||
if (Math.abs(rX) <= radius && Math.abs(rZ) <= radius) {
|
||||
mantle.deleteChunk(rX + x, rZ + z);
|
||||
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());
|
||||
return;
|
||||
}
|
||||
rX += x;
|
||||
rZ += z;
|
||||
chunkMap.put(new Position2(rX, rZ), mantle.getChunk(rX, rZ));
|
||||
mantle.deleteChunk(rX, rZ);
|
||||
chunkMap.put(cpos, mantle.getChunk(cpos.getX(), cpos.getZ()));
|
||||
mantle.deleteChunk(cpos.getX(), cpos.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Preparing Mantle";
|
||||
}
|
||||
}.retarget(radius + rad, 0, 0);
|
||||
};
|
||||
for (int xx = -(radius + rad); xx <= radius + rad; xx++) {
|
||||
for (int zz = -(radius + rad); zz <= radius + rad; zz++) {
|
||||
prep.queue(new Position2(xx, zz));
|
||||
}
|
||||
}
|
||||
CountDownLatch pLatch = new CountDownLatch(1);
|
||||
prep.execute(sender(), pLatch::countDown);
|
||||
pLatch.await();
|
||||
|
||||
|
||||
ParallelRadiusJob job = new ParallelRadiusJob(Integer.MAX_VALUE, service) {
|
||||
ParallelQueueJob<Position2> job = new ParallelQueueJob<>() {
|
||||
@Override
|
||||
protected void execute(int x, int z) {
|
||||
plat.injectChunkReplacement(world, x, z, executor);
|
||||
public void execute(Position2 p) {
|
||||
plat.injectChunkReplacement(world, p.getX(), p.getZ(), executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Regenerating";
|
||||
}
|
||||
}.retarget(radius, x, z);
|
||||
};
|
||||
for (int i = -radius; i <= radius; i++) {
|
||||
for (int j = -radius; j <= radius; j++) {
|
||||
job.queue(new Position2(i + x, j + z));
|
||||
}
|
||||
}
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
job.execute(sender(), latch::countDown);
|
||||
latch.await();
|
||||
|
||||
chunkMap.forEach((pos, chunk) ->
|
||||
mantle.getChunk(pos.getX(), pos.getZ()).copyFrom(chunk));
|
||||
int sections = mantle.getWorldHeight() >> 4;
|
||||
chunkMap.forEach((pos, chunk) -> {
|
||||
var c = mantle.getChunk(pos.getX(), pos.getZ()).use();
|
||||
try {
|
||||
c.copyFlags(chunk);
|
||||
c.clear();
|
||||
for (int y = 0; y < sections; y++) {
|
||||
var slice = chunk.get(y);
|
||||
if (slice == null) continue;
|
||||
var s = c.getOrCreate(y);
|
||||
slice.getSliceMap().forEach(s::putSlice);
|
||||
}
|
||||
} finally {
|
||||
c.release();
|
||||
}
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
sender().sendMessage("Error while regenerating chunks");
|
||||
e.printStackTrace();
|
||||
@@ -315,31 +332,25 @@ public class CommandStudio implements DecreeExecutor {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = player();
|
||||
var scheduler = Iris.platform.getEntityScheduler(player);
|
||||
scheduler.run(() -> {
|
||||
sender().sendMessage(C.GREEN + "Opening inventory now!");
|
||||
player.openInventory(inv);
|
||||
|
||||
O<Integer> ta = new O<>();
|
||||
ta.set(-1);
|
||||
scheduler.runAtFixedRate(refresh -> {
|
||||
if (!player.getOpenInventory().getType().equals(InventoryType.CHEST)) {
|
||||
refresh.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
var sender = sender();
|
||||
var player = player();
|
||||
var engine = engine();
|
||||
if (!add) {
|
||||
inv.clear();
|
||||
}
|
||||
|
||||
ta.set(Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () ->
|
||||
{
|
||||
if (!player.getOpenInventory().getType().equals(InventoryType.CHEST)) {
|
||||
Bukkit.getScheduler().cancelTask(ta.get());
|
||||
sender.sendMessage(C.GREEN + "Opened inventory!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!add) {
|
||||
inv.clear();
|
||||
}
|
||||
|
||||
engine.addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player.getWorld(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ(), 1);
|
||||
}, 0, fast ? 5 : 35));
|
||||
|
||||
sender().sendMessage(C.GREEN + "Opening inventory now!");
|
||||
player().openInventory(inv);
|
||||
engine().addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player.getWorld(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ(), 1);
|
||||
}, null, 1, fast ? 5 : 35);
|
||||
}, null);
|
||||
}
|
||||
|
||||
@Decree(description = "Calculate the chance for each region to generate", origin = DecreeOrigin.PLAYER)
|
||||
@@ -362,7 +373,7 @@ public class CommandStudio implements DecreeExecutor {
|
||||
var loc = player.getLocation();
|
||||
int totalTasks = d * d;
|
||||
AtomicInteger completedTasks = new AtomicInteger(0);
|
||||
int c = J.ar(() -> sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding regions"), 0);
|
||||
Task c = J.ar(() -> sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding regions"), 0);
|
||||
new Spiraler(d, d, (x, z) -> executor.queue(() -> {
|
||||
var region = engine.getRegion((x << 4) + 8, (z << 4) + 8);
|
||||
data.computeIfAbsent(region.getLoadKey(), (k) -> new AtomicInteger(0))
|
||||
@@ -371,7 +382,7 @@ public class CommandStudio implements DecreeExecutor {
|
||||
})).setOffset(loc.getBlockX(), loc.getBlockZ()).drain();
|
||||
executor.complete();
|
||||
multiBurst.close();
|
||||
J.car(c);
|
||||
c.cancel();
|
||||
|
||||
sender.sendMessage(C.GREEN + "Done!");
|
||||
var loader = engine.getData().getRegionLoader();
|
||||
@@ -396,9 +407,7 @@ public class CommandStudio implements DecreeExecutor {
|
||||
var loc = player().getLocation();
|
||||
int totalTasks = d * d;
|
||||
AtomicInteger completedTasks = new AtomicInteger(0);
|
||||
int c = J.ar(() -> {
|
||||
sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding structures");
|
||||
}, 0);
|
||||
var c = J.ar(() -> sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding structures"), 0);
|
||||
|
||||
new Spiraler(d, d, (x, z) -> executor.queue(() -> {
|
||||
var struct = engine.getStructureAt(x, z);
|
||||
@@ -410,7 +419,7 @@ public class CommandStudio implements DecreeExecutor {
|
||||
|
||||
executor.complete();
|
||||
multiBurst.close();
|
||||
J.car(c);
|
||||
if (c != null) c.cancel();
|
||||
|
||||
for (var key : data.keySet()) {
|
||||
var list = data.get(key);
|
||||
@@ -688,14 +697,9 @@ public class CommandStudio implements DecreeExecutor {
|
||||
}
|
||||
|
||||
sender().sendMessage(C.GREEN + "Sending you to the studio world!");
|
||||
var player = player();
|
||||
PaperLib.teleportAsync(player(), Iris.service(StudioSVC.class)
|
||||
.getActiveProject()
|
||||
.getActiveProvider()
|
||||
.getTarget()
|
||||
.getWorld()
|
||||
.spawnLocation()
|
||||
).thenRun(() -> player.setGameMode(GameMode.SPECTATOR));
|
||||
Player player = player();
|
||||
Iris.platform.teleportAsync(player, Iris.service(StudioSVC.class).getActiveProject().getActiveProvider().getTarget().getWorld().spawnLocation());
|
||||
Iris.platform.getEntityScheduler(player).run(() -> player.setGameMode(GameMode.SPECTATOR), null);
|
||||
}
|
||||
|
||||
@Decree(description = "Update your dimension projects VSCode workspace")
|
||||
@@ -711,7 +715,7 @@ public class CommandStudio implements DecreeExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
@Decree(aliases = "find-objects", description = "Get information about nearby structures")
|
||||
@Decree(aliases = "find-objects", description = "Get information about nearby structures", origin = DecreeOrigin.PLAYER)
|
||||
public void objects() {
|
||||
if (!IrisToolbelt.isIrisWorld(player().getWorld())) {
|
||||
sender().sendMessage(C.RED + "You must be in an Iris world");
|
||||
@@ -724,21 +728,29 @@ public class CommandStudio implements DecreeExecutor {
|
||||
sender().sendMessage("You must be in an iris world.");
|
||||
return;
|
||||
}
|
||||
KList<Chunk> chunks = new KList<>();
|
||||
int bx = player().getLocation().getChunk().getX();
|
||||
int bz = player().getLocation().getChunk().getZ();
|
||||
KMap<Position2, CompletableFuture<Chunk>> chunks = new KMap<>();
|
||||
var location = player().getLocation();
|
||||
int bx = location.getBlockX() >> 4;
|
||||
int bz = location.getBlockZ() >> 4;
|
||||
|
||||
Spiraled spiraled = (x, z) -> chunks.putIfAbsent(new Position2(x, z), Iris.platform.getChunkAtAsync(world, x, z));
|
||||
try {
|
||||
Location l = player().getTargetBlockExact(48, FluidCollisionMode.NEVER).getLocation();
|
||||
var player = player();
|
||||
var task = Iris.platform.getEntityScheduler(player).run(() -> {
|
||||
var target = player.getTargetBlockExact(48, FluidCollisionMode.NEVER);
|
||||
if (target == null) return;
|
||||
Location l = target.getLocation();
|
||||
|
||||
int cx = l.getChunk().getX();
|
||||
int cz = l.getChunk().getZ();
|
||||
new Spiraler(3, 3, (x, z) -> chunks.addIfMissing(world.getChunkAt(x + cx, z + cz))).drain();
|
||||
int cx = l.getBlockX() >> 4;
|
||||
int cz = l.getBlockZ() >> 4;
|
||||
new Spiraler(3, 3, (x, z) -> spiraled.on(x + cx, z + cz)).drain();
|
||||
}, null);
|
||||
if (task != null) task.getResult().join();
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
}
|
||||
|
||||
new Spiraler(3, 3, (x, z) -> chunks.addIfMissing(world.getChunkAt(x + bx, z + bz))).drain();
|
||||
new Spiraler(3, 3, (x, z) -> spiraled.on(x + bx, z + bz)).drain();
|
||||
sender().sendMessage("Capturing IGenData from " + chunks.size() + " nearby chunks.");
|
||||
try {
|
||||
File ff = Iris.instance.getDataFile("reports/" + M.ms() + ".txt");
|
||||
@@ -748,11 +760,11 @@ public class CommandStudio implements DecreeExecutor {
|
||||
pw.println("Iris Version: " + Iris.instance.getDescription().getVersion());
|
||||
pw.println("Bukkit Version: " + Bukkit.getBukkitVersion());
|
||||
pw.println("MC Version: " + Bukkit.getVersion());
|
||||
pw.println("PaperSpigot: " + (PaperLib.isPaper() ? "Yup!" : "Nope!"));
|
||||
//pw.println("PaperSpigot: " + (PaperLib.isPaper() ? "Yup!" : "Nope!")); //TODO update this
|
||||
pw.println("Report Captured At: " + new Date());
|
||||
pw.println("Chunks: (" + chunks.size() + "): ");
|
||||
|
||||
for (Chunk i : chunks) {
|
||||
for (Position2 i : chunks.keySet()) {
|
||||
pw.println("- [" + i.getX() + ", " + i.getZ() + "]");
|
||||
}
|
||||
|
||||
@@ -777,25 +789,31 @@ public class CommandStudio implements DecreeExecutor {
|
||||
Iris.reportError(e);
|
||||
}
|
||||
|
||||
KList<String> biomes = new KList<>();
|
||||
KList<String> caveBiomes = new KList<>();
|
||||
KMap<String, KMap<String, KList<String>>> objects = new KMap<>();
|
||||
KSet<String> biomes = new KSet<>();
|
||||
KSet<String> caveBiomes = new KSet<>();
|
||||
KMap<String, KMap<String, KSet<String>>> objects = new KMap<>();
|
||||
|
||||
for (Chunk i : chunks) {
|
||||
for (int j = 0; j < 16; j += 3) {
|
||||
var engine = engine();
|
||||
assert engine != null;
|
||||
|
||||
for (int k = 0; k < 16; k += 3) {
|
||||
|
||||
assert engine() != null;
|
||||
IrisBiome bb = engine().getSurfaceBiome((i.getX() * 16) + j, (i.getZ() * 16) + k);
|
||||
IrisBiome bxf = engine().getCaveBiome((i.getX() * 16) + j, (i.getZ() * 16) + k);
|
||||
biomes.addIfMissing(bb.getName() + " [" + Form.capitalize(bb.getInferredType().name().toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")");
|
||||
caveBiomes.addIfMissing(bxf.getName() + " (" + bxf.getLoadFile().getName() + ")");
|
||||
exportObjects(bb, pw, engine(), objects);
|
||||
exportObjects(bxf, pw, engine(), objects);
|
||||
KList<CompletableFuture<?>> futures = new KList<>(chunks.size());
|
||||
for (var future : chunks.values()) {
|
||||
futures.add(future.thenAccept(i -> {
|
||||
int bX = i.getX() << 4;
|
||||
int bZ = i.getZ() << 4;
|
||||
for (int j = 0; j < 16; j += 3) {
|
||||
for (int k = 0; k < 16; k += 3) {
|
||||
IrisBiome bb = engine.getSurfaceBiome(bX + j, bZ + k);
|
||||
IrisBiome bxf = engine.getCaveBiome(bX + j, bZ + k);
|
||||
biomes.add(bb.getName() + " [" + Form.capitalize(String.valueOf(bb.getInferredType()).toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")");
|
||||
caveBiomes.add(bxf.getName() + " (" + bxf.getLoadFile().getName() + ")");
|
||||
exportObjects(bb, pw, engine, objects);
|
||||
exportObjects(bxf, pw, engine, objects);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).join();
|
||||
|
||||
regions = Objects.requireNonNull(new File(world.getWorldFolder().getPath() + "/region").list()).length;
|
||||
|
||||
@@ -815,6 +833,13 @@ public class CommandStudio implements DecreeExecutor {
|
||||
pw.println("- " + i);
|
||||
}
|
||||
pw.println();
|
||||
pw.println("== Cave Biome Info ==");
|
||||
pw.println("Found " + caveBiomes.size() + " Cave Biome(s): ");
|
||||
|
||||
for (String i : caveBiomes) {
|
||||
pw.println("- " + i);
|
||||
}
|
||||
pw.println();
|
||||
|
||||
pw.println("== Object Info ==");
|
||||
|
||||
@@ -840,8 +865,8 @@ public class CommandStudio implements DecreeExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
private void exportObjects(IrisBiome bb, PrintWriter pw, Engine g, KMap<String, KMap<String, KList<String>>> objects) {
|
||||
String n1 = bb.getName() + " [" + Form.capitalize(bb.getInferredType().name().toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")";
|
||||
private void exportObjects(IrisBiome bb, PrintWriter pw, Engine g, KMap<String, KMap<String, KSet<String>>> objects) {
|
||||
String n1 = bb.getName() + " [" + Form.capitalize(String.valueOf(bb.getInferredType()).toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")";
|
||||
int m = 0;
|
||||
KSet<String> stop = new KSet<>();
|
||||
for (IrisObjectPlacement f : bb.getObjects()) {
|
||||
@@ -866,7 +891,7 @@ public class CommandStudio implements DecreeExecutor {
|
||||
|
||||
String n3 = nn3;
|
||||
objects.computeIfAbsent(n1, (k1) -> new KMap<>())
|
||||
.computeIfAbsent(n2, (k) -> new KList<>()).addIfMissing(n3);
|
||||
.computeIfAbsent(n2, (k) -> new KSet<>()).add(n3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,22 +74,22 @@ public class CommandWhat implements DecreeExecutor {
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
sender().sendMessage("Non-Iris Biome: " + player().getLocation().getBlock().getBiome().name());
|
||||
|
||||
if (player().getLocation().getBlock().getBiome().equals(Biome.CUSTOM)) {
|
||||
try {
|
||||
sender().sendMessage("Data Pack Biome: " + INMS.get().getTrueBiomeBaseKey(player().getLocation()) + " (ID: " + INMS.get().getTrueBiomeBaseId(INMS.get().getTrueBiomeBase(player().getLocation())) + ")");
|
||||
} catch (Throwable ee) {
|
||||
Iris.reportError(ee);
|
||||
}
|
||||
}
|
||||
var loc = player().getLocation();
|
||||
var sender = sender();
|
||||
Iris.platform.getRegionScheduler().run(loc, () -> {
|
||||
var biome = loc.getBlock().getBiome();
|
||||
if (biome != Biome.CUSTOM && biome.getKey().getNamespace().equals("minecraft"))
|
||||
return;
|
||||
sender.sendMessage("Data Pack Biome: " + INMS.get().getTrueBiomeBaseKey(loc) + " (ID: " + INMS.get().getTrueBiomeBaseId(INMS.get().getTrueBiomeBase(loc)) + ")");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Decree(description = "What region am i in?", origin = DecreeOrigin.PLAYER)
|
||||
public void region() {
|
||||
try {
|
||||
Chunk chunk = world().getChunkAt(player().getLocation().getBlockZ() / 16, player().getLocation().getBlockZ() / 16);
|
||||
IrisRegion r = engine().getRegion(chunk);
|
||||
var loc = player().getLocation();
|
||||
IrisRegion r = engine().getRegion(loc);
|
||||
sender().sendMessage("IRegion: " + r.getLoadKey() + " (" + r.getName() + ")");
|
||||
|
||||
} catch (Throwable e) {
|
||||
@@ -98,7 +98,7 @@ public class CommandWhat implements DecreeExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
@Decree(description = "What block am i looking at?", origin = DecreeOrigin.PLAYER)
|
||||
@Decree(description = "What block am i looking at?", origin = DecreeOrigin.PLAYER, sync = true)
|
||||
public void block() {
|
||||
BlockData bd;
|
||||
try {
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
|
||||
package com.volmit.iris.core.edit;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import com.volmit.iris.util.scheduling.AR;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.SR;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
@@ -79,7 +80,7 @@ public class BlockSignal {
|
||||
e.setTicksLived(1);
|
||||
e.setVelocity(new Vector(0, 0, 0));
|
||||
|
||||
new SR(20) {
|
||||
new AR(20) {
|
||||
@Override
|
||||
public void run() {
|
||||
if (e.isDead()) {
|
||||
@@ -87,9 +88,10 @@ public class BlockSignal {
|
||||
return;
|
||||
}
|
||||
|
||||
e.setTicksLived(1);
|
||||
e.teleport(tg.clone());
|
||||
e.setVelocity(new Vector(0, 0, 0));
|
||||
Iris.platform.teleportAsync(e, tg.clone()).thenAccept(b -> {
|
||||
e.setTicksLived(1);
|
||||
e.setVelocity(new Vector(0, 0, 0));
|
||||
}).join();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import de.crazydev22.platformutils.scheduler.task.Task;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
@@ -55,20 +56,20 @@ public class JigsawEditor implements Listener {
|
||||
private final IrisJigsawPiece piece;
|
||||
private final Location origin;
|
||||
private final Cuboid cuboid;
|
||||
private final int ticker;
|
||||
private final Task ticker;
|
||||
private final KMap<IrisPosition, Runnable> falling = new KMap<>();
|
||||
private final ChronoLatch cl = new ChronoLatch(100);
|
||||
private Location target;
|
||||
|
||||
public JigsawEditor(Player player, IrisJigsawPiece piece, IrisObject object, File saveLocation) {
|
||||
if (object == null) throw new RuntimeException("Object is null! " + piece.getObject());
|
||||
editors.compute(player, ($, current) -> {
|
||||
if (current != null) {
|
||||
current.exit();
|
||||
}
|
||||
return this;
|
||||
});
|
||||
if (editors.containsKey(player)) {
|
||||
editors.get(player).close();
|
||||
}
|
||||
|
||||
editors.put(player, this);
|
||||
if (object == null) {
|
||||
throw new RuntimeException("Object is null! " + piece.getObject());
|
||||
}
|
||||
this.object = object;
|
||||
this.player = player;
|
||||
origin = player.getLocation().clone().add(0, 7, 0);
|
||||
@@ -106,21 +107,26 @@ public class JigsawEditor implements Listener {
|
||||
}
|
||||
|
||||
public Location toLocation(IrisPosition i) {
|
||||
return origin.clone()
|
||||
return toBlock(origin.clone()
|
||||
.add(new Vector(i.getX(), i.getY(), i.getZ()))
|
||||
.add(object.getCenter())
|
||||
.getBlock()
|
||||
.getLocation();
|
||||
.add(object.getCenter()));
|
||||
}
|
||||
|
||||
public IrisPosition toPosition(Location l) {
|
||||
return new IrisPosition(l.clone().getBlock().getLocation()
|
||||
return new IrisPosition(l.clone()
|
||||
.subtract(origin.clone())
|
||||
.subtract(object.getCenter())
|
||||
.add(1, 1, 1)
|
||||
.toVector());
|
||||
}
|
||||
|
||||
private Location toBlock(Location location) {
|
||||
location.setX(Math.floor(location.getX()));
|
||||
location.setY(Math.floor(location.getY()));
|
||||
location.setZ(Math.floor(location.getZ()));
|
||||
return location;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(PlayerInteractEvent e) {
|
||||
if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
|
||||
@@ -197,7 +203,7 @@ public class JigsawEditor implements Listener {
|
||||
}
|
||||
|
||||
public void exit() {
|
||||
J.car(ticker);
|
||||
if (ticker != null) ticker.cancel();
|
||||
Iris.instance.unregisterListener(this);
|
||||
try {
|
||||
J.sfut(() -> {
|
||||
|
||||
@@ -763,7 +763,7 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
|
||||
int xx = (int) getWorldX(hx);
|
||||
int zz = (int) getWorldZ(hz);
|
||||
int h = engine.getComplex().getRoundedHeighteightStream().get(xx, zz);
|
||||
player.teleport(new Location(player.getWorld(), xx, h, zz));
|
||||
Iris.platform.teleportAsync(player, new Location(player.getWorld(), xx, h, zz));
|
||||
notify("Teleporting to " + xx + ", " + h + ", " + zz);
|
||||
} else {
|
||||
notify("No player in world, can't teleport.");
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.volmit.iris.core.link;
|
||||
|
||||
import lombok.NonNull;
|
||||
import net.thenextlvl.worlds.api.WorldsProvider;
|
||||
import net.thenextlvl.worlds.api.generator.GeneratorType;
|
||||
import net.thenextlvl.worlds.api.generator.LevelStem;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class FoliaWorldsLink {
|
||||
private static FoliaWorldsLink instance;
|
||||
private final Object provider;
|
||||
|
||||
private FoliaWorldsLink(Object provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public static FoliaWorldsLink get() {
|
||||
if(instance == null) {
|
||||
synchronized (FoliaWorldsLink.class) {
|
||||
try {
|
||||
Server.class.getDeclaredMethod("isGlobalTickThread");
|
||||
instance = new FoliaWorldsLink(Bukkit.getServicesManager().load(WorldsProvider.class));
|
||||
} catch (Throwable e) {
|
||||
instance = new FoliaWorldsLink(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return provider != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CompletableFuture<World> createWorld(@NonNull WorldCreator creator) {
|
||||
if (provider == null) return null;
|
||||
return ((WorldsProvider) provider)
|
||||
.levelBuilder(new File(Bukkit.getWorldContainer(), creator.name()).toPath())
|
||||
.name(creator.name())
|
||||
.seed(creator.seed())
|
||||
.levelStem(switch (creator.environment()) {
|
||||
case CUSTOM, NORMAL -> LevelStem.OVERWORLD;
|
||||
case NETHER -> LevelStem.NETHER;
|
||||
case THE_END -> LevelStem.END;
|
||||
})
|
||||
.chunkGenerator(creator.generator())
|
||||
.biomeProvider(creator.biomeProvider())
|
||||
.generatorType(switch (creator.type()) {
|
||||
case NORMAL -> GeneratorType.NORMAL;
|
||||
case FLAT -> GeneratorType.FLAT;
|
||||
case LARGE_BIOMES -> GeneratorType.LARGE_BIOMES;
|
||||
case AMPLIFIED -> GeneratorType.AMPLIFIED;
|
||||
})
|
||||
.structures(creator.generateStructures())
|
||||
.hardcore(creator.hardcore())
|
||||
.build()
|
||||
.createAsync();
|
||||
}
|
||||
}
|
||||
@@ -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 IrisCustomData.of(blockData, ExternalDataSVC.buildState(blockId, state));
|
||||
return new IrisCustomData(blockData, ExternalDataSVC.buildState(blockId, state));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.volmit.iris.core.link.ExternalDataProvider;
|
||||
import com.volmit.iris.core.link.Identifier;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.data.IrisCustomData;
|
||||
import dev.lone.itemsadder.api.CustomBlock;
|
||||
import dev.lone.itemsadder.api.CustomStack;
|
||||
@@ -18,13 +19,12 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ItemAdderDataProvider extends ExternalDataProvider {
|
||||
|
||||
private volatile Set<String> itemNamespaces = Set.of();
|
||||
private volatile Set<String> blockNamespaces = Set.of();
|
||||
private final KSet<String> itemNamespaces = new KSet<>();
|
||||
private final KSet<String> blockNamespaces = new KSet<>();
|
||||
|
||||
public ItemAdderDataProvider() {
|
||||
super("ItemsAdder");
|
||||
@@ -47,7 +47,7 @@ public class ItemAdderDataProvider extends ExternalDataProvider {
|
||||
if (block == null) {
|
||||
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
|
||||
}
|
||||
return IrisCustomData.of(block.getBaseBlockData(), blockId);
|
||||
return new IrisCustomData(block.getBaseBlockData(), blockId);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -94,9 +94,9 @@ public class ItemAdderDataProvider extends ExternalDataProvider {
|
||||
|
||||
private void updateNamespaces(DataType dataType) {
|
||||
var namespaces = getTypes(dataType).stream().map(Identifier::namespace).collect(Collectors.toSet());
|
||||
if (dataType == DataType.ITEM) itemNamespaces = namespaces;
|
||||
else blockNamespaces = namespaces;
|
||||
Iris.debug("Updated ItemAdder namespaces: " + dataType + " - " + namespaces);
|
||||
var currentNamespaces = dataType == DataType.ITEM ? itemNamespaces : blockNamespaces;
|
||||
currentNamespaces.removeIf(n -> !namespaces.contains(n));
|
||||
currentNamespaces.addAll(namespaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,7 +33,7 @@ public class KGeneratorsDataProvider extends ExternalDataProvider {
|
||||
@Override
|
||||
public @NotNull BlockData getBlockData(@NotNull Identifier blockId, @NotNull KMap<String, String> state) throws MissingResourceException {
|
||||
if (Main.getGenerators().get(blockId.key()) == null) throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
|
||||
return IrisCustomData.of(Material.STRUCTURE_VOID.createBlockData(), ExternalDataSVC.buildState(blockId, state));
|
||||
return new IrisCustomData(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 IrisCustomData.of(B.getAir(), ExternalDataSVC.buildState(blockId, state));
|
||||
return new IrisCustomData(B.getAir(), ExternalDataSVC.buildState(blockId, state));
|
||||
} else if (blockItemContext != null) {
|
||||
return blockItemContext.getBlockData();
|
||||
}
|
||||
|
||||
@@ -49,9 +49,9 @@ public class NexoDataProvider extends ExternalDataProvider {
|
||||
BlockData data = NexoBlocks.blockData(blockId.key());
|
||||
if (data == null)
|
||||
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
|
||||
return IrisCustomData.of(data, blockState);
|
||||
return new IrisCustomData(data, blockState);
|
||||
} else if (NexoFurniture.isFurniture(blockId.key())) {
|
||||
return IrisCustomData.of(B.getAir(), blockState);
|
||||
return new IrisCustomData(B.getAir(), blockState);
|
||||
}
|
||||
|
||||
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
|
||||
|
||||
@@ -50,15 +50,16 @@ import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
@Data
|
||||
public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
private static final KMap<File, IrisData> dataLoaders = new KMap<>();
|
||||
private final File dataFolder;
|
||||
private final int id;
|
||||
private final PackEnvironment environment;
|
||||
private boolean closed = false;
|
||||
private PackEnvironment environment;
|
||||
private ResourceLoader<IrisBiome> biomeLoader;
|
||||
private ResourceLoader<IrisLootTable> lootLoader;
|
||||
private ResourceLoader<IrisRegion> regionLoader;
|
||||
@@ -91,6 +92,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
this.engine = null;
|
||||
this.dataFolder = dataFolder;
|
||||
this.id = RNG.r.imax();
|
||||
this.environment = PackEnvironment.create(this);
|
||||
hotloaded();
|
||||
}
|
||||
|
||||
@@ -103,7 +105,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
}
|
||||
|
||||
public static void dereference() {
|
||||
dataLoaders.values().forEach(IrisData::cleanupEngine);
|
||||
dataLoaders.v().forEach(IrisData::cleanupEngine);
|
||||
}
|
||||
|
||||
public static int cacheSize() {
|
||||
@@ -348,6 +350,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
|
||||
public synchronized void hotloaded() {
|
||||
closed = false;
|
||||
environment.close();
|
||||
possibleSnippets = new KMap<>();
|
||||
builder = new GsonBuilder()
|
||||
.addDeserializationExclusionStrategy(this)
|
||||
@@ -379,7 +382,6 @@ 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();
|
||||
@@ -387,10 +389,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
.map(IrisDimension::getDataScripts)
|
||||
.flatMap(KList::stream)
|
||||
.forEach(environment::execute);
|
||||
|
||||
if (engine != null) {
|
||||
engine.hotload();
|
||||
}
|
||||
}
|
||||
|
||||
public void dump() {
|
||||
@@ -406,33 +404,6 @@ 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 'object' and modify properties about this object before it's used.\nFile extension: .proc.kts")
|
||||
@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.")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@ArrayType(min = 1, type = String.class)
|
||||
private KList<String> preprocessors = new KList<>();
|
||||
|
||||
@@ -46,7 +46,6 @@ 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;
|
||||
@@ -171,6 +170,7 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
|
||||
return possibleKeys;
|
||||
}
|
||||
|
||||
KSet<String> m = new KSet<>();
|
||||
KList<File> files = getFolders();
|
||||
|
||||
if (files == null) {
|
||||
@@ -178,7 +178,6 @@ 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", ""));
|
||||
@@ -320,8 +319,7 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
|
||||
return null;
|
||||
}
|
||||
|
||||
var set = firstAccess;
|
||||
if (set != null) firstAccess.add(name);
|
||||
firstAccess.add(name);
|
||||
return loadCache.get(name);
|
||||
}
|
||||
|
||||
@@ -344,24 +342,21 @@ 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);
|
||||
var set = firstAccess;
|
||||
firstAccess = null;
|
||||
dos.writeInt(set.size());
|
||||
dos.writeInt(firstAccess.size());
|
||||
|
||||
for (String i : set) {
|
||||
for (String i : firstAccess) {
|
||||
dos.writeUTF(i);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,10 +28,9 @@ 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, 10, null);
|
||||
new Version(21, 8, 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"),
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.volmit.iris.core.nms;
|
||||
|
||||
import com.volmit.iris.core.link.Identifier;
|
||||
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||
import com.volmit.iris.core.link.FoliaWorldsLink;
|
||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||
import com.volmit.iris.core.nms.container.BlockProperty;
|
||||
import com.volmit.iris.core.nms.container.Pair;
|
||||
@@ -43,6 +44,7 @@ import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.List;
|
||||
|
||||
public interface INMSBinding {
|
||||
@@ -101,6 +103,15 @@ public interface INMSBinding {
|
||||
return c.createWorld();
|
||||
}
|
||||
|
||||
default CompletableFuture<World> createWorldAsync(WorldCreator c) {
|
||||
try {
|
||||
var link = FoliaWorldsLink.get();
|
||||
return link.isActive() ? link.createWorld(c) : CompletableFuture.completedFuture(createWorld(c));
|
||||
} catch (Throwable e) {
|
||||
return CompletableFuture.failedFuture(e);
|
||||
}
|
||||
}
|
||||
|
||||
int countCustomBiomes();
|
||||
|
||||
void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk);
|
||||
|
||||
@@ -2,24 +2,25 @@ package com.volmit.iris.core.pregenerator;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.service.PreservationSVC;
|
||||
import com.volmit.iris.core.nms.container.Pair;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
import com.volmit.iris.engine.data.cache.Cache;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RollingSequence;
|
||||
import com.volmit.iris.util.plugin.chunk.TicketHolder;
|
||||
import com.volmit.iris.util.profile.LoadBalancer;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -29,7 +30,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 TicketHolder holder;
|
||||
private final KMap<Long, Pair<Long, AtomicInteger>> lastUse = new KMap<>();
|
||||
private final RollingSequence chunksPerSecond = new RollingSequence(5);
|
||||
private final AtomicInteger totalMaxChunks = new AtomicInteger();
|
||||
private final AtomicInteger chunksProcessed = new AtomicInteger();
|
||||
@@ -38,13 +39,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 chunkExecutor = IrisSettings.get().getUpdater().isNativeThreads() ? Executors.newFixedThreadPool(coreLimit) : Executors.newVirtualThreadPerTaskExecutor();
|
||||
private final ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
|
||||
private final ExecutorService chunkExecutor = Executors.newVirtualThreadPerTaskExecutor();
|
||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
private final CountDownLatch latch;
|
||||
private final Engine engine;
|
||||
@@ -53,7 +54,6 @@ public class ChunkUpdater {
|
||||
public ChunkUpdater(World world) {
|
||||
this.engine = IrisToolbelt.access(world).getEngine();
|
||||
this.world = world;
|
||||
this.holder = Iris.tickets.getHolder(world);
|
||||
this.dimensions = calculateWorldDimensions(new File(world.getWorldFolder(), "region"));
|
||||
this.task = dimensions.task();
|
||||
this.totalMaxChunks.set(dimensions.count * 1024);
|
||||
@@ -112,6 +112,7 @@ 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)
|
||||
@@ -126,7 +127,6 @@ public class ChunkUpdater {
|
||||
t.setPriority(Thread.MAX_PRIORITY);
|
||||
t.start();
|
||||
|
||||
Iris.service(PreservationSVC.class).register(t);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -139,6 +139,8 @@ public class ChunkUpdater {
|
||||
|
||||
chunkExecutor.shutdown();
|
||||
chunkExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
scheduler.shutdownNow();
|
||||
unloadAndSaveAllChunks();
|
||||
} catch (Exception ignored) {}
|
||||
@@ -197,16 +199,20 @@ 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);
|
||||
|
||||
removeTickets(x, z);
|
||||
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();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
chunksUpdated.incrementAndGet();
|
||||
chunksProcessed.getAndIncrement();
|
||||
mc.release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +222,7 @@ public class ChunkUpdater {
|
||||
|
||||
for (int dx = -1; dx <= 1; dx++) {
|
||||
for (int dz = -1; dz <= 1; dz++) {
|
||||
if (!PaperLib.isChunkGenerated(world, x + dx, z + dz)) {
|
||||
if (!Iris.platform.isChunkGenerated(world, x + dx, z + dz)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -228,16 +234,41 @@ public class ChunkUpdater {
|
||||
for (int dz = -1; dz <= 1; dz++) {
|
||||
int xx = x + dx;
|
||||
int zz = z + dz;
|
||||
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();
|
||||
});
|
||||
executor.submit(() -> {
|
||||
try {
|
||||
Chunk c;
|
||||
try {
|
||||
c = Iris.platform.getChunkAtAsync(world, xx, zz, false, true)
|
||||
.thenApply(chunk -> {
|
||||
if (chunk != null)
|
||||
chunk.addPluginChunkTicket(Iris.instance);
|
||||
return chunk;
|
||||
}).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
generated.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (c == null) {
|
||||
generated.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!c.isLoaded()) {
|
||||
var future = J.sfut(() -> c.load(false));
|
||||
if (future != null) future.join();
|
||||
}
|
||||
|
||||
if (!Iris.platform.isChunkGenerated(c.getWorld(), xx, zz))
|
||||
generated.set(false);
|
||||
|
||||
var pair = lastUse.computeIfAbsent(Cache.key(c), k -> new Pair<>(0L, new AtomicInteger(-1)));
|
||||
pair.setA(M.ms());
|
||||
pair.getB().updateAndGet(i -> i == -1 ? 1 : ++i);
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,16 +277,27 @@ public class ChunkUpdater {
|
||||
} catch (InterruptedException e) {
|
||||
Iris.info("Interrupted while waiting for chunks to load");
|
||||
}
|
||||
|
||||
if (generated.get()) return true;
|
||||
removeTickets(x, z);
|
||||
return false;
|
||||
return generated.get();
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,6 +310,7 @@ public class ChunkUpdater {
|
||||
return;
|
||||
}
|
||||
|
||||
unloadChunks();
|
||||
world.save();
|
||||
}).get();
|
||||
} catch (Throwable e) {
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.bukkit.World;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
@@ -235,16 +234,13 @@ public class DeepSearchPregenerator extends Thread implements Listener {
|
||||
}
|
||||
save();
|
||||
jobs.remove(world.getName());
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (deepFile.exists()){
|
||||
deepFile.delete();
|
||||
J.sleep(1000);
|
||||
}
|
||||
Iris.info("DeepSearch: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
|
||||
J.a(() -> {
|
||||
while (deepFile.exists()) {
|
||||
deepFile.delete();
|
||||
J.sleep(1000);
|
||||
}
|
||||
}.runTaskLater(Iris.instance, 20L);
|
||||
Iris.info("DeepSearch: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
|
||||
}, 10);
|
||||
} catch (Exception e) {
|
||||
Iris.error("Failed to shutdown DeepSearch for " + world.getName());
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -11,7 +11,6 @@ import com.volmit.iris.util.math.RollingSequence;
|
||||
import com.volmit.iris.util.math.Spiraler;
|
||||
import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -19,7 +18,6 @@ import org.bukkit.World;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -149,23 +147,9 @@ public class LazyPregenerator extends Thread implements Listener {
|
||||
|
||||
private void tickGenerate(Position2 chunk) {
|
||||
executorService.submit(() -> {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
if (PaperLib.isPaper()) {
|
||||
PaperLib.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true)
|
||||
.thenAccept((i) -> {
|
||||
Iris.verbose("Generated Async " + chunk);
|
||||
latch.countDown();
|
||||
});
|
||||
} else {
|
||||
J.s(() -> {
|
||||
world.getChunkAt(chunk.getX(), chunk.getZ());
|
||||
Iris.verbose("Generated " + chunk);
|
||||
latch.countDown();
|
||||
});
|
||||
}
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException ignored) {}
|
||||
Iris.platform.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true).thenAccept((i) -> {
|
||||
Iris.verbose("Generated Async " + chunk);
|
||||
}).join();
|
||||
lazyGeneratedChunks.addAndGet(1);
|
||||
});
|
||||
}
|
||||
@@ -238,16 +222,13 @@ public class LazyPregenerator extends Thread implements Listener {
|
||||
}
|
||||
save();
|
||||
jobs.remove(world.getName());
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (lazyFile.exists()){
|
||||
lazyFile.delete();
|
||||
J.sleep(1000);
|
||||
}
|
||||
Iris.info("LazyGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
|
||||
J.a(() -> {
|
||||
while (lazyFile.exists()){
|
||||
lazyFile.delete();
|
||||
J.sleep(1000);
|
||||
}
|
||||
}.runTaskLater(Iris.instance, 20L);
|
||||
Iris.info("LazyGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
|
||||
}, 20);
|
||||
} catch (Exception e) {
|
||||
Iris.error("Failed to shutdown Lazygen for " + world.getName());
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -17,7 +17,6 @@ import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.apache.logging.log4j.core.util.ExecutorServices;
|
||||
@@ -26,7 +25,6 @@ import org.bukkit.World;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.checkerframework.checker.units.qual.N;
|
||||
|
||||
import java.io.File;
|
||||
@@ -227,7 +225,7 @@ public class TurboPregenerator extends Thread implements Listener {
|
||||
private void tickGenerate(Position2 chunk) {
|
||||
executorService.submit(() -> {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
PaperLib.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true)
|
||||
Iris.platform.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true)
|
||||
.thenAccept((i) -> {
|
||||
latch.countDown();
|
||||
});
|
||||
@@ -302,16 +300,13 @@ public class TurboPregenerator extends Thread implements Listener {
|
||||
}
|
||||
save();
|
||||
jobs.remove(world.getName());
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (turboFile.exists()) {
|
||||
turboFile.delete();
|
||||
J.sleep(1000);
|
||||
}
|
||||
Iris.info("turboGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
|
||||
J.a(() -> {
|
||||
while (turboFile.exists()) {
|
||||
turboFile.delete();
|
||||
J.sleep(1000);
|
||||
}
|
||||
}.runTaskLater(Iris.instance, 20L);
|
||||
Iris.info("turboGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
|
||||
}, 20);
|
||||
} catch (Exception e) {
|
||||
Iris.error("Failed to shutdown turbogen for " + world.getName());
|
||||
e.printStackTrace();
|
||||
|
||||
+9
-8
@@ -24,11 +24,9 @@ public interface PregenCache {
|
||||
|
||||
void write();
|
||||
|
||||
void trim(long unloadDuration);
|
||||
|
||||
static PregenCache create(File directory) {
|
||||
if (directory == null) return EMPTY;
|
||||
return new PregenCacheImpl(directory, 16);
|
||||
return new PregenCacheImpl(directory);
|
||||
}
|
||||
|
||||
default PregenCache sync() {
|
||||
@@ -53,16 +51,19 @@ 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) {}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
+220
@@ -0,0 +1,220 @@
|
||||
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) {}
|
||||
}
|
||||
+6
-8
@@ -1,6 +1,11 @@
|
||||
package com.volmit.iris.core.pregenerator.cache;
|
||||
|
||||
record SynchronizedCache(PregenCache cache) implements PregenCache {
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
class SynchronizedCache implements PregenCache {
|
||||
private final PregenCache cache;
|
||||
|
||||
@Override
|
||||
public boolean isThreadSafe() {
|
||||
return true;
|
||||
@@ -40,11 +45,4 @@ record SynchronizedCache(PregenCache cache) implements PregenCache {
|
||||
cache.write();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trim(long unloadDuration) {
|
||||
synchronized (cache) {
|
||||
cache.trim(unloadDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.volmit.iris.core.pregenerator.methods;
|
||||
|
||||
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.bukkit.World;
|
||||
|
||||
public class AsyncOrMedievalPregenMethod implements PregeneratorMethod {
|
||||
private final PregeneratorMethod method;
|
||||
|
||||
public AsyncOrMedievalPregenMethod(World world, int threads) {
|
||||
method = PaperLib.isPaper() ? new AsyncPregenMethod(world, threads) : new MedievalPregenMethod(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
method.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
method.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
method.save();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod(int x, int z) {
|
||||
return method.getMethod(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRegions(int x, int z, PregenListener listener) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateRegion(int x, int z, PregenListener listener) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateChunk(int x, int z, PregenListener listener) {
|
||||
method.generateChunk(x, z, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mantle getMantle() {
|
||||
return method.getMantle();
|
||||
}
|
||||
}
|
||||
+26
-28
@@ -23,17 +23,17 @@ import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Semaphore;
|
||||
@@ -48,11 +48,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
||||
private final boolean urgent;
|
||||
private final Map<Chunk, Long> lastUse;
|
||||
|
||||
public AsyncPregenMethod(World world, int unusedThreads) {
|
||||
if (!PaperLib.isPaper()) {
|
||||
throw new UnsupportedOperationException("Cannot use PaperAsync on non paper!");
|
||||
}
|
||||
|
||||
public AsyncPregenMethod(World world) {
|
||||
this.world = world;
|
||||
this.executor = IrisSettings.get().getPregen().isUseTicketQueue() ? new TicketExecutor() : new ServiceExecutor();
|
||||
this.threads = IrisSettings.get().getPregen().getMaxConcurrency();
|
||||
@@ -63,26 +59,28 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
||||
|
||||
private void unloadAndSaveAllChunks() {
|
||||
try {
|
||||
J.sfut(() -> {
|
||||
if (world == null) {
|
||||
Iris.warn("World was null somehow...");
|
||||
return;
|
||||
}
|
||||
if (world == null) {
|
||||
Iris.warn("World was null somehow...");
|
||||
return;
|
||||
}
|
||||
|
||||
long minTime = M.ms() - 10_000;
|
||||
lastUse.entrySet().removeIf(i -> {
|
||||
final Chunk chunk = i.getKey();
|
||||
final Long lastUseTime = i.getValue();
|
||||
if (!chunk.isLoaded() || lastUseTime == null)
|
||||
return true;
|
||||
if (lastUseTime < minTime) {
|
||||
chunk.unload();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
world.save();
|
||||
}).get();
|
||||
long minTime = M.ms() - 10_000;
|
||||
KList<CompletableFuture<?>> futures = new KList<>();
|
||||
lastUse.entrySet().removeIf(i -> {
|
||||
final Chunk chunk = i.getKey();
|
||||
final Long lastUseTime = i.getValue();
|
||||
if (!chunk.isLoaded() || lastUseTime == null)
|
||||
return true;
|
||||
if (lastUseTime < minTime) {
|
||||
futures.add(Iris.platform.getRegionScheduler()
|
||||
.run(chunk.getWorld(), chunk.getX(), chunk.getZ(), () -> chunk.unload())
|
||||
.getResult());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
futures.add(Iris.platform.getRegionScheduler().run(world, 0, 0, world::save).getResult());
|
||||
CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).join();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -197,7 +195,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
||||
public void generate(int x, int z, PregenListener listener) {
|
||||
service.submit(() -> {
|
||||
try {
|
||||
PaperLib.getChunkAtAsync(world, x, z, true, urgent).thenAccept((i) -> {
|
||||
Iris.platform.getChunkAtAsync(world, x, z, true, urgent).thenAccept((i) -> {
|
||||
listener.onChunkGenerated(x, z);
|
||||
listener.onChunkCleaned(x, z);
|
||||
if (i == null) return;
|
||||
@@ -222,7 +220,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
||||
private class TicketExecutor implements Executor {
|
||||
@Override
|
||||
public void generate(int x, int z, PregenListener listener) {
|
||||
PaperLib.getChunkAtAsync(world, x, z, true, urgent)
|
||||
Iris.platform.getChunkAtAsync(world, x, z, true, urgent)
|
||||
.exceptionally(e -> {
|
||||
Iris.reportError(e);
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.volmit.iris.core.pregenerator.methods;
|
||||
|
||||
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import org.bukkit.World;
|
||||
|
||||
public class HybridPregenMethod implements PregeneratorMethod {
|
||||
private final PregeneratorMethod inWorld;
|
||||
private final World world;
|
||||
|
||||
public HybridPregenMethod(World world, int threads) {
|
||||
this.world = world;
|
||||
inWorld = new AsyncOrMedievalPregenMethod(world, threads);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod(int x, int z) {
|
||||
return "Hybrid<" + inWorld.getMethod(x, z) + ">";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
inWorld.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
inWorld.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
inWorld.save();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRegions(int x, int z, PregenListener listener) {
|
||||
return inWorld.supportsRegions(x, z, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateRegion(int x, int z, PregenListener listener) {
|
||||
inWorld.generateRegion(x, z, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateChunk(int x, int z, PregenListener listener) {
|
||||
inWorld.generateChunk(x, z, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mantle getMantle() {
|
||||
return inWorld.getMantle();
|
||||
}
|
||||
}
|
||||
-138
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.volmit.iris.core.pregenerator.methods;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class MedievalPregenMethod implements PregeneratorMethod {
|
||||
private final World world;
|
||||
private final KList<CompletableFuture<?>> futures;
|
||||
private final Map<Chunk, Long> lastUse;
|
||||
|
||||
public MedievalPregenMethod(World world) {
|
||||
this.world = world;
|
||||
futures = new KList<>();
|
||||
this.lastUse = new KMap<>();
|
||||
}
|
||||
|
||||
private void waitForChunks() {
|
||||
for (CompletableFuture<?> i : futures) {
|
||||
try {
|
||||
i.get();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
futures.clear();
|
||||
}
|
||||
|
||||
private void unloadAndSaveAllChunks() {
|
||||
try {
|
||||
J.sfut(() -> {
|
||||
if (world == null) {
|
||||
Iris.warn("World was null somehow...");
|
||||
return;
|
||||
}
|
||||
|
||||
for (Chunk i : new ArrayList<>(lastUse.keySet())) {
|
||||
Long lastUseTime = lastUse.get(i);
|
||||
if (lastUseTime != null && M.ms() - lastUseTime >= 10) {
|
||||
i.unload();
|
||||
lastUse.remove(i);
|
||||
}
|
||||
}
|
||||
world.save();
|
||||
}).get();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
unloadAndSaveAllChunks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
unloadAndSaveAllChunks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
unloadAndSaveAllChunks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRegions(int x, int z, PregenListener listener) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateRegion(int x, int z, PregenListener listener) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod(int x, int z) {
|
||||
return "Medieval";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateChunk(int x, int z, PregenListener listener) {
|
||||
if (futures.size() > IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())) {
|
||||
waitForChunks();
|
||||
}
|
||||
|
||||
listener.onChunkGenerating(x, z);
|
||||
futures.add(J.sfut(() -> {
|
||||
world.getChunkAt(x, z);
|
||||
Chunk c = Bukkit.getWorld(world.getUID()).getChunkAt(x, z);
|
||||
lastUse.put(c, M.ms());
|
||||
listener.onChunkGenerated(x, z);
|
||||
listener.onChunkCleaned(x, z);
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mantle getMantle() {
|
||||
if (IrisToolbelt.isIrisWorld(world)) {
|
||||
return IrisToolbelt.access(world).getEngine().getMantle().getMantle();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,9 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class Gradle {
|
||||
private static final boolean WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
|
||||
@@ -36,15 +38,10 @@ public class Gradle {
|
||||
cmd[0] = gradle.getAbsolutePath();
|
||||
System.arraycopy(args, 0, cmd, 1, args.length);
|
||||
var process = Runtime.getRuntime().exec(cmd, ENVIRONMENT, projectDir);
|
||||
var lines = Collections.synchronizedList(new ArrayList<String>());
|
||||
attach(process.getInputStream(), lines);
|
||||
attach(process.getErrorStream(), lines);
|
||||
attach(process.getInputStream());
|
||||
attach(process.getErrorStream());
|
||||
var code = process.waitFor();
|
||||
if (code == 0) {
|
||||
lines.forEach(Iris::debug);
|
||||
return;
|
||||
}
|
||||
lines.forEach(Iris::error);
|
||||
if (code == 0) return;
|
||||
throw new RuntimeException("Gradle exited with code " + code);
|
||||
}
|
||||
|
||||
@@ -94,12 +91,12 @@ public class Gradle {
|
||||
.orElseThrow(() -> new RuntimeException("Failed to find java home, please set java.home system property"));
|
||||
}
|
||||
|
||||
private static void attach(InputStream stream, List<String> list) {
|
||||
Thread.ofPlatform().start(() -> {
|
||||
private static void attach(InputStream stream) {
|
||||
Thread.ofVirtual().start(() -> {
|
||||
try (var in = new Scanner(stream)) {
|
||||
while (in.hasNextLine()) {
|
||||
String line = in.nextLine();
|
||||
list.add(line);
|
||||
Iris.debug("[GRADLE] " + line);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.core.loader.IrisRegistrant;
|
||||
import com.volmit.iris.core.loader.ResourceLoader;
|
||||
import com.volmit.iris.core.scripting.environment.SimpleEnvironment;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
import com.volmit.iris.engine.object.*;
|
||||
import com.volmit.iris.engine.object.annotations.Snippet;
|
||||
@@ -225,7 +226,7 @@ public class IrisProject {
|
||||
sender.sendMessage("Can't find dimension: " + getName());
|
||||
return;
|
||||
} else if (sender.isPlayer()) {
|
||||
J.s(() -> sender.player().setGameMode(GameMode.SPECTATOR));
|
||||
sender.player().setGameMode(GameMode.SPECTATOR);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -325,7 +326,7 @@ public class IrisProject {
|
||||
}
|
||||
}
|
||||
|
||||
for (Class<?> i : dm.resolveSnippets()) {
|
||||
for (Class<?> i : Iris.getClasses("com.volmit.iris.engine.object.", Snippet.class)) {
|
||||
try {
|
||||
String snipType = i.getDeclaredAnnotation(Snippet.class).value();
|
||||
JSONObject o = new JSONObject();
|
||||
|
||||
@@ -38,7 +38,6 @@ 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;
|
||||
@@ -118,13 +117,49 @@ public class SchemaBuilder {
|
||||
JSONArray required = new JSONArray();
|
||||
JSONArray extended = new JSONArray();
|
||||
|
||||
var parent = c.getSuperclass();
|
||||
while (parent != null && IrisRegistrant.class.isAssignableFrom(parent)) {
|
||||
buildProperties(properties, required, extended, parent);
|
||||
parent = parent.getSuperclass();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
buildProperties(properties, required, extended, c);
|
||||
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);
|
||||
}
|
||||
|
||||
if (required.length() > 0) {
|
||||
o.put("required", required);
|
||||
@@ -139,33 +174,6 @@ 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());
|
||||
@@ -608,7 +616,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 (!k.getType().isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(value instanceof Enum<?>) && !KeyedType.isKeyed(k.getType())) {
|
||||
} else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum()) && !KeyedType.isKeyed(cl)) {
|
||||
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);
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.volmit.iris.core.safeguard;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import io.papermc.lib.PaperLib;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class IrisSafeguard {
|
||||
private static final AtomicBoolean sfg = new AtomicBoolean(false);
|
||||
public static boolean unstablemode = false;
|
||||
public static boolean warningmode = false;
|
||||
public static boolean stablemode = false;
|
||||
|
||||
public static void IrisSafeguardSystem() {
|
||||
Iris.info("Enabled Iris SafeGuard");
|
||||
ServerBootSFG.BootCheck();
|
||||
}
|
||||
|
||||
public static void splash(boolean early) {
|
||||
if (early && (ServerBootSFG.safeguardPassed || IrisSettings.get().getGeneral().DoomsdayAnnihilationSelfDestructMode))
|
||||
return;
|
||||
|
||||
if (!sfg.getAndSet(true)) {
|
||||
Iris.instance.splash();
|
||||
UtilsSFG.splash();
|
||||
}
|
||||
}
|
||||
|
||||
public static String mode() {
|
||||
if (unstablemode) {
|
||||
return "unstable";
|
||||
} else if (warningmode) {
|
||||
return "warning";
|
||||
} else {
|
||||
return "stable";
|
||||
}
|
||||
}
|
||||
|
||||
public static void suggestPaper() {
|
||||
PaperLib.suggestPaper(Iris.instance);
|
||||
}
|
||||
|
||||
public static KMap<String, Object> asContext() {
|
||||
KMap<String, Object> m = new KMap<>();
|
||||
m.put("diskSpace", !ServerBootSFG.hasEnoughDiskSpace);
|
||||
m.put("javaVersion", !ServerBootSFG.isCorrectJDK);
|
||||
m.put("jre", ServerBootSFG.isJRE);
|
||||
m.put("missingAgent", ServerBootSFG.missingAgent);
|
||||
m.put("missingDimensionTypes", ServerBootSFG.missingDimensionTypes);
|
||||
m.put("failedInjection", ServerBootSFG.failedInjection);
|
||||
m.put("unsupportedVersion", ServerBootSFG.unsuportedversion);
|
||||
m.put("serverSoftware", !ServerBootSFG.passedserversoftware);
|
||||
KList<String> incompatiblePlugins = new KList<>();
|
||||
ServerBootSFG.incompatibilities.forEach((plugin, present) -> {
|
||||
if (present) incompatiblePlugins.add(plugin);
|
||||
});
|
||||
m.put("plugins", incompatiblePlugins);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.volmit.iris.core.safeguard;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.util.format.C;
|
||||
|
||||
public class ModesSFG {
|
||||
public static void selectMode() {
|
||||
if (IrisSafeguard.unstablemode) {
|
||||
Iris.safeguard(C.DARK_RED + "Iris is running in Unstable Mode");
|
||||
unstable();
|
||||
}
|
||||
if (IrisSafeguard.warningmode) {
|
||||
Iris.safeguard(C.GOLD + "Iris is running in Warning Mode");
|
||||
warning();
|
||||
}
|
||||
if (IrisSafeguard.stablemode) {
|
||||
stable();
|
||||
}
|
||||
}
|
||||
|
||||
public static void stable() {
|
||||
Iris.safeguard(C.BLUE + "Iris is running Stable");
|
||||
}
|
||||
|
||||
public static void unstable() {
|
||||
|
||||
UtilsSFG.printIncompatibleWarnings();
|
||||
|
||||
if (IrisSafeguard.unstablemode) {
|
||||
Iris.info("");
|
||||
Iris.info(C.DARK_GRAY + "--==<" + C.RED + " IMPORTANT " + C.DARK_GRAY + ">==--");
|
||||
Iris.info(C.RED + "Iris is running in unstable mode which may cause the following issues:");
|
||||
Iris.info(C.DARK_RED + "Server Issues");
|
||||
Iris.info(C.RED + "- Server won't boot");
|
||||
Iris.info(C.RED + "- Data Loss");
|
||||
Iris.info(C.RED + "- Unexpected behavior.");
|
||||
Iris.info(C.RED + "- And More...");
|
||||
Iris.info(C.DARK_RED + "World Issues");
|
||||
Iris.info(C.RED + "- Worlds can't load due to corruption.");
|
||||
Iris.info(C.RED + "- Worlds may slowly corrupt until they can't load.");
|
||||
Iris.info(C.RED + "- World data loss.");
|
||||
Iris.info(C.RED + "- And More...");
|
||||
Iris.info(C.DARK_RED + "ATTENTION: " + C.RED + "While running Iris in unstable mode, you won't be eligible for support.");
|
||||
Iris.info(C.DARK_RED + "CAUSE: " + C.RED + UtilsSFG.MSGIncompatibleWarnings());
|
||||
|
||||
if (IrisSettings.get().getGeneral().DoomsdayAnnihilationSelfDestructMode) {
|
||||
Iris.info(C.DARK_RED + "Boot Unstable is set to true, continuing with the startup process.");
|
||||
} else {
|
||||
Iris.info(C.DARK_RED + "Go to plugins/iris/settings.json and set DoomsdayAnnihilationSelfDestructMode to true if you wish to proceed.");
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(Long.MAX_VALUE);
|
||||
} catch (InterruptedException e) {
|
||||
// no
|
||||
}
|
||||
}
|
||||
}
|
||||
Iris.info("");
|
||||
}
|
||||
}
|
||||
|
||||
public static void warning() {
|
||||
|
||||
UtilsSFG.printIncompatibleWarnings();
|
||||
|
||||
if (IrisSafeguard.warningmode) {
|
||||
Iris.info("");
|
||||
Iris.info(C.DARK_GRAY + "--==<" + C.GOLD + " IMPORTANT " + C.DARK_GRAY + ">==--");
|
||||
Iris.info(C.GOLD + "Iris is running in warning mode which may cause the following issues:");
|
||||
Iris.info(C.YELLOW + "- Data Loss");
|
||||
Iris.info(C.YELLOW + "- Errors");
|
||||
Iris.info(C.YELLOW + "- Broken worlds");
|
||||
Iris.info(C.YELLOW + "- Unexpected behavior.");
|
||||
Iris.info(C.YELLOW + "- And perhaps further complications.");
|
||||
Iris.info(C.GOLD + "CAUSE: " + C.YELLOW + UtilsSFG.MSGIncompatibleWarnings());
|
||||
Iris.info("");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.volmit.iris.core.safeguard;
|
||||
|
||||
public class PerformanceSFG {
|
||||
public static void calculatePerformance() {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
package com.volmit.iris.core.safeguard;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisWorlds;
|
||||
import com.volmit.iris.core.nms.INMS;
|
||||
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
||||
import com.volmit.iris.engine.object.IrisDimension;
|
||||
import com.volmit.iris.util.agent.Agent;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.ToolProvider;
|
||||
import java.io.File;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.volmit.iris.Iris.getJavaVersion;
|
||||
import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
|
||||
|
||||
public class ServerBootSFG {
|
||||
public static final Map<String, Boolean> incompatibilities = new HashMap<>();
|
||||
public static boolean isCorrectJDK = true;
|
||||
public static boolean hasEnoughDiskSpace = true;
|
||||
public static boolean isJRE = false;
|
||||
public static boolean hasPrivileges = true;
|
||||
public static boolean unsuportedversion = false;
|
||||
public static boolean missingDimensionTypes = false;
|
||||
public static boolean missingAgent = false;
|
||||
public static boolean failedInjection = false;
|
||||
protected static boolean safeguardPassed;
|
||||
public static boolean passedserversoftware = true;
|
||||
protected static int count;
|
||||
protected static byte severityLow;
|
||||
protected static byte severityMedium;
|
||||
protected static byte severityHigh;
|
||||
public static String allIncompatibilities;
|
||||
|
||||
public static void BootCheck() {
|
||||
Iris.info("Checking for possible conflicts..");
|
||||
PluginManager pluginManager = Bukkit.getPluginManager();
|
||||
Plugin[] plugins = pluginManager.getPlugins();
|
||||
|
||||
incompatibilities.clear();
|
||||
incompatibilities.put("dynmap", false);
|
||||
incompatibilities.put("Stratos", false);
|
||||
|
||||
String pluginName;
|
||||
for (Plugin plugin : plugins) {
|
||||
pluginName = plugin.getName();
|
||||
Boolean flag = incompatibilities.get(pluginName);
|
||||
if (flag != null && !flag) {
|
||||
severityHigh++;
|
||||
incompatibilities.put(pluginName, true);
|
||||
}
|
||||
}
|
||||
|
||||
StringJoiner joiner = new StringJoiner(", ");
|
||||
for (Map.Entry<String, Boolean> entry : incompatibilities.entrySet()) {
|
||||
if (entry.getValue()) {
|
||||
joiner.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
// Legacy ServerInfo
|
||||
String distro = Bukkit.getName().toLowerCase();
|
||||
if (
|
||||
!distro.contains("purpur") &&
|
||||
!distro.contains("paper") &&
|
||||
!distro.contains("spigot") &&
|
||||
!distro.contains("pufferfish") &&
|
||||
!distro.contains("bukkit")) {
|
||||
|
||||
|
||||
passedserversoftware = false;
|
||||
joiner.add("Server Software");
|
||||
severityMedium++;
|
||||
}
|
||||
|
||||
|
||||
if (INMS.get() instanceof NMSBinding1X) {
|
||||
unsuportedversion = true;
|
||||
joiner.add("Unsupported Minecraft Version");
|
||||
severityHigh++;
|
||||
}
|
||||
|
||||
if (!List.of(21).contains(getJavaVersion())) {
|
||||
isCorrectJDK = false;
|
||||
joiner.add("Unsupported Java version");
|
||||
severityMedium++;
|
||||
}
|
||||
|
||||
if (!isJDK()) {
|
||||
isJRE = true;
|
||||
joiner.add("Unsupported JDK");
|
||||
severityMedium++;
|
||||
}
|
||||
|
||||
// if (!hasPrivileges()){
|
||||
// hasPrivileges = false;
|
||||
// joiner.add("Insufficient Privileges");
|
||||
// severityMedium++;
|
||||
// } Some servers dont like this
|
||||
|
||||
if (!enoughDiskSpace()){
|
||||
hasEnoughDiskSpace = false;
|
||||
joiner.add("Insufficient Disk Space");
|
||||
severityMedium++;
|
||||
}
|
||||
|
||||
if (!Agent.install()) {
|
||||
missingAgent = true;
|
||||
joiner.add("Missing Java Agent");
|
||||
severityHigh++;
|
||||
} else {
|
||||
if (missingDimensionTypes()) {
|
||||
missingDimensionTypes = true;
|
||||
joiner.add("Missing Dimension Types");
|
||||
severityHigh++;
|
||||
}
|
||||
if (!INMS.get().injectBukkit()) {
|
||||
failedInjection = true;
|
||||
joiner.add("Failed Bukkit Injection");
|
||||
severityHigh++;
|
||||
}
|
||||
}
|
||||
|
||||
allIncompatibilities = joiner.toString();
|
||||
|
||||
safeguardPassed = (severityHigh == 0 && severityMedium == 0 && severityLow == 0);
|
||||
count = severityHigh + severityMedium + severityLow;
|
||||
if (safeguardPassed) {
|
||||
stablemode = true;
|
||||
Iris.safeguard("Stable mode has been activated.");
|
||||
}
|
||||
if (!safeguardPassed) {
|
||||
if (severityMedium >= 1 && severityHigh == 0) {
|
||||
warningmode = true;
|
||||
Iris.safeguard("Warning mode has been activated.");
|
||||
}
|
||||
if (severityHigh >= 1) {
|
||||
unstablemode = true;
|
||||
Iris.safeguard("Unstable mode has been activated.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean isJDK() {
|
||||
try {
|
||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
// If the compiler is null, it means this is a JRE environment, not a JDK.
|
||||
return compiler != null;
|
||||
} catch (Exception ignored) {}
|
||||
return false;
|
||||
}
|
||||
public static boolean hasPrivileges() {
|
||||
Path pv = Paths.get(Bukkit.getWorldContainer() + "iristest.json");
|
||||
try (FileChannel fc = FileChannel.open(pv, StandardOpenOption.CREATE, StandardOpenOption.DELETE_ON_CLOSE, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
||||
if (Files.isReadable(pv) && Files.isWritable(pv)) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean enoughDiskSpace() {
|
||||
File freeSpace = Bukkit.getWorldContainer();
|
||||
double gigabytes = freeSpace.getFreeSpace() / (1024.0 * 1024.0 * 1024.0);
|
||||
return gigabytes > 3;
|
||||
}
|
||||
|
||||
private static boolean checkJavac(String path) {
|
||||
return !path.isEmpty() && (new File(path, "javac").exists() || new File(path, "javac.exe").exists());
|
||||
}
|
||||
|
||||
private static boolean missingDimensionTypes() {
|
||||
return INMS.get().missingDimensionTypes(getDimensionTypes().toArray(String[]::new));
|
||||
}
|
||||
|
||||
private static KSet<String> getDimensionTypes() {
|
||||
return IrisWorlds.get()
|
||||
.getDimensions()
|
||||
.map(IrisDimension::getDimensionTypeKey)
|
||||
.collect(Collectors.toCollection(KSet::new));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.volmit.iris.core.safeguard;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.agent.Agent;
|
||||
import com.volmit.iris.util.format.C;
|
||||
|
||||
public class UtilsSFG {
|
||||
public static void splash() {
|
||||
ModesSFG.selectMode();
|
||||
}
|
||||
|
||||
public static void printIncompatibleWarnings() {
|
||||
String[] parts = Iris.instance.getDescription().getVersion().split("-");
|
||||
String minVersion = parts[1];
|
||||
String maxVersion = parts[2];
|
||||
|
||||
if (ServerBootSFG.safeguardPassed) {
|
||||
Iris.safeguard(C.BLUE + "0 Conflicts found");
|
||||
} else {
|
||||
if (IrisSafeguard.unstablemode) {
|
||||
Iris.safeguard(C.DARK_RED + "" + ServerBootSFG.count + " Conflicts found");
|
||||
}
|
||||
if (IrisSafeguard.warningmode) {
|
||||
Iris.safeguard(C.YELLOW + "" + ServerBootSFG.count + " Conflicts found");
|
||||
}
|
||||
|
||||
if (ServerBootSFG.incompatibilities.get("dynmap")) {
|
||||
Iris.safeguard(C.RED + "Dynmap");
|
||||
Iris.safeguard(C.RED + "- The plugin Dynmap is not compatible with the server.");
|
||||
Iris.safeguard(C.RED + "- If you want to have a map plugin like Dynmap, consider Bluemap.");
|
||||
}
|
||||
if (ServerBootSFG.incompatibilities.get("Stratos")) {
|
||||
Iris.safeguard(C.YELLOW + "Stratos");
|
||||
Iris.safeguard(C.YELLOW + "- Iris is not compatible with other worldgen plugins.");
|
||||
}
|
||||
if (ServerBootSFG.unsuportedversion) {
|
||||
Iris.safeguard(C.RED + "Server Version");
|
||||
Iris.safeguard(C.RED + "- Iris only supports " + minVersion + " > " + maxVersion);
|
||||
}
|
||||
if (ServerBootSFG.missingDimensionTypes) {
|
||||
Iris.safeguard(C.RED + "Dimension Types");
|
||||
Iris.safeguard(C.RED + "- Required Iris dimension types were not loaded.");
|
||||
Iris.safeguard(C.RED + "- If this still happens after a restart please contact support.");
|
||||
}
|
||||
if (ServerBootSFG.missingAgent) {
|
||||
Iris.safeguard(C.RED + "Java Agent");
|
||||
Iris.safeguard(C.RED + "- Please enable dynamic agent loading by adding -XX:+EnableDynamicAgentLoading to your jvm arguments.");
|
||||
Iris.safeguard(C.RED + "- or add the jvm argument -javaagent:" + Agent.AGENT_JAR.getPath());
|
||||
}
|
||||
if (!ServerBootSFG.passedserversoftware) {
|
||||
Iris.safeguard(C.YELLOW + "Unsupported Server Software");
|
||||
Iris.safeguard(C.YELLOW + "- Please consider using Paper or Purpur instead.");
|
||||
}
|
||||
if (!ServerBootSFG.hasPrivileges) {
|
||||
Iris.safeguard(C.YELLOW + "Insufficient Privileges");
|
||||
Iris.safeguard(C.YELLOW + "- The server has insufficient Privileges to run iris. Please contact support.");
|
||||
}
|
||||
if (!ServerBootSFG.hasEnoughDiskSpace) {
|
||||
Iris.safeguard(C.YELLOW + "Insufficient Disk Space");
|
||||
Iris.safeguard(C.YELLOW + "- The server has insufficient Free DiskSpace to run iris required 3GB+.");
|
||||
}
|
||||
if (!ServerBootSFG.isCorrectJDK) {
|
||||
Iris.safeguard(C.YELLOW + "Unsupported java version");
|
||||
Iris.safeguard(C.YELLOW + "- Please consider using JDK 21 Instead of JDK " + Iris.getJavaVersion());
|
||||
}
|
||||
if (ServerBootSFG.isJRE) {
|
||||
Iris.safeguard(C.YELLOW + "Unsupported Server JDK");
|
||||
Iris.safeguard(C.YELLOW + "- Please consider using JDK 21 Instead of JRE " + Iris.getJavaVersion());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String MSGIncompatibleWarnings() {
|
||||
return ServerBootSFG.allIncompatibilities;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
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;
|
||||
@@ -25,6 +22,4 @@ 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,7 +2,6 @@ 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;
|
||||
@@ -17,6 +16,4 @@ public interface PackEnvironment extends SimpleEnvironment {
|
||||
|
||||
@Nullable
|
||||
Object createNoise(@NonNull String script, @NonNull RNG rng);
|
||||
|
||||
EngineEnvironment with(@NonNull Engine engine);
|
||||
}
|
||||
@@ -27,4 +27,8 @@ public interface SimpleEnvironment {
|
||||
|
||||
@Nullable
|
||||
Object evaluate(@NonNull String script, @NonNull Class<?> type, @Nullable Map<@NonNull String, Object> vars);
|
||||
|
||||
default void close() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.volmit.iris.core.scripting.func;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface UpdateExecutor {
|
||||
|
||||
@NotNull Runnable wrap(int delay, @NotNull Runnable runnable);
|
||||
|
||||
@NotNull
|
||||
default Runnable wrap(@NotNull Runnable runnable) {
|
||||
return wrap(1, runnable);
|
||||
}
|
||||
|
||||
default void execute(@NotNull Runnable runnable) {
|
||||
execute(1, runnable);
|
||||
}
|
||||
|
||||
default void execute(int delay, @NotNull Runnable runnable) {
|
||||
wrap(delay, runnable).run();
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@ import com.volmit.iris.core.edit.BukkitBlockEditor;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.plugin.IrisService;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
@@ -38,7 +37,7 @@ public class EditSVC implements IrisService {
|
||||
@Override
|
||||
public void onEnable() {
|
||||
this.editors = new KMap<>();
|
||||
Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::update, 1000, 1000);
|
||||
Iris.platform.getGlobalScheduler().runAtFixedRate(this::update, 1000, 1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
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;
|
||||
@@ -17,33 +19,21 @@ 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 KMap<String, Reference<PregenCache>> REFERENCE_CACHE = new KMap<>();
|
||||
private static final Cache<String, PregenCache> REFERENCE_CACHE = Caffeine.newBuilder()
|
||||
.executor(KCache.EXECUTOR)
|
||||
.scheduler(Scheduler.systemScheduler())
|
||||
.weakValues()
|
||||
.build();
|
||||
private final KMap<String, PregenCache> globalCache = new KMap<>();
|
||||
private transient boolean lastState;
|
||||
private static boolean disabled = true;
|
||||
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);
|
||||
@@ -52,9 +42,6 @@ public class GlobalCacheSVC implements IrisService {
|
||||
@Override
|
||||
public void onDisable() {
|
||||
disabled = true;
|
||||
try {
|
||||
trimmer.join();
|
||||
} catch (InterruptedException ignored) {}
|
||||
globalCache.qclear((world, cache) -> cache.write());
|
||||
}
|
||||
|
||||
@@ -89,7 +76,6 @@ public class GlobalCacheSVC implements IrisService {
|
||||
}
|
||||
|
||||
private void createCache(World world) {
|
||||
if (!IrisToolbelt.isIrisWorld(world)) return;
|
||||
globalCache.computeIfAbsent(world.getName(), GlobalCacheSVC::createDefault);
|
||||
}
|
||||
|
||||
@@ -113,15 +99,7 @@ public class GlobalCacheSVC implements IrisService {
|
||||
|
||||
@NonNull
|
||||
public static PregenCache createCache(@NonNull String worldName, @NonNull Function<String, PregenCache> 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];
|
||||
return REFERENCE_CACHE.get(worldName, provider);
|
||||
}
|
||||
|
||||
@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.ResourceLoader;
|
||||
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;
|
||||
@@ -14,8 +14,6 @@ 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;
|
||||
@@ -29,7 +27,6 @@ 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();
|
||||
@@ -67,26 +64,10 @@ 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:");
|
||||
@@ -95,14 +76,10 @@ 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 + "-------------------------");
|
||||
}
|
||||
|
||||
@@ -136,12 +113,12 @@ public class IrisEngineSVC implements IrisService {
|
||||
@Override
|
||||
protected long loop() {
|
||||
try {
|
||||
int queuedPlates = 0;
|
||||
int totalPlates = 0;
|
||||
long chunks = 0;
|
||||
int unloaders = 0;
|
||||
int trimmers = 0;
|
||||
int iris = 0;
|
||||
queuedTectonicPlates.set(0);
|
||||
tectonicPlates.set(0);
|
||||
loadedChunks.set(0);
|
||||
unloaderAlive.set(0);
|
||||
trimmerAlive.set(0);
|
||||
totalWorlds.set(0);
|
||||
|
||||
double maxDuration = Long.MIN_VALUE;
|
||||
double minDuration = Long.MAX_VALUE;
|
||||
@@ -149,30 +126,23 @@ public class IrisEngineSVC implements IrisService {
|
||||
var registered = entry.getValue();
|
||||
if (registered.closed) continue;
|
||||
|
||||
iris++;
|
||||
if (registered.unloaderAlive()) unloaders++;
|
||||
if (registered.trimmerAlive()) trimmers++;
|
||||
totalWorlds.incrementAndGet();
|
||||
unloaderAlive.addAndGet(registered.unloaderAlive() ? 1 : 0);
|
||||
trimmerAlive.addAndGet(registered.trimmerAlive() ? 1 : 0);
|
||||
|
||||
var engine = registered.getEngine();
|
||||
if (engine == null) continue;
|
||||
|
||||
queuedPlates += engine.getMantle().getUnloadRegionCount();
|
||||
totalPlates += engine.getMantle().getLoadedRegionCount();
|
||||
chunks += entry.getKey().getLoadedChunks().length;
|
||||
queuedTectonicPlates.addAndGet((int) engine.getMantle().getUnloadRegionCount());
|
||||
tectonicPlates.addAndGet(engine.getMantle().getLoadedRegionCount());
|
||||
loadedChunks.addAndGet(entry.getKey().getLoadedChunks().length);
|
||||
|
||||
double duration = engine.getMantle().getAdjustedIdleDuration();
|
||||
if (duration > maxDuration) maxDuration = duration;
|
||||
if (duration < minDuration) minDuration = duration;
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -187,7 +157,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(TRIM_PERIOD);
|
||||
private final int offset = RNG.r.nextInt(1000);
|
||||
private transient ScheduledFuture<?> trimmer;
|
||||
private transient ScheduledFuture<?> unloader;
|
||||
private transient boolean closed;
|
||||
@@ -224,7 +194,7 @@ public class IrisEngineSVC implements IrisService {
|
||||
Iris.error("EngineSVC: Failed to trim for " + name);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, offset, TRIM_PERIOD, TimeUnit.MILLISECONDS);
|
||||
}, offset, 2000, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
if (unloader == null || unloader.isDone() || unloader.isCancelled()) {
|
||||
@@ -244,7 +214,7 @@ public class IrisEngineSVC implements IrisService {
|
||||
Iris.error("EngineSVC: Failed to unload for " + name);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, offset + TRIM_PERIOD / 2, TRIM_PERIOD, TimeUnit.MILLISECONDS);
|
||||
}, offset + 1000, 2000, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.plugin.IrisService;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
@@ -71,21 +70,18 @@ public class ObjectSVC implements IrisService {
|
||||
*/
|
||||
private void revert(Map<Block, BlockData> blocks) {
|
||||
Iterator<Map.Entry<Block, BlockData>> it = blocks.entrySet().iterator();
|
||||
Bukkit.getScheduler().runTask(Iris.instance, () -> {
|
||||
int amount = 0;
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<Block, BlockData> entry = it.next();
|
||||
BlockData data = entry.getValue();
|
||||
entry.getKey().setBlockData(data, false);
|
||||
var scheduler = Iris.platform.getRegionScheduler();
|
||||
for (int i = 0; i < 200 && it.hasNext(); i++) {
|
||||
Map.Entry<Block, BlockData> entry = it.next();
|
||||
Block block = entry.getKey();
|
||||
BlockData data = entry.getValue();
|
||||
it.remove();
|
||||
|
||||
it.remove();
|
||||
scheduler.run(block.getLocation(), () -> block.setBlockData(data, false));
|
||||
}
|
||||
|
||||
amount++;
|
||||
|
||||
if (amount > 200) {
|
||||
J.s(() -> revert(blocks), 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (it.hasNext()) {
|
||||
J.s(() -> revert(blocks), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,22 +24,19 @@ 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<WeakReference<MeteredCache>> caches = new CopyOnWriteArrayList<>();
|
||||
private final List<MeteredCache> caches = new CopyOnWriteArrayList<>();
|
||||
private Looper dereferencer;
|
||||
|
||||
public void register(Thread t) {
|
||||
@@ -51,18 +48,22 @@ public class PreservationSVC implements IrisService {
|
||||
}
|
||||
|
||||
public void printCaches() {
|
||||
var c = getCaches();
|
||||
long s = 0;
|
||||
long m = 0;
|
||||
long s = caches.stream().filter(i -> !i.isClosed()).mapToLong(MeteredCache::getSize).sum();
|
||||
long m = caches.stream().filter(i -> !i.isClosed()).mapToLong(MeteredCache::getMaxSize).sum();
|
||||
double p = 0;
|
||||
double mf = Math.max(c.size(), 1);
|
||||
double mf = 0;
|
||||
|
||||
for (MeteredCache i : c) {
|
||||
s += i.getSize();
|
||||
m += i.getMaxSize();
|
||||
for (MeteredCache i : caches) {
|
||||
if (i.isClosed()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mf++;
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -118,29 +119,14 @@ public class PreservationSVC implements IrisService {
|
||||
}
|
||||
|
||||
public void updateCaches() {
|
||||
caches.removeIf(ref -> {
|
||||
var c = ref.get();
|
||||
return c == null || c.isClosed();
|
||||
});
|
||||
caches.removeIf(MeteredCache::isClosed);
|
||||
}
|
||||
|
||||
public void registerCache(MeteredCache cache) {
|
||||
caches.add(new WeakReference<>(cache));
|
||||
caches.add(cache);
|
||||
}
|
||||
|
||||
public List<KCache<?, ?>> caches() {
|
||||
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());
|
||||
return caches.stream().map(MeteredCache::getRawCache).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,9 +142,10 @@ public class TreeSVC implements IrisService {
|
||||
public void set(int x, int y, int z, BlockData d) {
|
||||
Block b = event.getWorld().getBlockAt(x, y, z);
|
||||
BlockState state = b.getState();
|
||||
if (d instanceof IrisCustomData data)
|
||||
if (d instanceof IrisCustomData data) {
|
||||
state.setBlockData(data.getBase());
|
||||
else state.setBlockData(d);
|
||||
Iris.service(ExternalDataSVC.class).processUpdate(engine, b, data.getCustom());
|
||||
} else state.setBlockData(d);
|
||||
blockStateList.add(b.getState());
|
||||
dataCache.put(new Location(event.getWorld(), x, y, z), d);
|
||||
}
|
||||
@@ -189,16 +190,6 @@ 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;
|
||||
@@ -217,8 +208,7 @@ public class TreeSVC implements IrisService {
|
||||
|
||||
event.setCancelled(true);
|
||||
|
||||
J.s(() -> {
|
||||
|
||||
Iris.platform.getRegionScheduler().run(event.getLocation(), () -> {
|
||||
StructureGrowEvent iGrow = new StructureGrowEvent(event.getLocation(), event.getSpecies(), event.isFromBonemeal(), event.getPlayer(), blockStateList);
|
||||
block = true;
|
||||
Bukkit.getServer().getPluginManager().callEvent(iGrow);
|
||||
@@ -235,7 +225,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, false);
|
||||
} else block.setBlockData(d);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.SR;
|
||||
import com.volmit.iris.util.scheduling.jobs.Job;
|
||||
import com.volmit.iris.util.scheduling.jobs.ScanJob;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -86,82 +87,10 @@ public class WandSVC implements IrisService {
|
||||
Cuboid c = new Cuboid(f[0], f[1]);
|
||||
IrisObject s = new IrisObject(c.getSizeX(), c.getSizeY(), c.getSizeZ());
|
||||
|
||||
var it = c.chunkedIterator();
|
||||
|
||||
int total = c.getSizeX() * c.getSizeY() * c.getSizeZ();
|
||||
var latch = new CountDownLatch(1);
|
||||
var holder = Iris.tickets.getHolder(p.getWorld());
|
||||
new Job() {
|
||||
private int i;
|
||||
private Chunk chunk;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Scanning Selection";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
new SR() {
|
||||
@Override
|
||||
public void run() {
|
||||
var time = M.ms() + MS_PER_TICK;
|
||||
while (time > M.ms()) {
|
||||
if (!it.hasNext()) {
|
||||
if (chunk != null) {
|
||||
holder.removeTicket(chunk);
|
||||
chunk = null;
|
||||
}
|
||||
|
||||
cancel();
|
||||
latch.countDown();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var b = it.next();
|
||||
var bChunk = b.getChunk();
|
||||
if (chunk == null) {
|
||||
chunk = bChunk;
|
||||
holder.addTicket(chunk);
|
||||
} else if (chunk != bChunk) {
|
||||
holder.removeTicket(chunk);
|
||||
holder.addTicket(bChunk);
|
||||
chunk = bChunk;
|
||||
}
|
||||
|
||||
if (b.getType().equals(Material.AIR))
|
||||
continue;
|
||||
|
||||
BlockVector bv = b.getLocation().subtract(c.getLowerNE().toVector()).toVector().toBlockVector();
|
||||
s.setUnsigned(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), b, legacy);
|
||||
} finally {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException ignored) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeWork() {}
|
||||
|
||||
@Override
|
||||
public int getTotalWork() {
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWorkCompleted() {
|
||||
return i;
|
||||
}
|
||||
}.execute(new VolmitSender(p), true, () -> {});
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException ignored) {}
|
||||
new ScanJob("Scanning Selection", c, MS_PER_TICK, (bv, b) -> {
|
||||
if (b.getType().equals(Material.AIR)) return;
|
||||
s.setUnsigned(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), b, legacy);
|
||||
}).execute(new VolmitSender(p), true, () -> {});
|
||||
|
||||
return s;
|
||||
} catch (Throwable e) {
|
||||
|
||||
@@ -2,21 +2,30 @@ package com.volmit.iris.core.tools;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.engine.object.*;
|
||||
import com.volmit.iris.util.data.Varint;
|
||||
import com.volmit.iris.util.format.C;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.nbt.io.NBTUtil;
|
||||
import com.volmit.iris.util.nbt.io.NamedTag;
|
||||
import com.volmit.iris.util.nbt.tag.*;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.reflect.V;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
import de.crazydev22.platformutils.scheduler.task.Task;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.util.FileUtil;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -31,17 +40,13 @@ public class IrisConverter {
|
||||
sender.sendMessage("No schematic files to convert found in " + folder.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
|
||||
AtomicInteger counter = new AtomicInteger(0);
|
||||
var stopwatch = PrecisionStopwatch.start();
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(1);
|
||||
executorService.submit(() -> {
|
||||
for (File schem : fileList) {
|
||||
try {
|
||||
for (File schem : fileList) {
|
||||
try {
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
IrisObject object;
|
||||
boolean largeObject = false;
|
||||
NamedTag tag;
|
||||
NamedTag tag = null;
|
||||
try {
|
||||
tag = NBTUtil.read(schem);
|
||||
} catch (IOException e) {
|
||||
@@ -49,29 +54,23 @@ public class IrisConverter {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
CompoundTag compound = (CompoundTag) tag.getTag();
|
||||
int version = resolveVersion(compound);
|
||||
if (!(version == 2 || version == 3))
|
||||
throw new RuntimeException(C.RED + "Unsupported schematic version: " + version);
|
||||
|
||||
compound = version == 3 ? (CompoundTag) compound.get("Schematic") : compound;
|
||||
if (compound.containsKey("Palette") && compound.containsKey("Width") && compound.containsKey("Height") && compound.containsKey("Length")) {
|
||||
int objW = ((ShortTag) compound.get("Width")).getValue();
|
||||
int objH = ((ShortTag) compound.get("Height")).getValue();
|
||||
int objD = ((ShortTag) compound.get("Length")).getValue();
|
||||
int i = -1;
|
||||
Task i = null;
|
||||
int mv = objW * objH * objD;
|
||||
AtomicInteger v = new AtomicInteger(0);
|
||||
if (mv > 2_000_000) {
|
||||
if (mv > 500_000) {
|
||||
largeObject = true;
|
||||
Iris.info(C.GRAY + "Converting.. " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
|
||||
Iris.info(C.GRAY + "Converting.. "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
|
||||
Iris.info(C.GRAY + "- It may take a while");
|
||||
if (sender.isPlayer()) {
|
||||
i = J.ar(() -> {
|
||||
sender.sendProgress((double) v.get() / mv, "Converting");
|
||||
}, 0);
|
||||
i = J.ar(() -> sender.sendProgress((double) v.get() / mv, "Converting"), 0);
|
||||
}
|
||||
}
|
||||
|
||||
compound = version == 3 ? (CompoundTag) compound.get("Blocks") : compound;
|
||||
CompoundTag paletteTag = (CompoundTag) compound.get("Palette");
|
||||
Map<Integer, BlockData> blockmap = new HashMap<>(paletteTag.size(), 0.9f);
|
||||
for (Map.Entry<String, Tag<?>> entry : paletteTag.getValue().entrySet()) {
|
||||
@@ -82,16 +81,14 @@ public class IrisConverter {
|
||||
blockmap.put(blockId, bd);
|
||||
}
|
||||
|
||||
boolean isBytes = version == 3 ? compound.getByteArrayTag("Data").length() < 128 : ((IntTag) compound.get("PaletteMax")).getValue() < 128;
|
||||
ByteArrayTag byteArray = version == 3 ? (ByteArrayTag) compound.get("Data") : (ByteArrayTag) compound.get("BlockData");
|
||||
ByteArrayTag byteArray = (ByteArrayTag) compound.get("BlockData");
|
||||
byte[] originalBlockArray = byteArray.getValue();
|
||||
var din = new DataInputStream(new ByteArrayInputStream(originalBlockArray));
|
||||
object = new IrisObject(objW, objH, objD);
|
||||
|
||||
IrisObject object = new IrisObject(objW, objH, objD);
|
||||
for (int h = 0; h < objH; h++) {
|
||||
for (int d = 0; d < objD; d++) {
|
||||
for (int w = 0; w < objW; w++) {
|
||||
int blockIndex = isBytes ? din.read() & 0xFF : Varint.readUnsignedVarInt(din);
|
||||
BlockData bd = blockmap.get(blockIndex);
|
||||
BlockData bd = blockmap.get((int) originalBlockArray[v.get()]);
|
||||
if (!bd.getMaterial().isAir()) {
|
||||
object.setUnsigned(w, h, d, bd);
|
||||
}
|
||||
@@ -99,59 +96,42 @@ public class IrisConverter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i != -1) J.car(i);
|
||||
if (i != null) i.cancel();
|
||||
try {
|
||||
object.shrinkwrap();
|
||||
object.write(new File(folder, schem.getName().replace(".schem", ".iob")));
|
||||
counter.incrementAndGet();
|
||||
if (sender.isPlayer()) {
|
||||
if (largeObject) {
|
||||
sender.sendMessage(C.IRIS + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis()));
|
||||
} else {
|
||||
sender.sendMessage(C.IRIS + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
|
||||
}
|
||||
}
|
||||
if (largeObject) {
|
||||
Iris.info(C.GRAY + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis()));
|
||||
} else {
|
||||
Iris.info(C.GRAY + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
|
||||
}
|
||||
FileUtils.delete(schem);
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(C.RED + "Failed to save: " + schem.getName());
|
||||
throw new IOException(e);
|
||||
Iris.info(C.RED + "Failed to save: " + schem.getName());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
sender.sendMessage(C.RED + "Failed to convert: " + schem.getName());
|
||||
e.printStackTrace();
|
||||
if (sender.isPlayer()) {
|
||||
if (largeObject) {
|
||||
sender.sendMessage(C.IRIS + "Converted "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis()));
|
||||
} else {
|
||||
sender.sendMessage(C.IRIS + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
|
||||
}
|
||||
}
|
||||
if (largeObject) {
|
||||
Iris.info(C.GRAY + "Converted "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis()));
|
||||
} else {
|
||||
Iris.info(C.GRAY + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob"));
|
||||
}
|
||||
FileUtils.delete(schem);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Iris.info(C.RED + "Failed to convert: " + schem.getName());
|
||||
if (sender.isPlayer()) {
|
||||
sender.sendMessage(C.RED + "Failed to convert: " + schem.getName());
|
||||
}
|
||||
e.printStackTrace();
|
||||
Iris.reportError(e);
|
||||
}
|
||||
stopwatch.end();
|
||||
if (counter.get() != 0) {
|
||||
sender.sendMessage(C.GRAY + "Converted: " + counter.get() + " in " + Form.duration(stopwatch.getMillis()));
|
||||
}
|
||||
if (counter.get() < fileList.length) {
|
||||
sender.sendMessage(C.RED + "Some schematics failed to convert. Check the console for details.");
|
||||
}
|
||||
}
|
||||
sender.sendMessage(C.GRAY + "converted: " + fileList.length);
|
||||
});
|
||||
}
|
||||
|
||||
private static int resolveVersion(CompoundTag compound) throws Exception {
|
||||
try {
|
||||
|
||||
IntTag root = compound.getIntTag("Version");
|
||||
if (root != null) {
|
||||
return root.getValue();
|
||||
}
|
||||
CompoundTag schematic = (CompoundTag) compound.get("Schematic");
|
||||
return schematic.getIntTag("Version").getValue();
|
||||
} catch (NullPointerException e) {
|
||||
throw new Exception("Cannot resolve schematic version", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ import com.volmit.iris.util.format.C;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.O;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.bukkit.*;
|
||||
@@ -41,8 +40,10 @@ import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML;
|
||||
@@ -128,8 +129,6 @@ public class IrisCreator {
|
||||
}
|
||||
|
||||
AtomicDouble pp = new AtomicDouble(0);
|
||||
O<Boolean> done = new O<>();
|
||||
done.set(false);
|
||||
WorldCreator wc = new IrisWorldCreator()
|
||||
.dimension(dimension)
|
||||
.name(name)
|
||||
@@ -143,6 +142,7 @@ public class IrisCreator {
|
||||
PlatformChunkGenerator access = (PlatformChunkGenerator) wc.generator();
|
||||
if (access == null) throw new IrisException("Access is null. Something bad happened.");
|
||||
|
||||
AtomicBoolean done = new AtomicBoolean(false);
|
||||
J.a(() -> {
|
||||
IntSupplier g = () -> {
|
||||
if (access.getEngine() == null) {
|
||||
@@ -166,9 +166,11 @@ public class IrisCreator {
|
||||
});
|
||||
|
||||
|
||||
World world;
|
||||
final World world;
|
||||
try {
|
||||
world = J.sfut(() -> INMS.get().createWorld(wc)).get();
|
||||
world = J.sfut(() -> INMS.get().createWorldAsync(wc))
|
||||
.thenCompose(Function.identity())
|
||||
.get();
|
||||
} catch (Throwable e) {
|
||||
done.set(true);
|
||||
throw new IrisException("Failed to create world!", e);
|
||||
@@ -177,7 +179,15 @@ public class IrisCreator {
|
||||
done.set(true);
|
||||
|
||||
if (sender.isPlayer() && !benchmark) {
|
||||
J.s(() -> sender.player().teleport(new Location(world, 0, world.getHighestBlockYAt(0, 0) + 1, 0)));
|
||||
Iris.platform.getChunkAtAsync(world, 0, 0, true, true)
|
||||
.thenApply(Objects::requireNonNull)
|
||||
.thenApply(c -> c.getChunkSnapshot(true, false, false).getHighestBlockYAt(0, 0) + 1)
|
||||
.thenAccept(y -> Iris.platform.teleportAsync(sender.player(), new Location(world, 0, y, 0)))
|
||||
.exceptionally(err -> {
|
||||
sender.sendMessage(C.RED + "Failed to teleport you to the world!");
|
||||
err.printStackTrace();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
if (studio || benchmark) {
|
||||
|
||||
@@ -24,8 +24,8 @@ import com.volmit.iris.core.gui.PregeneratorJob;
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.core.pregenerator.PregenTask;
|
||||
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||
import com.volmit.iris.core.pregenerator.methods.AsyncPregenMethod;
|
||||
import com.volmit.iris.core.pregenerator.methods.CachedPregenMethod;
|
||||
import com.volmit.iris.core.pregenerator.methods.HybridPregenMethod;
|
||||
import com.volmit.iris.core.service.StudioSVC;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.object.IrisDimension;
|
||||
@@ -34,7 +34,6 @@ 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;
|
||||
@@ -46,7 +45,6 @@ import java.util.Map;
|
||||
* Hope you packed snacks & road sodas.
|
||||
*/
|
||||
public class IrisToolbelt {
|
||||
@ApiStatus.Internal
|
||||
public static Map<String, Boolean> toolbeltConfiguration = new HashMap<>();
|
||||
|
||||
/**
|
||||
@@ -167,8 +165,7 @@ public class IrisToolbelt {
|
||||
* @return the pregenerator job (already started)
|
||||
*/
|
||||
public static PregeneratorJob pregenerate(PregenTask task, PlatformChunkGenerator gen) {
|
||||
return pregenerate(task, new HybridPregenMethod(gen.getEngine().getWorld().realWorld(),
|
||||
IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())), gen.getEngine());
|
||||
return pregenerate(task, new AsyncPregenMethod(gen.getEngine().getWorld().realWorld()), gen.getEngine());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,7 +181,7 @@ public class IrisToolbelt {
|
||||
return pregenerate(task, access(world));
|
||||
}
|
||||
|
||||
return pregenerate(task, new HybridPregenMethod(world, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())), null);
|
||||
return pregenerate(task, new AsyncPregenMethod(world), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,7 +195,7 @@ public class IrisToolbelt {
|
||||
if (!i.getName().equals(world.getName())) {
|
||||
for (Player j : world.getPlayers()) {
|
||||
new VolmitSender(j, Iris.instance.getTag()).sendMessage("You have been evacuated from this world.");
|
||||
j.teleport(i.getSpawnLocation());
|
||||
Iris.platform.teleportAsync(j, i.getSpawnLocation());
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -220,7 +217,7 @@ public class IrisToolbelt {
|
||||
if (!i.getName().equals(world.getName())) {
|
||||
for (Player j : world.getPlayers()) {
|
||||
new VolmitSender(j, Iris.instance.getTag()).sendMessage("You have been evacuated from this world. " + m);
|
||||
j.teleport(i.getSpawnLocation());
|
||||
Iris.platform.teleportAsync(j, i.getSpawnLocation());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -234,11 +231,7 @@ public class IrisToolbelt {
|
||||
}
|
||||
|
||||
public static void retainMantleDataForSlice(String className) {
|
||||
toolbeltConfiguration.put("retain.mantle." + className, Boolean.TRUE);
|
||||
}
|
||||
|
||||
public static boolean isRetainingMantleDataForSlice(String className) {
|
||||
return !toolbeltConfiguration.isEmpty() && toolbeltConfiguration.get("retain.mantle." + className) == Boolean.TRUE;
|
||||
toolbeltConfiguration.put("retain.mantle." + className, true);
|
||||
}
|
||||
|
||||
public static <T> T getMantleData(World world, int x, int y, int z, Class<T> of) {
|
||||
|
||||
@@ -89,7 +89,7 @@ public class IrisComplex implements DataProvider {
|
||||
}
|
||||
|
||||
public IrisComplex(Engine engine, boolean simple) {
|
||||
int cacheSize = IrisSettings.get().getPerformance().getNoiseCacheSize();
|
||||
int cacheSize = IrisSettings.get().getPerformance().getCacheSize();
|
||||
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,13 +86,11 @@ public class IrisEngineMantle implements EngineMantle {
|
||||
.map(components::get)
|
||||
.map(components -> {
|
||||
int radius = components.stream()
|
||||
.filter(MantleComponent::isEnabled)
|
||||
.mapToInt(MantleComponent::getRadius)
|
||||
.max()
|
||||
.orElse(0);
|
||||
return new Pair<>(List.copyOf(components), radius);
|
||||
})
|
||||
.filter(pair -> !pair.getA().isEmpty())
|
||||
.toList();
|
||||
|
||||
int radius = 0;
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.link.Identifier;
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.core.service.ExternalDataSVC;
|
||||
import com.volmit.iris.engine.data.cache.Cache;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.framework.EngineAssignedWorldManager;
|
||||
import com.volmit.iris.engine.object.*;
|
||||
@@ -44,7 +43,6 @@ import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.Looper;
|
||||
import com.volmit.iris.util.scheduling.jobs.QueueJob;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.bukkit.Chunk;
|
||||
@@ -58,11 +56,11 @@ import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -79,8 +77,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
private final ChronoLatch cln;
|
||||
private final ChronoLatch chunkUpdater;
|
||||
private final ChronoLatch chunkDiscovery;
|
||||
private final KMap<Long, Future<?>> cleanup = new KMap<>();
|
||||
private final ScheduledExecutorService cleanupService;
|
||||
private double energy = 25;
|
||||
private int entityCount = 0;
|
||||
private long charge = 0;
|
||||
@@ -98,7 +94,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
looper = null;
|
||||
chunkUpdater = null;
|
||||
chunkDiscovery = null;
|
||||
cleanupService = null;
|
||||
id = -1;
|
||||
}
|
||||
|
||||
@@ -110,11 +105,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
cl = new ChronoLatch(3000);
|
||||
ecl = new ChronoLatch(250);
|
||||
clw = new ChronoLatch(1000, true);
|
||||
cleanupService = Executors.newSingleThreadScheduledExecutor(runnable -> {
|
||||
var thread = new Thread(runnable, "Iris Mantle Cleanup " + getTarget().getWorld().name());
|
||||
thread.setPriority(Thread.MIN_PRIORITY);
|
||||
return thread;
|
||||
});
|
||||
id = engine.getCacheID();
|
||||
energy = 25;
|
||||
looper = new Looper() {
|
||||
@@ -128,6 +118,10 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
getEngine().getWorld().tryGetRealWorld();
|
||||
}
|
||||
|
||||
if (!IrisSettings.get().getWorld().isMarkerEntitySpawningSystem() && !IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()) {
|
||||
return 3000;
|
||||
}
|
||||
|
||||
if (getEngine().getWorld().hasRealWorld()) {
|
||||
if (getEngine().getWorld().getPlayers().isEmpty()) {
|
||||
return 5000;
|
||||
@@ -141,13 +135,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
discoverChunks();
|
||||
}
|
||||
|
||||
if (cln.flip()) {
|
||||
engine.getEngineData().cleanup(getEngine());
|
||||
}
|
||||
|
||||
if (!IrisSettings.get().getWorld().isMarkerEntitySpawningSystem() && !IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()) {
|
||||
return 3000;
|
||||
}
|
||||
|
||||
if (getDimension().isInfiniteEnergy()) {
|
||||
energy += 1000;
|
||||
@@ -159,6 +146,10 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
fixEnergy();
|
||||
}
|
||||
|
||||
if (cln.flip()) {
|
||||
engine.getEngineData().cleanup(getEngine());
|
||||
}
|
||||
|
||||
if (precount != null) {
|
||||
entityCount = 0;
|
||||
for (Entity i : precount) {
|
||||
@@ -186,7 +177,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
}
|
||||
};
|
||||
looper.setPriority(Thread.MIN_PRIORITY);
|
||||
looper.setName("Iris World Manager " + getTarget().getWorld().name());
|
||||
looper.setName("Iris World Manager");
|
||||
looper.start();
|
||||
}
|
||||
|
||||
@@ -195,32 +186,54 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
for (Player i : getEngine().getWorld().realWorld().getPlayers()) {
|
||||
int r = 1;
|
||||
|
||||
int cX = i.getLocation().getBlockX() >> 4;
|
||||
int cZ = i.getLocation().getBlockZ() >> 4;
|
||||
for (int x = -r; x <= r; x++) {
|
||||
for (int z = -r; z <= r; z++) {
|
||||
mantle.getChunk(i.getLocation().getChunk()).flag(MantleFlag.DISCOVERED, true);
|
||||
mantle.getChunk(cX + x, cZ + z).flag(MantleFlag.DISCOVERED, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateChunks() {
|
||||
for (Player i : getEngine().getWorld().realWorld().getPlayers()) {
|
||||
int r = 1;
|
||||
int radius = 1;
|
||||
int diameter = radius * 2 + 1;
|
||||
int count = (diameter * diameter) + 1;
|
||||
|
||||
Chunk c = i.getLocation().getChunk();
|
||||
for (int x = -r; x <= r; x++) {
|
||||
for (int z = -r; z <= r; z++) {
|
||||
if (c.getWorld().isChunkLoaded(c.getX() + x, c.getZ() + z) && Chunks.isSafe(getEngine().getWorld().realWorld(), c.getX() + x, c.getZ() + z)) {
|
||||
var players = new KList<>(getEngine().getWorld().realWorld().getPlayers());
|
||||
var latch = new CountDownLatch(count * players.size());
|
||||
|
||||
if (IrisSettings.get().getWorld().isPostLoadBlockUpdates()) {
|
||||
getEngine().updateChunk(c.getWorld().getChunkAt(c.getX() + x, c.getZ() + z));
|
||||
for (Player i : players) {
|
||||
if (!i.isOnline() || !i.isValid() || i.isDead()) {
|
||||
for (int j = 0; j < count; j++) {
|
||||
latch.countDown();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Iris.platform.getEntityScheduler(i).run(() -> {
|
||||
Chunk c = i.getLocation().getChunk();
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
for (int z = -radius; z <= radius; z++) {
|
||||
int cX = c.getX() + x;
|
||||
int cZ = c.getZ() + z;
|
||||
if (!c.getWorld().isChunkLoaded(cX, cZ) || !Chunks.isSafe(getEngine().getWorld().realWorld(), cX, cZ)) {
|
||||
latch.countDown();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IrisSettings.get().getWorld().isPostLoadBlockUpdates()) {
|
||||
Chunk cx = c.getWorld().getChunkAt(cX, cZ);
|
||||
J.a(() -> {
|
||||
getEngine().updateChunk(cx);
|
||||
latch.countDown();
|
||||
});
|
||||
} else latch.countDown();
|
||||
|
||||
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
|
||||
Chunk cx = getEngine().getWorld().realWorld().getChunkAt(c.getX() + x, c.getZ() + z);
|
||||
int finalX = c.getX() + x;
|
||||
int finalZ = c.getZ() + z;
|
||||
J.a(() -> getMantle().raiseFlag(finalX, finalZ, MantleFlag.INITIAL_SPAWNED_MARKER,
|
||||
Chunk cx = getEngine().getWorld().realWorld().getChunkAt(cX, cZ);
|
||||
J.a(() -> getMantle().raiseFlag(cX, cZ, MantleFlag.INITIAL_SPAWNED_MARKER,
|
||||
() -> {
|
||||
J.a(() -> spawnIn(cx, true), RNG.r.i(5, 200));
|
||||
getSpawnersFromMarkers(cx).forEach((blockf, spawners) -> {
|
||||
@@ -236,8 +249,17 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
latch.countDown();
|
||||
}, () -> {
|
||||
for (int j = 0; j < count; j++) {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException ignored) {}
|
||||
}
|
||||
|
||||
private boolean onAsyncTick() {
|
||||
@@ -430,20 +452,22 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
return;
|
||||
}
|
||||
|
||||
var ref = new WeakReference<>(e.getWorld());
|
||||
int cX = e.getX(), cZ = e.getZ();
|
||||
Long key = Cache.key(e);
|
||||
cleanup.put(key, cleanupService.schedule(() -> {
|
||||
cleanup.remove(key);
|
||||
J.s(() -> {
|
||||
World world = ref.get();
|
||||
if (world == null || !world.isChunkLoaded(cX, cZ))
|
||||
return;
|
||||
energy += 0.3;
|
||||
fixEnergy();
|
||||
getEngine().cleanupMantleChunk(cX, cZ);
|
||||
}, Math.max(IrisSettings.get().getPerformance().mantleCleanupDelay * 50L, 0), TimeUnit.MILLISECONDS));
|
||||
}, IrisSettings.get().getPerformance().mantleCleanupDelay);
|
||||
|
||||
if (generated) {
|
||||
//INMS.get().injectBiomesFromMantle(e, getMantle());
|
||||
|
||||
if (!IrisSettings.get().getGenerator().earlyCustomBlocks) return;
|
||||
Iris.tickets.addTicket(e);
|
||||
e.addPluginChunkTicket(Iris.instance);
|
||||
J.s(() -> {
|
||||
var chunk = getMantle().getChunk(e).use();
|
||||
int minY = getTarget().getWorld().minHeight();
|
||||
@@ -455,20 +479,12 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
});
|
||||
} finally {
|
||||
chunk.release();
|
||||
Iris.tickets.removeTicket(e);
|
||||
e.removePluginChunkTicket(Iris.instance);
|
||||
}
|
||||
}, RNG.r.i(20, 60));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkUnload(Chunk e) {
|
||||
final var future = cleanup.remove(Cache.key(e));
|
||||
if (future != null) {
|
||||
future.cancel(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void spawn(IrisPosition block, IrisSpawner spawner, boolean initial) {
|
||||
if (getEngine().isClosed()) {
|
||||
return;
|
||||
@@ -504,8 +520,8 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
e.setCancelled(true);
|
||||
warmupAreaAsync(e.getPlayer(), e.getTo(), () -> J.s(() -> {
|
||||
ignoreTP.set(true);
|
||||
e.getPlayer().teleport(e.getTo(), e.getCause());
|
||||
ignoreTP.set(false);
|
||||
Iris.platform.teleportAsync(e.getPlayer(), e.getTo(), e.getCause())
|
||||
.thenRun(() -> ignoreTP.set(false));
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -525,7 +541,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
}
|
||||
|
||||
futures.add(MultiBurst.burst.completeValue(()
|
||||
-> PaperLib.getChunkAtAsync(to.getWorld(),
|
||||
-> Iris.platform.getChunkAtAsync(to.getWorld(),
|
||||
(to.getBlockX() >> 4) + finalI,
|
||||
(to.getBlockZ() >> 4) + finalJ,
|
||||
true, IrisSettings.get().getWorld().getAsyncTeleport().isUrgent()).get()));
|
||||
@@ -562,19 +578,17 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
||||
IrisPosition pos = new IrisPosition((c.getX() << 4) + x, y, (c.getZ() << 4) + z);
|
||||
|
||||
if (mark.isEmptyAbove()) {
|
||||
AtomicBoolean remove = new AtomicBoolean(false);
|
||||
Boolean remove = Iris.platform.getRegionScheduler()
|
||||
.run(c.getWorld(), c.getX(), c.getZ(), () -> c.getBlock(x, y + 1, z).getType().isSolid() || c.getBlock(x, y + 2, z).getType().isSolid())
|
||||
.getResult()
|
||||
.exceptionally(e -> {
|
||||
Iris.reportError(e);
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
})
|
||||
.join();
|
||||
|
||||
try {
|
||||
J.sfut(() -> {
|
||||
if (c.getBlock(x, y + 1, z).getBlockData().getMaterial().isSolid() || c.getBlock(x, y + 2, z).getBlockData().getMaterial().isSolid()) {
|
||||
remove.set(true);
|
||||
}
|
||||
}).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (remove.get()) {
|
||||
if (remove == Boolean.TRUE) {
|
||||
b.add(pos);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
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;
|
||||
@@ -29,5 +28,5 @@ public interface BlockUpdater {
|
||||
|
||||
void updateChunk(Chunk c);
|
||||
|
||||
void update(int x, int y, int z, Chunk c, MantleChunk mc, RNG rf);
|
||||
void update(int x, int y, int z, Chunk c, RNG rf);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ 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;
|
||||
@@ -65,7 +64,6 @@ import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
import com.volmit.iris.util.stream.ProceduralStream;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.Block;
|
||||
@@ -295,20 +293,20 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
|
||||
var chunk = mantle.getChunk(c).use();
|
||||
try {
|
||||
Semaphore semaphore = new Semaphore(1024);
|
||||
chunk.raiseFlagUnchecked(MantleFlag.ETCHED, () -> {
|
||||
Semaphore semaphore = new Semaphore(3);
|
||||
chunk.raiseFlag(MantleFlag.ETCHED, () -> {
|
||||
chunk.raiseFlagUnchecked(MantleFlag.TILE, run(semaphore, () -> {
|
||||
chunk.iterate(TileWrapper.class, (x, y, z, v) -> {
|
||||
Block block = c.getBlock(x & 15, y + getWorld().minHeight(), z & 15);
|
||||
if (!TileData.setTileState(block, v.getData()))
|
||||
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", block.getX(), block.getY(), block.getZ(), block.getType().getKey(), v.getData().getMaterial().getKey());
|
||||
});
|
||||
}, 0));
|
||||
}, c, 1));
|
||||
chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, run(semaphore, () -> {
|
||||
chunk.iterate(Identifier.class, (x, y, z, v) -> {
|
||||
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
|
||||
});
|
||||
}, 0));
|
||||
}, c, 1));
|
||||
|
||||
chunk.raiseFlagUnchecked(MantleFlag.UPDATE, run(semaphore, () -> {
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
@@ -341,48 +339,35 @@ 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, chunk, rng);
|
||||
update(x, grid[x][z], z, c, rng);
|
||||
}
|
||||
}
|
||||
|
||||
chunk.iterate(MatterUpdate.class, (x, yf, z, v) -> {
|
||||
int y = yf + getWorld().minHeight();
|
||||
if (v != null && v.isUpdate()) {
|
||||
update(x, y, z, c, chunk, rng);
|
||||
update(x, y, z, c, rng);
|
||||
}
|
||||
});
|
||||
chunk.deleteSlices(MatterUpdate.class);
|
||||
getMetrics().getUpdates().put(p.getMilliseconds());
|
||||
}, 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));
|
||||
}
|
||||
}, c, RNG.r.i(2, 20))); //Why is there a random delay here?
|
||||
});
|
||||
|
||||
try {
|
||||
semaphore.acquire(1024);
|
||||
semaphore.acquire(3);
|
||||
} catch (InterruptedException ignored) {}
|
||||
} finally {
|
||||
chunk.release();
|
||||
}
|
||||
}
|
||||
|
||||
private static Runnable run(Semaphore semaphore, Runnable runnable, int delay) {
|
||||
private static Runnable run(Semaphore semaphore, Runnable runnable, Chunk chunk, int delay) {
|
||||
return () -> {
|
||||
try {
|
||||
semaphore.acquire();
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (!semaphore.tryAcquire())
|
||||
return;
|
||||
|
||||
J.s(() -> {
|
||||
Iris.platform.getRegionScheduler().runDelayed(chunk.getWorld(), chunk.getX(), chunk.getZ(), () -> {
|
||||
try {
|
||||
runnable.run();
|
||||
} finally {
|
||||
@@ -395,7 +380,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
@BlockCoordinates
|
||||
@Override
|
||||
|
||||
default void update(int x, int y, int z, Chunk c, MantleChunk mc, RNG rf) {
|
||||
default void update(int x, int y, int z, Chunk c, RNG rf) {
|
||||
Block block = c.getBlock(x, y, z);
|
||||
BlockData data = block.getBlockData();
|
||||
blockUpdatedMetric();
|
||||
@@ -408,11 +393,17 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
}
|
||||
|
||||
if (slot != null) {
|
||||
KList<IrisLootTable> tables = getLootTables(rx, block, mc);
|
||||
KList<IrisLootTable> tables = getLootTables(rx, block);
|
||||
|
||||
try {
|
||||
Bukkit.getPluginManager().callEvent(new IrisLootEvent(this, block, slot, tables));
|
||||
if (tables.isEmpty()) return;
|
||||
|
||||
if (!tables.isEmpty()){
|
||||
Iris.debug("IrisLootEvent has been accessed");
|
||||
}
|
||||
|
||||
if (tables.isEmpty())
|
||||
return;
|
||||
InventoryHolder m = (InventoryHolder) block.getState();
|
||||
addItems(false, m.getInventory(), rx, tables, slot, c.getWorld(), x, y, z, 15);
|
||||
|
||||
@@ -478,23 +469,13 @@ 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, mc);
|
||||
PlacedObject po = getObjectPlacement(rx, ry, rz);
|
||||
if (po != null && po.getPlacement() != null) {
|
||||
if (B.isStorageChest(b.getBlockData())) {
|
||||
IrisLootTable table = po.getPlacement().getTable(b.getBlockData(), getData());
|
||||
@@ -545,8 +526,9 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
if (IrisLootEvent.callLootEvent(items, inv, world, x, y, z))
|
||||
return;
|
||||
|
||||
if (PaperLib.isPaper() && getWorld().hasRealWorld()) {
|
||||
PaperLib.getChunkAtAsync(getWorld().realWorld(), x >> 4, z >> 4).thenAccept((c) -> {
|
||||
if (world != null) {
|
||||
final int cX = x >> 4, cZ = z >> 4;
|
||||
Iris.platform.getChunkAtAsync(world, cX, cZ, true, false).thenAccept((c) -> {
|
||||
Runnable r = () -> {
|
||||
for (ItemStack i : items) {
|
||||
inv.addItem(i);
|
||||
@@ -555,10 +537,10 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
scramble(inv, rng);
|
||||
};
|
||||
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
if (Iris.platform.isOwnedByCurrentRegion(world, cX, cZ)) {
|
||||
r.run();
|
||||
} else {
|
||||
J.s(r);
|
||||
Iris.platform.getRegionScheduler().run(world, cX, cZ, r);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -817,16 +799,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
}
|
||||
|
||||
default PlacedObject getObjectPlacement(int x, int y, int z) {
|
||||
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);
|
||||
String objectAt = getMantle().getMantle().get(x, y, z, String.class);
|
||||
if (objectAt == null || objectAt.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@@ -836,7 +809,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
int id = Integer.parseInt(v[1]);
|
||||
|
||||
|
||||
JigsawPieceContainer container = chunk.get(x & 15, y, z & 15, JigsawPieceContainer.class);
|
||||
JigsawPieceContainer container = getMantle().getMantle().get(x, y, z, JigsawPieceContainer.class);
|
||||
if (container != null) {
|
||||
IrisJigsawPiece piece = container.load(getData());
|
||||
if (piece.getObject().equals(object))
|
||||
@@ -851,7 +824,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
}
|
||||
}
|
||||
|
||||
IrisBiome biome = getSurfaceBiome(x, z);
|
||||
IrisBiome biome = getBiome(x, y, z);
|
||||
|
||||
for (IrisObjectPlacement i : biome.getObjects()) {
|
||||
if (i.getPlace().contains(object)) {
|
||||
@@ -912,7 +885,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
player.sendMessage(C.GOLD + "No strongholds in world.");
|
||||
} else {
|
||||
Location ll = new Location(player.getWorld(), pr.getX(), 40, pr.getZ());
|
||||
J.s(() -> player.teleport(ll));
|
||||
Iris.platform.teleportAsync(player, ll);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -1000,7 +973,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
|
||||
default void cleanupMantleChunk(int x, int z) {
|
||||
if (IrisSettings.get().getPerformance().isTrimMantleInStudio() || !isStudio()) {
|
||||
getMantle().cleanupChunk(x, z);
|
||||
J.a(() -> getMantle().cleanupChunk(x, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-18
@@ -20,40 +20,34 @@ package com.volmit.iris.engine.framework;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.events.IrisEngineHotloadEvent;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.format.C;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import de.crazydev22.platformutils.scheduler.task.Task;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.EnderSignal;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||
import org.bukkit.event.world.WorldSaveEvent;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public abstract class EngineAssignedWorldManager extends EngineAssignedComponent implements EngineWorldManager, Listener {
|
||||
private final int taskId;
|
||||
private final Task task;
|
||||
protected AtomicBoolean ignoreTP = new AtomicBoolean(false);
|
||||
|
||||
public EngineAssignedWorldManager() {
|
||||
super(null, null);
|
||||
taskId = -1;
|
||||
task = null;
|
||||
}
|
||||
|
||||
public EngineAssignedWorldManager(Engine engine) {
|
||||
super(engine, "World");
|
||||
Iris.instance.registerListener(this);
|
||||
taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::onTick, 0, 0);
|
||||
task = Iris.platform.getGlobalScheduler().runAtFixedRate(this::onTick, 1, 1);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -126,17 +120,10 @@ public abstract class EngineAssignedWorldManager extends EngineAssignedComponent
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(ChunkUnloadEvent e) {
|
||||
if (e.getChunk().getWorld().equals(getTarget().getWorld().realWorld())) {
|
||||
onChunkUnload(e.getChunk());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
Iris.instance.unregisterListener(this);
|
||||
Bukkit.getScheduler().cancelTask(taskId);
|
||||
if (task != null) task.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +45,6 @@ public interface EngineWorldManager {
|
||||
|
||||
void onChunkLoad(Chunk e, boolean generated);
|
||||
|
||||
void onChunkUnload(Chunk e);
|
||||
|
||||
void chargeEnergy();
|
||||
|
||||
void teleportAsync(PlayerTeleportEvent e);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
package com.volmit.iris.engine.framework;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.nms.container.BlockPos;
|
||||
import com.volmit.iris.core.nms.container.Pair;
|
||||
@@ -36,7 +37,6 @@ import com.volmit.iris.util.matter.MatterCavern;
|
||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
import com.volmit.iris.util.scheduling.jobs.SingleJob;
|
||||
import org.bukkit.Location;
|
||||
@@ -114,7 +114,7 @@ public interface Locator<T> {
|
||||
default void find(Player player, boolean teleport, String message) {
|
||||
find(player, location -> {
|
||||
if (teleport) {
|
||||
J.s(() -> player.teleport(location));
|
||||
Iris.platform.teleportAsync(player, location);
|
||||
} else {
|
||||
player.sendMessage(C.GREEN + message + " at: " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ());
|
||||
}
|
||||
|
||||
+1
-10
@@ -24,6 +24,7 @@ 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 {
|
||||
@@ -82,16 +83,6 @@ 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;
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.volmit.iris.engine.framework.placer;
|
||||
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.object.IObjectPlacer;
|
||||
import com.volmit.iris.engine.object.TileData;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import static com.volmit.iris.Iris.platform;
|
||||
|
||||
@EqualsAndHashCode
|
||||
public class SafeObjectPlacer implements IObjectPlacer {
|
||||
private final World world;
|
||||
private final IObjectPlacer placer;
|
||||
|
||||
public SafeObjectPlacer(World world, IObjectPlacer placer) {
|
||||
this.world = world;
|
||||
this.placer = placer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHighest(int x, int z, IrisData data) {
|
||||
if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) {
|
||||
return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> getHighest(x, z, data))
|
||||
.getResult()
|
||||
.join();
|
||||
}
|
||||
return placer.getHighest(x, z, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHighest(int x, int z, IrisData data, boolean ignoreFluid) {
|
||||
if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) {
|
||||
if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!");
|
||||
return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> getHighest(x, z, data, ignoreFluid))
|
||||
.getResult()
|
||||
.join();
|
||||
}
|
||||
return placer.getHighest(x, z, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(int x, int y, int z, BlockData d) {
|
||||
if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) {
|
||||
if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!");
|
||||
platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> set(x, y, z, d)).getResult().join();
|
||||
} else placer.set(x, y, z, d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData get(int x, int y, int z) {
|
||||
if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) {
|
||||
if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!");
|
||||
return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> get(x, y, z)).getResult().join();
|
||||
}
|
||||
return placer.get(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreventingDecay() {
|
||||
return placer.isPreventingDecay();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCarved(int x, int y, int z) {
|
||||
return placer.isCarved(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid(int x, int y, int z) {
|
||||
if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) {
|
||||
if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!");
|
||||
return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> isSolid(x, y, z)).getResult().join();
|
||||
}
|
||||
return placer.isSolid(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnderwater(int x, int z) {
|
||||
if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) {
|
||||
if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!");
|
||||
return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> isUnderwater(x, z)).getResult().join();
|
||||
}
|
||||
return placer.isUnderwater(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFluidHeight() {
|
||||
return placer.getFluidHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugSmartBore() {
|
||||
return placer.isDebugSmartBore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTile(int xx, int yy, int zz, TileData tile) {
|
||||
if (!platform.isOwnedByCurrentRegion(world, xx >> 4, zz >> 4)) {
|
||||
if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!");
|
||||
platform.getRegionScheduler().run(world, xx >> 4, zz >> 4, () -> setTile(xx, yy, zz, tile)).getResult().join();
|
||||
} else placer.setTile(xx, yy, zz, tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Engine getEngine() {
|
||||
return placer.getEngine();
|
||||
}
|
||||
}
|
||||
@@ -59,11 +59,6 @@ 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);
|
||||
@@ -83,6 +78,12 @@ 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
|
||||
@@ -124,13 +125,4 @@ public class WorldObjectPlacer implements IObjectPlacer {
|
||||
public void setTile(int xx, int yy, int zz, TileData tile) {
|
||||
tile.toBukkitTry(world.getBlockAt(xx, yy + world.getMinHeight(), zz));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void setData(int xx, int yy, int zz, T data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getData(int xx, int yy, int zz, Class<T> t) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public class PlannedPiece {
|
||||
this.setRotation(rot);
|
||||
this.ogObject = data.getObjectLoader().load(piece.getObject());
|
||||
this.object = structure.rotated(piece, rotation);
|
||||
this.piece = rotation.rotateCopy(piece, new IrisPosition(object.getShrinkOffset()));
|
||||
this.piece = rotation.rotateCopy(piece);
|
||||
this.piece.setLoadKey(piece.getLoadKey());
|
||||
this.object.setLoadKey(piece.getObject());
|
||||
this.ogObject.setLoadKey(piece.getObject());
|
||||
|
||||
@@ -154,14 +154,15 @@ 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) -> {
|
||||
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);
|
||||
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);
|
||||
}, null, getData().getEngine() != null ? getData() : eng.getData()) != -1;
|
||||
}
|
||||
|
||||
//TODO properly fix for folia
|
||||
public void place(WorldObjectPlacer placer, Consumer<Boolean> consumer) {
|
||||
J.s(() -> consumer.accept(place(placer, placer.getMantle().getMantle(), placer.getEngine())));
|
||||
Iris.platform.getRegionScheduler().run(placer.getWorld(), position.getX() >> 4, position.getZ() >> 4, () -> consumer.accept(place(placer, placer.getMantle().getMantle(), placer.getEngine())));
|
||||
}
|
||||
|
||||
private void generateOutwards() {
|
||||
|
||||
@@ -29,6 +29,8 @@ 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;
|
||||
@@ -36,6 +38,7 @@ 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;
|
||||
@@ -46,7 +49,10 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public interface EngineMantle extends MatterGenerator {
|
||||
import static com.volmit.iris.util.parallel.StreamUtils.forEach;
|
||||
import static com.volmit.iris.util.parallel.StreamUtils.streamRadius;
|
||||
|
||||
public interface EngineMantle {
|
||||
BlockData AIR = B.get("AIR");
|
||||
|
||||
Mantle getMantle();
|
||||
@@ -174,6 +180,49 @@ public interface EngineMantle extends MatterGenerator {
|
||||
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()) {
|
||||
@@ -213,6 +262,9 @@ public interface EngineMantle extends MatterGenerator {
|
||||
default int getLoadedRegionCount() {
|
||||
return getMantle().getLoadedRegionCount();
|
||||
}
|
||||
default long getLastUseMapMemoryUsage(){
|
||||
return getMantle().LastUseMapMemoryUsage();
|
||||
}
|
||||
|
||||
MantleJigsawComponent getJigsawComponent();
|
||||
|
||||
@@ -238,7 +290,7 @@ public interface EngineMantle extends MatterGenerator {
|
||||
if (!isCovered(x, z)) return;
|
||||
MantleChunk chunk = getMantle().getChunk(x, z).use();
|
||||
try {
|
||||
chunk.raiseFlagUnchecked(MantleFlag.CLEANED, () -> {
|
||||
chunk.raiseFlag(MantleFlag.CLEANED, () -> {
|
||||
chunk.deleteSlices(BlockData.class);
|
||||
chunk.deleteSlices(String.class);
|
||||
chunk.deleteSlices(MatterCavern.class);
|
||||
@@ -249,7 +301,7 @@ public interface EngineMantle extends MatterGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
default int getUnloadRegionCount() {
|
||||
default long getUnloadRegionCount() {
|
||||
return getMantle().getUnloadRegionCount();
|
||||
}
|
||||
|
||||
|
||||
@@ -40,12 +40,13 @@ import com.volmit.iris.util.matter.Matter;
|
||||
import com.volmit.iris.util.matter.MatterCavern;
|
||||
import com.volmit.iris.util.matter.TileWrapper;
|
||||
import com.volmit.iris.util.noise.CNG;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import lombok.Data;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.volmit.iris.engine.mantle.EngineMantle.AIR;
|
||||
|
||||
@@ -53,31 +54,25 @@ 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 Map<Long, MantleChunk> cachedChunks;
|
||||
private final KMap<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, boolean multicore) {
|
||||
public MantleWriter(EngineMantle engineMantle, Mantle mantle, int x, int z, int radius) {
|
||||
this.engineMantle = engineMantle;
|
||||
this.mantle = mantle;
|
||||
this.radius = radius * 2;
|
||||
final int d = this.radius + 1;
|
||||
this.cachedChunks = multicore ? new KMap<>(d * d, 0.75f, Math.max(32, Runtime.getRuntime().availableProcessors() * 4)) : new Long2ObjectOpenHashMap<>(d * d);
|
||||
this.cachedChunks = new KMap<>();
|
||||
this.radius = radius;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
|
||||
final int parallelism = multicore ? Runtime.getRuntime().availableProcessors() / 2 : 4;
|
||||
final var map = multicore ? cachedChunks : new KMap<Long, MantleChunk>(d * d, 1f, parallelism);
|
||||
mantle.getChunks(
|
||||
x - radius,
|
||||
x + radius,
|
||||
z - radius,
|
||||
z + radius,
|
||||
parallelism,
|
||||
(i, j, c) -> map.put(Cache.key(i, j), c.use())
|
||||
);
|
||||
if (!multicore) cachedChunks.putAll(map);
|
||||
int r = radius / 4;
|
||||
for (int i = -r; i <= r; i++) {
|
||||
for (int j = -r; j <= r; j++) {
|
||||
cachedChunks.put(Cache.key(i + x, j + z), mantle.getChunk(i + x, j + z).use());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<IrisPosition> getBallooned(Set<IrisPosition> vset, double radius) {
|
||||
@@ -187,13 +182,8 @@ public class MantleWriter implements IObjectPlacer, AutoCloseable {
|
||||
Iris.error("Mantle Writer Accessed chunk out of bounds" + cx + "," + cz);
|
||||
return null;
|
||||
}
|
||||
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();
|
||||
}
|
||||
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!)");
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -35,6 +35,7 @@ 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;
|
||||
@@ -44,7 +45,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
|
||||
private final CNG cng;
|
||||
|
||||
public MantleJigsawComponent(EngineMantle engineMantle) {
|
||||
super(engineMantle, ReservedFlag.JIGSAW, 1);
|
||||
super(engineMantle, ReservedFlag.JIGSAW, 2);
|
||||
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().keys()) {
|
||||
for (BlockVector j : clump.getBlocks().keySet()) {
|
||||
int nx = j.getBlockX() + x;
|
||||
int ny = j.getBlockY() + y;
|
||||
int nz = j.getBlockZ() + z;
|
||||
|
||||
@@ -18,10 +18,13 @@
|
||||
|
||||
package com.volmit.iris.engine.object;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.framework.placer.SafeObjectPlacer;
|
||||
import de.crazydev22.platformutils.Type;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface IObjectPlacer {
|
||||
int getHighest(int x, int z, IrisData data);
|
||||
@@ -46,9 +49,11 @@ 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();
|
||||
|
||||
default IObjectPlacer sync(World world) {
|
||||
if (Iris.platform.getType() == Type.FOLIA)
|
||||
return new SafeObjectPlacer(world, this);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ public class IrisCommand {
|
||||
return;
|
||||
}
|
||||
|
||||
var scheduler = Iris.platform.getGlobalScheduler();
|
||||
for (String command : commands) {
|
||||
command = (command.startsWith("/") ? command.replaceFirst("/", "") : command)
|
||||
.replaceAll("\\Q{x}\\E", String.valueOf(at.getBlockX()))
|
||||
@@ -74,9 +75,9 @@ public class IrisCommand {
|
||||
.replaceAll("\\Q{z}\\E", String.valueOf(at.getBlockZ()));
|
||||
final String finalCommand = command;
|
||||
if (repeat) {
|
||||
Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), delay, repeatDelay);
|
||||
scheduler.runAtFixedRate(() -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), Math.max(delay, 1), Math.max(repeatDelay, 1));
|
||||
} else {
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), delay);
|
||||
scheduler.runDelayed(() -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), Math.max(delay, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,10 +122,6 @@ 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"));
|
||||
@@ -164,7 +160,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("IRON_CHAIN", "IRON_BARS"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("CHAIN", "IRON_BARS"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("NETHERITE_BLOCK", "QUARTZ_BLOCK"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("BLACKSTONE", "COBBLESTONE"));
|
||||
filters.add(new IrisCompatabilityBlockFilter("BASALT", "STONE"));
|
||||
@@ -258,6 +254,7 @@ 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,18 +249,14 @@ 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\nFile extension: .engine.kts")
|
||||
@Desc("A list of scripts executed on engine setup")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@ArrayType(type = String.class, min = 1)
|
||||
private KList<String> engineScripts = new KList<>();
|
||||
@Desc("A list of scripts executed on data setup\nFile extension: .data.kts")
|
||||
@Desc("A list of scripts executed on data setup")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@ArrayType(type = String.class, min = 1)
|
||||
private KList<String> dataScripts = new KList<>();
|
||||
@Desc("A list of scripts executed on chunk update\nFile extension: .update.kts")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@ArrayType(type = String.class, min = 1)
|
||||
private KList<String> chunkUpdateScripts = new KList<>();
|
||||
@Desc("Use legacy rarity instead of modern one\nWARNING: Changing this may break expressions and image maps")
|
||||
private boolean legacyRarity = true;
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public class IrisDimensionMode {
|
||||
private IrisDimensionModeType type = IrisDimensionModeType.OVERWORLD;
|
||||
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@Desc("The script to create the dimension mode instead of using provided types\nFile extension: .engine.kts")
|
||||
@Desc("The script to create the dimension mode instead of using provided types")
|
||||
private String script;
|
||||
|
||||
public EngineMode create(Engine engine) {
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.object.annotations.*;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@@ -194,7 +193,7 @@ public class IrisEffect {
|
||||
if (sound != null) {
|
||||
Location part = p.getLocation().clone().add(RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance));
|
||||
|
||||
J.s(() -> p.playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch)));
|
||||
schedule(p, () -> p.playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch)));
|
||||
}
|
||||
|
||||
if (particleEffect != null) {
|
||||
@@ -204,7 +203,7 @@ public class IrisEffect {
|
||||
part.add(RNG.r.d(), 0, RNG.r.d());
|
||||
int offset = p.getWorld().getMinHeight();
|
||||
if (extra != 0) {
|
||||
J.s(() -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset),
|
||||
schedule(p, () -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset),
|
||||
part.getZ(),
|
||||
particleCount,
|
||||
randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX,
|
||||
@@ -212,7 +211,7 @@ public class IrisEffect {
|
||||
randomAltZ ? RNG.r.d(-particleAltZ, particleAltZ) : particleAltZ,
|
||||
extra));
|
||||
} else {
|
||||
J.s(() -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(),
|
||||
schedule(p, () -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(),
|
||||
particleCount,
|
||||
randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX,
|
||||
randomAltY ? RNG.r.d(-particleAltY, particleAltY) : particleAltY,
|
||||
@@ -231,10 +230,10 @@ public class IrisEffect {
|
||||
return;
|
||||
}
|
||||
|
||||
J.s(() -> p.removePotionEffect(getRealType()));
|
||||
schedule(p, () -> p.removePotionEffect(getRealType()));
|
||||
}
|
||||
|
||||
J.s(() -> p.addPotionEffect(new PotionEffect(getRealType(),
|
||||
schedule(p, () -> p.addPotionEffect(new PotionEffect(getRealType(),
|
||||
RNG.r.i(Math.min(potionTicksMax, potionTicksMin),
|
||||
Math.max(potionTicksMax, potionTicksMin)),
|
||||
getPotionStrength(),
|
||||
@@ -254,7 +253,7 @@ public class IrisEffect {
|
||||
if (sound != null) {
|
||||
Location part = p.getLocation().clone().add(RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance));
|
||||
|
||||
J.s(() -> p.getWorld().playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch)));
|
||||
schedule(p, () -> p.getWorld().playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch)));
|
||||
}
|
||||
|
||||
if (particleEffect != null) {
|
||||
@@ -262,7 +261,7 @@ public class IrisEffect {
|
||||
part.add(RNG.r.d(), 0, RNG.r.d());
|
||||
int offset = p.getWorld().getMinHeight();
|
||||
if (extra != 0) {
|
||||
J.s(() -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset),
|
||||
schedule(p, () -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset),
|
||||
part.getZ(),
|
||||
particleCount,
|
||||
randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX,
|
||||
@@ -270,7 +269,7 @@ public class IrisEffect {
|
||||
randomAltZ ? RNG.r.d(-particleAltZ, particleAltZ) : particleAltZ,
|
||||
extra));
|
||||
} else {
|
||||
J.s(() -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(),
|
||||
schedule(p, () -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(),
|
||||
particleCount,
|
||||
randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX,
|
||||
randomAltY ? RNG.r.d(-particleAltY, particleAltY) : particleAltY,
|
||||
@@ -278,4 +277,8 @@ public class IrisEffect {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void schedule(Entity entity, Runnable task) {
|
||||
Iris.platform.getEntityScheduler(entity).run(task, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,6 @@ import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.plugin.Chunks;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -50,13 +48,11 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.loot.LootContext;
|
||||
import org.bukkit.loot.LootTable;
|
||||
import org.bukkit.loot.Lootable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static com.volmit.iris.util.data.registry.Particles.ITEM;
|
||||
|
||||
@@ -166,12 +162,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 location to find the target location. You can spawn any entity this way.\nFile extension: .spawn.kts")
|
||||
@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.")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
private String spawnerScript = "";
|
||||
|
||||
@ArrayType(min = 1, type = String.class)
|
||||
@Desc("Executed post spawn you can modify the entity however you want with it\nFile extension: .postspawn.kts")
|
||||
@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.")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
private KList<String> postSpawnScripts = new KList<>();
|
||||
|
||||
@@ -183,38 +179,34 @@ public class IrisEntity extends IrisRegistrant {
|
||||
return spawn(gen, at, new RNG(at.hashCode()));
|
||||
}
|
||||
|
||||
public Entity spawn(Engine gen, Location at, RNG rng) {
|
||||
public Entity spawn(Engine gen, final Location at, RNG rng) {
|
||||
if (!Iris.platform.isOwnedByCurrentRegion(at)) {
|
||||
try {
|
||||
final Location finalAt = at;
|
||||
return Iris.platform.getRegionScheduler().run(at, () -> spawn(gen, finalAt, rng))
|
||||
.getResult()
|
||||
.get(500, TimeUnit.MILLISECONDS);
|
||||
} catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Chunks.isSafe(at)) {
|
||||
return null;
|
||||
}
|
||||
if (isSpawnEffectRiseOutOfGround()) {
|
||||
AtomicReference<Location> f = new AtomicReference<>(at);
|
||||
try {
|
||||
J.sfut(() -> {
|
||||
if (Chunks.hasPlayersNearby(f.get())) {
|
||||
Location b = f.get().clone();
|
||||
Location start = new Location(b.getWorld(), b.getX(), b.getY() - 5, b.getZ());
|
||||
f.set(start);
|
||||
}
|
||||
}).get();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
at = f.get();
|
||||
if (isSpawnEffectRiseOutOfGround() && Chunks.hasPlayersNearby(at)) {
|
||||
at.add(0, -5, 0);
|
||||
}
|
||||
|
||||
Entity ee = doSpawn(at);
|
||||
|
||||
if (ee == null && !Chunks.isSafe(at)) {
|
||||
if (ee == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!spawnerScript.isEmpty() && ee == null) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
ee = (Entity) gen.getExecution().spawnMob(spawnerScript, at);
|
||||
ee = (Entity) gen.getExecution().spawnMob(spawnerScript, at.clone());
|
||||
} catch (Throwable ex) {
|
||||
Iris.error("You must return an Entity in your scripts to use entity scripts!");
|
||||
ex.printStackTrace();
|
||||
@@ -241,111 +233,96 @@ public class IrisEntity extends IrisRegistrant {
|
||||
|
||||
int gg = 0;
|
||||
for (IrisEntity i : passengers) {
|
||||
Entity passenger = i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++));
|
||||
if (!Bukkit.isPrimaryThread()) {
|
||||
J.s(() -> e.addPassenger(passenger));
|
||||
}
|
||||
e.addPassenger(i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++)));
|
||||
}
|
||||
|
||||
if (e instanceof Attributable) {
|
||||
Attributable a = (Attributable) e;
|
||||
|
||||
if (e instanceof Attributable attributable) {
|
||||
for (IrisAttributeModifier i : getAttributes()) {
|
||||
i.apply(rng, a);
|
||||
i.apply(rng, attributable);
|
||||
}
|
||||
}
|
||||
|
||||
if (e instanceof Lootable) {
|
||||
Lootable l = (Lootable) e;
|
||||
if (e instanceof Lootable lootable && getLoot().getTables().isNotEmpty()) {
|
||||
lootable.setLootTable(new LootTable() {
|
||||
@Override
|
||||
public NamespacedKey getKey() {
|
||||
return new NamespacedKey(Iris.instance, "loot-" + IrisEntity.this.hashCode());
|
||||
}
|
||||
|
||||
if (getLoot().getTables().isNotEmpty()) {
|
||||
Location finalAt = at;
|
||||
l.setLootTable(new LootTable() {
|
||||
@Override
|
||||
public NamespacedKey getKey() {
|
||||
return new NamespacedKey(Iris.instance, "loot-" + IrisEntity.this.hashCode());
|
||||
@Override
|
||||
public Collection<ItemStack> populateLoot(Random random, LootContext context) {
|
||||
KList<ItemStack> items = new KList<>();
|
||||
|
||||
for (String fi : getLoot().getTables()) {
|
||||
IrisLootTable i = gen.getData().getLootLoader().load(fi);
|
||||
items.addAll(i.getLoot(gen.isStudio(), rng.nextParallelRNG(345911), InventorySlotType.STORAGE, at.getWorld(), at.getBlockX(), at.getBlockY(), at.getBlockZ()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ItemStack> populateLoot(Random random, LootContext context) {
|
||||
KList<ItemStack> items = new KList<>();
|
||||
return items;
|
||||
}
|
||||
|
||||
for (String fi : getLoot().getTables()) {
|
||||
IrisLootTable i = gen.getData().getLootLoader().load(fi);
|
||||
items.addAll(i.getLoot(gen.isStudio(), rng.nextParallelRNG(345911), InventorySlotType.STORAGE, finalAt.getWorld(), finalAt.getBlockX(), finalAt.getBlockY(), finalAt.getBlockZ()));
|
||||
}
|
||||
|
||||
return items;
|
||||
@Override
|
||||
public void fillInventory(Inventory inventory, Random random, LootContext context) {
|
||||
for (ItemStack i : populateLoot(random, context)) {
|
||||
inventory.addItem(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillInventory(Inventory inventory, Random random, LootContext context) {
|
||||
for (ItemStack i : populateLoot(random, context)) {
|
||||
inventory.addItem(i);
|
||||
}
|
||||
|
||||
gen.scramble(inventory, rng);
|
||||
}
|
||||
});
|
||||
}
|
||||
gen.scramble(inventory, rng);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (e instanceof LivingEntity) {
|
||||
LivingEntity l = (LivingEntity) e;
|
||||
l.setAI(isAi());
|
||||
l.setCanPickupItems(isPickupItems());
|
||||
if (e instanceof LivingEntity living) {
|
||||
living.setAI(isAi());
|
||||
living.setCanPickupItems(isPickupItems());
|
||||
|
||||
if (getLeashHolder() != null) {
|
||||
l.setLeashHolder(getLeashHolder().spawn(gen, at, rng.nextParallelRNG(234548)));
|
||||
living.setLeashHolder(getLeashHolder().spawn(gen, at, rng.nextParallelRNG(234548)));
|
||||
}
|
||||
|
||||
l.setRemoveWhenFarAway(isRemovable());
|
||||
living.setRemoveWhenFarAway(isRemovable());
|
||||
|
||||
if (getHelmet() != null && rng.i(1, getHelmet().getRarity()) == 1) {
|
||||
l.getEquipment().setHelmet(getHelmet().get(gen.isStudio(), rng));
|
||||
living.getEquipment().setHelmet(getHelmet().get(gen.isStudio(), rng));
|
||||
}
|
||||
|
||||
if (getChestplate() != null && rng.i(1, getChestplate().getRarity()) == 1) {
|
||||
l.getEquipment().setChestplate(getChestplate().get(gen.isStudio(), rng));
|
||||
living.getEquipment().setChestplate(getChestplate().get(gen.isStudio(), rng));
|
||||
}
|
||||
|
||||
if (getLeggings() != null && rng.i(1, getLeggings().getRarity()) == 1) {
|
||||
l.getEquipment().setLeggings(getLeggings().get(gen.isStudio(), rng));
|
||||
living.getEquipment().setLeggings(getLeggings().get(gen.isStudio(), rng));
|
||||
}
|
||||
|
||||
if (getBoots() != null && rng.i(1, getBoots().getRarity()) == 1) {
|
||||
l.getEquipment().setBoots(getBoots().get(gen.isStudio(), rng));
|
||||
living.getEquipment().setBoots(getBoots().get(gen.isStudio(), rng));
|
||||
}
|
||||
|
||||
if (getMainHand() != null && rng.i(1, getMainHand().getRarity()) == 1) {
|
||||
l.getEquipment().setItemInMainHand(getMainHand().get(gen.isStudio(), rng));
|
||||
living.getEquipment().setItemInMainHand(getMainHand().get(gen.isStudio(), rng));
|
||||
}
|
||||
|
||||
if (getOffHand() != null && rng.i(1, getOffHand().getRarity()) == 1) {
|
||||
l.getEquipment().setItemInOffHand(getOffHand().get(gen.isStudio(), rng));
|
||||
living.getEquipment().setItemInOffHand(getOffHand().get(gen.isStudio(), rng));
|
||||
}
|
||||
}
|
||||
|
||||
if (e instanceof Ageable && isBaby()) {
|
||||
((Ageable) e).setBaby();
|
||||
if (e instanceof Ageable ageable && isBaby()) {
|
||||
ageable.setBaby();
|
||||
}
|
||||
|
||||
if (e instanceof Panda) {
|
||||
((Panda) e).setMainGene(getPandaMainGene());
|
||||
((Panda) e).setMainGene(getPandaHiddenGene());
|
||||
if (e instanceof Panda panda) {
|
||||
panda.setMainGene(getPandaMainGene());
|
||||
panda.setMainGene(getPandaHiddenGene());
|
||||
}
|
||||
|
||||
if (e instanceof Villager) {
|
||||
Villager villager = (Villager) e;
|
||||
if (e instanceof Villager villager) {
|
||||
villager.setRemoveWhenFarAway(false);
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> {
|
||||
villager.setPersistent(true);
|
||||
}, 1);
|
||||
villager.setPersistent(true);
|
||||
}
|
||||
|
||||
if (e instanceof Mob) {
|
||||
Mob m = (Mob) e;
|
||||
m.setAware(isAware());
|
||||
if (e instanceof Mob mob) {
|
||||
mob.setAware(isAware());
|
||||
}
|
||||
|
||||
if (spawnEffect != null) {
|
||||
@@ -365,41 +342,35 @@ public class IrisEntity extends IrisRegistrant {
|
||||
rawCommands.forEach(r -> r.run(fat));
|
||||
}
|
||||
|
||||
Location finalAt1 = at;
|
||||
if (isSpawnEffectRiseOutOfGround() && e instanceof LivingEntity living && Chunks.hasPlayersNearby(at)) {
|
||||
e.setInvulnerable(true);
|
||||
living.setAI(false);
|
||||
living.setCollidable(false);
|
||||
living.setNoDamageTicks(100000);
|
||||
AtomicInteger t = new AtomicInteger(0);
|
||||
Iris.platform.getRegionScheduler().runAtFixedRate(at, task -> {
|
||||
if (t.get() > 100) {
|
||||
task.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
J.s(() -> {
|
||||
if (isSpawnEffectRiseOutOfGround() && e instanceof LivingEntity && Chunks.hasPlayersNearby(finalAt1)) {
|
||||
Location start = finalAt1.clone();
|
||||
e.setInvulnerable(true);
|
||||
((LivingEntity) e).setAI(false);
|
||||
((LivingEntity) e).setCollidable(false);
|
||||
((LivingEntity) e).setNoDamageTicks(100000);
|
||||
AtomicInteger t = new AtomicInteger(0);
|
||||
AtomicInteger v = new AtomicInteger(0);
|
||||
v.set(J.sr(() -> {
|
||||
if (t.get() > 100) {
|
||||
J.csr(v.get());
|
||||
return;
|
||||
t.incrementAndGet();
|
||||
if (e.getLocation().getBlock().getType().isSolid() || living.getEyeLocation().getBlock().getType().isSolid()) {
|
||||
Iris.platform.teleportAsync(e, at.add(0, 0.1, 0));
|
||||
Material material = living.getEyeLocation().subtract(0, 2, 0).getBlock().getType();
|
||||
if (!material.isAir()) e.getWorld().spawnParticle(ITEM, living.getEyeLocation(), 6, 0.2, 0.4, 0.2, 0.06f, new ItemStack(material));
|
||||
if (M.r(0.2)) {
|
||||
e.getWorld().playSound(e.getLocation(), Sound.BLOCK_CHORUS_FLOWER_GROW, 0.8f, 0.1f);
|
||||
}
|
||||
|
||||
t.incrementAndGet();
|
||||
if (e.getLocation().getBlock().getType().isSolid() || ((LivingEntity) e).getEyeLocation().getBlock().getType().isSolid()) {
|
||||
e.teleport(start.add(new Vector(0, 0.1, 0)));
|
||||
ItemStack itemCrackData = new ItemStack(((LivingEntity) e).getEyeLocation().clone().subtract(0, 2, 0).getBlock().getBlockData().getMaterial());
|
||||
e.getWorld().spawnParticle(ITEM, ((LivingEntity) e).getEyeLocation(), 6, 0.2, 0.4, 0.2, 0.06f, itemCrackData);
|
||||
if (M.r(0.2)) {
|
||||
e.getWorld().playSound(e.getLocation(), Sound.BLOCK_CHORUS_FLOWER_GROW, 0.8f, 0.1f);
|
||||
}
|
||||
} else {
|
||||
J.csr(v.get());
|
||||
((LivingEntity) e).setNoDamageTicks(0);
|
||||
((LivingEntity) e).setCollidable(true);
|
||||
((LivingEntity) e).setAI(true);
|
||||
e.setInvulnerable(false);
|
||||
}
|
||||
}, 0));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
task.cancel();
|
||||
living.setNoDamageTicks(0);
|
||||
living.setCollidable(true);
|
||||
living.setAI(true);
|
||||
e.setInvulnerable(false);
|
||||
}
|
||||
}, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
return e;
|
||||
@@ -429,29 +400,6 @@ public class IrisEntity extends IrisRegistrant {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Bukkit.isPrimaryThread()) {
|
||||
// Someone called spawn (worldedit maybe?) on a non server thread
|
||||
// Due to the structure of iris, we will call it sync and busy wait until it's done.
|
||||
AtomicReference<Entity> ae = new AtomicReference<>();
|
||||
|
||||
try {
|
||||
J.s(() -> ae.set(doSpawn(at)));
|
||||
} catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
|
||||
while (ae.get() == null) {
|
||||
J.sleep(25);
|
||||
|
||||
if (p.getMilliseconds() > 500) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return ae.get();
|
||||
}
|
||||
|
||||
if (isSpecialType()) {
|
||||
return Iris.service(ExternalDataSVC.class).spawnMob(at, Identifier.fromString(specialType));
|
||||
}
|
||||
|
||||
@@ -36,8 +36,14 @@ import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static com.volmit.iris.Iris.platform;
|
||||
|
||||
@Snippet("entity-spawn")
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@@ -164,8 +170,15 @@ public class IrisEntitySpawn implements IRare {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!ignoreSurfaces && !irisEntity.getSurface().matches(at.clone().subtract(0, 1, 0).getBlock())) {
|
||||
return null;
|
||||
if (!ignoreSurfaces) {
|
||||
Location block = at.clone().subtract(0, 1, 0);
|
||||
BlockData data = platform.getRegionScheduler()
|
||||
.run(block, () -> block.getBlock().getBlockData())
|
||||
.getResult()
|
||||
.join();
|
||||
if (!irisEntity.getSurface().matches(data)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3d boundingBox = INMS.get().getBoundingbox(irisEntity.getType());
|
||||
@@ -199,15 +212,22 @@ public class IrisEntitySpawn implements IRare {
|
||||
int startZ = center.getBlockZ() - (int) (boundingBox.z / 2);
|
||||
int endZ = center.getBlockZ() + (int) (boundingBox.z / 2);
|
||||
|
||||
var region = platform.getRegionScheduler();
|
||||
var lock = new Semaphore(Integer.MAX_VALUE, true);
|
||||
var bool = new AtomicBoolean(true);
|
||||
for (int x = startX; x <= endX; x++) {
|
||||
for (int y = startY; y <= endY; y++) {
|
||||
for (int z = startZ; z <= endZ; z++) {
|
||||
if (world.getBlockAt(x, y, z).getType() != Material.AIR) {
|
||||
return false;
|
||||
}
|
||||
Location l = new Location(world, x, y, z);
|
||||
lock.acquireUninterruptibly();
|
||||
region.run(l, () -> {
|
||||
if (!bool.get()) return false;
|
||||
return bool.compareAndSet(true, l.getBlock().getType() == Material.AIR);
|
||||
}).getResult().exceptionally(f -> false).thenRun(lock::release);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
lock.acquireUninterruptibly(Integer.MAX_VALUE);
|
||||
return bool.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.\nFile extension: .noise.kts")
|
||||
@Desc("Instead of using the style property, use a custom noise generator to represent this style.")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
private String script = null;
|
||||
@MinNumber(0.00001)
|
||||
|
||||
@@ -30,15 +30,18 @@ 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.*;
|
||||
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.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;
|
||||
@@ -62,10 +65,7 @@ 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 Lock readLock;
|
||||
protected transient final Lock writeLock;
|
||||
protected transient final IrisLock readLock = new IrisLock("read-conclock");
|
||||
@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<>();
|
||||
@Getter
|
||||
private VectorMap<BlockData> blocks;
|
||||
@Getter
|
||||
private VectorMap<TileData> states;
|
||||
private KMap<BlockVector, BlockData> blocks;
|
||||
private KMap<BlockVector, TileData> states;
|
||||
@Getter
|
||||
@Setter
|
||||
private int w;
|
||||
@@ -97,21 +97,15 @@ public class IrisObject extends IrisRegistrant {
|
||||
private int h;
|
||||
@Getter
|
||||
@Setter
|
||||
private transient Vector3i center;
|
||||
@Getter
|
||||
private transient Vector3i shrinkOffset;
|
||||
private transient BlockVector center;
|
||||
|
||||
public IrisObject(int w, int h, int d) {
|
||||
blocks = new VectorMap<>();
|
||||
states = new VectorMap<>();
|
||||
blocks = new KMap<>();
|
||||
states = new KMap<>();
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
this.d = d;
|
||||
center = new Vector3i(w / 2, h / 2, d / 2);
|
||||
shrinkOffset = new Vector3i(0, 0, 0);
|
||||
var lock = new ReentrantReadWriteLock();
|
||||
readLock = lock.readLock();
|
||||
writeLock = lock.writeLock();
|
||||
center = new BlockVector(w / 2, h / 2, d / 2);
|
||||
}
|
||||
|
||||
public IrisObject() {
|
||||
@@ -167,10 +161,10 @@ public class IrisObject extends IrisRegistrant {
|
||||
|
||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
BlockData vair = debug ? VAIR_DEBUG : VAIR;
|
||||
writeLock.lock();
|
||||
lock.lock();
|
||||
AtomicInteger applied = new AtomicInteger();
|
||||
if (blocks.isEmpty()) {
|
||||
writeLock.unlock();
|
||||
if (getBlocks().isEmpty()) {
|
||||
lock.unlock();
|
||||
Iris.warn("Cannot Smart Bore " + getLoadKey() + " because it has 0 blocks in it.");
|
||||
smartBored = true;
|
||||
return;
|
||||
@@ -179,7 +173,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 : blocks.keys()) {
|
||||
for (BlockVector i : getBlocks().keySet()) {
|
||||
max.setX(Math.max(i.getX(), max.getX()));
|
||||
min.setX(Math.min(i.getX(), min.getX()));
|
||||
max.setY(Math.max(i.getY(), max.getY()));
|
||||
@@ -199,7 +193,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
int end = Integer.MIN_VALUE;
|
||||
|
||||
for (int ray = min.getBlockX(); ray <= max.getBlockX(); ray++) {
|
||||
if (blocks.containsKey(new Vector3i(ray, finalRayY, rayZ))) {
|
||||
if (getBlocks().containsKey(new BlockVector(ray, finalRayY, rayZ))) {
|
||||
start = Math.min(ray, start);
|
||||
end = Math.max(ray, end);
|
||||
}
|
||||
@@ -207,10 +201,10 @@ public class IrisObject extends IrisRegistrant {
|
||||
|
||||
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
|
||||
for (int i = start; i <= end; i++) {
|
||||
Vector3i v = new Vector3i(i, finalRayY, rayZ);
|
||||
BlockVector v = new BlockVector(i, finalRayY, rayZ);
|
||||
|
||||
if (!vair.equals(blocks.get(v))) {
|
||||
blocks.computeIfAbsent(v, (vv) -> vair);
|
||||
if (!B.isAir(getBlocks().get(v))) {
|
||||
getBlocks().computeIfAbsent(v, (vv) -> vair);
|
||||
applied.getAndIncrement();
|
||||
}
|
||||
}
|
||||
@@ -228,7 +222,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
int end = Integer.MIN_VALUE;
|
||||
|
||||
for (int ray = min.getBlockY(); ray <= max.getBlockY(); ray++) {
|
||||
if (blocks.containsKey(new Vector3i(finalRayX, ray, rayZ))) {
|
||||
if (getBlocks().containsKey(new BlockVector(finalRayX, ray, rayZ))) {
|
||||
start = Math.min(ray, start);
|
||||
end = Math.max(ray, end);
|
||||
}
|
||||
@@ -236,10 +230,10 @@ public class IrisObject extends IrisRegistrant {
|
||||
|
||||
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
|
||||
for (int i = start; i <= end; i++) {
|
||||
Vector3i v = new Vector3i(finalRayX, i, rayZ);
|
||||
BlockVector v = new BlockVector(finalRayX, i, rayZ);
|
||||
|
||||
if (!vair.equals(blocks.get(v))) {
|
||||
blocks.computeIfAbsent(v, (vv) -> vair);
|
||||
if (!B.isAir(getBlocks().get(v))) {
|
||||
getBlocks().computeIfAbsent(v, (vv) -> vair);
|
||||
applied.getAndIncrement();
|
||||
}
|
||||
}
|
||||
@@ -257,7 +251,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
int end = Integer.MIN_VALUE;
|
||||
|
||||
for (int ray = min.getBlockZ(); ray <= max.getBlockZ(); ray++) {
|
||||
if (blocks.containsKey(new Vector3i(finalRayX, rayY, ray))) {
|
||||
if (getBlocks().containsKey(new BlockVector(finalRayX, rayY, ray))) {
|
||||
start = Math.min(ray, start);
|
||||
end = Math.max(ray, end);
|
||||
}
|
||||
@@ -265,10 +259,10 @@ public class IrisObject extends IrisRegistrant {
|
||||
|
||||
if (start != Integer.MAX_VALUE && end != Integer.MIN_VALUE) {
|
||||
for (int i = start; i <= end; i++) {
|
||||
Vector3i v = new Vector3i(finalRayX, rayY, i);
|
||||
BlockVector v = new BlockVector(finalRayX, rayY, i);
|
||||
|
||||
if (!vair.equals(blocks.get(v))) {
|
||||
blocks.computeIfAbsent(v, (vv) -> vair);
|
||||
if (!B.isAir(getBlocks().get(v))) {
|
||||
getBlocks().computeIfAbsent(v, (vv) -> vair);
|
||||
applied.getAndIncrement();
|
||||
}
|
||||
}
|
||||
@@ -279,7 +273,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
|
||||
burst.complete();
|
||||
smartBored = true;
|
||||
writeLock.unlock();
|
||||
lock.unlock();
|
||||
Iris.debug("Smart Bore: " + getLoadKey() + " in " + Form.duration(p.getMilliseconds(), 2) + " (" + Form.f(applied.get()) + ")");
|
||||
}
|
||||
|
||||
@@ -290,8 +284,13 @@ public class IrisObject extends IrisRegistrant {
|
||||
o.setLoadFile(getLoadFile());
|
||||
o.setCenter(getCenter().clone());
|
||||
|
||||
blocks.forEach((i, v) -> o.blocks.put(i.clone(), v.clone()));
|
||||
states.forEach((i, v) -> o.states.put(i.clone(), v.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());
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
@@ -301,24 +300,22 @@ public class IrisObject extends IrisRegistrant {
|
||||
this.w = din.readInt();
|
||||
this.h = din.readInt();
|
||||
this.d = din.readInt();
|
||||
center = new Vector3i(w / 2, h / 2, d / 2);
|
||||
center = new BlockVector(w / 2, h / 2, d / 2);
|
||||
int s = din.readInt();
|
||||
|
||||
for (int i = 0; i < s; i++) {
|
||||
blocks.put(new Vector3i(din.readShort(), din.readShort(), din.readShort()), B.get(din.readUTF()));
|
||||
getBlocks().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), B.get(din.readUTF()));
|
||||
}
|
||||
|
||||
if (din.available() == 0)
|
||||
return;
|
||||
|
||||
try {
|
||||
int size = din.readInt();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
states.put(new Vector3i(din.readShort(), din.readShort(), din.readShort()), TileData.read(din));
|
||||
getStates().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), TileData.read(din));
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,9 +325,9 @@ public class IrisObject extends IrisRegistrant {
|
||||
this.h = din.readInt();
|
||||
this.d = din.readInt();
|
||||
if (!din.readUTF().equals("Iris V2 IOB;")) {
|
||||
throw new HeaderException();
|
||||
return;
|
||||
}
|
||||
center = new Vector3i(w / 2, h / 2, d / 2);
|
||||
center = new BlockVector(w / 2, h / 2, d / 2);
|
||||
int s = din.readShort();
|
||||
int i;
|
||||
KList<String> palette = new KList<>();
|
||||
@@ -342,13 +339,13 @@ public class IrisObject extends IrisRegistrant {
|
||||
s = din.readInt();
|
||||
|
||||
for (i = 0; i < s; i++) {
|
||||
blocks.put(new Vector3i(din.readShort(), din.readShort(), din.readShort()), B.get(palette.get(din.readShort())));
|
||||
getBlocks().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), B.get(palette.get(din.readShort())));
|
||||
}
|
||||
|
||||
s = din.readInt();
|
||||
|
||||
for (i = 0; i < s; i++) {
|
||||
states.put(new Vector3i(din.readShort(), din.readShort(), din.readShort()), TileData.read(din));
|
||||
getStates().put(new BlockVector(din.readShort(), din.readShort(), din.readShort()), TileData.read(din));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,7 +357,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
dos.writeUTF("Iris V2 IOB;");
|
||||
KList<String> palette = new KList<>();
|
||||
|
||||
for (BlockData i : blocks.values()) {
|
||||
for (BlockData i : getBlocks().values()) {
|
||||
palette.addIfMissing(i.getAsString());
|
||||
}
|
||||
|
||||
@@ -370,23 +367,21 @@ public class IrisObject extends IrisRegistrant {
|
||||
dos.writeUTF(i);
|
||||
}
|
||||
|
||||
dos.writeInt(blocks.size());
|
||||
dos.writeInt(getBlocks().size());
|
||||
|
||||
for (var entry : blocks) {
|
||||
var i = entry.getKey();
|
||||
for (BlockVector i : getBlocks().keySet()) {
|
||||
dos.writeShort(i.getBlockX());
|
||||
dos.writeShort(i.getBlockY());
|
||||
dos.writeShort(i.getBlockZ());
|
||||
dos.writeShort(palette.indexOf(entry.getValue().getAsString()));
|
||||
dos.writeShort(palette.indexOf(getBlocks().get(i).getAsString()));
|
||||
}
|
||||
|
||||
dos.writeInt(states.size());
|
||||
for (var entry : states) {
|
||||
var i = entry.getKey();
|
||||
dos.writeInt(getStates().size());
|
||||
for (BlockVector i : getStates().keySet()) {
|
||||
dos.writeShort(i.getBlockX());
|
||||
dos.writeShort(i.getBlockY());
|
||||
dos.writeShort(i.getBlockZ());
|
||||
entry.getValue().toBinary(dos);
|
||||
getStates().get(i).toBinary(dos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,7 +389,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
AtomicReference<IOException> ref = new AtomicReference<>();
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
new Job() {
|
||||
private int total = blocks.size() * 3 + states.size();
|
||||
private int total = getBlocks().size() * 3 + getStates().size();
|
||||
private int c = 0;
|
||||
|
||||
@Override
|
||||
@@ -413,11 +408,11 @@ public class IrisObject extends IrisRegistrant {
|
||||
|
||||
KList<String> palette = new KList<>();
|
||||
|
||||
for (BlockData i : blocks.values()) {
|
||||
for (BlockData i : getBlocks().values()) {
|
||||
palette.addIfMissing(i.getAsString());
|
||||
++c;
|
||||
}
|
||||
total -= blocks.size() - palette.size();
|
||||
total -= getBlocks().size() - palette.size();
|
||||
|
||||
dos.writeShort(palette.size());
|
||||
|
||||
@@ -426,24 +421,22 @@ public class IrisObject extends IrisRegistrant {
|
||||
++c;
|
||||
}
|
||||
|
||||
dos.writeInt(blocks.size());
|
||||
dos.writeInt(getBlocks().size());
|
||||
|
||||
for (var entry : blocks) {
|
||||
var i = entry.getKey();
|
||||
for (BlockVector i : getBlocks().keySet()) {
|
||||
dos.writeShort(i.getBlockX());
|
||||
dos.writeShort(i.getBlockY());
|
||||
dos.writeShort(i.getBlockZ());
|
||||
dos.writeShort(palette.indexOf(entry.getValue().getAsString()));
|
||||
dos.writeShort(palette.indexOf(getBlocks().get(i).getAsString()));
|
||||
++c;
|
||||
}
|
||||
|
||||
dos.writeInt(states.size());
|
||||
for (var entry : states) {
|
||||
var i = entry.getKey();
|
||||
dos.writeInt(getStates().size());
|
||||
for (BlockVector i : getStates().keySet()) {
|
||||
dos.writeShort(i.getBlockX());
|
||||
dos.writeShort(i.getBlockY());
|
||||
dos.writeShort(i.getBlockZ());
|
||||
entry.getValue().toBinary(dos);
|
||||
getStates().get(i).toBinary(dos);
|
||||
++c;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@@ -475,14 +468,16 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
public void read(File file) throws IOException {
|
||||
try (var fin = new BufferedInputStream(new FileInputStream(file))) {
|
||||
var fin = new BufferedInputStream(new FileInputStream(file));
|
||||
try {
|
||||
read(fin);
|
||||
fin.close();
|
||||
} catch (Throwable e) {
|
||||
if (!(e instanceof HeaderException))
|
||||
Iris.reportError(e);
|
||||
try (var fin = new BufferedInputStream(new FileInputStream(file))) {
|
||||
readLegacy(fin);
|
||||
}
|
||||
Iris.reportError(e);
|
||||
fin.close();
|
||||
fin = new BufferedInputStream(new FileInputStream(file));
|
||||
readLegacy(fin);
|
||||
fin.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,11 +502,10 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
public void shrinkwrap() {
|
||||
if (blocks.isEmpty()) return;
|
||||
BlockVector min = new BlockVector(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
BlockVector max = new BlockVector(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
|
||||
BlockVector min = new BlockVector();
|
||||
BlockVector max = new BlockVector();
|
||||
|
||||
for (BlockVector i : blocks.keys()) {
|
||||
for (BlockVector i : getBlocks().keySet()) {
|
||||
min.setX(Math.min(min.getX(), i.getX()));
|
||||
min.setY(Math.min(min.getY(), i.getY()));
|
||||
min.setZ(Math.min(min.getZ(), i.getZ()));
|
||||
@@ -523,77 +517,62 @@ 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 Vector3i(w / 2, h / 2, d / 2);
|
||||
|
||||
Vector3i offset = new Vector3i(
|
||||
-center.getBlockX() - min.getBlockX(),
|
||||
-center.getBlockY() - min.getBlockY(),
|
||||
-center.getBlockZ() - min.getBlockZ()
|
||||
);
|
||||
if (offset.getBlockX() == 0 && offset.getBlockY() == 0 && offset.getBlockZ() == 0)
|
||||
return;
|
||||
|
||||
VectorMap<BlockData> b = new VectorMap<>();
|
||||
VectorMap<TileData> s = new VectorMap<>();
|
||||
|
||||
blocks.forEach((vector, data) -> {
|
||||
vector.add(offset);
|
||||
b.put(vector, data);
|
||||
});
|
||||
|
||||
states.forEach((vector, data) -> {
|
||||
vector.add(offset);
|
||||
s.put(vector, data);
|
||||
});
|
||||
|
||||
shrinkOffset = offset;
|
||||
blocks = b;
|
||||
states = s;
|
||||
center = new BlockVector(w / 2, h / 2, d / 2);
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
VectorMap<BlockData> d = new VectorMap<>();
|
||||
d.putAll(blocks);
|
||||
KMap<BlockVector, BlockData> d = new KMap<>();
|
||||
|
||||
VectorMap<TileData> dx = new VectorMap<>();
|
||||
dx.putAll(states);
|
||||
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)));
|
||||
}
|
||||
|
||||
blocks = d;
|
||||
states = dx;
|
||||
}
|
||||
|
||||
public Vector3i getSigned(int x, int y, int z) {
|
||||
public BlockVector 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 (Vector3i) new Vector3i(x, y, z).subtract(center);
|
||||
return new BlockVector(x, y, z).subtract(center).toBlockVector();
|
||||
}
|
||||
|
||||
public void setUnsigned(int x, int y, int z, BlockData block) {
|
||||
Vector3i v = getSigned(x, y, z);
|
||||
BlockVector v = getSigned(x, y, z);
|
||||
|
||||
if (block == null) {
|
||||
blocks.remove(v);
|
||||
states.remove(v);
|
||||
getBlocks().remove(v);
|
||||
getStates().remove(v);
|
||||
} else {
|
||||
blocks.put(v, block);
|
||||
getBlocks().put(v, block);
|
||||
}
|
||||
}
|
||||
|
||||
public void setUnsigned(int x, int y, int z, Block block, boolean legacy) {
|
||||
Vector3i v = getSigned(x, y, z);
|
||||
BlockVector v = getSigned(x, y, z);
|
||||
|
||||
if (block == null) {
|
||||
blocks.remove(v);
|
||||
states.remove(v);
|
||||
getBlocks().remove(v);
|
||||
getStates().remove(v);
|
||||
} else {
|
||||
BlockData data = block.getBlockData();
|
||||
blocks.put(v, data);
|
||||
getBlocks().put(v, data);
|
||||
TileData state = TileData.getTileState(block, legacy);
|
||||
if (state != null) {
|
||||
Iris.debug("Saved State " + v);
|
||||
states.put(v, state);
|
||||
getStates().put(v, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -890,9 +869,6 @@ 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());
|
||||
|
||||
@@ -901,12 +877,13 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
int max = j.getMaximumMarkers();
|
||||
for (BlockVector i : list.shuffle()) {
|
||||
|
||||
for (BlockVector i : getBlocks().k().shuffle()) {
|
||||
if (max <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
BlockData data = blocks.get(i);
|
||||
BlockData data = getBlocks().get(i);
|
||||
|
||||
for (BlockData k : j.getMark(rdata)) {
|
||||
if (max <= 0) {
|
||||
@@ -914,8 +891,8 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
if (j.isExact() ? k.matches(data) : k.getMaterial().equals(data.getMaterial())) {
|
||||
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)));
|
||||
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))));
|
||||
|
||||
if (!marker.isEmptyAbove() || (a && fff)) {
|
||||
markers.put(i, j.getMarker());
|
||||
@@ -927,14 +904,13 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
}
|
||||
|
||||
for (var entry : blocks) {
|
||||
var g = entry.getKey();
|
||||
for (BlockVector g : getBlocks().keySet()) {
|
||||
BlockData d;
|
||||
TileData tile = null;
|
||||
|
||||
try {
|
||||
d = entry.getValue();
|
||||
tile = states.get(g);
|
||||
d = getBlocks().get(g);
|
||||
tile = getStates().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)");
|
||||
@@ -1052,12 +1028,12 @@ public class IrisObject extends IrisRegistrant {
|
||||
if (stilting) {
|
||||
readLock.lock();
|
||||
IrisStiltSettings settings = config.getStiltSettings();
|
||||
for (BlockVector g : blocks.keys()) {
|
||||
for (BlockVector g : getBlocks().keySet()) {
|
||||
BlockData d;
|
||||
|
||||
if (settings == null || settings.getPalette() == null) {
|
||||
try {
|
||||
d = blocks.get(g);
|
||||
d = getBlocks().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)");
|
||||
@@ -1164,60 +1140,59 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
public void rotate(IrisObjectRotation r, int spinx, int spiny, int spinz) {
|
||||
writeLock.lock();
|
||||
VectorMap<BlockData> d = new VectorMap<>();
|
||||
KMap<BlockVector, BlockData> d = new KMap<>();
|
||||
|
||||
for (var entry : blocks) {
|
||||
d.put(r.rotate(entry.getKey(), spinx, spiny, spinz), r.rotate(entry.getValue(), spinx, spiny, spinz));
|
||||
for (BlockVector i : getBlocks().keySet()) {
|
||||
d.put(r.rotate(i.clone(), spinx, spiny, spinz), r.rotate(getBlocks().get(i).clone(),
|
||||
spinx, spiny, spinz));
|
||||
}
|
||||
|
||||
VectorMap<TileData> dx = new VectorMap<>();
|
||||
KMap<BlockVector, TileData> dx = new KMap<>();
|
||||
|
||||
for (var entry : states) {
|
||||
dx.put(r.rotate(entry.getKey(), spinx, spiny, spinz), entry.getValue());
|
||||
for (BlockVector i : getStates().keySet()) {
|
||||
dx.put(r.rotate(i.clone(), spinx, spiny, spinz), getStates().get(i));
|
||||
}
|
||||
|
||||
blocks = d;
|
||||
states = dx;
|
||||
shrinkwrap();
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
public void place(Location at) {
|
||||
readLock.lock();
|
||||
for (var entry : blocks) {
|
||||
var i = entry.getKey();
|
||||
for (BlockVector i : getBlocks().keySet()) {
|
||||
Block b = at.clone().add(0, getCenter().getY(), 0).add(i).getBlock();
|
||||
b.setBlockData(Objects.requireNonNull(entry.getValue()), false);
|
||||
b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false);
|
||||
|
||||
if (states.containsKey(i)) {
|
||||
if (getStates().containsKey(i)) {
|
||||
Iris.info(Objects.requireNonNull(states.get(i)).toString());
|
||||
Objects.requireNonNull(states.get(i)).toBukkitTry(b);
|
||||
Objects.requireNonNull(getStates().get(i)).toBukkitTry(b);
|
||||
}
|
||||
}
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
public void placeCenterY(Location at) {
|
||||
readLock.lock();
|
||||
for (var entry : blocks) {
|
||||
var i = entry.getKey();
|
||||
for (BlockVector i : getBlocks().keySet()) {
|
||||
Block b = at.clone().add(getCenter().getX(), getCenter().getY(), getCenter().getZ()).add(i).getBlock();
|
||||
b.setBlockData(Objects.requireNonNull(entry.getValue()), false);
|
||||
b.setBlockData(Objects.requireNonNull(getBlocks().get(i)), false);
|
||||
|
||||
if (states.containsKey(i)) {
|
||||
Objects.requireNonNull(states.get(i)).toBukkitTry(b);
|
||||
if (getStates().containsKey(i)) {
|
||||
Objects.requireNonNull(getStates().get(i)).toBukkitTry(b);
|
||||
}
|
||||
}
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
public synchronized KMap<BlockVector, BlockData> getBlocks() {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
public synchronized KMap<BlockVector, TileData> getStates() {
|
||||
return states;
|
||||
}
|
||||
|
||||
public void unplaceCenterY(Location at) {
|
||||
readLock.lock();
|
||||
for (BlockVector i : blocks.keys()) {
|
||||
for (BlockVector i : getBlocks().keySet()) {
|
||||
at.clone().add(getCenter().getX(), getCenter().getY(), getCenter().getZ()).add(i).getBlock().setBlockData(AIR, false);
|
||||
}
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
public IrisObject scaled(double scale, IrisObjectPlacementScaleInterpolator interpolation) {
|
||||
@@ -1229,7 +1204,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
|
||||
IrisPosition l1 = getAABB().max();
|
||||
IrisPosition l2 = getAABB().min();
|
||||
VectorMap<BlockData> placeBlock = new VectorMap<>();
|
||||
@SuppressWarnings({"unchecked", "rawtypes"}) HashMap<BlockVector, BlockData> placeBlock = new HashMap();
|
||||
|
||||
Vector center = getCenter();
|
||||
if (getH() == 2) {
|
||||
@@ -1244,19 +1219,17 @@ 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)));
|
||||
|
||||
readLock.lock();
|
||||
for (var entry : blocks) {
|
||||
for (Map.Entry<BlockVector, BlockData> entry : blocks.entrySet()) {
|
||||
BlockData bd = entry.getValue();
|
||||
placeBlock.put(entry.getKey().clone().add(HALF).subtract(center)
|
||||
.multiply(scale).add(sm1).toBlockVector(), bd);
|
||||
}
|
||||
readLock.unlock();
|
||||
|
||||
for (var entry : placeBlock) {
|
||||
for (Map.Entry<BlockVector, BlockData> entry : placeBlock.entrySet()) {
|
||||
BlockVector v = entry.getKey();
|
||||
if (scale > 1) {
|
||||
for (BlockVector vec : blocksBetweenTwoPoints(v.clone().add(center), v.clone().add(center).add(sm1))) {
|
||||
oo.blocks.put(vec, entry.getValue());
|
||||
oo.getBlocks().put(vec, entry.getValue());
|
||||
}
|
||||
} else {
|
||||
oo.setUnsigned(v.getBlockX(), v.getBlockY(), v.getBlockZ(), entry.getValue());
|
||||
@@ -1275,9 +1248,8 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
public void trilinear(int rad) {
|
||||
writeLock.lock();
|
||||
VectorMap<BlockData> v = blocks;
|
||||
VectorMap<BlockData> b = new VectorMap<>();
|
||||
KMap<BlockVector, BlockData> v = getBlocks().copy();
|
||||
KMap<BlockVector, BlockData> b = new KMap<>();
|
||||
BlockVector min = getAABB().minbv();
|
||||
BlockVector max = getAABB().maxbv();
|
||||
|
||||
@@ -1302,13 +1274,11 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
blocks = b;
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
public void tricubic(int rad) {
|
||||
writeLock.lock();
|
||||
VectorMap<BlockData> v = blocks;
|
||||
VectorMap<BlockData> b = new VectorMap<>();
|
||||
KMap<BlockVector, BlockData> v = getBlocks().copy();
|
||||
KMap<BlockVector, BlockData> b = new KMap<>();
|
||||
BlockVector min = getAABB().minbv();
|
||||
BlockVector max = getAABB().maxbv();
|
||||
|
||||
@@ -1333,7 +1303,6 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
blocks = b;
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
public void trihermite(int rad) {
|
||||
@@ -1341,9 +1310,8 @@ public class IrisObject extends IrisRegistrant {
|
||||
}
|
||||
|
||||
public void trihermite(int rad, double tension, double bias) {
|
||||
writeLock.lock();
|
||||
VectorMap<BlockData> v = blocks;
|
||||
VectorMap<BlockData> b = new VectorMap<>();
|
||||
KMap<BlockVector, BlockData> v = getBlocks().copy();
|
||||
KMap<BlockVector, BlockData> b = new KMap<>();
|
||||
BlockVector min = getAABB().minbv();
|
||||
BlockVector max = getAABB().maxbv();
|
||||
|
||||
@@ -1368,13 +1336,11 @@ 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);
|
||||
readLock.lock();
|
||||
BlockData r = blocks.get(vv);
|
||||
BlockData r = getBlocks().get(vv);
|
||||
|
||||
if (r != null && !r.getMaterial().isAir()) {
|
||||
return r;
|
||||
@@ -1382,7 +1348,7 @@ public class IrisObject extends IrisRegistrant {
|
||||
|
||||
double d = Double.MAX_VALUE;
|
||||
|
||||
for (var entry : blocks) {
|
||||
for (Map.Entry<BlockVector, BlockData> entry : blocks.entrySet()) {
|
||||
BlockData dat = entry.getValue();
|
||||
|
||||
if (dat.getMaterial().isAir()) {
|
||||
@@ -1396,7 +1362,6 @@ public class IrisObject extends IrisRegistrant {
|
||||
r = dat;
|
||||
}
|
||||
}
|
||||
readLock.unlock();
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1418,10 +1383,4 @@ public class IrisObject extends IrisRegistrant {
|
||||
@Override
|
||||
public void scanForErrors(JSONObject p, VolmitSender sender) {
|
||||
}
|
||||
|
||||
private static class HeaderException extends IOException {
|
||||
public HeaderException() {
|
||||
super("Invalid Header");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,13 +28,13 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.*;
|
||||
import org.bukkit.block.data.type.RedstoneWire;
|
||||
import org.bukkit.block.data.type.Wall;
|
||||
import org.bukkit.block.structure.StructureRotation;
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -101,15 +101,15 @@ public class IrisObjectRotation {
|
||||
return e.rotateCopy(this);
|
||||
}
|
||||
|
||||
public IrisJigsawPiece rotateCopy(IrisJigsawPiece v, IrisPosition offset) {
|
||||
public IrisJigsawPiece rotateCopy(IrisJigsawPiece v) {
|
||||
IrisJigsawPiece piece = v.copy();
|
||||
for (IrisJigsawPieceConnector i : piece.getConnectors()) {
|
||||
i.setPosition(rotate(i.getPosition()).add(offset));
|
||||
i.setPosition(rotate(i.getPosition()));
|
||||
i.setDirection(rotate(i.getDirection()));
|
||||
}
|
||||
try {
|
||||
var translate = piece.getPlacementOptions().getTranslate();
|
||||
var pos = rotate(new IrisPosition(translate.getX(), translate.getY(), translate.getZ())).add(offset);
|
||||
var pos = rotate(new IrisPosition(translate.getX(), translate.getY(), translate.getZ()));
|
||||
translate.setX(pos.getX()).setY(pos.getY()).setZ(pos.getZ());
|
||||
} catch (NullPointerException ignored) {}
|
||||
|
||||
@@ -259,14 +259,14 @@ public class IrisObjectRotation {
|
||||
|
||||
g.setRotation(face);
|
||||
|
||||
} else if (d instanceof Orientable g) {
|
||||
BlockFace f = getFace(g.getAxis());
|
||||
} else if (d instanceof Orientable) {
|
||||
BlockFace f = getFace(((Orientable) d).getAxis());
|
||||
BlockVector bv = new BlockVector(f.getModX(), f.getModY(), f.getModZ());
|
||||
bv = rotate(bv.clone(), spinx, spiny, spinz);
|
||||
Axis a = getAxis(bv);
|
||||
|
||||
if (!a.equals(g.getAxis()) && g.getAxes().contains(a)) {
|
||||
g.setAxis(a);
|
||||
if (!a.equals(((Orientable) d).getAxis()) && ((Orientable) d).getAxes().contains(a)) {
|
||||
((Orientable) d).setAxis(a);
|
||||
}
|
||||
} else if (d instanceof MultipleFacing g) {
|
||||
List<BlockFace> faces = new KList<>();
|
||||
@@ -304,22 +304,14 @@ public class IrisObjectRotation {
|
||||
for (BlockFace i : WALL_FACES) {
|
||||
wall.setHeight(i, faces.getOrDefault(i, Wall.Height.NONE));
|
||||
}
|
||||
} else if (d instanceof RedstoneWire wire) {
|
||||
Map<BlockFace, RedstoneWire.Connection> faces = new HashMap<>();
|
||||
|
||||
var allowed = wire.getAllowedFaces();
|
||||
for (BlockFace i : allowed) {
|
||||
RedstoneWire.Connection connection = wire.getFace(i);
|
||||
BlockVector bv = new BlockVector(i.getModX(), i.getModY(), i.getModZ());
|
||||
bv = rotate(bv.clone(), spinx, spiny, spinz);
|
||||
BlockFace r = getFace(bv);
|
||||
if (allowed.contains(r))
|
||||
faces.put(r, connection);
|
||||
}
|
||||
|
||||
for (BlockFace i : allowed) {
|
||||
wire.setFace(i, faces.getOrDefault(i, RedstoneWire.Connection.NONE));
|
||||
}
|
||||
} else if (d.getMaterial().equals(Material.NETHER_PORTAL) && d instanceof Orientable g) {
|
||||
//TODO: Fucks up logs
|
||||
BlockFace f = faceForAxis(g.getAxis());
|
||||
BlockVector bv = new BlockVector(f.getModX(), f.getModY(), f.getModZ());
|
||||
bv = rotate(bv.clone(), spinx, spiny, spinz);
|
||||
BlockFace t = getFace(bv);
|
||||
Axis a = !g.getAxes().contains(Axis.Y) ? axisFor(t) : axisFor2D(t);
|
||||
((Orientable) d).setAxis(a);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
|
||||
@@ -18,7 +18,7 @@ public class IrisPreProcessors {
|
||||
private String type = "dimension";
|
||||
|
||||
@Required
|
||||
@Desc("The preprocessor scripts\nFile extension: .proc.kts")
|
||||
@Desc("The preprocessor scripts")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@ArrayType(type = String.class, min = 1)
|
||||
private KList<String> scripts = new KList<>();
|
||||
|
||||
@@ -20,7 +20,7 @@ package com.volmit.iris.engine.object;
|
||||
|
||||
import com.volmit.iris.engine.object.annotations.Desc;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Waterlogged;
|
||||
|
||||
@Desc("The type of surface entities should spawn on")
|
||||
@@ -47,8 +47,8 @@ public enum IrisSurface {
|
||||
* @param state The blockstate
|
||||
* @return True if it matches
|
||||
*/
|
||||
public boolean matches(Block state) {
|
||||
Material type = state.getType();
|
||||
public boolean matches(BlockData state) {
|
||||
Material type = state.getMaterial();
|
||||
if (type.isSolid()) {
|
||||
return this == LAND || this == OVERWORLD || (this == ANIMAL
|
||||
&& (type == Material.GRASS_BLOCK || type == Material.DIRT
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.volmit.iris.engine.object;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.nms.container.Pair;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NonNull;
|
||||
@@ -80,7 +80,7 @@ public class LegacyTileData extends TileData {
|
||||
|
||||
@Override
|
||||
public void toBukkit(Block block) {
|
||||
J.s(() -> handler.toBukkit(block));
|
||||
Iris.platform.getRegionScheduler().run(block.getLocation(), () -> handler.toBukkit(block));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,10 +38,11 @@ import com.volmit.iris.util.data.IrisBiomeStorage;
|
||||
import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder;
|
||||
import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder;
|
||||
import com.volmit.iris.util.io.ReactiveFolder;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import com.volmit.iris.util.scheduling.Looper;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import de.crazydev22.platformutils.scheduler.IRegionExecutor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Setter;
|
||||
@@ -142,7 +143,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
@Override
|
||||
public Location getFixedSpawnLocation(@NotNull World world, @NotNull Random random) {
|
||||
Location location = new Location(world, 0, 64, 0);
|
||||
PaperLib.getChunkAtAsync(location)
|
||||
Iris.platform.getChunkAtAsync(location)
|
||||
.thenAccept(c -> {
|
||||
World w = c.getWorld();
|
||||
if (!w.getSpawnLocation().equals(location))
|
||||
@@ -166,8 +167,6 @@ 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) {
|
||||
@@ -197,17 +196,17 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectChunkReplacement(World world, int x, int z, Executor syncExecutor) {
|
||||
public void injectChunkReplacement(World world, int x, int z, IRegionExecutor executor) {
|
||||
try {
|
||||
loadLock.acquire();
|
||||
IrisBiomeStorage st = new IrisBiomeStorage();
|
||||
TerrainChunk tc = TerrainChunk.createUnsafe(world, st);
|
||||
this.world.bind(world);
|
||||
getEngine().generate(x << 4, z << 4, tc, IrisSettings.get().getGenerator().useMulticore);
|
||||
generateNoise(world, RNG.r, x, z, tc);
|
||||
|
||||
Chunk c = PaperLib.getChunkAtAsync(world, x, z)
|
||||
Chunk c = Iris.platform.getChunkAtAsync(world, x, z)
|
||||
.thenApply(d -> {
|
||||
Iris.tickets.addTicket(d);
|
||||
if (d == null) throw new IllegalStateException("Chunk is null!");
|
||||
d.addPluginChunkTicket(Iris.instance);
|
||||
|
||||
for (Entity ee : d.getEntities()) {
|
||||
if (ee instanceof Player) {
|
||||
@@ -217,6 +216,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
ee.remove();
|
||||
}
|
||||
|
||||
engine.getWorldManager().onChunkLoad(d, false);
|
||||
return d;
|
||||
}).get();
|
||||
|
||||
@@ -224,7 +224,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
KList<CompletableFuture<?>> futures = new KList<>(1 + getEngine().getHeight() >> 4);
|
||||
for (int i = getEngine().getHeight() >> 4; i >= 0; i--) {
|
||||
int finalI = i << 4;
|
||||
futures.add(CompletableFuture.runAsync(() -> {
|
||||
futures.add(executor.queue(world, x, z, () -> {
|
||||
for (int xx = 0; xx < 16; xx++) {
|
||||
for (int yy = 0; yy < 16; yy++) {
|
||||
for (int zz = 0; zz < 16; zz++) {
|
||||
@@ -236,15 +236,15 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
}
|
||||
}
|
||||
}
|
||||
}, syncExecutor));
|
||||
}));
|
||||
}
|
||||
futures.add(CompletableFuture.runAsync(() -> INMS.get().placeStructures(c), syncExecutor));
|
||||
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
||||
.thenRunAsync(() -> {
|
||||
Iris.tickets.removeTicket(c);
|
||||
CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new))
|
||||
.thenCompose($ -> executor.queue(world, x, z, () -> INMS.get().placeStructures(c)))
|
||||
.thenCompose($ -> executor.queue(world, x, z, () -> {
|
||||
c.removePluginChunkTicket(Iris.instance);
|
||||
engine.getWorldManager().onChunkLoad(c, true);
|
||||
}, syncExecutor)
|
||||
}))
|
||||
.get();
|
||||
Iris.debug("Regenerated " + x + " " + z);
|
||||
|
||||
@@ -255,14 +255,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
e.printStackTrace();
|
||||
Iris.reportErrorChunk(x, z, e, "CHUNK");
|
||||
Iris.error("======================================");
|
||||
|
||||
ChunkData d = Bukkit.createChunkData(world);
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int j = 0; j < 16; j++) {
|
||||
d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,12 +23,12 @@ import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.framework.EngineTarget;
|
||||
import com.volmit.iris.engine.framework.Hotloadable;
|
||||
import com.volmit.iris.util.data.DataProvider;
|
||||
import de.crazydev22.platformutils.scheduler.IRegionExecutor;
|
||||
import org.bukkit.World;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public interface PlatformChunkGenerator extends Hotloadable, DataProvider {
|
||||
@Nullable
|
||||
@@ -42,7 +42,7 @@ public interface PlatformChunkGenerator extends Hotloadable, DataProvider {
|
||||
@NotNull
|
||||
EngineTarget getTarget();
|
||||
|
||||
void injectChunkReplacement(World world, int x, int z, Executor syncExecutor);
|
||||
void injectChunkReplacement(World world, int x, int z, IRegionExecutor executor);
|
||||
|
||||
void close();
|
||||
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
|
||||
package com.volmit.iris.util.board;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import de.crazydev22.platformutils.scheduler.task.Task;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -34,7 +35,7 @@ public class BoardManager {
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final Map<UUID, Board> scoreboards;
|
||||
private final BukkitTask updateTask;
|
||||
private final Task updateTask;
|
||||
private BoardSettings boardSettings;
|
||||
|
||||
|
||||
@@ -42,7 +43,7 @@ public class BoardManager {
|
||||
this.plugin = plugin;
|
||||
this.boardSettings = boardSettings;
|
||||
this.scoreboards = new ConcurrentHashMap<>();
|
||||
this.updateTask = new BoardUpdateTask(this).runTaskTimer(plugin, 2L, 20L);
|
||||
this.updateTask = Iris.platform.getGlobalScheduler().runAtFixedRate(new BoardUpdateTask(this), 2L, 20L);
|
||||
plugin.getServer().getOnlinePlayers().forEach(this::setup);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ package com.volmit.iris.util.board;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
@@ -30,7 +29,7 @@ import java.util.function.Predicate;
|
||||
* @since 5/31/2018
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class BoardUpdateTask extends BukkitRunnable {
|
||||
public class BoardUpdateTask implements Runnable {
|
||||
|
||||
private static final Predicate<UUID> PLAYER_IS_ONLINE = uuid -> Bukkit.getPlayer(uuid) != null;
|
||||
|
||||
|
||||
@@ -2,55 +2,24 @@ package com.volmit.iris.util.cache;
|
||||
|
||||
import com.volmit.iris.util.function.Function2;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
public class ChunkCache2D<T> {
|
||||
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 AtomicReferenceArray<T> cache;
|
||||
|
||||
private final Entry<T>[] cache;
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public ChunkCache2D() {
|
||||
this.cache = new Entry[256];
|
||||
if (DYNAMIC) return;
|
||||
for (int i = 0; i < cache.length; i++) {
|
||||
cache[i] = FAST ? new FastEntry<>() : new Entry<>();
|
||||
}
|
||||
this.cache = new AtomicReferenceArray<>(256);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public T get(int x, int z, Function2<Integer, Integer, T> resolver) {
|
||||
int key = ((z & 15) * 16) + (x & 15);
|
||||
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);
|
||||
}
|
||||
T t = cache.get(key);
|
||||
|
||||
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;
|
||||
}
|
||||
if (t == null) {
|
||||
t = resolver.apply(x, z);
|
||||
cache.set(key, 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);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,24 @@
|
||||
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 ConcurrentLinkedHashMap<Long, ChunkCache2D<T>> chunks;
|
||||
private final KCache<Long, ChunkCache2D<T>> chunks;
|
||||
private final Function2<Integer, Integer, T> resolver;
|
||||
|
||||
public WorldCache2D(Function2<Integer, Integer, T> resolver, int size) {
|
||||
public WorldCache2D(Function2<Integer, Integer, T> resolver) {
|
||||
this.resolver = resolver;
|
||||
chunks = new ConcurrentLinkedHashMap.Builder<Long, ChunkCache2D<T>>()
|
||||
.initialCapacity(size)
|
||||
.maximumWeightedCapacity(size)
|
||||
.concurrencyLevel(Math.max(32, Runtime.getRuntime().availableProcessors() * 4))
|
||||
.build();
|
||||
chunks = new KCache<>((x) -> new ChunkCache2D<>(), 1024);
|
||||
}
|
||||
|
||||
public T get(int x, int z) {
|
||||
ChunkCache2D<T> chunk = chunks.computeIfAbsent(Cache.key(x >> 4, z >> 4), $ -> new ChunkCache2D<>());
|
||||
ChunkCache2D<T> chunk = chunks.get(Cache.key(x >> 4, z >> 4));
|
||||
return chunk.get(x, z, resolver);
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return chunks.size() * 256L;
|
||||
}
|
||||
|
||||
public long getMaxSize() {
|
||||
return chunks.capacity() * 256L;
|
||||
return chunks.getSize() * 256L;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,15 +33,7 @@ public class KMap<K, V> extends ConcurrentHashMap<K, V> {
|
||||
private static final long serialVersionUID = 7288942695300448163L;
|
||||
|
||||
public KMap() {
|
||||
this(16);
|
||||
}
|
||||
|
||||
public KMap(int initialCapacity) {
|
||||
this(initialCapacity, 0.75f, 1);
|
||||
}
|
||||
|
||||
public KMap(int initialCapacity, float loadFactor, int concurrencyLevel) {
|
||||
super(initialCapacity, loadFactor, concurrencyLevel);
|
||||
super();
|
||||
}
|
||||
|
||||
public KMap(Map<K, V> gMap) {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user