Merge pull request #1223 from VolmitSoftware/dev

3.7.10
This commit is contained in:
Aidan Aeternum authored and GitHub committed 2025-09-27 07:34:31 -04:00
commit 1a9a5d80ad
178 files changed
+5985 -1677

No files matched your search

+3 -7
View File
@@ -24,7 +24,7 @@ import kotlin.system.exitProcess
buildscript { buildscript {
repositories.maven("https://jitpack.io") repositories.maven("https://jitpack.io")
dependencies.classpath("com.github.VolmitSoftware:NMSTools:c5cbc46ce6") dependencies.classpath("com.github.VolmitSoftware:NMSTools:c88961416f")
} }
plugins { plugins {
@@ -62,10 +62,10 @@ val serverMinHeap = "2G"
val serverMaxHeap = "8G" val serverMaxHeap = "8G"
//Valid values are: none, truecolor, indexed256, indexed16, indexed8 //Valid values are: none, truecolor, indexed256, indexed16, indexed8
val color = "truecolor" val color = "truecolor"
val errorReporting = false val errorReporting = findProperty("errorReporting") as Boolean? ?: false
val nmsBindings = mapOf( val nmsBindings = mapOf(
"v1_21_R5" to "1.21.7-R0.1-SNAPSHOT", "v1_21_R5" to "1.21.8-R0.1-SNAPSHOT",
"v1_21_R4" to "1.21.5-R0.1-SNAPSHOT", "v1_21_R4" to "1.21.5-R0.1-SNAPSHOT",
"v1_21_R3" to "1.21.4-R0.1-SNAPSHOT", "v1_21_R3" to "1.21.4-R0.1-SNAPSHOT",
"v1_21_R2" to "1.21.3-R0.1-SNAPSHOT", "v1_21_R2" to "1.21.3-R0.1-SNAPSHOT",
@@ -81,10 +81,6 @@ nmsBindings.forEach { key, value ->
apply<JavaPlugin>() apply<JavaPlugin>()
apply<NMSToolsPlugin>() apply<NMSToolsPlugin>()
repositories {
maven("https://libraries.minecraft.net")
}
extensions.configure(NMSToolsExtension::class) { extensions.configure(NMSToolsExtension::class) {
jvm = jvmVersion.getOrDefault(key, 21) jvm = jvmVersion.getOrDefault(key, 21)
version = value version = value
+55 -16
View File
@@ -28,6 +28,8 @@ plugins {
alias(libs.plugins.sentry) alias(libs.plugins.sentry)
alias(libs.plugins.slimjar) alias(libs.plugins.slimjar)
alias(libs.plugins.grgit) alias(libs.plugins.grgit)
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.lombok)
} }
val apiVersion = "1.19" val apiVersion = "1.19"
@@ -81,6 +83,7 @@ dependencies {
slim(libs.commons.io) slim(libs.commons.io)
slim(libs.commons.lang) slim(libs.commons.lang)
slim(libs.commons.lang3) slim(libs.commons.lang3)
slim(libs.commons.math3)
slim(libs.oshi) slim(libs.oshi)
slim(libs.lz4) slim(libs.lz4)
slim(libs.fastutil) slim(libs.fastutil)
@@ -88,11 +91,23 @@ dependencies {
slim(libs.zip) slim(libs.zip)
slim(libs.gson) slim(libs.gson)
slim(libs.asm) slim(libs.asm)
slim(libs.bsf)
slim(libs.rhino)
slim(libs.caffeine) slim(libs.caffeine)
slim(libs.byteBuddy.core) slim(libs.byteBuddy.core)
slim(libs.byteBuddy.agent) slim(libs.byteBuddy.agent)
slim(libs.dom4j)
slim(libs.jaxen)
// Script Engine
slim(libs.kotlin.stdlib)
slim(libs.kotlin.coroutines)
slim(libs.kotlin.scripting.common)
slim(libs.kotlin.scripting.jvm)
slim(libs.kotlin.scripting.jvm.host)
slim(libs.kotlin.scripting.dependencies.maven) {
constraints {
slim(libs.mavenCore)
}
}
} }
java { java {
@@ -120,6 +135,13 @@ slimJar {
relocate("net.kyori", "$lib.kyori") relocate("net.kyori", "$lib.kyori")
relocate("org.bstats", "$lib.metrics") relocate("org.bstats", "$lib.metrics")
relocate("io.sentry", "$lib.sentry") relocate("io.sentry", "$lib.sentry")
relocate("org.apache.maven", "$lib.maven")
relocate("org.codehaus.plexus", "$lib.plexus")
relocate("org.eclipse.sisu", "$lib.sisu")
relocate("org.eclipse.aether", "$lib.aether")
relocate("com.google.inject", "$lib.guice")
relocate("org.dom4j", "$lib.dom4j")
relocate("org.jaxen", "$lib.jaxen")
} }
tasks { tasks {
@@ -140,15 +162,6 @@ tasks {
"version" to rootProject.version, "version" to rootProject.version,
"apiVersion" to apiVersion, "apiVersion" to apiVersion,
"main" to main, "main" to main,
"environment" to if (project.hasProperty("release")) "production" else "development",
"commit" to provider {
val res = runCatching { project.extensions.getByType<Grgit>().head().id }
res.getOrDefault("")
.takeIf { it.length == 40 } ?: {
logger.error("Git commit hash not found", res.exceptionOrNull())
"unknown"
}()
},
) )
filesMatching("**/plugin.yml") { filesMatching("**/plugin.yml") {
expand(inputs.properties) expand(inputs.properties)
@@ -163,9 +176,35 @@ tasks {
} }
} }
/** val templateSource = file("src/main/templates")
* Gradle is weird sometimes, we need to delete the plugin yml from the build folder to actually filter properly. val templateDest = layout.buildDirectory.dir("generated/sources/templates")
*/ val generateTemplates = tasks.register<Copy>("generateTemplates") {
afterEvaluate { inputs.properties(
layout.buildDirectory.file("resources/main/plugin.yml").get().asFile.delete() "environment" to if (project.hasProperty("release")) "production" else "development",
"commit" to provider {
val res = runCatching { project.extensions.getByType<Grgit>().head().id }
res.getOrDefault("")
.takeIf { it.length == 40 } ?: {
logger.error("Git commit hash not found", res.exceptionOrNull())
"unknown"
}()
},
)
from(templateSource)
into(templateDest)
rename { "com/volmit/iris/$it" }
expand(inputs.properties)
}
tasks.generateSentryBundleIdJava {
dependsOn(generateTemplates)
}
rootProject.tasks.named("prepareKotlinBuildScriptModel") {
dependsOn(generateTemplates)
}
sourceSets.main {
java.srcDir(generateTemplates.map { it.outputs })
} }
+12 -7
View File
@@ -485,6 +485,7 @@ public class Iris extends VolmitPlugin implements Listener {
.forEach(PlatformChunkGenerator::close); .forEach(PlatformChunkGenerator::close);
MultiBurst.burst.close(); MultiBurst.burst.close();
MultiBurst.ioBurst.close();
services.clear(); services.clear();
}); });
Runtime.getRuntime().addShutdownHook(shutdownHook); Runtime.getRuntime().addShutdownHook(shutdownHook);
@@ -566,7 +567,7 @@ public class Iris extends VolmitPlugin implements Listener {
postShutdown.forEach(Runnable::run); postShutdown.forEach(Runnable::run);
super.onDisable(); super.onDisable();
J.attempt(new JarScanner(instance.getJarFile(), "", false)::scan); J.attempt(new JarScanner(instance.getJarFile(), "", false)::scanAll);
} }
private void setupPapi() { private void setupPapi() {
@@ -706,7 +707,11 @@ public class Iris extends VolmitPlugin implements Listener {
Iris.debug("Generator Config: " + w.toString()); Iris.debug("Generator Config: " + w.toString());
File ff = new File(w.worldFolder(), "iris/pack"); File ff = new File(w.worldFolder(), "iris/pack");
if (!ff.exists() || ff.listFiles().length == 0) { var files = ff.listFiles();
if (files == null || files.length == 0)
IO.delete(ff);
if (!ff.exists()) {
ff.mkdirs(); ff.mkdirs();
service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w.worldFolder()); service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w.worldFolder());
} }
@@ -716,13 +721,13 @@ public class Iris extends VolmitPlugin implements Listener {
@Nullable @Nullable
public static IrisDimension loadDimension(@NonNull String worldName, @NonNull String id) { public static IrisDimension loadDimension(@NonNull String worldName, @NonNull String id) {
var data = IrisData.get(new File(Bukkit.getWorldContainer(), String.join(File.separator, worldName, "iris", "pack"))); File pack = new File(Bukkit.getWorldContainer(), String.join(File.separator, worldName, "iris", "pack"));
var dimension = data.getDimensionLoader().load(id); var dimension = pack.isDirectory() ? IrisData.get(pack).getDimensionLoader().load(id) : null;
if (dimension == null) dimension = IrisData.loadAnyDimension(id); if (dimension == null) dimension = IrisData.loadAnyDimension(id, null);
if (dimension == null) { if (dimension == null) {
Iris.warn("Unable to find dimension type " + id + " Looking for online packs..."); Iris.warn("Unable to find dimension type " + id + " Looking for online packs...");
Iris.service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, false); Iris.service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, false);
dimension = IrisData.loadAnyDimension(id); dimension = IrisData.loadAnyDimension(id, null);
if (dimension != null) { if (dimension != null) {
Iris.info("Resolved missing dimension, proceeding."); Iris.info("Resolved missing dimension, proceeding.");
@@ -741,7 +746,7 @@ public class Iris extends VolmitPlugin implements Listener {
String padd2 = Form.repeat(" ", 4); 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()}; String[] info = {"", "", "", "", "", padd2 + C.IRIS + " Iris", padd2 + C.GRAY + " by " + "<rainbow>Volmit Software", padd2 + C.GRAY + " v" + C.IRIS + getDescription().getVersion()};
if (unstablemode) { if (unstablemode) {
info = new String[]{"", "", "", "", "", padd2 + C.RED + " Iris", padd2 + C.GRAY + " by " + C.DARK_RED + "Volmit Software", padd2 + C.GRAY + " v" + C.RED + getDescription().getVersion()}; info = new String[]{"", "", "", "", "", padd2 + C.RED + " Iris", padd2 + C.GRAY + " by " + C.DARK_RED + "Volmit Software", padd2 + C.GRAY + " v" + C.RED + getDescription().getVersion()};
} }
if (warningmode) { 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()}; info = new String[]{"", "", "", "", "", padd2 + C.GOLD + " Iris", padd2 + C.GRAY + " by " + C.GOLD + "Volmit Software", padd2 + C.GRAY + " v" + C.GOLD + getDescription().getVersion()};
@@ -49,11 +49,10 @@ public class IrisSettings {
private IrisSettingsSentry sentry = new IrisSettingsSentry(); private IrisSettingsSentry sentry = new IrisSettingsSentry();
public static int getThreadCount(int c) { public static int getThreadCount(int c) {
return switch (c) { return Math.max(switch (c) {
case -1, -2, -4 -> Runtime.getRuntime().availableProcessors() / -c; case -1, -2, -4 -> Runtime.getRuntime().availableProcessors() / -c;
case 0, 1, 2 -> 1;
default -> Math.max(c, 2); default -> Math.max(c, 2);
}; }, 1);
} }
public static IrisSettings get() { public static IrisSettings get() {
@@ -138,6 +137,7 @@ public class IrisSettings {
@Data @Data
public static class IrisSettingsConcurrency { public static class IrisSettingsConcurrency {
public int parallelism = -1; public int parallelism = -1;
public int ioParallelism = -2;
public int worldGenParallelism = -1; public int worldGenParallelism = -1;
public int getWorldGenThreads() { public int getWorldGenThreads() {
@@ -243,6 +243,8 @@ public class IrisSettings {
public int maxBiomeChildDepth = 4; public int maxBiomeChildDepth = 4;
public boolean preventLeafDecay = true; public boolean preventLeafDecay = true;
public boolean useMulticore = false; public boolean useMulticore = false;
public boolean offsetNoiseTypes = false;
public boolean earlyCustomBlocks = false;
} }
@Data @Data
@@ -66,6 +66,7 @@ public class IrisWorlds {
} }
public KMap<String, String> getWorlds() { public KMap<String, String> getWorlds() {
clean();
return readBukkitWorlds().put(worlds); return readBukkitWorlds().put(worlds);
} }
@@ -76,8 +77,7 @@ public class IrisWorlds {
} }
public Stream<IrisDimension> getDimensions() { public Stream<IrisDimension> getDimensions() {
return readBukkitWorlds() return getWorlds()
.put(worlds)
.entrySet() .entrySet()
.stream() .stream()
.map(entry -> Iris.loadDimension(entry.getKey(), entry.getValue())) .map(entry -> Iris.loadDimension(entry.getKey(), entry.getValue()))
@@ -103,14 +103,14 @@ public class ServerConfigurator {
return worlds; return worlds;
} }
public static void installDataPacks(boolean fullInstall) { public static boolean installDataPacks(boolean fullInstall) {
installDataPacks(DataVersion.getDefault(), fullInstall); return installDataPacks(DataVersion.getDefault(), fullInstall);
} }
public static void installDataPacks(IDataFixer fixer, boolean fullInstall) { public static boolean installDataPacks(IDataFixer fixer, boolean fullInstall) {
if (fixer == null) { if (fixer == null) {
Iris.error("Unable to install datapacks, fixer is null!"); Iris.error("Unable to install datapacks, fixer is null!");
return; return false;
} }
Iris.info("Checking Data Packs..."); Iris.info("Checking Data Packs...");
DimensionHeight height = new DimensionHeight(fixer); DimensionHeight height = new DimensionHeight(fixer);
@@ -129,11 +129,10 @@ public class ServerConfigurator {
IrisDimension.writeShared(folders, height); IrisDimension.writeShared(folders, height);
Iris.info("Data Packs Setup!"); Iris.info("Data Packs Setup!");
if (fullInstall) return fullInstall && verifyDataPacksPost(IrisSettings.get().getAutoConfiguration().isAutoRestartOnCustomBiomeInstall());
verifyDataPacksPost(IrisSettings.get().getAutoConfiguration().isAutoRestartOnCustomBiomeInstall());
} }
private static void verifyDataPacksPost(boolean allowRestarting) { private static boolean verifyDataPacksPost(boolean allowRestarting) {
try (Stream<IrisData> stream = allPacks()) { try (Stream<IrisData> stream = allPacks()) {
boolean bad = stream boolean bad = stream
.map(data -> { .map(data -> {
@@ -148,7 +147,7 @@ public class ServerConfigurator {
}) })
.toList() .toList()
.contains(true); .contains(true);
if (!bad) return; if (!bad) return false;
} }
@@ -172,6 +171,7 @@ public class ServerConfigurator {
J.sleep(3000); J.sleep(3000);
} }
return true;
} }
public static void restart() { public static void restart() {
@@ -18,19 +18,29 @@
package com.volmit.iris.core.commands; package com.volmit.iris.core.commands;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.ServerConfigurator; import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.core.service.IrisEngineSVC; import com.volmit.iris.core.service.IrisEngineSVC;
import com.volmit.iris.core.tools.IrisPackBenchmarking; import com.volmit.iris.core.tools.IrisPackBenchmarking;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.context.IrisContext; import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin; import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree; import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param; import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.decree.specialhandlers.NullableDimensionHandler;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.CountingDataInputStream; import com.volmit.iris.util.io.CountingDataInputStream;
@@ -42,6 +52,7 @@ import com.volmit.iris.util.nbt.mca.MCAFile;
import com.volmit.iris.util.nbt.mca.MCAUtil; import com.volmit.iris.util.nbt.mca.MCAUtil;
import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import lombok.SneakyThrows;
import net.jpountz.lz4.LZ4BlockInputStream; import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream; import net.jpountz.lz4.LZ4BlockOutputStream;
import net.jpountz.lz4.LZ4FrameInputStream; import net.jpountz.lz4.LZ4FrameInputStream;
@@ -59,6 +70,7 @@ import java.util.*;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
@@ -143,6 +155,130 @@ public class CommandDeveloper implements DecreeExecutor {
} }
} }
@SneakyThrows
@Decree(description = "Generate Iris structures for all loaded datapack structures")
public void generateStructures(
@Param(description = "The pack to add the generated structures to", aliases = "pack", defaultValue = "null", customHandler = NullableDimensionHandler.class)
IrisDimension dimension,
@Param(description = "Ignore existing structures", defaultValue = "false")
boolean force
) {
var map = INMS.get().collectStructures();
if (map.isEmpty()) {
sender().sendMessage(C.IRIS + "No structures found");
return;
}
sender().sendMessage(C.IRIS + "Found " + map.size() + " structures");
final File dataDir;
final IrisData data;
final Set<String> existingStructures;
final Map<String, Set<String>> snippets;
final File dimensionFile;
final File structuresFolder;
final File snippetsFolder;
var dimensionObj = new JsonObject();
if (dimension == null) {
dataDir = Iris.instance.getDataFolder("structures");
IO.delete(dataDir);
data = IrisData.get(dataDir);
existingStructures = Set.of();
snippets = Map.of();
dimensionFile = new File(dataDir, "structures.json");
} else {
data = dimension.getLoader();
dataDir = data.getDataFolder();
existingStructures = new KSet<>(data.getJigsawStructureLoader().getPossibleKeys());
dimensionObj = data.getGson().fromJson(IO.readAll(dimension.getLoadFile()), JsonObject.class);
snippets = Optional.ofNullable(dimensionObj.getAsJsonArray("jigsawStructures"))
.map(array -> array.asList()
.stream()
.filter(JsonElement::isJsonPrimitive)
.collect(Collectors.toMap(element -> data.getGson()
.fromJson(element, IrisJigsawStructurePlacement.class)
.getStructure(),
element -> Set.of(element.getAsString()),
KSet::merge)))
.orElse(Map.of());
dimensionFile = dimension.getLoadFile();
}
structuresFolder = new File(dataDir, "jigsaw-structures");
snippetsFolder = new File(dataDir, "snippet" + "/" + IrisJigsawStructurePlacement.class.getAnnotation(Snippet.class).value());
var gson = data.getGson();
var jigsawStructures = Optional.ofNullable(dimensionObj.getAsJsonArray("jigsawStructures"))
.orElse(new JsonArray(map.size()));
map.forEach((key, placement) -> {
String loadKey = "datapack/" + key.namespace() + "/" + key.key();
if (existingStructures.contains(loadKey) && !force)
return;
var structures = placement.structures();
var obj = placement.toJson(loadKey);
if (obj == null || structures.isEmpty()) {
sender().sendMessage(C.RED + "Failed to generate hook for " + key);
return;
}
File snippetFile = new File(snippetsFolder, loadKey + ".json");
try {
IO.writeAll(snippetFile, gson.toJson(obj));
} catch (IOException e) {
sender().sendMessage(C.RED + "Failed to generate snippet for " + key);
e.printStackTrace();
return;
}
Set<String> loadKeys = snippets.getOrDefault(loadKey, Set.of(loadKey));
jigsawStructures.asList().removeIf(e -> loadKeys.contains((e.isJsonObject() ? e.getAsJsonObject().get("structure") : e).getAsString()));
jigsawStructures.add("snippet/" + loadKey);
String structureKey;
if (structures.size() > 1) {
KList<String> common = new KList<>();
for (int i = 0; i < structures.size(); i++) {
var tags = structures.get(i).tags();
if (i == 0) common.addAll(tags);
else common.removeIf(tag -> !tags.contains(tag));
}
structureKey = common.isNotEmpty() ? "#" + common.getFirst() : structures.getFirst().key();
} else structureKey = structures.getFirst().key();
JsonArray array = new JsonArray();
if (structures.size() > 1) {
structures.stream()
.flatMap(structure -> {
String[] arr = new String[structure.weight()];
Arrays.fill(arr, structure.key());
return Arrays.stream(arr);
})
.forEach(array::add);
} else array.add(structureKey);
obj = new JsonObject();
obj.addProperty("structureKey", structureKey);
obj.add("datapackStructures", array);
File out = new File(structuresFolder, loadKey + ".json");
out.getParentFile().mkdirs();
try {
IO.writeAll(out, gson.toJson(obj));
} catch (IOException e) {
e.printStackTrace();
}
});
dimensionObj.add("jigsawStructures", jigsawStructures);
IO.writeAll(dimensionFile, gson.toJson(dimensionObj));
data.hotloaded();
}
@Decree(description = "Test") @Decree(description = "Test")
public void packBenchmark( public void packBenchmark(
@Param(description = "The pack to bench", aliases = {"pack"}, defaultValue = "overworld") @Param(description = "The pack to bench", aliases = {"pack"}, defaultValue = "overworld")
@@ -48,7 +48,7 @@ public class CommandJigsaw implements DecreeExecutor {
IrisJigsawPiece piece IrisJigsawPiece piece
) { ) {
File dest = piece.getLoadFile(); File dest = piece.getLoadFile();
new JigsawEditor(player(), piece, IrisData.loadAnyObject(piece.getObject()), dest); new JigsawEditor(player(), piece, IrisData.loadAnyObject(piece.getObject(), data()), dest);
} }
@Decree(description = "Place a jigsaw structure") @Decree(description = "Place a jigsaw structure")
@@ -78,7 +78,7 @@ public class CommandJigsaw implements DecreeExecutor {
@Param(description = "The object to use for this piece", customHandler = ObjectHandler.class) @Param(description = "The object to use for this piece", customHandler = ObjectHandler.class)
String object String object
) { ) {
IrisObject o = IrisData.loadAnyObject(object); IrisObject o = IrisData.loadAnyObject(object, data());
if (object == null) { if (object == null) {
sender().sendMessage(C.RED + "Failed to find existing object"); sender().sendMessage(C.RED + "Failed to find existing object");
@@ -136,7 +136,7 @@ public class CommandObject implements DecreeExecutor {
@Param(description = "The object to analyze", customHandler = ObjectHandler.class) @Param(description = "The object to analyze", customHandler = ObjectHandler.class)
String object String object
) { ) {
IrisObject o = IrisData.loadAnyObject(object); IrisObject o = IrisData.loadAnyObject(object, data());
sender().sendMessage("Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD() + ""); sender().sendMessage("Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD() + "");
sender().sendMessage("Blocks Used: " + NumberFormat.getIntegerInstance().format(o.getBlocks().size())); sender().sendMessage("Blocks Used: " + NumberFormat.getIntegerInstance().format(o.getBlocks().size()));
@@ -201,7 +201,7 @@ public class CommandObject implements DecreeExecutor {
@Decree(description = "Shrink an object to its minimum size") @Decree(description = "Shrink an object to its minimum size")
public void shrink(@Param(description = "The object to shrink", customHandler = ObjectHandler.class) String object) { public void shrink(@Param(description = "The object to shrink", customHandler = ObjectHandler.class) String object) {
IrisObject o = IrisData.loadAnyObject(object); IrisObject o = IrisData.loadAnyObject(object, data());
sender().sendMessage("Current Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD()); sender().sendMessage("Current Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD());
o.shrinkwrap(); o.shrinkwrap();
sender().sendMessage("New Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD()); sender().sendMessage("New Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD());
@@ -325,7 +325,7 @@ public class CommandObject implements DecreeExecutor {
// @Param(description = "The scale interpolator to use", defaultValue = "none") // @Param(description = "The scale interpolator to use", defaultValue = "none")
// IrisObjectPlacementScaleInterpolator interpolator // IrisObjectPlacementScaleInterpolator interpolator
) { ) {
IrisObject o = IrisData.loadAnyObject(object); IrisObject o = IrisData.loadAnyObject(object, data());
double maxScale = Double.max(10 - o.getBlocks().size() / 10000d, 1); double maxScale = Double.max(10 - o.getBlocks().size() / 10000d, 1);
if (scale > maxScale) { if (scale > maxScale) {
sender().sendMessage(C.YELLOW + "Indicated scale exceeds maximum. Downscaled to maximum: " + maxScale); sender().sendMessage(C.YELLOW + "Indicated scale exceeds maximum. Downscaled to maximum: " + maxScale);
@@ -47,7 +47,6 @@ import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONArray; import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.mantle.MantleChunk; import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
@@ -172,9 +171,9 @@ public class CommandStudio implements DecreeExecutor {
var loc = player().getLocation().clone(); var loc = player().getLocation().clone();
J.a(() -> { J.a(() -> {
DecreeContext.touch(sender);
PlatformChunkGenerator plat = IrisToolbelt.access(world); PlatformChunkGenerator plat = IrisToolbelt.access(world);
Engine engine = plat.getEngine(); Engine engine = plat.getEngine();
DecreeContext.touch(sender);
try (SyncExecutor executor = new SyncExecutor(20)) { try (SyncExecutor executor = new SyncExecutor(20)) {
int x = loc.getBlockX() >> 4; int x = loc.getBlockX() >> 4;
int z = loc.getBlockZ() >> 4; int z = loc.getBlockZ() >> 4;
@@ -233,9 +232,7 @@ public class CommandStudio implements DecreeExecutor {
chunkMap.forEach((pos, chunk) -> { chunkMap.forEach((pos, chunk) -> {
var c = mantle.getChunk(pos.getX(), pos.getZ()).use(); var c = mantle.getChunk(pos.getX(), pos.getZ()).use();
try { try {
for (MantleFlag flag : MantleFlag.values()) { c.copyFlags(chunk);
c.flag(flag, chunk.isFlagged(flag));
}
c.clear(); c.clear();
for (int y = 0; y < sections; y++) { for (int y = 0; y < sections; y++) {
var slice = chunk.get(y); var slice = chunk.get(y);
@@ -250,6 +247,8 @@ public class CommandStudio implements DecreeExecutor {
} catch (Throwable e) { } catch (Throwable e) {
sender().sendMessage("Error while regenerating chunks"); sender().sendMessage("Error while regenerating chunks");
e.printStackTrace(); e.printStackTrace();
} finally {
DecreeContext.remove();
} }
}); });
} }
@@ -359,6 +358,42 @@ public class CommandStudio implements DecreeExecutor {
player().openInventory(inv); player().openInventory(inv);
} }
@Decree(description = "Calculate the chance for each region to generate", origin = DecreeOrigin.PLAYER)
public void regions(@Param(description = "The radius in chunks", defaultValue = "500") int radius) {
var engine = engine();
if (engine == null) {
sender().sendMessage(C.RED + "Only works in an Iris world!");
return;
}
var sender = sender();
var player = player();
Thread.ofVirtual()
.start(() -> {
int d = radius * 2;
KMap<String, AtomicInteger> data = new KMap<>();
engine.getDimension().getRegions().forEach(key -> data.put(key, new AtomicInteger(0)));
var multiBurst = new MultiBurst("Region Sampler");
var executor = multiBurst.burst(radius * radius);
sender.sendMessage(C.GRAY + "Generating data...");
var loc = player.getLocation();
int totalTasks = d * d;
AtomicInteger completedTasks = new AtomicInteger(0);
int c = J.ar(() -> sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding regions"), 0);
new Spiraler(d, d, (x, z) -> executor.queue(() -> {
var region = engine.getRegion((x << 4) + 8, (z << 4) + 8);
data.computeIfAbsent(region.getLoadKey(), (k) -> new AtomicInteger(0))
.incrementAndGet();
completedTasks.incrementAndGet();
})).setOffset(loc.getBlockX(), loc.getBlockZ()).drain();
executor.complete();
multiBurst.close();
J.car(c);
sender.sendMessage(C.GREEN + "Done!");
var loader = engine.getData().getRegionLoader();
data.forEach((k, v) -> sender.sendMessage(C.GREEN + k + ": " + loader.load(k).getRarity() + " / " + Form.f((double) v.get() / totalTasks * 100, 2) + "%"));
});
}
@Decree(description = "Get all structures in a radius of chunks", aliases = "dist", origin = DecreeOrigin.PLAYER) @Decree(description = "Get all structures in a radius of chunks", aliases = "dist", origin = DecreeOrigin.PLAYER)
public void distances(@Param(description = "The radius in chunks") int radius) { public void distances(@Param(description = "The radius in chunks") int radius) {
@@ -370,7 +405,7 @@ public class CommandStudio implements DecreeExecutor {
var sender = sender(); var sender = sender();
int d = radius * 2; int d = radius * 2;
KMap<String, KList<Position2>> data = new KMap<>(); KMap<String, KList<Position2>> data = new KMap<>();
var multiBurst = new MultiBurst("Distance Sampler", Thread.MIN_PRIORITY); var multiBurst = new MultiBurst("Distance Sampler");
var executor = multiBurst.burst(radius * radius); var executor = multiBurst.burst(radius * radius);
sender.sendMessage(C.GRAY + "Generating data..."); sender.sendMessage(C.GRAY + "Generating data...");
@@ -1,6 +1,8 @@
package com.volmit.iris.core.link; package com.volmit.iris.core.link;
import com.volmit.iris.core.link.data.DataType; import com.volmit.iris.core.link.data.DataType;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
@@ -22,7 +24,9 @@ import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException; import java.util.MissingResourceException;
@Getter @Getter
@@ -66,6 +70,18 @@ public abstract class ExternalDataProvider implements Listener {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
} }
/**
* Retrieves a list of all {@link BlockProperty} objects associated with the specified block identifier.
*
* @param blockId The identifier of the block whose properties are to be retrieved. Must not be null.
* @return A list of {@link BlockProperty} objects representing the properties of the block.
* @throws MissingResourceException If the specified block identifier is invalid or cannot be found.
*/
@NotNull
public List<BlockProperty> getBlockProperties(@NotNull Identifier blockId) throws MissingResourceException {
return List.of();
}
/** /**
* @see ExternalDataProvider#getItemStack(Identifier) * @see ExternalDataProvider#getItemStack(Identifier)
*/ */
@@ -137,4 +153,18 @@ public abstract class ExternalDataProvider implements Listener {
return new Pair<>(yaw, face); return new Pair<>(yaw, face);
} }
protected static List<BlockProperty> YAW_FACE_BIOME_PROPERTIES = List.of(
BlockProperty.ofEnum(BiomeColor.class, "matchBiome", null),
BlockProperty.ofBoolean("randomYaw", false),
BlockProperty.ofFloat("yaw", 0, 0, 360f, false, true),
BlockProperty.ofBoolean("randomFace", true),
new BlockProperty(
"face",
BlockFace.class,
BlockFace.NORTH,
Arrays.asList(BlockFace.values()).subList(0, BlockFace.values().length - 1),
BlockFace::name
)
);
} }
@@ -62,7 +62,10 @@ public class ItemAdderDataProvider extends ExternalDataProvider {
@Override @Override
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) { public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
CustomBlock.place(blockId.toString(), block.getLocation()); CustomBlock custom;
if ((custom = CustomBlock.place(blockId.toString(), block.getLocation())) == null)
return;
block.setBlockData(custom.getBaseBlockData(), false);
} }
@Override @Override
@@ -23,6 +23,7 @@ import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
@@ -41,6 +42,7 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.Optional; import java.util.Optional;
@@ -77,6 +79,19 @@ public class MythicCrucibleDataProvider extends ExternalDataProvider {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
} }
@Override
public @NotNull List<BlockProperty> getBlockProperties(@NotNull Identifier blockId) throws MissingResourceException {
CrucibleItem crucibleItem = this.itemManager.getItem(blockId.key())
.orElseThrow(() -> new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()));
if (crucibleItem.getFurnitureData() != null) {
return YAW_FACE_BIOME_PROPERTIES;
} else if (crucibleItem.getBlockData() != null) {
return List.of();
}
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
@NotNull @NotNull
@Override @Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException { public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
@@ -5,10 +5,14 @@ import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
import io.lumine.mythic.api.adapters.AbstractLocation; import io.lumine.mythic.api.adapters.AbstractLocation;
import io.lumine.mythic.api.config.MythicLineConfig; import io.lumine.mythic.api.config.MythicLineConfig;
import io.lumine.mythic.api.mobs.entities.SpawnReason;
import io.lumine.mythic.api.skills.conditions.ILocationCondition; import io.lumine.mythic.api.skills.conditions.ILocationCondition;
import io.lumine.mythic.bukkit.BukkitAdapter;
import io.lumine.mythic.bukkit.MythicBukkit; import io.lumine.mythic.bukkit.MythicBukkit;
import io.lumine.mythic.bukkit.adapters.BukkitWorld; import io.lumine.mythic.bukkit.adapters.BukkitWorld;
import io.lumine.mythic.bukkit.events.MythicConditionLoadEvent; import io.lumine.mythic.bukkit.events.MythicConditionLoadEvent;
import io.lumine.mythic.core.mobs.ActiveMob;
import io.lumine.mythic.core.mobs.MobStack;
import io.lumine.mythic.core.skills.SkillCondition; import io.lumine.mythic.core.skills.SkillCondition;
import io.lumine.mythic.core.utils.annotations.MythicCondition; import io.lumine.mythic.core.utils.annotations.MythicCondition;
import io.lumine.mythic.core.utils.annotations.MythicField; import io.lumine.mythic.core.utils.annotations.MythicField;
@@ -20,6 +24,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
public class MythicMobsDataProvider extends ExternalDataProvider { public class MythicMobsDataProvider extends ExternalDataProvider {
public MythicMobsDataProvider() { public MythicMobsDataProvider() {
@@ -32,18 +37,31 @@ public class MythicMobsDataProvider extends ExternalDataProvider {
@Override @Override
public @Nullable Entity spawnMob(@NotNull Location location, @NotNull Identifier entityId) throws MissingResourceException { public @Nullable Entity spawnMob(@NotNull Location location, @NotNull Identifier entityId) throws MissingResourceException {
var mm = MythicBukkit.inst().getMobManager().spawnMob(entityId.key(), location); var mm = spawnMob(BukkitAdapter.adapt(location), entityId);
if (mm == null) throw new MissingResourceException("Failed to find mob!", entityId.namespace(), entityId.key()); return mm == null ? null : mm.getEntity().getBukkitEntity();
return mm.getEntity().getBukkitEntity(); }
private ActiveMob spawnMob(AbstractLocation location, Identifier entityId) throws MissingResourceException {
var manager = MythicBukkit.inst().getMobManager();
var mm = manager.getMythicMob(entityId.key()).orElse(null);
if (mm == null) {
var stack = manager.getMythicMobStack(entityId.key());
if (stack == null) throw new MissingResourceException("Failed to find Mob!", entityId.namespace(), entityId.key());
return stack.spawn(location, 1d, SpawnReason.OTHER, null);
}
return mm.spawn(location, 1d, SpawnReason.OTHER, null, null);
} }
@Override @Override
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) { public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
if (dataType != DataType.ENTITY) return List.of(); if (dataType != DataType.ENTITY) return List.of();
return MythicBukkit.inst() var manager = MythicBukkit.inst().getMobManager();
.getMobManager() return Stream.concat(manager.getMobNames().stream(),
.getMobNames() manager.getMobStacks()
.stream() .stream()
.map(MobStack::getName)
)
.distinct()
.map(name -> new Identifier("mythicmobs", name)) .map(name -> new Identifier("mythicmobs", name))
.toList(); .toList();
} }
@@ -8,6 +8,7 @@ import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
@@ -56,6 +57,15 @@ public class NexoDataProvider extends ExternalDataProvider {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()); throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
} }
@Override
public @NotNull List<BlockProperty> getBlockProperties(@NotNull Identifier blockId) throws MissingResourceException {
if (!NexoItems.exists(blockId.key())) {
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
}
return NexoFurniture.isFurniture(blockId.key()) ? YAW_FACE_BIOME_PROPERTIES : List.of();
}
@NotNull @NotNull
@Override @Override
public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException { public ItemStack getItemStack(@NotNull Identifier itemId, @NotNull KMap<String, Object> customNbt) throws MissingResourceException {
@@ -63,7 +73,12 @@ public class NexoDataProvider extends ExternalDataProvider {
if (builder == null) { if (builder == null) {
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()); throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
} }
return builder.build(); try {
return builder.build();
} catch (Exception e) {
e.printStackTrace();
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
}
} }
@Override @Override
@@ -24,6 +24,7 @@ import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.scripting.environment.PackEnvironment;
import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.object.*;
@@ -33,6 +34,8 @@ import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.IrisContext; import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
import com.volmit.iris.util.mantle.flag.MantleFlagAdapter;
import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.parallel.MultiBurst;
@@ -40,6 +43,7 @@ import com.volmit.iris.util.reflect.KeyedType;
import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
import lombok.Data; import lombok.Data;
import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
@@ -47,13 +51,14 @@ import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function; import java.util.Optional;
@Data @Data
public class IrisData implements ExclusionStrategy, TypeAdapterFactory { public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
private static final KMap<File, IrisData> dataLoaders = new KMap<>(); private static final KMap<File, IrisData> dataLoaders = new KMap<>();
private final File dataFolder; private final File dataFolder;
private final int id; private final int id;
private final PackEnvironment environment;
private boolean closed = false; private boolean closed = false;
private ResourceLoader<IrisBiome> biomeLoader; private ResourceLoader<IrisBiome> biomeLoader;
private ResourceLoader<IrisLootTable> lootLoader; private ResourceLoader<IrisLootTable> lootLoader;
@@ -87,6 +92,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
this.engine = null; this.engine = null;
this.dataFolder = dataFolder; this.dataFolder = dataFolder;
this.id = RNG.r.imax(); this.id = RNG.r.imax();
this.environment = PackEnvironment.create(this);
hotloaded(); hotloaded();
} }
@@ -94,6 +100,10 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
return dataLoaders.computeIfAbsent(dataFolder, IrisData::new); return dataLoaders.computeIfAbsent(dataFolder, IrisData::new);
} }
public static Optional<IrisData> getLoaded(File dataFolder) {
return Optional.ofNullable(dataLoaders.get(dataFolder));
}
public static void dereference() { public static void dereference() {
dataLoaders.v().forEach(IrisData::cleanupEngine); dataLoaders.v().forEach(IrisData::cleanupEngine);
} }
@@ -113,92 +123,100 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
Iris.warn(" " + rl.getResourceTypeName() + " @ /" + rl.getFolderName() + ": Cache=" + rl.getLoadCache().getSize() + " Folders=" + rl.getFolders().size()); Iris.warn(" " + rl.getResourceTypeName() + " @ /" + rl.getFolderName() + ": Cache=" + rl.getLoadCache().getSize() + " Folders=" + rl.getFolders().size());
} }
public static IrisObject loadAnyObject(String key) { public static IrisObject loadAnyObject(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getObjectLoader().load(key, false)); return loadAny(IrisObject.class, key, nearest);
} }
public static IrisMatterObject loadAnyMatter(String key) { public static IrisMatterObject loadAnyMatter(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getMatterLoader().load(key, false)); return loadAny(IrisMatterObject.class, key, nearest);
} }
public static IrisBiome loadAnyBiome(String key) { public static IrisBiome loadAnyBiome(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getBiomeLoader().load(key, false)); return loadAny(IrisBiome.class, key, nearest);
} }
public static IrisExpression loadAnyExpression(String key) { public static IrisExpression loadAnyExpression(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getExpressionLoader().load(key, false)); return loadAny(IrisExpression.class, key, nearest);
} }
public static IrisMod loadAnyMod(String key) { public static IrisMod loadAnyMod(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getModLoader().load(key, false)); return loadAny(IrisMod.class, key, nearest);
} }
public static IrisJigsawPiece loadAnyJigsawPiece(String key) { public static IrisJigsawPiece loadAnyJigsawPiece(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getJigsawPieceLoader().load(key, false)); return loadAny(IrisJigsawPiece.class, key, nearest);
} }
public static IrisJigsawPool loadAnyJigsawPool(String key) { public static IrisJigsawPool loadAnyJigsawPool(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getJigsawPoolLoader().load(key, false)); return loadAny(IrisJigsawPool.class, key, nearest);
} }
public static IrisEntity loadAnyEntity(String key) { public static IrisEntity loadAnyEntity(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getEntityLoader().load(key, false)); return loadAny(IrisEntity.class, key, nearest);
} }
public static IrisLootTable loadAnyLootTable(String key) { public static IrisLootTable loadAnyLootTable(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getLootLoader().load(key, false)); return loadAny(IrisLootTable.class, key, nearest);
} }
public static IrisBlockData loadAnyBlock(String key) { public static IrisBlockData loadAnyBlock(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getBlockLoader().load(key, false)); return loadAny(IrisBlockData.class, key, nearest);
} }
public static IrisSpawner loadAnySpaner(String key) { public static IrisSpawner loadAnySpaner(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getSpawnerLoader().load(key, false)); return loadAny(IrisSpawner.class, key, nearest);
} }
public static IrisScript loadAnyScript(String key) { public static IrisScript loadAnyScript(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getScriptLoader().load(key, false)); return loadAny(IrisScript.class, key, nearest);
} }
public static IrisRavine loadAnyRavine(String key) { public static IrisRavine loadAnyRavine(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getRavineLoader().load(key, false)); return loadAny(IrisRavine.class, key, nearest);
} }
public static IrisRegion loadAnyRegion(String key) { public static IrisRegion loadAnyRegion(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getRegionLoader().load(key, false)); return loadAny(IrisRegion.class, key, nearest);
} }
public static IrisMarker loadAnyMarker(String key) { public static IrisMarker loadAnyMarker(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getMarkerLoader().load(key, false)); return loadAny(IrisMarker.class, key, nearest);
} }
public static IrisCave loadAnyCave(String key) { public static IrisCave loadAnyCave(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getCaveLoader().load(key, false)); return loadAny(IrisCave.class, key, nearest);
} }
public static IrisImage loadAnyImage(String key) { public static IrisImage loadAnyImage(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getImageLoader().load(key, false)); return loadAny(IrisImage.class, key, nearest);
} }
public static IrisDimension loadAnyDimension(String key) { public static IrisDimension loadAnyDimension(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getDimensionLoader().load(key, false)); return loadAny(IrisDimension.class, key, nearest);
} }
public static IrisJigsawStructure loadAnyJigsawStructure(String key) { public static IrisJigsawStructure loadAnyJigsawStructure(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getJigsawStructureLoader().load(key, false)); return loadAny(IrisJigsawStructure.class, key, nearest);
} }
public static IrisGenerator loadAnyGenerator(String key) { public static IrisGenerator loadAnyGenerator(String key, @Nullable IrisData nearest) {
return loadAny(key, (dm) -> dm.getGeneratorLoader().load(key, false)); return loadAny(IrisGenerator.class, key, nearest);
} }
public static <T extends IrisRegistrant> T loadAny(String key, Function<IrisData, T> v) { public static <T extends IrisRegistrant> T loadAny(Class<T> type, String key, @Nullable IrisData nearest) {
try { try {
if (nearest != null) {
T t = nearest.load(type, key, false);
if (t != null) {
return t;
}
}
for (File i : Objects.requireNonNull(Iris.instance.getDataFolder("packs").listFiles())) { for (File i : Objects.requireNonNull(Iris.instance.getDataFolder("packs").listFiles())) {
if (i.isDirectory()) { if (i.isDirectory()) {
IrisData dm = get(i); IrisData dm = get(i);
T t = v.apply(dm); if (dm == nearest) continue;
T t = dm.load(type, key, false);
if (t != null) { if (t != null) {
return t; return t;
@@ -213,6 +231,17 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
return null; return null;
} }
public <T extends IrisRegistrant> T load(Class<T> type, String key, boolean warn) {
var loader = getLoader(type);
if (loader == null) return null;
return loader.load(key, warn);
}
@SuppressWarnings("unchecked")
public <T extends IrisRegistrant> ResourceLoader<T> getLoader(Class<T> type) {
return (ResourceLoader<T>) loaders.get(type);
}
public ResourceLoader<?> getTypedLoaderFor(File f) { public ResourceLoader<?> getTypedLoaderFor(File f) {
String[] k = f.getPath().split("\\Q" + File.separator + "\\E"); String[] k = f.getPath().split("\\Q" + File.separator + "\\E");
@@ -252,12 +281,20 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
} }
} }
if (engine != null && t.getPreprocessors().isNotEmpty()) { if (engine == null) return;
var global = engine.getDimension().getPreProcessors(t.getFolderName());
var local = t.getPreprocessors();
if ((global != null && global.isNotEmpty()) || local.isNotEmpty()) {
synchronized (this) { synchronized (this) {
engine.getExecution().getAPI().setPreprocessorObject(t); if (global != null) {
for (String i : global) {
engine.getExecution().preprocessObject(i, t);
Iris.debug("Loader<" + C.GREEN + t.getTypeName() + C.LIGHT_PURPLE + "> iprocess " + C.YELLOW + t.getLoadKey() + C.LIGHT_PURPLE + " in <rainbow>" + i);
}
}
for (String i : t.getPreprocessors()) { for (String i : local) {
engine.getExecution().execute(i); engine.getExecution().preprocessObject(i, t);
Iris.debug("Loader<" + C.GREEN + t.getTypeName() + C.LIGHT_PURPLE + "> iprocess " + C.YELLOW + t.getLoadKey() + C.LIGHT_PURPLE + " in <rainbow>" + i); Iris.debug("Loader<" + C.GREEN + t.getTypeName() + C.LIGHT_PURPLE + "> iprocess " + C.YELLOW + t.getLoadKey() + C.LIGHT_PURPLE + " in <rainbow>" + i);
} }
} }
@@ -271,6 +308,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
public void close() { public void close() {
closed = true; closed = true;
dump(); dump();
dataLoaders.remove(dataFolder);
} }
public IrisData copy() { public IrisData copy() {
@@ -311,12 +349,15 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
} }
public synchronized void hotloaded() { public synchronized void hotloaded() {
closed = false;
environment.close();
possibleSnippets = new KMap<>(); possibleSnippets = new KMap<>();
builder = new GsonBuilder() builder = new GsonBuilder()
.addDeserializationExclusionStrategy(this) .addDeserializationExclusionStrategy(this)
.addSerializationExclusionStrategy(this) .addSerializationExclusionStrategy(this)
.setLenient() .setLenient()
.registerTypeAdapterFactory(this) .registerTypeAdapterFactory(this)
.registerTypeAdapter(MantleFlag.class, new MantleFlagAdapter())
.setPrettyPrinting(); .setPrettyPrinting();
loaders.clear(); loaders.clear();
File packs = dataFolder; File packs = dataFolder;
@@ -344,6 +385,10 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
builder.registerTypeAdapterFactory(KeyedType::createTypeAdapter); builder.registerTypeAdapterFactory(KeyedType::createTypeAdapter);
gson = builder.create(); gson = builder.create();
dimensionLoader.streamAll()
.map(IrisDimension::getDataScripts)
.flatMap(KList::stream)
.forEach(environment::execute);
} }
public void dump() { public void dump() {
@@ -405,6 +450,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
} }
String snippetType = typeToken.getRawType().getDeclaredAnnotation(Snippet.class).value(); String snippetType = typeToken.getRawType().getDeclaredAnnotation(Snippet.class).value();
String snippedBase = "snippet/" + snippetType + "/";
return new TypeAdapter<>() { return new TypeAdapter<>() {
@Override @Override
@@ -418,19 +464,20 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
if (reader.peek().equals(JsonToken.STRING)) { if (reader.peek().equals(JsonToken.STRING)) {
String r = reader.nextString(); String r = reader.nextString();
if (!r.startsWith("snippet/"))
return null;
if (!r.startsWith(snippedBase))
r = snippedBase + r.substring(8);
if (r.startsWith("snippet/" + snippetType + "/")) { File f = new File(getDataFolder(), r + ".json");
File f = new File(getDataFolder(), r + ".json"); if (f.exists()) {
try (JsonReader snippetReader = new JsonReader(new FileReader(f))){
if (f.exists()) { return adapter.read(snippetReader);
try (JsonReader snippetReader = new JsonReader(new FileReader(f))){ } catch (Throwable e) {
return adapter.read(snippetReader); Iris.error("Couldn't read snippet " + r + " in " + reader.getPath() + " (" + e.getMessage() + ")");
} catch (Throwable e) {
Iris.error("Couldn't read snippet " + r + " in " + reader.getPath() + " (" + e.getMessage() + ")");
}
} else {
Iris.error("Couldn't find snippet " + r + " in " + reader.getPath());
} }
} else {
Iris.error("Couldn't find snippet " + r + " in " + reader.getPath());
} }
return null; return null;
@@ -468,7 +515,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
.map(s -> s.substring(absPath.length() + 1)) .map(s -> s.substring(absPath.length() + 1))
.map(s -> s.replace("\\", "/")) .map(s -> s.replace("\\", "/"))
.map(s -> s.split("\\Q.\\E")[0]) .map(s -> s.split("\\Q.\\E")[0])
.forEach(s -> l.add("snippet/" + f + "/" + s)); .forEach(s -> l.add("snippet/" + s));
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -482,7 +529,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
} }
public void savePrefetch(Engine engine) { public void savePrefetch(Engine engine) {
BurstExecutor b = MultiBurst.burst.burst(loaders.size()); BurstExecutor b = MultiBurst.ioBurst.burst(loaders.size());
for (ResourceLoader<?> i : loaders.values()) { for (ResourceLoader<?> i : loaders.values()) {
b.queue(() -> { b.queue(() -> {
@@ -499,7 +546,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
} }
public void loadPrefetch(Engine engine) { public void loadPrefetch(Engine engine) {
BurstExecutor b = MultiBurst.burst.burst(loaders.size()); BurstExecutor b = MultiBurst.ioBurst.burst(loaders.size());
for (ResourceLoader<?> i : loaders.values()) { for (ResourceLoader<?> i : loaders.values()) {
b.queue(() -> { b.queue(() -> {
@@ -28,17 +28,19 @@ import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import java.awt.*; import java.awt.*;
import java.io.File; import java.io.File;
@Data @Data
public abstract class IrisRegistrant { public abstract class IrisRegistrant {
@Desc("Preprocess this object in-memory when it's loaded, run scripts using the variable 'Iris.getPreprocessorObject()' and modify properties about this object before it's used.") @Desc("Preprocess this object in-memory when it's loaded, run scripts using the variable 'object' and modify properties about this object before it's used.\nFile extension: .prox.kts")
@RegistryListResource(IrisScript.class) @RegistryListResource(IrisScript.class)
@ArrayType(min = 1, type = String.class) @ArrayType(min = 1, type = String.class)
private KList<String> preprocessors = new KList<>(); private KList<String> preprocessors = new KList<>();
@EqualsAndHashCode.Exclude
private transient IrisData loader; private transient IrisData loader;
private transient String loadKey; private transient String loadKey;
@@ -45,6 +45,7 @@ import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import java.io.*; import java.io.*;
import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -215,6 +216,10 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
return j; return j;
} }
public Stream<T> streamAll() {
return streamAll(Arrays.stream(getPossibleKeys()));
}
public Stream<T> streamAll(Stream<String> s) { public Stream<T> streamAll(Stream<String> s) {
return s.map(this::load); return s.map(this::load);
} }
@@ -235,7 +240,7 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
public KList<T> loadAllParallel(KList<String> s) { public KList<T> loadAllParallel(KList<String> s) {
KList<T> m = new KList<>(); KList<T> m = new KList<>();
BurstExecutor burst = MultiBurst.burst.burst(s.size()); BurstExecutor burst = MultiBurst.ioBurst.burst(s.size());
for (String i : s) { for (String i : s) {
burst.queue(() -> { burst.queue(() -> {
@@ -82,8 +82,8 @@ public class ScriptResourceLoader extends ResourceLoader<IrisScript> {
private Set<String> getKeysInDirectory(File directory) { private Set<String> getKeysInDirectory(File directory) {
Set<String> keys = new HashSet<>(); Set<String> keys = new HashSet<>();
for (File file : directory.listFiles()) { for (File file : directory.listFiles()) {
if (file.isFile() && file.getName().endsWith(".js")) { if (file.isFile() && file.getName().endsWith(".kts")) {
keys.add(file.getName().replaceAll("\\Q.js\\E", "")); keys.add(file.getName().replaceAll("\\Q.kts\\E", ""));
} else if (file.isDirectory()) { } else if (file.isDirectory()) {
keys.addAll(getKeysInDirectory(file)); keys.addAll(getKeysInDirectory(file));
} }
@@ -127,12 +127,12 @@ public class ScriptResourceLoader extends ResourceLoader<IrisScript> {
public File findFile(String name) { public File findFile(String name) {
for (File i : getFolders(name)) { for (File i : getFolders(name)) {
for (File j : i.listFiles()) { for (File j : i.listFiles()) {
if (j.isFile() && j.getName().endsWith(".js") && j.getName().split("\\Q.\\E")[0].equals(name)) { if (j.isFile() && j.getName().endsWith(".kts") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return j; return j;
} }
} }
File file = new File(i, name + ".js"); File file = new File(i, name + ".kts");
if (file.exists()) { if (file.exists()) {
return file; return file;
@@ -147,12 +147,12 @@ public class ScriptResourceLoader extends ResourceLoader<IrisScript> {
private IrisScript loadRaw(String name) { private IrisScript loadRaw(String name) {
for (File i : getFolders(name)) { for (File i : getFolders(name)) {
for (File j : i.listFiles()) { for (File j : i.listFiles()) {
if (j.isFile() && j.getName().endsWith(".js") && j.getName().split("\\Q.\\E")[0].equals(name)) { if (j.isFile() && j.getName().endsWith(".kts") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return loadFile(j, name); return loadFile(j, name);
} }
} }
File file = new File(i, name + ".js"); File file = new File(i, name + ".kts");
if (file.exists()) { if (file.exists()) {
return loadFile(file, name); return loadFile(file, name);
@@ -18,7 +18,12 @@
package com.volmit.iris.core.nms; 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.nms.container.BiomeColor; import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.nms.container.StructurePlacement;
import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.engine.platform.PlatformChunkGenerator;
@@ -36,9 +41,9 @@ import org.bukkit.entity.EntityType;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.awt.Color; import java.awt.Color;
import java.util.List;
public interface INMSBinding { public interface INMSBinding {
boolean hasTile(Material material); boolean hasTile(Material material);
@@ -133,4 +138,10 @@ public interface INMSBinding {
default boolean injectBukkit() { default boolean injectBukkit() {
return true; return true;
} }
KMap<Material, List<BlockProperty>> getBlockProperties();
void placeStructures(Chunk chunk);
KMap<Identifier, StructurePlacement> collectStructures();
} }
@@ -0,0 +1,154 @@
package com.volmit.iris.core.nms.container;
import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.function.Function;
public class BlockProperty {
private static final Set<Class<?>> NATIVES = Set.of(Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Boolean.class, String.class);
private final String name;
private final Class<?> type;
private final Object defaultValue;
private final Set<Object> values;
private final Function<Object, String> nameFunction;
private final Function<Object, Object> jsonFunction;
public <T extends Comparable<T>> BlockProperty(
String name,
Class<T> type,
T defaultValue,
Collection<T> values,
Function<T, String> nameFunction
) {
this.name = name;
this.type = type;
this.defaultValue = defaultValue;
this.values = Collections.unmodifiableSet(new TreeSet<>(values));
this.nameFunction = (Function<Object, String>) (Object) nameFunction;
jsonFunction = NATIVES.contains(type) ? Function.identity() : this.nameFunction::apply;
}
public static <T extends Enum<T>> BlockProperty ofEnum(Class<T> type, String name, T defaultValue) {
return new BlockProperty(
name,
type,
defaultValue,
Arrays.asList(type.getEnumConstants()),
val -> val == null ? "null" : val.name()
);
}
public static BlockProperty ofFloat(String name, float defaultValue, float min, float max, boolean exclusiveMin, boolean exclusiveMax) {
return new BoundedDouble(
name,
defaultValue,
min,
max,
exclusiveMin,
exclusiveMax,
(f) -> String.format("%.2f", f)
);
}
public static BlockProperty ofBoolean(String name, boolean defaultValue) {
return new BlockProperty(
name,
Boolean.class,
defaultValue,
List.of(true, false),
(b) -> b ? "true" : "false"
);
}
@Override
public @NotNull String toString() {
return name + "=" + nameFunction.apply(defaultValue) + " [" + String.join(",", names()) + "]";
}
public String name() {
return name;
}
public String defaultValue() {
return nameFunction.apply(defaultValue);
}
public List<String> names() {
return values.stream().map(nameFunction).toList();
}
public Object defaultValueAsJson() {
return jsonFunction.apply(defaultValue);
}
public JSONArray valuesAsJson() {
return new JSONArray(values.stream().map(jsonFunction).toList());
}
public JSONObject buildJson() {
var json = new JSONObject();
json.put("type", jsonType());
json.put("default", defaultValueAsJson());
if (!values.isEmpty()) json.put("enum", valuesAsJson());
return json;
}
public String jsonType() {
if (type == Boolean.class)
return "boolean";
if (type == Byte.class || type == Short.class || type == Integer.class || type == Long.class)
return "integer";
if (type == Float.class || type == Double.class)
return "number";
return "string";
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (BlockProperty) obj;
return Objects.equals(this.name, that.name) &&
Objects.equals(this.values, that.values) &&
Objects.equals(this.type, that.type);
}
@Override
public int hashCode() {
return Objects.hash(name, values, type);
}
private static class BoundedDouble extends BlockProperty {
private final double min, max;
private final boolean exclusiveMin, exclusiveMax;
public BoundedDouble(
String name,
double defaultValue,
double min,
double max,
boolean exclusiveMin,
boolean exclusiveMax,
Function<Double, String> nameFunction
) {
super(name, Double.class, defaultValue, List.of(), nameFunction);
this.min = min;
this.max = max;
this.exclusiveMin = exclusiveMin;
this.exclusiveMax = exclusiveMax;
}
@Override
public JSONObject buildJson() {
return super.buildJson()
.put("minimum", min)
.put("maximum", max)
.put("exclusiveMinimum", exclusiveMin)
.put("exclusiveMaximum", exclusiveMax);
}
}
}
@@ -0,0 +1,77 @@
package com.volmit.iris.core.nms.container;
import com.google.gson.JsonObject;
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement.SpreadType;
import lombok.*;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import org.apache.commons.math3.fraction.Fraction;
import java.util.List;
@Data
@SuperBuilder
@Accessors(fluent = true, chain = true)
public abstract class StructurePlacement {
private final int salt;
private final float frequency;
private final List<Structure> structures;
public abstract JsonObject toJson(String structure);
protected JsonObject createBase(String structure) {
JsonObject object = new JsonObject();
object.addProperty("structure", structure);
object.addProperty("salt", salt);
return object;
}
public int frequencyToSpacing() {
var frac = new Fraction(Math.max(Math.min(frequency, 1), 0.000000001f));
return (int) Math.round(Math.sqrt((double) frac.getDenominator() / frac.getNumerator()));
}
@Getter
@Accessors(chain = true, fluent = true)
@EqualsAndHashCode(callSuper = true)
@SuperBuilder
public static class RandomSpread extends StructurePlacement {
private final int spacing;
private final int separation;
private final SpreadType spreadType;
@Override
public JsonObject toJson(String structure) {
JsonObject object = createBase(structure);
object.addProperty("spacing", Math.max(spacing, frequencyToSpacing()));
object.addProperty("separation", separation);
object.addProperty("spreadType", spreadType.name());
return object;
}
}
@Getter
@EqualsAndHashCode(callSuper = true)
@SuperBuilder
public static class ConcentricRings extends StructurePlacement {
private final int distance;
private final int spread;
private final int count;
@Override
public JsonObject toJson(String structure) {
return null;
}
}
public record Structure(
int weight,
String key,
List<String> tags
) {
public boolean isValid() {
return weight > 0 && key != null;
}
}
}
@@ -19,9 +19,13 @@
package com.volmit.iris.core.nms.v1X; package com.volmit.iris.core.nms.v1X;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.core.nms.INMSBinding;
import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.nms.container.StructurePlacement;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
@@ -40,6 +44,7 @@ import org.bukkit.generator.structure.Structure;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.awt.Color; import java.awt.Color;
import java.util.List;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
public class NMSBinding1X implements INMSBinding { public class NMSBinding1X implements INMSBinding {
@@ -124,6 +129,25 @@ public class NMSBinding1X implements INMSBinding {
return false; return false;
} }
@Override
public KMap<Material, List<BlockProperty>> getBlockProperties() {
KMap<Material, List<BlockProperty>> map = new KMap<>();
for (Material m : Material.values()) {
if (m.isBlock()) map.put(m, List.of());
}
return map;
}
@Override
public void placeStructures(Chunk chunk) {
}
@Override
public KMap<Identifier, StructurePlacement> collectStructures() {
return new KMap<>();
}
@Override @Override
public CompoundTag serializeEntity(Entity location) { public CompoundTag serializeEntity(Entity location) {
return null; return null;
@@ -8,7 +8,7 @@ import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.math.RollingSequence;
@@ -3,7 +3,9 @@ package com.volmit.iris.core.pregenerator.cache;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache; import com.github.benmanes.caffeine.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.RemovalCause; import com.github.benmanes.caffeine.cache.RemovalCause;
import com.github.benmanes.caffeine.cache.Scheduler;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.util.data.KCache;
import com.volmit.iris.util.data.Varint; import com.volmit.iris.util.data.Varint;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.documentation.RegionCoordinates; import com.volmit.iris.util.documentation.RegionCoordinates;
@@ -14,12 +16,10 @@ import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream; import net.jpountz.lz4.LZ4BlockOutputStream;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import java.io.*; import java.io.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Predicate; import java.util.function.Predicate;
@NotThreadSafe
@RequiredArgsConstructor @RequiredArgsConstructor
class PregenCacheImpl implements PregenCache { class PregenCacheImpl implements PregenCache {
private static final int SIZE = 32; private static final int SIZE = 32;
@@ -27,6 +27,8 @@ class PregenCacheImpl implements PregenCache {
private final HyperLock hyperLock = new HyperLock(SIZE * 2, true); private final HyperLock hyperLock = new HyperLock(SIZE * 2, true);
private final LoadingCache<Pos, Plate> cache = Caffeine.newBuilder() private final LoadingCache<Pos, Plate> cache = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS) .expireAfterAccess(10, TimeUnit.SECONDS)
.executor(KCache.EXECUTOR)
.scheduler(Scheduler.systemScheduler())
.maximumSize(SIZE) .maximumSize(SIZE)
.removalListener(this::onRemoval) .removalListener(this::onRemoval)
.evictionListener(this::onRemoval) .evictionListener(this::onRemoval)
@@ -192,7 +192,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
private class ServiceExecutor implements Executor { private class ServiceExecutor implements Executor {
private final ExecutorService service = IrisSettings.get().getPregen().isUseVirtualThreads() ? private final ExecutorService service = IrisSettings.get().getPregen().isUseVirtualThreads() ?
Executors.newVirtualThreadPerTaskExecutor() : Executors.newVirtualThreadPerTaskExecutor() :
new MultiBurst("Iris Async Pregen", Thread.MIN_PRIORITY); new MultiBurst("Iris Async Pregen");
public void generate(int x, int z, PregenListener listener) { public void generate(int x, int z, PregenListener listener) {
service.submit(() -> { service.submit(() -> {
@@ -0,0 +1,104 @@
package com.volmit.iris.core.project;
import com.volmit.iris.Iris;
import com.volmit.iris.util.io.IO;
import org.zeroturnaround.zip.ZipUtil;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Optional;
import java.util.Scanner;
public class Gradle {
private static final boolean WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
private static final String[] ENVIRONMENT = createEnvironment();
private static final String VERSION = "8.14.2";
private static final String DISTRIBUTION_URL = "https://services.gradle.org/distributions/gradle-" + VERSION + "-bin.zip";
private static final String HASH = IO.hash(DISTRIBUTION_URL);
public static synchronized void wrapper(File projectDir) {
try {
File settings = new File(projectDir, "settings.gradle.kts");
if (!settings.exists()) settings.createNewFile();
runGradle(projectDir, "wrapper");
} catch (Throwable e) {
Iris.error("Failed to install gradle wrapper!");
e.printStackTrace();
Iris.reportError(e);
}
}
public static void runGradle(File projectDir, String... args) throws IOException, InterruptedException {
File gradle = downloadGradle(false);
String[] cmd = new String[args.length + 1];
cmd[0] = gradle.getAbsolutePath();
System.arraycopy(args, 0, cmd, 1, args.length);
var process = Runtime.getRuntime().exec(cmd, ENVIRONMENT, projectDir);
attach(process.getInputStream());
attach(process.getErrorStream());
var code = process.waitFor();
if (code == 0) return;
throw new RuntimeException("Gradle exited with code " + code);
}
private static synchronized File downloadGradle(boolean force) {
var folder = Iris.instance.getDataFolder("cache", HASH.substring(0, 2), HASH);
if (force) {
IO.delete(folder);
folder.mkdirs();
}
var bin = new File(folder, "gradle-" + VERSION + "/bin/gradle" + (WINDOWS ? ".bat" : ""));
if (bin.exists()) {
bin.setExecutable(true);
return bin;
}
try (var input = new BufferedInputStream(URI.create(DISTRIBUTION_URL).toURL().openStream())) {
ZipUtil.unpack(input, folder);
} catch (Throwable e) {
throw new RuntimeException("Failed to download gradle", e);
}
bin.setExecutable(true);
return bin;
}
private static String[] createEnvironment() {
var env = new HashMap<>(System.getenv());
env.put("JAVA_HOME", findJavaHome());
return env.entrySet()
.stream()
.map(e -> e.getKey() + "=" + e.getValue())
.toArray(String[]::new);
}
private static String findJavaHome() {
String javaHome = System.getProperty("java.home");
if (javaHome != null && new File(javaHome + "/bin/java" + (WINDOWS ? ".exe" : "")).exists()) {
return javaHome;
}
return ProcessHandle.current()
.info()
.command()
.map(s -> new File(s).getAbsoluteFile().getParentFile().getParentFile())
.flatMap(f -> f.exists() ? Optional.of(f.getAbsolutePath()) : Optional.empty())
.orElseThrow(() -> new RuntimeException("Failed to find java home, please set java.home system property"));
}
private static void attach(InputStream stream) {
Thread.ofVirtual().start(() -> {
try (var in = new Scanner(stream)) {
while (in.hasNextLine()) {
String line = in.nextLine();
Iris.debug("[GRADLE] " + line);
}
}
});
}
}
@@ -24,6 +24,7 @@ import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.loader.ResourceLoader; 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.core.tools.IrisToolbelt;
import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.object.annotations.Snippet; import com.volmit.iris.engine.object.annotations.Snippet;
@@ -49,6 +50,8 @@ import lombok.Data;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.World; import org.bukkit.World;
import org.dom4j.Document;
import org.dom4j.Element;
import org.zeroturnaround.zip.ZipUtil; import org.zeroturnaround.zip.ZipUtil;
import java.awt.*; import java.awt.*;
@@ -156,7 +159,7 @@ public class IrisProject {
public void openVSCode(VolmitSender sender) { public void openVSCode(VolmitSender sender) {
IrisDimension d = IrisData.loadAnyDimension(getName()); IrisDimension d = IrisData.loadAnyDimension(getName(), null);
J.attemptAsync(() -> J.attemptAsync(() ->
{ {
try { try {
@@ -217,24 +220,15 @@ public class IrisProject {
close(); close();
} }
boolean hasError = false;
if (hasError) {
return;
}
IrisDimension d = IrisData.loadAnyDimension(getName());
if (d == null) {
sender.sendMessage("Can't find dimension: " + getName());
return;
} else if (sender.isPlayer()) {
sender.player().setGameMode(GameMode.SPECTATOR);
}
openVSCode(sender);
J.a(() -> { J.a(() -> {
IrisDimension d = IrisData.loadAnyDimension(getName(), null);
if (d == null) {
sender.sendMessage("Can't find dimension: " + getName());
return;
} else if (sender.isPlayer()) {
sender.player().setGameMode(GameMode.SPECTATOR);
}
try { try {
activeProvider = (PlatformChunkGenerator) IrisToolbelt.createWorld() activeProvider = (PlatformChunkGenerator) IrisToolbelt.createWorld()
.seed(seed) .seed(seed)
@@ -247,6 +241,8 @@ public class IrisProject {
} catch (IrisException e) { } catch (IrisException e) {
e.printStackTrace(); e.printStackTrace();
} }
openVSCode(sender);
}); });
} }
@@ -359,6 +355,74 @@ public class IrisProject {
settings.put("json.schemas", schemas); settings.put("json.schemas", schemas);
ws.put("settings", settings); ws.put("settings", settings);
dm.getEnvironment().configureProject();
File schemasFile = new File(path, ".idea" + File.separator + "jsonSchemas.xml");
Document doc = IO.read(schemasFile);
Element mappings = (Element) doc.selectSingleNode("//component[@name='JsonSchemaMappingsProjectConfiguration']");
if (mappings == null) {
mappings = doc.getRootElement()
.addElement("component")
.addAttribute("name", "JsonSchemaMappingsProjectConfiguration");
}
Element state = (Element) mappings.selectSingleNode("state");
if (state == null) state = mappings.addElement("state");
Element map = (Element) state.selectSingleNode("map");
if (map == null) map = state.addElement("map");
var schemaMap = new KMap<String, String>();
schemas.forEach(element -> {
if (!(element instanceof JSONObject obj))
return;
String url = obj.getString("url");
String dir = obj.getJSONArray("fileMatch").getString(0);
schemaMap.put(url, dir.substring(1, dir.indexOf("/*")));
});
map.selectNodes("entry/value/SchemaInfo/option[@name='relativePathToSchema']")
.stream()
.map(node -> node.valueOf("@value"))
.forEach(schemaMap::remove);
var ideaSchemas = map;
schemaMap.forEach((url, dir) -> {
var genName = UUID.randomUUID().toString();
var info = ideaSchemas.addElement("entry")
.addAttribute("key", genName)
.addElement("value")
.addElement("SchemaInfo");
info.addElement("option")
.addAttribute("name", "generatedName")
.addAttribute("value", genName);
info.addElement("option")
.addAttribute("name", "name")
.addAttribute("value", dir);
info.addElement("option")
.addAttribute("name", "relativePathToSchema")
.addAttribute("value", url);
var item = info.addElement("option")
.addAttribute("name", "patterns")
.addElement("list")
.addElement("Item");
item.addElement("option")
.addAttribute("name", "directory")
.addAttribute("value", "true");
item.addElement("option")
.addAttribute("name", "path")
.addAttribute("value", dir);
item.addElement("option")
.addAttribute("name", "mappingKind")
.addAttribute("value", "Directory");
});
if (!schemaMap.isEmpty()) {
IO.write(schemasFile, doc);
}
Gradle.wrapper(path);
return ws; return ws;
} }
@@ -110,9 +110,12 @@ public class SchemaBuilder {
private JSONObject buildProperties(Class<?> c) { private JSONObject buildProperties(Class<?> c) {
JSONObject o = new JSONObject(); JSONObject o = new JSONObject();
JSONObject properties = new JSONObject(); JSONObject properties = new JSONObject();
o.put("description", getDescription(c)); String desc = getDescription(c);
o.put("description", desc);
o.put("x-intellij-html-description", desc.replace("\n", "<br>"));
o.put("type", getType(c)); o.put("type", getType(c));
JSONArray required = new JSONArray(); JSONArray required = new JSONArray();
JSONArray extended = new JSONArray();
if (c.isAssignableFrom(IrisRegistrant.class) || IrisRegistrant.class.isAssignableFrom(c)) { if (c.isAssignableFrom(IrisRegistrant.class) || IrisRegistrant.class.isAssignableFrom(c)) {
for (Field k : IrisRegistrant.class.getDeclaredFields()) { for (Field k : IrisRegistrant.class.getDeclaredFields()) {
@@ -124,11 +127,15 @@ public class SchemaBuilder {
JSONObject property = buildProperty(k, c); JSONObject property = buildProperty(k, c);
if (property.getBoolean("!required")) { if (Boolean.TRUE == property.remove("!required")) {
required.put(k.getName()); required.put(k.getName());
} }
property.remove("!required"); if (Boolean.TRUE == property.remove("!top")) {
extended.put(property);
continue;
}
properties.put(k.getName(), property); properties.put(k.getName(), property);
} }
} }
@@ -142,15 +149,24 @@ public class SchemaBuilder {
JSONObject property = buildProperty(k, c); JSONObject property = buildProperty(k, c);
if (property.getBoolean("!required")) if (Boolean.TRUE == property.remove("!required")) {
required.put(k.getName()); required.put(k.getName());
property.remove("!required"); }
if (Boolean.TRUE == property.remove("!top")) {
extended.put(property);
continue;
}
properties.put(k.getName(), property); properties.put(k.getName(), property);
} }
if (required.length() > 0) { if (required.length() > 0) {
o.put("required", required); o.put("required", required);
} }
if (extended.length() > 0) {
o.put("allOf", extended);
}
o.put("properties", properties); o.put("properties", properties);
@@ -343,13 +359,63 @@ public class SchemaBuilder {
} }
} }
case "object" -> { case "object" -> {
fancyType = k.getType().getSimpleName().replaceAll("\\QIris\\E", "") + " (Object)"; //TODO add back descriptions
String key = "obj-" + k.getType().getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase(); if (k.isAnnotationPresent(RegistryMapBlockState.class)) {
if (!definitions.containsKey(key)) { String blockType = k.getDeclaredAnnotation(RegistryMapBlockState.class).value();
definitions.put(key, new JSONObject()); fancyType = "Block State";
definitions.put(key, buildProperties(k.getType())); prop.put("!top", true);
JSONArray any = new JSONArray();
prop.put("anyOf", any);
B.getBlockStates().forEach((blocks, properties) -> {
if (blocks.isEmpty()) return;
String raw = blocks.getFirst().replace(':', '_');
String enumKey = "enum-block-state-" + raw;
String propertiesKey = "obj-block-state-" + raw;
any.put(new JSONObject()
.put("if", new JSONObject()
.put("properties", new JSONObject()
.put(blockType, new JSONObject()
.put("type", "string")
.put("$ref", "#/definitions/" + enumKey))))
.put("then", new JSONObject()
.put("properties", new JSONObject()
.put(k.getName(), new JSONObject()
.put("type", "object")
.put("$ref", "#/definitions/" + propertiesKey))))
.put("else", false));
if (!definitions.containsKey(enumKey)) {
JSONArray filters = new JSONArray();
blocks.forEach(filters::put);
definitions.put(enumKey, new JSONObject()
.put("type", "string")
.put("enum", filters));
}
if (!definitions.containsKey(propertiesKey)) {
JSONObject props = new JSONObject();
properties.forEach(property -> {
props.put(property.name(), property.buildJson());
});
definitions.put(propertiesKey, new JSONObject()
.put("type", "object")
.put("properties", props));
}
});
} else {
fancyType = k.getType().getSimpleName().replaceAll("\\QIris\\E", "") + " (Object)";
String key = "obj-" + k.getType().getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase();
if (!definitions.containsKey(key)) {
definitions.put(key, new JSONObject());
definitions.put(key, buildProperties(k.getType()));
}
prop.put("$ref", "#/definitions/" + key);
} }
prop.put("$ref", "#/definitions/" + key);
} }
case "array" -> { case "array" -> {
fancyType = "List of Something...?"; fancyType = "List of Something...?";
@@ -520,11 +586,12 @@ public class SchemaBuilder {
} }
KList<String> d = new KList<>(); KList<String> d = new KList<>();
d.add(k.getName()); d.add("<h>" + k.getName() + "</h>");
d.add(getFieldDescription(k)); d.add(getFieldDescription(k) + "<hr></hr>");
d.add(" "); d.add("<h>" + fancyType + "</h>");
d.add(fancyType); String typeDesc = getDescription(k.getType());
d.add(getDescription(k.getType())); boolean present = !typeDesc.isBlank();
if (present) d.add(typeDesc);
Snippet snippet = k.getType().getDeclaredAnnotation(Snippet.class); Snippet snippet = k.getType().getDeclaredAnnotation(Snippet.class);
if (snippet == null) { if (snippet == null) {
@@ -536,8 +603,9 @@ public class SchemaBuilder {
if (snippet != null) { if (snippet != null) {
String sm = snippet.value(); String sm = snippet.value();
d.add(" "); if (present) d.add(" ");
d.add("You can instead specify \"snippet/" + sm + "/some-name.json\" to use a snippet file instead of specifying it here."); d.add("You can instead specify \"snippet/" + sm + "/some-name.json\" to use a snippet file instead of specifying it here.");
present = false;
} }
try { try {
@@ -545,15 +613,13 @@ public class SchemaBuilder {
Object value = k.get(cl.newInstance()); Object value = k.get(cl.newInstance());
if (value != null) { if (value != null) {
if (present) d.add(" ");
if (value instanceof List) { if (value instanceof List) {
d.add(" "); d.add(SYMBOL_LIMIT__N + " Default Value is an empty list");
d.add("* Default Value is an empty list");
} else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum()) && !KeyedType.isKeyed(cl)) { } else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum()) && !KeyedType.isKeyed(cl)) {
d.add(" "); d.add(SYMBOL_LIMIT__N + " Default Value is a default object (create this object to see default properties)");
d.add("* Default Value is a default object (create this object to see default properties)");
} else { } else {
d.add(" "); d.add(SYMBOL_LIMIT__N + " Default Value is " + value);
d.add("* Default Value is " + value);
} }
} }
} catch (Throwable ignored) { } catch (Throwable ignored) {
@@ -561,8 +627,14 @@ public class SchemaBuilder {
} }
description.forEach((g) -> d.add(g.trim())); description.forEach((g) -> d.add(g.trim()));
String desc = d.toString("\n")
.replace("<hr></hr>", "\n")
.replace("<h>", "")
.replace("</h>", "");
String hDesc = d.toString("<br>");
prop.put("type", type); prop.put("type", type);
prop.put("description", d.toString("\n")); prop.put("description", desc);
prop.put("x-intellij-html-description", hDesc);
return buildSnippet(prop, k.getType()); return buildSnippet(prop, k.getType());
} }
@@ -588,8 +660,10 @@ public class SchemaBuilder {
arr.put(prop); arr.put(prop);
arr.put(str); arr.put(str);
str.put("description", prop.getString("description")); str.put("description", prop.getString("description"));
str.put("x-intellij-html-description", prop.getString("x-intellij-html-description"));
anyOf.put("anyOf", arr); anyOf.put("anyOf", arr);
anyOf.put("description", prop.getString("description")); anyOf.put("description", prop.getString("description"));
anyOf.put("x-intellij-html-description", prop.getString("x-intellij-html-description"));
anyOf.put("!required", type.isAnnotationPresent(Required.class)); anyOf.put("!required", type.isAnnotationPresent(Required.class));
return anyOf; return anyOf;
@@ -615,7 +689,9 @@ public class SchemaBuilder {
String name = function.apply(gg); String name = function.apply(gg);
j.put("const", name); j.put("const", name);
Desc dd = type.getField(name).getAnnotation(Desc.class); Desc dd = type.getField(name).getAnnotation(Desc.class);
j.put("description", dd == null ? ("No Description for " + name) : dd.value()); String desc = dd == null ? ("No Description for " + name) : dd.value();
j.put("description", desc);
j.put("x-intellij-html-description", desc.replace("\n", "<br>"));
a.put(j); a.put(j);
} catch (Throwable e) { } catch (Throwable e) {
Iris.reportError(e); Iris.reportError(e);
@@ -0,0 +1,30 @@
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;
public interface EngineEnvironment extends PackEnvironment {
static EngineEnvironment create(@NonNull Engine engine) {
return new IrisExecutionEnvironment(engine);
}
@NonNull
Engine getEngine();
@Nullable
Object spawnMob(@NonNull String script, @NonNull Location location);
void postSpawnMob(@NonNull String script, @NonNull Location location, @NonNull Entity mob);
void preprocessObject(@NonNull String script, @NonNull IrisRegistrant object);
void updateChunk(@NonNull String script, @NonNull MantleChunk mantleChunk, @NonNull Chunk chunk, @NonNull UpdateExecutor executor);
}
@@ -0,0 +1,19 @@
package com.volmit.iris.core.scripting.environment;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.scripting.kotlin.environment.IrisPackExecutionEnvironment;
import com.volmit.iris.util.math.RNG;
import lombok.NonNull;
import org.jetbrains.annotations.Nullable;
public interface PackEnvironment extends SimpleEnvironment {
static PackEnvironment create(@NonNull IrisData data) {
return new IrisPackExecutionEnvironment(data);
}
@NonNull
IrisData getData();
@Nullable
Object createNoise(@NonNull String script, @NonNull RNG rng);
}
@@ -0,0 +1,34 @@
package com.volmit.iris.core.scripting.environment;
import com.volmit.iris.core.scripting.kotlin.environment.IrisSimpleExecutionEnvironment;
import lombok.NonNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Map;
public interface SimpleEnvironment {
static SimpleEnvironment create() {
return new IrisSimpleExecutionEnvironment();
}
static SimpleEnvironment create(@NonNull File projectDir) {
return new IrisSimpleExecutionEnvironment(projectDir);
}
void configureProject();
void execute(@NonNull String script);
void execute(@NonNull String script, @NonNull Class<?> type, @Nullable Map<@NonNull String, Object> vars);
@Nullable
Object evaluate(@NonNull String script);
@Nullable
Object evaluate(@NonNull String script, @NonNull Class<?> type, @Nullable Map<@NonNull String, Object> vars);
default void close() {
}
}
@@ -0,0 +1,10 @@
package com.volmit.iris.core.scripting.func;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.documentation.BlockCoordinates;
@FunctionalInterface
public interface BiomeLookup {
@BlockCoordinates
IrisBiome at(int x, int z);
}
@@ -0,0 +1,22 @@
package com.volmit.iris.core.scripting.func;
import org.jetbrains.annotations.NotNull;
@FunctionalInterface
public interface UpdateExecutor {
@NotNull Runnable wrap(int delay, @NotNull Runnable runnable);
@NotNull
default Runnable wrap(@NotNull Runnable runnable) {
return wrap(1, runnable);
}
default void execute(@NotNull Runnable runnable) {
execute(1, runnable);
}
default void execute(int delay, @NotNull Runnable runnable) {
wrap(delay, runnable).run();
}
}
@@ -22,33 +22,39 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.board.BoardManager; import com.volmit.iris.util.board.BoardManager;
import com.volmit.iris.util.board.BoardProvider; import com.volmit.iris.util.board.BoardProvider;
import com.volmit.iris.util.board.BoardSettings; import com.volmit.iris.util.board.BoardSettings;
import com.volmit.iris.util.board.ScoreDirection; import com.volmit.iris.util.board.ScoreDirection;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.plugin.IrisService; import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
import lombok.Data; import lombok.Data;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class BoardSVC implements IrisService, BoardProvider { public class BoardSVC implements IrisService, BoardProvider {
private final KMap<Player, PlayerBoard> boards = new KMap<>(); private final KMap<Player, PlayerBoard> boards = new KMap<>();
private com.volmit.iris.util.board.BoardManager manager; private ScheduledExecutorService executor;
private BoardManager manager;
@Override @Override
public void onEnable() { public void onEnable() {
J.ar(this::tick, 20); executor = Executors.newScheduledThreadPool(0, Thread.ofVirtual().factory());
manager = new BoardManager(Iris.instance, BoardSettings.builder() manager = new BoardManager(Iris.instance, BoardSettings.builder()
.boardProvider(this) .boardProvider(this)
.scoreDirection(ScoreDirection.DOWN) .scoreDirection(ScoreDirection.DOWN)
@@ -57,6 +63,7 @@ public class BoardSVC implements IrisService, BoardProvider {
@Override @Override
public void onDisable() { public void onDisable() {
executor.shutdownNow();
manager.onDisable(); manager.onDisable();
boards.clear(); boards.clear();
} }
@@ -71,14 +78,22 @@ public class BoardSVC implements IrisService, BoardProvider {
J.s(() -> updatePlayer(e.getPlayer())); J.s(() -> updatePlayer(e.getPlayer()));
} }
@EventHandler
public void on(PlayerQuitEvent e) {
remove(e.getPlayer());
}
public void updatePlayer(Player p) { public void updatePlayer(Player p) {
if (IrisToolbelt.isIrisStudioWorld(p.getWorld())) { if (IrisToolbelt.isIrisStudioWorld(p.getWorld())) {
manager.remove(p); manager.remove(p);
manager.setup(p); manager.setup(p);
} else { } else remove(p);
manager.remove(p); }
boards.remove(p);
} private void remove(Player player) {
manager.remove(player);
var board = boards.remove(player);
if (board != null) board.task.cancel(true);
} }
@Override @Override
@@ -86,73 +101,63 @@ public class BoardSVC implements IrisService, BoardProvider {
return C.GREEN + "Iris"; return C.GREEN + "Iris";
} }
public void tick() {
if (!Iris.service(StudioSVC.class).isProjectOpen()) {
return;
}
boards.forEach((k, v) -> v.update());
}
@Override @Override
public List<String> getLines(Player player) { public List<String> getLines(Player player) {
PlayerBoard pb = boards.computeIfAbsent(player, PlayerBoard::new); return boards.computeIfAbsent(player, PlayerBoard::new).lines;
synchronized (pb.lines) {
return pb.lines;
}
} }
@Data @Data
public static class PlayerBoard { public class PlayerBoard {
private final Player player; private final Player player;
private final CopyOnWriteArrayList<String> lines; private final ScheduledFuture<?> task;
private volatile List<String> lines;
public PlayerBoard(Player player) { public PlayerBoard(Player player) {
this.player = player; this.player = player;
this.lines = new CopyOnWriteArrayList<>(); this.lines = new ArrayList<>();
this.task = executor.scheduleAtFixedRate(this::tick, 0, 1, TimeUnit.SECONDS);
}
private void tick() {
if (!Iris.service(StudioSVC.class).isProjectOpen()) {
return;
}
update(); update();
} }
public void update() { public void update() {
synchronized (lines) { final World world = player.getWorld();
lines.clear(); final Location loc = player.getLocation();
if (!IrisToolbelt.isIrisStudioWorld(player.getWorld())) { final var access = IrisToolbelt.access(world);
return; if (access == null) return;
}
Engine engine = IrisToolbelt.access(player.getWorld()).getEngine(); final var engine = access.getEngine();
int x = player.getLocation().getBlockX(); if (engine == null) return;
int y = player.getLocation().getBlockY() - player.getWorld().getMinHeight();
int z = player.getLocation().getBlockZ();
if(IrisSettings.get().getGeneral().debug){ int x = loc.getBlockX();
lines.add("&7&m "); int y = loc.getBlockY() - world.getMinHeight();
lines.add(C.GREEN + "Speed" + C.GRAY + ": " + Form.f(engine.getGeneratedPerSecond(), 0) + "/s " + Form.duration(1000D / engine.getGeneratedPerSecond(), 0)); int z = loc.getBlockZ();
lines.add(C.AQUA + "Cache" + C.GRAY + ": " + Form.f(IrisData.cacheSize()));
lines.add(C.AQUA + "Mantle" + C.GRAY + ": " + engine.getMantle().getLoadedRegionCount()); List<String> lines = new ArrayList<>(this.lines.size());
lines.add(C.LIGHT_PURPLE + "Carving" + C.GRAY + ": " + engine.getMantle().isCarved(x,y,z)); lines.add("&7&m ");
lines.add("&7&m "); lines.add(C.GREEN + "Speed" + C.GRAY + ": " + Form.f(engine.getGeneratedPerSecond(), 0) + "/s " + Form.duration(1000D / engine.getGeneratedPerSecond(), 0));
lines.add(C.AQUA + "Region" + C.GRAY + ": " + engine.getRegion(x, z).getName()); lines.add(C.AQUA + "Cache" + C.GRAY + ": " + Form.f(IrisData.cacheSize()));
lines.add(C.AQUA + "Biome" + C.GRAY + ": " + engine.getBiomeOrMantle(x, y, z).getName()); lines.add(C.AQUA + "Mantle" + C.GRAY + ": " + engine.getMantle().getLoadedRegionCount());
lines.add(C.AQUA + "Height" + C.GRAY + ": " + Math.round(engine.getHeight(x, z)));
lines.add(C.AQUA + "Slope" + C.GRAY + ": " + Form.f(engine.getComplex().getSlopeStream().get(x, z), 2)); if (IrisSettings.get().getGeneral().debug) {
lines.add(C.AQUA + "BUD/s" + C.GRAY + ": " + Form.f(engine.getBlockUpdatesPerSecond())); lines.add(C.LIGHT_PURPLE + "Carving" + C.GRAY + ": " + engine.getMantle().isCarved(x,y,z));
lines.add("&7&m ");
} else {
lines.add("&7&m ");
lines.add(C.GREEN + "Speed" + C.GRAY + ": " + Form.f(engine.getGeneratedPerSecond(), 0) + "/s " + Form.duration(1000D / engine.getGeneratedPerSecond(), 0));
lines.add(C.AQUA + "Cache" + C.GRAY + ": " + Form.f(IrisData.cacheSize()));
lines.add(C.AQUA + "Mantle" + C.GRAY + ": " + engine.getMantle().getLoadedRegionCount());
lines.add("&7&m ");
lines.add(C.AQUA + "Region" + C.GRAY + ": " + engine.getRegion(x, z).getName());
lines.add(C.AQUA + "Biome" + C.GRAY + ": " + engine.getBiomeOrMantle(x, y, z).getName());
lines.add(C.AQUA + "Height" + C.GRAY + ": " + Math.round(engine.getHeight(x, z)));
lines.add(C.AQUA + "Slope" + C.GRAY + ": " + Form.f(engine.getComplex().getSlopeStream().get(x, z), 2));
lines.add(C.AQUA + "BUD/s" + C.GRAY + ": " + Form.f(engine.getBlockUpdatesPerSecond()));
lines.add("&7&m ");
}
} }
lines.add("&7&m ");
lines.add(C.AQUA + "Region" + C.GRAY + ": " + engine.getRegion(x, z).getName());
lines.add(C.AQUA + "Biome" + C.GRAY + ": " + engine.getBiomeOrMantle(x, y, z).getName());
lines.add(C.AQUA + "Height" + C.GRAY + ": " + Math.round(engine.getHeight(x, z)));
lines.add(C.AQUA + "Slope" + C.GRAY + ": " + Form.f(engine.getComplex().getSlopeStream().get(x, z), 2));
lines.add(C.AQUA + "BUD/s" + C.GRAY + ": " + Form.f(engine.getBlockUpdatesPerSecond()));
lines.add("&7&m ");
this.lines = lines;
} }
} }
} }
@@ -23,6 +23,7 @@ import com.volmit.iris.core.commands.CommandIris;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeContext;
import com.volmit.iris.util.decree.DecreeSystem; import com.volmit.iris.util.decree.DecreeSystem;
import com.volmit.iris.util.decree.virtual.VirtualDecreeCommand; import com.volmit.iris.util.decree.virtual.VirtualDecreeCommand;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
@@ -44,7 +45,14 @@ public class CommandSVC implements IrisService, DecreeSystem {
@Override @Override
public void onEnable() { public void onEnable() {
Iris.instance.getCommand("iris").setExecutor(this); Iris.instance.getCommand("iris").setExecutor(this);
J.a(() -> getRoot().cacheAll()); J.a(() -> {
DecreeContext.touch(Iris.getSender());
try {
getRoot().cacheAll();
} finally {
DecreeContext.remove();
}
});
} }
@Override @Override
@@ -21,6 +21,7 @@ package com.volmit.iris.core.service;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.link.*; import com.volmit.iris.core.link.*;
import com.volmit.iris.core.link.data.DataType; import com.volmit.iris.core.link.data.DataType;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
@@ -107,6 +108,18 @@ public class ExternalDataSVC implements IrisService {
} }
} }
public Optional<List<BlockProperty>> getBlockProperties(final Identifier key) {
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(key, DataType.BLOCK)).findFirst();
if (provider.isEmpty())
return Optional.empty();
try {
return Optional.of(provider.get().getBlockProperties(key));
} catch (MissingResourceException e) {
Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]");
return Optional.empty();
}
}
public Optional<ItemStack> getItemStack(Identifier key, KMap<String, Object> customNbt) { public Optional<ItemStack> getItemStack(Identifier key, KMap<String, Object> customNbt) {
Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(key, DataType.ITEM)).findFirst(); Optional<ExternalDataProvider> provider = activeProviders.stream().filter(p -> p.isValidProvider(key, DataType.ITEM)).findFirst();
if (provider.isEmpty()) { if (provider.isEmpty()) {
@@ -150,6 +163,14 @@ public class ExternalDataSVC implements IrisService {
.toList(); .toList();
} }
public Collection<Pair<Identifier, List<BlockProperty>>> getAllBlockProperties() {
return activeProviders.stream()
.flatMap(p -> p.getTypes(DataType.BLOCK)
.stream()
.map(id -> new Pair<>(id, p.getBlockProperties(id))))
.toList();
}
public static Pair<Identifier, KMap<String, String>> parseState(Identifier key) { public static Pair<Identifier, KMap<String, String>> parseState(Identifier key) {
if (!key.key().contains("[") || !key.key().contains("]")) { if (!key.key().contains("[") || !key.key().contains("]")) {
return new Pair<>(key, new KMap<>()); return new Pair<>(key, new KMap<>());
@@ -2,9 +2,11 @@ package com.volmit.iris.core.service;
import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine; 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.IrisSettings;
import com.volmit.iris.core.pregenerator.cache.PregenCache; import com.volmit.iris.core.pregenerator.cache.PregenCache;
import com.volmit.iris.util.collection.KMap; 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.plugin.IrisService;
import lombok.NonNull; import lombok.NonNull;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@@ -20,7 +22,11 @@ import java.io.File;
import java.util.function.Function; import java.util.function.Function;
public class GlobalCacheSVC implements IrisService { public class GlobalCacheSVC implements IrisService {
private static final Cache<String, PregenCache> REFERENCE_CACHE = Caffeine.newBuilder().weakValues().build(); private static final Cache<String, PregenCache> REFERENCE_CACHE = Caffeine.newBuilder()
.executor(KCache.EXECUTOR)
.scheduler(Scheduler.systemScheduler())
.weakValues()
.build();
private final KMap<String, PregenCache> globalCache = new KMap<>(); private final KMap<String, PregenCache> globalCache = new KMap<>();
private transient boolean lastState; private transient boolean lastState;
private static boolean disabled = true; private static boolean disabled = true;
@@ -43,10 +43,6 @@ public class PreservationSVC implements IrisService {
threads.add(t); threads.add(t);
} }
public void register(MultiBurst burst) {
}
public void register(ExecutorService service) { public void register(ExecutorService service) {
services.add(service); services.add(service);
} }
@@ -88,16 +88,18 @@ public class StudioSVC implements IrisService {
} }
public IrisDimension installIntoWorld(VolmitSender sender, String type, File folder) { public IrisDimension installIntoWorld(VolmitSender sender, String type, File folder) {
return installInto(sender, type, new File(folder, "iris/pack"));
}
public IrisDimension installInto(VolmitSender sender, String type, File folder) {
sender.sendMessage("Looking for Package: " + type); sender.sendMessage("Looking for Package: " + type);
File iris = new File(folder, "iris"); IrisDimension dim = IrisData.loadAnyDimension(type, null);
File irispack = new File(folder, "iris/pack");
IrisDimension dim = IrisData.loadAnyDimension(type);
if (dim == null) { if (dim == null) {
for (File i : getWorkspaceFolder().listFiles()) { for (File i : getWorkspaceFolder().listFiles()) {
if (i.isFile() && i.getName().equals(type + ".iris")) { if (i.isFile() && i.getName().equals(type + ".iris")) {
sender.sendMessage("Found " + type + ".iris in " + WORKSPACE_NAME + " folder"); sender.sendMessage("Found " + type + ".iris in " + WORKSPACE_NAME + " folder");
ZipUtil.unpack(i, irispack); ZipUtil.unpack(i, folder);
break; break;
} }
} }
@@ -106,29 +108,29 @@ public class StudioSVC implements IrisService {
File f = new IrisProject(new File(getWorkspaceFolder(), type)).getPath(); File f = new IrisProject(new File(getWorkspaceFolder(), type)).getPath();
try { try {
FileUtils.copyDirectory(f, irispack); FileUtils.copyDirectory(f, folder);
} catch (IOException e) { } catch (IOException e) {
Iris.reportError(e); Iris.reportError(e);
} }
} }
File dimf = new File(irispack, "dimensions/" + type + ".json"); File dimensionFile = new File(folder, "dimensions/" + type + ".json");
if (!dimf.exists() || !dimf.isFile()) { if (!dimensionFile.exists() || !dimensionFile.isFile()) {
downloadSearch(sender, type, false); downloadSearch(sender, type, false);
File downloaded = getWorkspaceFolder(type); File downloaded = getWorkspaceFolder(type);
for (File i : downloaded.listFiles()) { for (File i : downloaded.listFiles()) {
if (i.isFile()) { if (i.isFile()) {
try { try {
FileUtils.copyFile(i, new File(irispack, i.getName())); FileUtils.copyFile(i, new File(folder, i.getName()));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
Iris.reportError(e); Iris.reportError(e);
} }
} else { } else {
try { try {
FileUtils.copyDirectory(i, new File(irispack, i.getName())); FileUtils.copyDirectory(i, new File(folder, i.getName()));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
Iris.reportError(e); Iris.reportError(e);
@@ -139,12 +141,13 @@ public class StudioSVC implements IrisService {
IO.delete(downloaded); IO.delete(downloaded);
} }
if (!dimf.exists() || !dimf.isFile()) { if (!dimensionFile.exists() || !dimensionFile.isFile()) {
sender.sendMessage("Can't find the " + dimf.getName() + " in the dimensions folder of this pack! Failed!"); sender.sendMessage("Can't find the " + dimensionFile.getName() + " in the dimensions folder of this pack! Failed!");
return null; return null;
} }
IrisData dm = IrisData.get(irispack); IrisData dm = IrisData.get(folder);
dm.hotloaded();
dim = dm.getDimensionLoader().load(type); dim = dm.getDimensionLoader().load(type);
if (dim == null) { if (dim == null) {
@@ -261,6 +264,7 @@ public class StudioSVC implements IrisService {
} }
IrisDimension d = data.getDimensionLoader().load(dimensions[0]); IrisDimension d = data.getDimensionLoader().load(dimensions[0]);
data.close();
if (d == null) { if (d == null) {
sender.sendMessage("Invalid dimension (folder) in dimensions folder"); sender.sendMessage("Invalid dimension (folder) in dimensions folder");
@@ -275,7 +279,7 @@ public class StudioSVC implements IrisService {
IO.delete(packEntry); IO.delete(packEntry);
} }
if (IrisData.loadAnyDimension(key) != null) { if (IrisData.loadAnyDimension(key, null) != null) {
sender.sendMessage("Another dimension in the packs folder is already using the key " + key + " IMPORT FAILED!"); sender.sendMessage("Another dimension in the packs folder is already using the key " + key + " IMPORT FAILED!");
return; return;
} }
@@ -294,6 +298,8 @@ public class StudioSVC implements IrisService {
packEntry.mkdirs(); packEntry.mkdirs();
ZipUtil.unpack(cp, packEntry); ZipUtil.unpack(cp, packEntry);
} }
IrisData.getLoaded(packEntry)
.ifPresent(IrisData::hotloaded);
sender.sendMessage("Successfully Aquired " + d.getName()); sender.sendMessage("Successfully Aquired " + d.getName());
ServerConfigurator.installDataPacks(true); ServerConfigurator.installDataPacks(true);
@@ -43,8 +43,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference; import java.util.function.IntSupplier;
import java.util.function.Supplier;
import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML; import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML;
@@ -128,8 +127,6 @@ public class IrisCreator {
Iris.service(StudioSVC.class).installIntoWorld(sender, d.getLoadKey(), new File(Bukkit.getWorldContainer(), name())); Iris.service(StudioSVC.class).installIntoWorld(sender, d.getLoadKey(), new File(Bukkit.getWorldContainer(), name()));
} }
PlatformChunkGenerator access;
AtomicReference<World> world = new AtomicReference<>();
AtomicDouble pp = new AtomicDouble(0); AtomicDouble pp = new AtomicDouble(0);
O<Boolean> done = new O<>(); O<Boolean> done = new O<>();
done.set(false); done.set(false);
@@ -139,30 +136,29 @@ public class IrisCreator {
.seed(seed) .seed(seed)
.studio(studio) .studio(studio)
.create(); .create();
ServerConfigurator.installDataPacks(false); if (ServerConfigurator.installDataPacks(true)) {
throw new IrisException("Datapacks were missing!");
}
access = (PlatformChunkGenerator) wc.generator(); PlatformChunkGenerator access = (PlatformChunkGenerator) wc.generator();
PlatformChunkGenerator finalAccess1 = access; if (access == null) throw new IrisException("Access is null. Something bad happened.");
J.a(() -> J.a(() -> {
{ IntSupplier g = () -> {
Supplier<Integer> g = () -> { if (access.getEngine() == null) {
if (finalAccess1 == null || finalAccess1.getEngine() == null) {
return 0; return 0;
} }
return finalAccess1.getEngine().getGenerated(); return access.getEngine().getGenerated();
}; };
if(!benchmark) { if(!benchmark) {
if (finalAccess1 == null) return; int req = access.getSpawnChunks().join();
int req = finalAccess1.getSpawnChunks().join(); for (int c = 0; c < req && !done.get(); c = g.getAsInt()) {
double v = (double) c / req;
while (g.get() < req) {
double v = (double) g.get() / (double) req;
if (sender.isPlayer()) { if (sender.isPlayer()) {
sender.sendProgress(v, "Generating"); sender.sendProgress(v, "Generating");
J.sleep(16); J.sleep(16);
} else { } else {
sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - g.get()) + " Left)"))); sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - c) + " Left)")));
J.sleep(1000); J.sleep(1000);
} }
} }
@@ -170,39 +166,33 @@ public class IrisCreator {
}); });
World world;
try { try {
J.sfut(() -> { world = J.sfut(() -> INMS.get().createWorld(wc)).get();
world.set(INMS.get().createWorld(wc));
}).get();
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); done.set(true);
} throw new IrisException("Failed to create world!", e);
if (access == null) {
throw new IrisException("Access is null. Something bad happened.");
} }
done.set(true); done.set(true);
if (sender.isPlayer() && !benchmark) { if (sender.isPlayer() && !benchmark) {
J.s(() -> { J.s(() -> sender.player().teleport(new Location(world, 0, world.getHighestBlockYAt(0, 0) + 1, 0)));
sender.player().teleport(new Location(world.get(), 0, world.get().getHighestBlockYAt(0, 0), 0));
});
} }
if (studio || benchmark) { if (studio || benchmark) {
J.s(() -> { J.s(() -> {
Iris.linkMultiverseCore.removeFromConfig(world.get()); Iris.linkMultiverseCore.removeFromConfig(world);
if (IrisSettings.get().getStudio().isDisableTimeAndWeather()) { if (IrisSettings.get().getStudio().isDisableTimeAndWeather()) {
world.get().setGameRule(GameRule.DO_WEATHER_CYCLE, false); world.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
world.get().setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false); world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
world.get().setTime(6000); world.setTime(6000);
} }
}); });
} else { } else {
addToBukkitYml(); addToBukkitYml();
J.s(() -> Iris.linkMultiverseCore.updateWorld(world.get(), dimension)); J.s(() -> Iris.linkMultiverseCore.updateWorld(world, dimension));
} }
if (pregen != null) { if (pregen != null) {
@@ -233,7 +223,7 @@ public class IrisCreator {
e.printStackTrace(); e.printStackTrace();
} }
} }
return world.get(); return world;
} }
private void addToBukkitYml() { private void addToBukkitYml() {
@@ -64,7 +64,7 @@ public class IrisWorldCreator {
} }
public WorldCreator create() { public WorldCreator create() {
IrisDimension dim = IrisData.loadAnyDimension(dimensionName); IrisDimension dim = IrisData.loadAnyDimension(dimensionName, null);
IrisWorld w = IrisWorld.builder() IrisWorld w = IrisWorld.builder()
.name(name) .name(name)
@@ -80,13 +80,13 @@ public class IrisWorldCreator {
return new WorldCreator(name) return new WorldCreator(name)
.environment(findEnvironment()) .environment(w.environment())
.generateStructures(true) .generateStructures(true)
.generator(g).seed(seed); .generator(g).seed(seed);
} }
private World.Environment findEnvironment() { private World.Environment findEnvironment() {
IrisDimension dim = IrisData.loadAnyDimension(dimensionName); IrisDimension dim = IrisData.loadAnyDimension(dimensionName, null);
if (dim == null || dim.getEnvironment() == null) { if (dim == null || dim.getEnvironment() == null) {
return World.Environment.NORMAL; return World.Environment.NORMAL;
} else { } else {
@@ -25,8 +25,6 @@ import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.object.*;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.context.IrisContext; import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.DataProvider; import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.interpolation.IrisInterpolation.NoiseKey; import com.volmit.iris.util.interpolation.IrisInterpolation.NoiseKey;
@@ -43,7 +41,7 @@ import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import java.io.File; import java.io.File;
import java.util.UUID; import java.util.*;
@Data @Data
@EqualsAndHashCode(exclude = "data") @EqualsAndHashCode(exclude = "data")
@@ -53,7 +51,7 @@ public class IrisComplex implements DataProvider {
private RNG rng; private RNG rng;
private double fluidHeight; private double fluidHeight;
private IrisData data; private IrisData data;
private KMap<IrisInterpolator, KSet<IrisGenerator>> generators; private Map<IrisInterpolator, Set<IrisGenerator>> generators;
private ProceduralStream<IrisRegion> regionStream; private ProceduralStream<IrisRegion> regionStream;
private ProceduralStream<Double> regionStyleStream; private ProceduralStream<Double> regionStyleStream;
private ProceduralStream<Double> regionIdentityStream; private ProceduralStream<Double> regionIdentityStream;
@@ -98,10 +96,10 @@ public class IrisComplex implements DataProvider {
this.data = engine.getData(); this.data = engine.getData();
double height = engine.getMaxHeight(); double height = engine.getMaxHeight();
fluidHeight = engine.getDimension().getFluidHeight(); fluidHeight = engine.getDimension().getFluidHeight();
generators = new KMap<>(); generators = new HashMap<>();
focusBiome = engine.getFocus(); focusBiome = engine.getFocus();
focusRegion = engine.getFocusRegion(); focusRegion = engine.getFocusRegion();
KMap<InferredType, ProceduralStream<IrisBiome>> inferredStreams = new KMap<>(); Map<InferredType, ProceduralStream<IrisBiome>> inferredStreams = new HashMap<>();
if (focusBiome != null) { if (focusBiome != null) {
focusBiome.setInferredType(InferredType.LAND); focusBiome.setInferredType(InferredType.LAND);
@@ -118,6 +116,7 @@ public class IrisComplex implements DataProvider {
.getAllBiomes(this) .getAllBiomes(this)
.forEach(this::registerGenerators)); .forEach(this::registerGenerators));
} }
boolean legacy = engine.getDimension().isLegacyRarity();
overlayStream = ProceduralStream.ofDouble((x, z) -> 0.0D).waste("Overlay Stream"); overlayStream = ProceduralStream.ofDouble((x, z) -> 0.0D).waste("Overlay Stream");
engine.getDimension().getOverlayNoise().forEach(i -> overlayStream = overlayStream.add((x, z) -> i.get(rng, getData(), x, z))); engine.getDimension().getOverlayNoise().forEach(i -> overlayStream = overlayStream.add((x, z) -> i.get(rng, getData(), x, z)));
rockStream = engine.getDimension().getRockPalette().getLayerGenerator(rng.nextParallelRNG(45), data).stream() rockStream = engine.getDimension().getRockPalette().getLayerGenerator(rng.nextParallelRNG(45), data).stream()
@@ -131,7 +130,7 @@ public class IrisComplex implements DataProvider {
ProceduralStream.of((x, z) -> focusRegion, ProceduralStream.of((x, z) -> focusRegion,
Interpolated.of(a -> 0D, a -> focusRegion)) Interpolated.of(a -> 0D, a -> focusRegion))
: regionStyleStream : regionStyleStream
.selectRarity(data.getRegionLoader().loadAll(engine.getDimension().getRegions())) .selectRarity(data.getRegionLoader().loadAll(engine.getDimension().getRegions()), legacy)
.cache2D("regionStream", engine, cacheSize).waste("Region Stream"); .cache2D("regionStream", engine, cacheSize).waste("Region Stream");
regionIDStream = regionIdentityStream.convertCached((i) -> new UUID(Double.doubleToLongBits(i), regionIDStream = regionIdentityStream.convertCached((i) -> new UUID(Double.doubleToLongBits(i),
String.valueOf(i * 38445).hashCode() * 3245556666L)).waste("Region ID Stream"); String.valueOf(i * 38445).hashCode() * 3245556666L)).waste("Region ID Stream");
@@ -140,7 +139,7 @@ public class IrisComplex implements DataProvider {
-> engine.getDimension().getCaveBiomeStyle().create(rng.nextParallelRNG(InferredType.CAVE.ordinal()), getData()).stream() -> engine.getDimension().getCaveBiomeStyle().create(rng.nextParallelRNG(InferredType.CAVE.ordinal()), getData()).stream()
.zoom(engine.getDimension().getBiomeZoom()) .zoom(engine.getDimension().getBiomeZoom())
.zoom(r.getCaveBiomeZoom()) .zoom(r.getCaveBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getCaveBiomes())) .selectRarity(data.getBiomeLoader().loadAll(r.getCaveBiomes()), legacy)
.onNull(emptyBiome) .onNull(emptyBiome)
).convertAware2D(ProceduralStream::get).cache2D("caveBiomeStream", engine, cacheSize).waste("Cave Biome Stream"); ).convertAware2D(ProceduralStream::get).cache2D("caveBiomeStream", engine, cacheSize).waste("Cave Biome Stream");
inferredStreams.put(InferredType.CAVE, caveBiomeStream); inferredStreams.put(InferredType.CAVE, caveBiomeStream);
@@ -150,7 +149,7 @@ public class IrisComplex implements DataProvider {
.zoom(engine.getDimension().getBiomeZoom()) .zoom(engine.getDimension().getBiomeZoom())
.zoom(engine.getDimension().getLandZoom()) .zoom(engine.getDimension().getLandZoom())
.zoom(r.getLandBiomeZoom()) .zoom(r.getLandBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getLandBiomes(), (t) -> t.setInferredType(InferredType.LAND))) .selectRarity(data.getBiomeLoader().loadAll(r.getLandBiomes(), (t) -> t.setInferredType(InferredType.LAND)), legacy)
).convertAware2D(ProceduralStream::get) ).convertAware2D(ProceduralStream::get)
.cache2D("landBiomeStream", engine, cacheSize).waste("Land Biome Stream"); .cache2D("landBiomeStream", engine, cacheSize).waste("Land Biome Stream");
inferredStreams.put(InferredType.LAND, landBiomeStream); inferredStreams.put(InferredType.LAND, landBiomeStream);
@@ -160,7 +159,7 @@ public class IrisComplex implements DataProvider {
.zoom(engine.getDimension().getBiomeZoom()) .zoom(engine.getDimension().getBiomeZoom())
.zoom(engine.getDimension().getSeaZoom()) .zoom(engine.getDimension().getSeaZoom())
.zoom(r.getSeaBiomeZoom()) .zoom(r.getSeaBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getSeaBiomes(), (t) -> t.setInferredType(InferredType.SEA))) .selectRarity(data.getBiomeLoader().loadAll(r.getSeaBiomes(), (t) -> t.setInferredType(InferredType.SEA)), legacy)
).convertAware2D(ProceduralStream::get) ).convertAware2D(ProceduralStream::get)
.cache2D("seaBiomeStream", engine, cacheSize).waste("Sea Biome Stream"); .cache2D("seaBiomeStream", engine, cacheSize).waste("Sea Biome Stream");
inferredStreams.put(InferredType.SEA, seaBiomeStream); inferredStreams.put(InferredType.SEA, seaBiomeStream);
@@ -169,7 +168,7 @@ public class IrisComplex implements DataProvider {
-> engine.getDimension().getShoreBiomeStyle().create(rng.nextParallelRNG(InferredType.SHORE.ordinal()), getData()).stream() -> engine.getDimension().getShoreBiomeStyle().create(rng.nextParallelRNG(InferredType.SHORE.ordinal()), getData()).stream()
.zoom(engine.getDimension().getBiomeZoom()) .zoom(engine.getDimension().getBiomeZoom())
.zoom(r.getShoreBiomeZoom()) .zoom(r.getShoreBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getShoreBiomes(), (t) -> t.setInferredType(InferredType.SHORE))) .selectRarity(data.getBiomeLoader().loadAll(r.getShoreBiomes(), (t) -> t.setInferredType(InferredType.SHORE)), legacy)
).convertAware2D(ProceduralStream::get).cache2D("shoreBiomeStream", engine, cacheSize).waste("Shore Biome Stream"); ).convertAware2D(ProceduralStream::get).cache2D("shoreBiomeStream", engine, cacheSize).waste("Shore Biome Stream");
inferredStreams.put(InferredType.SHORE, shoreBiomeStream); inferredStreams.put(InferredType.SHORE, shoreBiomeStream);
bridgeStream = focusBiome != null ? ProceduralStream.of((x, z) -> focusBiome.getInferredType(), bridgeStream = focusBiome != null ? ProceduralStream.of((x, z) -> focusBiome.getInferredType(),
@@ -302,12 +301,12 @@ public class IrisComplex implements DataProvider {
return biome; return biome;
} }
private double interpolateGenerators(Engine engine, IrisInterpolator interpolator, KSet<IrisGenerator> generators, double x, double z, long seed) { private double interpolateGenerators(Engine engine, IrisInterpolator interpolator, Set<IrisGenerator> generators, double x, double z, long seed) {
if (generators.isEmpty()) { if (generators.isEmpty()) {
return 0; return 0;
} }
KMap<NoiseKey, IrisBiome> cache = new KMap<>(); HashMap<NoiseKey, IrisBiome> cache = new HashMap<>(64);
double hi = interpolator.interpolate(x, z, (xx, zz) -> { double hi = interpolator.interpolate(x, z, (xx, zz) -> {
try { try {
IrisBiome bx = baseBiomeStream.get(xx, zz); IrisBiome bx = baseBiomeStream.get(xx, zz);
@@ -379,7 +378,7 @@ public class IrisComplex implements DataProvider {
} }
private void registerGenerator(IrisGenerator cachedGenerator) { private void registerGenerator(IrisGenerator cachedGenerator) {
generators.computeIfAbsent(cachedGenerator.getInterpolator(), (k) -> new KSet<>()).add(cachedGenerator); generators.computeIfAbsent(cachedGenerator.getInterpolator(), (k) -> new HashSet<>()).add(cachedGenerator);
} }
private IrisBiome implode(IrisBiome b, Double x, Double z) { private IrisBiome implode(IrisBiome b, Double x, Double z) {
@@ -28,12 +28,12 @@ import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.core.nms.container.BlockPos; import com.volmit.iris.core.nms.container.BlockPos;
import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.project.IrisProject; import com.volmit.iris.core.project.IrisProject;
import com.volmit.iris.core.scripting.environment.EngineEnvironment;
import com.volmit.iris.core.service.PreservationSVC; import com.volmit.iris.core.service.PreservationSVC;
import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.*; import com.volmit.iris.engine.framework.*;
import com.volmit.iris.engine.mantle.EngineMantle; import com.volmit.iris.engine.mantle.EngineMantle;
import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
import com.volmit.iris.util.atomics.AtomicRollingSequence; import com.volmit.iris.util.atomics.AtomicRollingSequence;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.ChunkContext;
@@ -43,7 +43,7 @@ import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.io.IO; import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.MatterStructurePOI; import com.volmit.iris.util.matter.MatterStructurePOI;
@@ -94,7 +94,7 @@ public class IrisEngine implements Engine {
private CompletableFuture<Long> hash32; private CompletableFuture<Long> hash32;
private EngineMode mode; private EngineMode mode;
private EngineEffects effects; private EngineEffects effects;
private EngineExecutionEnvironment execution; private EngineEnvironment execution;
private EngineWorldManager worldManager; private EngineWorldManager worldManager;
private volatile int parallelism; private volatile int parallelism;
private boolean failing; private boolean failing;
@@ -170,10 +170,12 @@ public class IrisEngine implements Engine {
cacheId = RNG.r.nextInt(); cacheId = RNG.r.nextInt();
worldManager = new IrisWorldManager(this); worldManager = new IrisWorldManager(this);
complex = new IrisComplex(this); complex = new IrisComplex(this);
execution = new IrisExecutionEnvironment(this); execution = EngineEnvironment.create(this);
effects = new IrisEngineEffects(this); effects = new IrisEngineEffects(this);
hash32 = new CompletableFuture<>(); hash32 = new CompletableFuture<>();
mantle.hotload();
setupMode(); setupMode();
getDimension().getEngineScripts().forEach(execution::execute);
J.a(this::computeBiomeMaxes); J.a(this::computeBiomeMaxes);
J.a(() -> { J.a(() -> {
File[] roots = getData().getLoaders() File[] roots = getData().getLoaders()
@@ -199,7 +201,7 @@ public class IrisEngine implements Engine {
mode.close(); mode.close();
} }
mode = getDimension().getMode().getType().create(this); mode = getDimension().getMode().create(this);
} }
@Override @Override
@@ -29,13 +29,15 @@ import com.volmit.iris.engine.mantle.components.MantleJigsawComponent;
import com.volmit.iris.engine.mantle.components.MantleObjectComponent; import com.volmit.iris.engine.mantle.components.MantleObjectComponent;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.MantleFlag;
import lombok.*; import lombok.*;
import java.io.File; import java.io.File;
import java.util.stream.Collectors; import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Data @Data
@EqualsAndHashCode(exclude = "engine") @EqualsAndHashCode(exclude = "engine")
@@ -45,8 +47,9 @@ public class IrisEngineMantle implements EngineMantle {
private final Mantle mantle; private final Mantle mantle;
@Getter(AccessLevel.NONE) @Getter(AccessLevel.NONE)
private final KMap<Integer, KList<MantleComponent>> components; private final KMap<Integer, KList<MantleComponent>> components;
private final AtomicCache<KList<Pair<KList<MantleComponent>, Integer>>> componentsCache = new AtomicCache<>(); private final KMap<MantleFlag, MantleComponent> registeredComponents = new KMap<>();
private final AtomicCache<KSet<MantleFlag>> disabledFlags = new AtomicCache<>(); private final AtomicCache<List<Pair<List<MantleComponent>, Integer>>> componentsCache = new AtomicCache<>();
private final AtomicCache<Set<MantleFlag>> disabledFlags = new AtomicCache<>();
private final MantleObjectComponent object; private final MantleObjectComponent object;
private final MantleJigsawComponent jigsaw; private final MantleJigsawComponent jigsaw;
@@ -75,7 +78,7 @@ public class IrisEngineMantle implements EngineMantle {
} }
@Override @Override
public KList<Pair<KList<MantleComponent>, Integer>> getComponents() { public List<Pair<List<MantleComponent>, Integer>> getComponents() {
return componentsCache.aquire(() -> { return componentsCache.aquire(() -> {
var list = components.keySet() var list = components.keySet()
.stream() .stream()
@@ -86,10 +89,9 @@ public class IrisEngineMantle implements EngineMantle {
.mapToInt(MantleComponent::getRadius) .mapToInt(MantleComponent::getRadius)
.max() .max()
.orElse(0); .orElse(0);
return new Pair<>(components, radius); return new Pair<>(List.copyOf(components), radius);
}) })
.collect(Collectors.toCollection(KList::new)); .toList();
int radius = 0; int radius = 0;
for (var pair : list.reversed()) { for (var pair : list.reversed()) {
@@ -102,19 +104,36 @@ public class IrisEngineMantle implements EngineMantle {
} }
@Override @Override
public void registerComponent(MantleComponent c) { public Map<MantleFlag, MantleComponent> getRegisteredComponents() {
c.setEnabled(!getDimension().getDisabledComponents().contains(c.getFlag())); return Collections.unmodifiableMap(registeredComponents);
}
@Override
public boolean registerComponent(MantleComponent c) {
if (registeredComponents.putIfAbsent(c.getFlag(), c) != null) return false;
c.setEnabled(!getDisabledFlags().contains(c.getFlag()));
components.computeIfAbsent(c.getPriority(), k -> new KList<>()).add(c); components.computeIfAbsent(c.getPriority(), k -> new KList<>()).add(c);
componentsCache.reset(); componentsCache.reset();
return true;
} }
@Override @Override
public KList<MantleFlag> getComponentFlags() { public KList<MantleFlag> getComponentFlags() {
return components.values() return new KList<>(registeredComponents.keySet());
.stream() }
.flatMap(KList::stream)
.map(MantleComponent::getFlag) @Override
.collect(KList.collector()); public void hotload() {
disabledFlags.reset();
for (var component : registeredComponents.values()) {
component.hotload();
component.setEnabled(!getDisabledFlags().contains(component.getFlag()));
}
componentsCache.reset();
}
private Set<MantleFlag> getDisabledFlags() {
return disabledFlags.aquire(() -> Set.copyOf(getDimension().getDisabledComponents()));
} }
@Override @Override
@@ -1,84 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisScript;
import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
import com.volmit.iris.engine.scripting.IrisScriptingAPI;
import com.volmit.iris.util.format.C;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.apache.bsf.BSFException;
import org.apache.bsf.BSFManager;
import org.apache.bsf.engines.javascript.JavaScriptEngine;
@Data
@EqualsAndHashCode(exclude = "engine")
@ToString(exclude = "engine")
public class IrisExecutionEnvironment implements EngineExecutionEnvironment {
private final BSFManager manager;
private final Engine engine;
private final IrisScriptingAPI api;
private JavaScriptEngine javaScriptEngine;
public IrisExecutionEnvironment(Engine engine) {
this.engine = engine;
this.api = new IrisScriptingAPI(engine);
this.manager = new BSFManager();
this.manager.setClassLoader(Iris.class.getClassLoader());
try {
this.manager.declareBean("Iris", api, api.getClass());
this.javaScriptEngine = (JavaScriptEngine) this.manager.loadScriptingEngine("javascript");
} catch (Throwable e) {
e.printStackTrace();
}
}
@Override
public IrisScriptingAPI getAPI() {
return api;
}
public void execute(String script) {
execute(getEngine().getData().getScriptLoader().load(script));
}
public void execute(IrisScript script) {
Iris.debug("Execute Script (void) " + C.DARK_GREEN + script.getLoadKey());
try {
javaScriptEngine.exec("", 0, 0, script);
} catch (BSFException e) {
e.printStackTrace();
}
}
public Object evaluate(String script) {
Iris.debug("Execute Script (for result) " + C.DARK_GREEN + script);
try {
return javaScriptEngine.eval("", 0, 0, getEngine().getData().getScriptLoader().load(script));
} catch (BSFException e) {
e.printStackTrace();
}
return null;
}
}
@@ -20,7 +20,9 @@ package com.volmit.iris.engine;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; 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.loader.IrisData;
import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineAssignedWorldManager; import com.volmit.iris.engine.framework.EngineAssignedWorldManager;
import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.object.*;
@@ -29,7 +31,7 @@ import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
@@ -424,18 +426,35 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
} }
var ref = new WeakReference<>(e.getWorld()); var ref = new WeakReference<>(e.getWorld());
int x = e.getX(), z = e.getZ(); int cX = e.getX(), cZ = e.getZ();
J.s(() -> { J.s(() -> {
World world = ref.get(); World world = ref.get();
if (world == null || !world.isChunkLoaded(x, z)) if (world == null || !world.isChunkLoaded(cX, cZ))
return; return;
energy += 0.3; energy += 0.3;
fixEnergy(); fixEnergy();
getEngine().cleanupMantleChunk(x, z); getEngine().cleanupMantleChunk(cX, cZ);
}, IrisSettings.get().getPerformance().mantleCleanupDelay); }, IrisSettings.get().getPerformance().mantleCleanupDelay);
if (generated) { if (generated) {
//INMS.get().injectBiomesFromMantle(e, getMantle()); //INMS.get().injectBiomesFromMantle(e, getMantle());
if (!IrisSettings.get().getGenerator().earlyCustomBlocks) return;
e.addPluginChunkTicket(Iris.instance);
J.s(() -> {
var chunk = getMantle().getChunk(e).use();
int minY = getTarget().getWorld().minHeight();
try {
chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, () -> {
chunk.iterate(Identifier.class, (x, y, z, v) -> {
Iris.service(ExternalDataSVC.class).processUpdate(getEngine(), e.getBlock(x & 15, y + minY, z & 15), v);
});
});
} finally {
chunk.release();
e.removePluginChunkTicket(Iris.instance);
}
}, RNG.r.i(20, 60));
} }
} }
@@ -29,13 +29,13 @@ import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.nms.container.BlockPos; import com.volmit.iris.core.nms.container.BlockPos;
import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.core.nms.container.Pair;
import com.volmit.iris.core.pregenerator.ChunkUpdater; import com.volmit.iris.core.pregenerator.ChunkUpdater;
import com.volmit.iris.core.scripting.environment.EngineEnvironment;
import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.engine.IrisComplex; import com.volmit.iris.engine.IrisComplex;
import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.data.chunk.TerrainChunk; import com.volmit.iris.engine.data.chunk.TerrainChunk;
import com.volmit.iris.engine.mantle.EngineMantle; import com.volmit.iris.engine.mantle.EngineMantle;
import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.ChunkContext;
@@ -48,7 +48,7 @@ import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
import com.volmit.iris.util.function.Function2; import com.volmit.iris.util.function.Function2;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.BlockPosition; import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.Position2;
@@ -110,7 +110,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
IrisContext getContext(); IrisContext getContext();
EngineExecutionEnvironment getExecution(); EngineEnvironment getExecution();
double getMaxBiomeObjectDensity(); double getMaxBiomeObjectDensity();
@@ -294,22 +294,22 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
var chunk = mantle.getChunk(c).use(); var chunk = mantle.getChunk(c).use();
try { try {
Semaphore semaphore = new Semaphore(3); Semaphore semaphore = new Semaphore(1024);
chunk.raiseFlag(MantleFlag.ETCHED, () -> { chunk.raiseFlag(MantleFlag.ETCHED, () -> {
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> { chunk.raiseFlagUnchecked(MantleFlag.TILE, run(semaphore, () -> {
chunk.iterate(TileWrapper.class, (x, y, z, v) -> { chunk.iterate(TileWrapper.class, (x, y, z, v) -> {
Block block = c.getBlock(x & 15, y + getWorld().minHeight(), z & 15); Block block = c.getBlock(x & 15, y + getWorld().minHeight(), z & 15);
if (!TileData.setTileState(block, v.getData())) 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()); 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)); }, 0));
chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> { chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, run(semaphore, () -> {
chunk.iterate(Identifier.class, (x, y, z, v) -> { chunk.iterate(Identifier.class, (x, y, z, v) -> {
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v); Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
}); });
}, 0)); }, 0));
chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> { chunk.raiseFlagUnchecked(MantleFlag.UPDATE, run(semaphore, () -> {
PrecisionStopwatch p = PrecisionStopwatch.start(); PrecisionStopwatch p = PrecisionStopwatch.start();
int[][] grid = new int[16][16]; int[][] grid = new int[16][16];
for (int x = 0; x < 16; x++) { for (int x = 0; x < 16; x++) {
@@ -355,8 +355,18 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
}, RNG.r.i(1, 20))); //Why is there a random delay here? }, RNG.r.i(1, 20))); //Why is there a random delay here?
}); });
chunk.raiseFlagUnchecked(MantleFlag.SCRIPT, () -> {
var scripts = getDimension().getChunkUpdateScripts();
if (scripts == null || scripts.isEmpty())
return;
for (var script : scripts) {
getExecution().updateChunk(script, chunk, c, (delay, task) -> run(semaphore, task, delay));
}
});
try { try {
semaphore.acquire(3); semaphore.acquire(1024);
} catch (InterruptedException ignored) {} } catch (InterruptedException ignored) {}
} finally { } finally {
chunk.release(); chunk.release();
@@ -365,8 +375,11 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
private static Runnable run(Semaphore semaphore, Runnable runnable, int delay) { private static Runnable run(Semaphore semaphore, Runnable runnable, int delay) {
return () -> { return () -> {
if (!semaphore.tryAcquire()) try {
return; semaphore.acquire();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
J.s(() -> { J.s(() -> {
try { try {
@@ -863,7 +876,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
default void gotoBiome(IrisBiome biome, Player player, boolean teleport) { default void gotoBiome(IrisBiome biome, Player player, boolean teleport) {
Set<String> regionKeys = getDimension() Set<String> regionKeys = getDimension()
.getAllRegions(this).stream() .getAllRegions(this).stream()
.filter((i) -> i.getAllBiomes(this).contains(biome)) .filter((i) -> i.getAllBiomeIds().contains(biome.getLoadKey()))
.map(IrisRegistrant::getLoadKey) .map(IrisRegistrant::getLoadKey)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Locator<IrisBiome> lb = Locator.surfaceBiome(biome.getLoadKey()); Locator<IrisBiome> lb = Locator.surfaceBiome(biome.getLoadKey());
@@ -959,7 +972,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
} }
default void gotoRegion(IrisRegion r, Player player, boolean teleport) { default void gotoRegion(IrisRegion r, Player player, boolean teleport) {
if (!getDimension().getAllRegions(this).contains(r)) { if (!getDimension().getRegions().contains(r.getLoadKey())) {
player.sendMessage(C.RED + r.getName() + " is not defined in the dimension!"); player.sendMessage(C.RED + r.getName() + " is not defined in the dimension!");
return; return;
} }
@@ -22,8 +22,7 @@ import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisObjectPlacement; import com.volmit.iris.engine.object.IrisObjectPlacement;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nullable;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@@ -1,6 +1,6 @@
package com.volmit.iris.engine.mantle; package com.volmit.iris.engine.mantle;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.ReservedFlag;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@@ -10,5 +10,5 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface ComponentFlag { public @interface ComponentFlag {
MantleFlag value(); ReservedFlag value();
} }
@@ -37,13 +37,16 @@ import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.MantleChunk; import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.matter.*; import com.volmit.iris.util.matter.*;
import com.volmit.iris.util.matter.slices.UpdateMatter; import com.volmit.iris.util.matter.slices.UpdateMatter;
import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.parallel.MultiBurst;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.UnmodifiableView;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static com.volmit.iris.util.parallel.StreamUtils.forEach; import static com.volmit.iris.util.parallel.StreamUtils.forEach;
@@ -60,12 +63,19 @@ public interface EngineMantle {
int getRealRadius(); int getRealRadius();
KList<Pair<KList<MantleComponent>, Integer>> getComponents(); @UnmodifiableView
List<Pair<List<MantleComponent>, Integer>> getComponents();
void registerComponent(MantleComponent c); @UnmodifiableView
Map<MantleFlag, MantleComponent> getRegisteredComponents();
boolean registerComponent(MantleComponent c);
@UnmodifiableView
KList<MantleFlag> getComponentFlags(); KList<MantleFlag> getComponentFlags();
void hotload();
default int getHighest(int x, int z) { default int getHighest(int x, int z) {
return getHighest(x, z, getData()); return getHighest(x, z, getData());
} }
@@ -185,6 +195,7 @@ public interface EngineMantle {
forEach(streamRadius(x, z, radius), forEach(streamRadius(x, z, radius),
pos -> pair.getA() pos -> pair.getA()
.stream() .stream()
.filter(MantleComponent::isEnabled)
.map(c -> new Pair<>(c, pos)), .map(c -> new Pair<>(c, pos)),
p -> { p -> {
MantleComponent c = p.getA(); MantleComponent c = p.getA();
@@ -18,7 +18,7 @@
package com.volmit.iris.engine.mantle; package com.volmit.iris.engine.mantle;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.MantleFlag;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
@@ -30,5 +30,32 @@ public abstract class IrisMantleComponent implements MantleComponent {
private final EngineMantle engineMantle; private final EngineMantle engineMantle;
private final MantleFlag flag; private final MantleFlag flag;
private final int priority; private final int priority;
private volatile int radius = -1;
private final Object lock = new Object();
private boolean enabled = true; private boolean enabled = true;
protected abstract int computeRadius();
@Override
public void hotload() {
synchronized (lock) {
radius = -1;
}
}
@Override
public final int getRadius() {
int r = radius;
if(r != -1) return r;
synchronized (lock) {
if((r = radius) != -1) {
return r;
}
r = computeRadius();
if(r < 0) r = 0;
return radius = r;
}
}
} }
@@ -24,7 +24,7 @@ import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.BurstExecutor;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -65,6 +65,8 @@ public interface MantleComponent extends Comparable<MantleComponent> {
void setEnabled(boolean b); void setEnabled(boolean b);
void hotload();
@ChunkCoordinates @ChunkCoordinates
void generateLayer(MantleWriter writer, int x, int z, ChunkContext context); void generateLayer(MantleWriter writer, int x, int z, ChunkContext context);
@@ -28,17 +28,13 @@ import com.volmit.iris.engine.object.IrisCarving;
import com.volmit.iris.engine.object.IrisRegion; import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.ReservedFlag;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import lombok.Getter;
@Getter @ComponentFlag(ReservedFlag.CARVED)
@ComponentFlag(MantleFlag.CARVED)
public class MantleCarvingComponent extends IrisMantleComponent { public class MantleCarvingComponent extends IrisMantleComponent {
private final int radius = computeRadius();
public MantleCarvingComponent(EngineMantle engineMantle) { public MantleCarvingComponent(EngineMantle engineMantle) {
super(engineMantle, MantleFlag.CARVED, 0); super(engineMantle, ReservedFlag.CARVED, 0);
} }
@Override @Override
@@ -63,7 +59,7 @@ public class MantleCarvingComponent extends IrisMantleComponent {
carving.doCarving(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4, 0); carving.doCarving(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4, 0);
} }
private int computeRadius() { protected int computeRadius() {
var dimension = getDimension(); var dimension = getDimension();
int max = 0; int max = 0;
@@ -28,17 +28,13 @@ import com.volmit.iris.engine.object.IrisFluidBodies;
import com.volmit.iris.engine.object.IrisRegion; import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.ReservedFlag;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import lombok.Getter;
@Getter @ComponentFlag(ReservedFlag.FLUID_BODIES)
@ComponentFlag(MantleFlag.FLUID_BODIES)
public class MantleFluidBodyComponent extends IrisMantleComponent { public class MantleFluidBodyComponent extends IrisMantleComponent {
private final int radius = computeRadius();
public MantleFluidBodyComponent(EngineMantle engineMantle) { public MantleFluidBodyComponent(EngineMantle engineMantle) {
super(engineMantle, MantleFlag.FLUID_BODIES, 0); super(engineMantle, ReservedFlag.FLUID_BODIES, 0);
} }
@Override @Override
@@ -63,7 +59,7 @@ public class MantleFluidBodyComponent extends IrisMantleComponent {
bodies.generate(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4); bodies.generate(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4);
} }
private int computeRadius() { protected int computeRadius() {
int max = 0; int max = 0;
max = Math.max(max, getDimension().getFluidBodies().getMaxRange(getData())); max = Math.max(max, getDimension().getFluidBodies().getMaxRange(getData()));
@@ -30,7 +30,7 @@ import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.ReservedFlag;
import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer; import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer;
@@ -40,14 +40,12 @@ import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
@ComponentFlag(MantleFlag.JIGSAW) @ComponentFlag(ReservedFlag.JIGSAW)
public class MantleJigsawComponent extends IrisMantleComponent { public class MantleJigsawComponent extends IrisMantleComponent {
@Getter
private final int radius = computeRadius();
private final CNG cng; private final CNG cng;
public MantleJigsawComponent(EngineMantle engineMantle) { public MantleJigsawComponent(EngineMantle engineMantle) {
super(engineMantle, MantleFlag.JIGSAW, 2); super(engineMantle, ReservedFlag.JIGSAW, 2);
cng = NoiseStyle.STATIC.create(new RNG(jigsaw())); cng = NoiseStyle.STATIC.create(new RNG(jigsaw()));
} }
@@ -169,6 +167,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
@BlockCoordinates @BlockCoordinates
private boolean place(MantleWriter writer, IrisPosition position, IrisJigsawStructure structure, RNG rng, boolean forcePlace) { private boolean place(MantleWriter writer, IrisPosition position, IrisJigsawStructure structure, RNG rng, boolean forcePlace) {
if (structure == null || structure.getDatapackStructures().isNotEmpty()) return false;
return new PlannedStructure(structure, position, rng, forcePlace).place(writer, getMantle(), writer.getEngine()); return new PlannedStructure(structure, position, rng, forcePlace).place(writer, getMantle(), writer.getEngine());
} }
@@ -176,7 +175,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
return getEngineMantle().getEngine().getSeedManager().getJigsaw(); return getEngineMantle().getEngine().getSeedManager().getJigsaw();
} }
private int computeRadius() { protected int computeRadius() {
var dimension = getDimension(); var dimension = getDimension();
KSet<String> structures = new KSet<>(); KSet<String> structures = new KSet<>();
@@ -33,13 +33,12 @@ import com.volmit.iris.util.data.B;
import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.ReservedFlag;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.MatterStructurePOI; import com.volmit.iris.util.matter.MatterStructurePOI;
import com.volmit.iris.util.noise.CNG; import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.noise.NoiseType; import com.volmit.iris.util.noise.NoiseType;
import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.BurstExecutor;
import lombok.Getter;
import org.bukkit.util.BlockVector; import org.bukkit.util.BlockVector;
import java.io.IOException; import java.io.IOException;
@@ -47,13 +46,11 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@Getter @ComponentFlag(ReservedFlag.OBJECT)
@ComponentFlag(MantleFlag.OBJECT)
public class MantleObjectComponent extends IrisMantleComponent { public class MantleObjectComponent extends IrisMantleComponent {
private final int radius = computeRadius();
public MantleObjectComponent(EngineMantle engineMantle) { public MantleObjectComponent(EngineMantle engineMantle) {
super(engineMantle, MantleFlag.OBJECT, 1); super(engineMantle, ReservedFlag.OBJECT, 1);
} }
@Override @Override
@@ -157,7 +154,7 @@ public class MantleObjectComponent extends IrisMantleComponent {
return v; return v;
} }
private int computeRadius() { protected int computeRadius() {
var dimension = getDimension(); var dimension = getDimension();
AtomicInteger xg = new AtomicInteger(); AtomicInteger xg = new AtomicInteger();
@@ -219,16 +219,21 @@ public class IrisCarveModifier extends EngineAssignedModifier<BlockData> {
if (!blocks.hasIndex(i)) { if (!blocks.hasIndex(i)) {
break; break;
} }
int y = zone.floor - i - 1;
if (!B.isSolid(output.get(rx, zone.floor - i - 1, rz))) { BlockData b = blocks.get(i);
BlockData down = output.get(rx, y, rz);
if (!B.isSolid(down)) {
continue; continue;
} }
if (B.isOre(output.get(rx, zone.floor - i - 1, rz))) { if (B.isOre(down)) {
output.set(rx, y, rz, B.toDeepSlateOre(down, b));
continue; continue;
} }
output.set(rx, zone.floor - i - 1, rz, blocks.get(i)); output.set(rx, y, rz, blocks.get(i));
} }
blocks = biome.generateCeilingLayers(getDimension(), xx, zz, rng, 3, zone.ceiling, getData(), getComplex()); blocks = biome.generateCeilingLayers(getDimension(), xx, zz, rng, 3, zone.ceiling, getData(), getComplex());
@@ -5,7 +5,7 @@ import com.volmit.iris.engine.framework.EngineAssignedModifier;
import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.data.IrisCustomData; import com.volmit.iris.util.data.IrisCustomData;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.parallel.MultiBurst;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
@@ -25,7 +25,9 @@ import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.HeightMap; import com.volmit.iris.util.data.HeightMap;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.MantleChunk;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.matter.MatterCavern;
import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.bukkit.Material; import org.bukkit.Material;
@@ -54,28 +56,30 @@ public class IrisDepositModifier extends EngineAssignedModifier<BlockData> {
long seed = x * 341873128712L + z * 132897987541L; long seed = x * 341873128712L + z * 132897987541L;
long mask = 0; long mask = 0;
MantleChunk chunk = getEngine().getMantle().getMantle().getChunk(x, z).use();
for (IrisDepositGenerator k : getDimension().getDeposits()) { for (IrisDepositGenerator k : getDimension().getDeposits()) {
long finalSeed = seed * ++mask; long finalSeed = seed * ++mask;
burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context)); burst.queue(() -> generate(k, chunk, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context));
} }
for (IrisDepositGenerator k : region.getDeposits()) { for (IrisDepositGenerator k : region.getDeposits()) {
long finalSeed = seed * ++mask; long finalSeed = seed * ++mask;
burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context)); burst.queue(() -> generate(k, chunk, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context));
} }
for (IrisDepositGenerator k : biome.getDeposits()) { for (IrisDepositGenerator k : biome.getDeposits()) {
long finalSeed = seed * ++mask; long finalSeed = seed * ++mask;
burst.queue(() -> generate(k, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context)); burst.queue(() -> generate(k, chunk, terrain, rng.nextParallelRNG(finalSeed), x, z, false, context));
} }
burst.complete(); burst.complete();
chunk.release();
} }
public void generate(IrisDepositGenerator k, Hunk<BlockData> data, RNG rng, int cx, int cz, boolean safe, ChunkContext context) { public void generate(IrisDepositGenerator k, MantleChunk chunk, Hunk<BlockData> data, RNG rng, int cx, int cz, boolean safe, ChunkContext context) {
generate(k, data, rng, cx, cz, safe, null, context); generate(k, chunk, data, rng, cx, cz, safe, null, context);
} }
public void generate(IrisDepositGenerator k, Hunk<BlockData> data, RNG rng, int cx, int cz, boolean safe, HeightMap he, ChunkContext context) { public void generate(IrisDepositGenerator k, MantleChunk chunk, Hunk<BlockData> data, RNG rng, int cx, int cz, boolean safe, HeightMap he, ChunkContext context) {
if (k.getSpawnChance() < rng.d()) if (k.getSpawnChance() < rng.d())
return; return;
@@ -127,7 +131,7 @@ public class IrisDepositModifier extends EngineAssignedModifier<BlockData> {
continue; continue;
} }
if (!getEngine().getMantle().isCarved((cx << 4) + nx, ny, (cz << 4) + nz)) { if (chunk.get(nx, ny, nz, MatterCavern.class) == null) {
data.set(nx, ny, nz, B.toDeepSlateOre(data.get(nx, ny, nz), clump.getBlocks().get(j))); data.set(nx, ny, nz, B.toDeepSlateOre(data.get(nx, ny, nz), clump.getBlocks().get(j)));
} }
} }
@@ -21,6 +21,7 @@ package com.volmit.iris.engine.modifier;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineAssignedModifier; import com.volmit.iris.engine.framework.EngineAssignedModifier;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisSlopeClip;
import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.data.B; import com.volmit.iris.util.data.B;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
@@ -174,7 +175,8 @@ public class IrisPostModifier extends EngineAssignedModifier<BlockData> {
|| (hd == h + 1 && isSolidNonSlab(x, hd, z - 1, currentPostX, currentPostZ, currentData))) || (hd == h + 1 && isSolidNonSlab(x, hd, z - 1, currentPostX, currentPostZ, currentData)))
//@done //@done
{ {
BlockData d = biome.getSlab().get(rng, x, h, z, getData()); IrisSlopeClip sc = biome.getSlab().getSlopeCondition();
BlockData d = sc.isValid(getComplex().getSlopeStream().get(x, z)) ? biome.getSlab().get(rng, x, h, z, getData()) : null;
if (d != null) { if (d != null) {
boolean cancel = B.isAir(d); boolean cancel = B.isAir(d);
@@ -25,9 +25,9 @@ import com.volmit.iris.util.stream.interpolation.Interpolated;
import java.util.List; import java.util.List;
public interface IRare { public interface IRare {
static <T extends IRare> ProceduralStream<T> stream(ProceduralStream<Double> noise, List<T> possibilities) { static <T extends IRare> ProceduralStream<T> stream(ProceduralStream<Double> noise, List<T> possibilities, boolean legacyRarity) {
return ProceduralStream.of((x, z) -> pick(possibilities, noise.get(x, z)), return ProceduralStream.of(legacyRarity ? (x, z) -> pickLegacy(possibilities, noise.get(x, z)) : (x, z) -> pick(possibilities, noise.get(x, z)),
(x, y, z) -> pick(possibilities, noise.get(x, y, z)), legacyRarity ? (x, y, z) -> pickLegacy(possibilities, noise.get(x, y, z)) : (x, y, z) -> pick(possibilities, noise.get(x, y, z)),
new Interpolated<T>() { new Interpolated<T>() {
@Override @Override
public double toDouble(T t) { public double toDouble(T t) {
@@ -69,6 +69,32 @@ public interface IRare {
return null; return null;
} }
if (possibilities.size() == 1) {
return possibilities.getFirst();
}
double total = 0;
for (T i : possibilities) {
total += 1d / i.getRarity();
}
double threshold = total * noiseValue;
double buffer = 0;
for (T i : possibilities) {
buffer += 1d / i.getRarity();
if (buffer >= threshold) {
return i;
}
}
return possibilities.getLast();
}
static <T extends IRare> T pickLegacy(List<T> possibilities, double noiseValue) {
if (possibilities.isEmpty()) {
return null;
}
if (possibilities.size() == 1) { if (possibilities.size() == 1) {
return possibilities.get(0); return possibilities.get(0);
} }
@@ -143,14 +143,14 @@ public class IrisBiome extends IrisRegistrant implements IRare {
@Desc("The default wall if iris decides to place a wall higher than 2 blocks (steep hills or possibly cliffs)") @Desc("The default wall if iris decides to place a wall higher than 2 blocks (steep hills or possibly cliffs)")
private IrisBiomePaletteLayer wall = new IrisBiomePaletteLayer().zero(); private IrisBiomePaletteLayer wall = new IrisBiomePaletteLayer().zero();
@Required @Required
@ArrayType(min = 1, type = IrisBiomePaletteLayer.class) @ArrayType(type = IrisBiomePaletteLayer.class)
@Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.") @Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.")
private KList<IrisBiomePaletteLayer> layers = new KList<IrisBiomePaletteLayer>().qadd(new IrisBiomePaletteLayer()); private KList<IrisBiomePaletteLayer> layers = new KList<IrisBiomePaletteLayer>().qadd(new IrisBiomePaletteLayer());
@Required @Required
@ArrayType(min = 1, type = IrisBiomePaletteLayer.class) @ArrayType(type = IrisBiomePaletteLayer.class)
@Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.") @Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.")
private KList<IrisBiomePaletteLayer> caveCeilingLayers = new KList<IrisBiomePaletteLayer>().qadd(new IrisBiomePaletteLayer()); private KList<IrisBiomePaletteLayer> caveCeilingLayers = new KList<IrisBiomePaletteLayer>().qadd(new IrisBiomePaletteLayer());
@ArrayType(min = 1, type = IrisBiomePaletteLayer.class) @ArrayType(type = IrisBiomePaletteLayer.class)
@Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.") @Desc("This defines the layers of materials in this biome. Each layer has a palette and min/max height and some other properties. Usually a grassy/sandy layer then a dirt layer then a stone layer. Iris will fill in the remaining blocks below your layers with stone.")
private KList<IrisBiomePaletteLayer> seaLayers = new KList<>(); private KList<IrisBiomePaletteLayer> seaLayers = new KList<>();
@ArrayType(min = 1, type = IrisDecorator.class) @ArrayType(min = 1, type = IrisDecorator.class)
@@ -61,6 +61,7 @@ public class IrisBlockData extends IrisRegistrant {
private int weight = 1; private int weight = 1;
@Desc("If the block cannot be created on this version, Iris will attempt to use this backup block data instead.") @Desc("If the block cannot be created on this version, Iris will attempt to use this backup block data instead.")
private IrisBlockData backup = null; private IrisBlockData backup = null;
@RegistryMapBlockState("block")
@Desc("Optional properties for this block data such as 'waterlogged': true") @Desc("Optional properties for this block data such as 'waterlogged': true")
private KMap<String, Object> data = new KMap<>(); private KMap<String, Object> data = new KMap<>();
@Desc("Optional tile data for this block data") @Desc("Optional tile data for this block data")
@@ -104,7 +104,7 @@ public class IrisCave extends IrisRegistrant {
CNG cng = shape.getNoise(base.nextParallelRNG(8131545), engine); CNG cng = shape.getNoise(base.nextParallelRNG(8131545), engine);
KSet<IrisPosition> mask = shape.getMasked(rng, engine); KSet<IrisPosition> mask = shape.getMasked(rng, engine);
writer.setNoiseMasked(points, writer.setNoiseMasked(points,
girth, cng.noise(x, y, z), cng, mask, true, girth, shape.getNoiseThreshold() < 0 ? cng.noise(x, y, z) : shape.getNoiseThreshold(), cng, mask, true,
(xf, yf, zf) -> yf <= h ? w : c); (xf, yf, zf) -> yf <= h ? w : c);
} }
@@ -1,9 +1,7 @@
package com.volmit.iris.engine.object; package com.volmit.iris.engine.object;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.engine.object.annotations.RegistryListResource;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
@@ -25,6 +23,11 @@ public class IrisCaveShape {
@Desc("Noise used for the shape of the cave") @Desc("Noise used for the shape of the cave")
private IrisGeneratorStyle noise = new IrisGeneratorStyle(); private IrisGeneratorStyle noise = new IrisGeneratorStyle();
@MinNumber(0)
@MaxNumber(1)
@Desc("The threshold for noise mask")
private double noiseThreshold = -1;
@RegistryListResource(IrisObject.class) @RegistryListResource(IrisObject.class)
@Desc("Object used as mask for the shape of the cave") @Desc("Object used as mask for the shape of the cave")
private String object = null; private String object = null;
@@ -21,6 +21,7 @@ package com.volmit.iris.engine.object;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.engine.object.annotations.ArrayType; import com.volmit.iris.engine.object.annotations.ArrayType;
import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.Required;
import com.volmit.iris.engine.object.annotations.Snippet; import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import lombok.Data; import lombok.Data;
@@ -37,6 +38,7 @@ import org.bukkit.World;
@Data @Data
public class IrisCommand { public class IrisCommand {
@Required
@ArrayType(min = 1, type = String.class) @ArrayType(min = 1, type = String.class)
@Desc("List of commands. Iris replaces {x} {y} and {z} with the location of the entity spawn") @Desc("List of commands. Iris replaces {x} {y} and {z} with the location of the entity spawn")
private KList<String> commands = new KList<>(); private KList<String> commands = new KList<>();
@@ -33,6 +33,7 @@ import org.bukkit.entity.Player;
@Desc("Represents a casting location for a command") @Desc("Represents a casting location for a command")
@Data @Data
public class IrisCommandRegistry { public class IrisCommandRegistry {
@Required
@ArrayType(min = 1, type = IrisCommand.class) @ArrayType(min = 1, type = IrisCommand.class)
@Desc("Run commands, at the exact location of the player") @Desc("Run commands, at the exact location of the player")
private KList<IrisCommand> rawCommands = new KList<>(); private KList<IrisCommand> rawCommands = new KList<>();
@@ -30,11 +30,12 @@ import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.engine.object.annotations.functions.ComponentFlagFunction; import com.volmit.iris.engine.object.annotations.functions.ComponentFlagFunction;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet; import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.DataProvider; import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.io.IO; import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.MantleFlag;
import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG; import com.volmit.iris.util.noise.CNG;
@@ -68,6 +69,7 @@ public class IrisDimension extends IrisRegistrant {
private final transient AtomicCache<Double> rad = new AtomicCache<>(); private final transient AtomicCache<Double> rad = new AtomicCache<>();
private final transient AtomicCache<Boolean> featuresUsed = new AtomicCache<>(); private final transient AtomicCache<Boolean> featuresUsed = new AtomicCache<>();
private final transient AtomicCache<KList<Position2>> strongholdsCache = new AtomicCache<>(); private final transient AtomicCache<KList<Position2>> strongholdsCache = new AtomicCache<>();
private final transient AtomicCache<KMap<String, KList<String>>> cachedPreProcessors = new AtomicCache<>();
@MinNumber(2) @MinNumber(2)
@Required @Required
@Desc("The human readable name of this dimension") @Desc("The human readable name of this dimension")
@@ -241,9 +243,26 @@ public class IrisDimension extends IrisRegistrant {
@Desc("The Subterrain Fluid Layer Height") @Desc("The Subterrain Fluid Layer Height")
private int caveLavaHeight = 8; private int caveLavaHeight = 8;
@RegistryListFunction(ComponentFlagFunction.class) @RegistryListFunction(ComponentFlagFunction.class)
@ArrayType(type = MantleFlag.class) @ArrayType(type = String.class)
@Desc("Collection of disabled components") @Desc("Collection of disabled components")
private KList<MantleFlag> disabledComponents = new KList<>(); private KList<MantleFlag> disabledComponents = new KList<>();
@Desc("A list of globally applied pre-processors")
@ArrayType(type = IrisPreProcessors.class)
private KList<IrisPreProcessors> globalPreProcessors = new KList<>();
@Desc("A list of scripts executed on engine setup\nFile extension: .engine.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> engineScripts = new KList<>();
@Desc("A list of scripts executed on data setup\nFile extension: .data.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> dataScripts = new KList<>();
@Desc("A list of scripts executed on chunk update\nFile extension: .update.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> chunkUpdateScripts = new KList<>();
@Desc("Use legacy rarity instead of modern one\nWARNING: Changing this may break expressions and image maps")
private boolean legacyRarity = true;
public int getMaxHeight() { public int getMaxHeight() {
return (int) getDimensionHeight().getMax(); return (int) getDimensionHeight().getMax();
@@ -340,7 +359,7 @@ public class IrisDimension extends IrisRegistrant {
KList<IrisRegion> r = new KList<>(); KList<IrisRegion> r = new KList<>();
for (String i : getRegions()) { for (String i : getRegions()) {
r.add(IrisData.loadAnyRegion(i)); r.add(IrisData.loadAnyRegion(i, getLoader()));
} }
return r; return r;
@@ -364,6 +383,17 @@ public class IrisDimension extends IrisRegistrant {
return r; return r;
} }
public KList<String> getPreProcessors(String type) {
return cachedPreProcessors.aquire(() -> {
KMap<String, KList<String>> preProcessors = new KMap<>();
for (var entry : globalPreProcessors) {
preProcessors.computeIfAbsent(entry.getType(), k -> new KList<>())
.addAll(entry.getScripts());
}
return preProcessors;
}).get(type);
}
public IrisGeneratorStyle getBiomeStyle(InferredType type) { public IrisGeneratorStyle getBiomeStyle(InferredType type) {
switch (type) { switch (type) {
case CAVE: case CAVE:
@@ -18,7 +18,10 @@
package com.volmit.iris.engine.object; package com.volmit.iris.engine.object;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineMode;
import com.volmit.iris.engine.object.annotations.Desc; import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.RegistryListResource;
import com.volmit.iris.engine.object.annotations.Snippet; import com.volmit.iris.engine.object.annotations.Snippet;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
@@ -35,4 +38,19 @@ public class IrisDimensionMode {
@Desc("The dimension type") @Desc("The dimension type")
private IrisDimensionModeType type = IrisDimensionModeType.OVERWORLD; 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")
private String script;
public EngineMode create(Engine engine) {
if (script == null) {
return type.create(engine);
}
Object result = engine.getExecution().evaluate(script);
if (result instanceof EngineMode) {
return (EngineMode) result;
}
throw new IllegalStateException("The script '" + script + "' did not return an engine mode!");
}
} }
@@ -146,7 +146,6 @@ public class IrisEffect {
@MinNumber(1) @MinNumber(1)
@Desc("The chance is 1 in CHANCE per interval") @Desc("The chance is 1 in CHANCE per interval")
private int chance = 50; private int chance = 50;
@ArrayType(min = 1, type = IrisCommandRegistry.class)
@Desc("Run commands, with configurable location parameters") @Desc("Run commands, with configurable location parameters")
private IrisCommandRegistry commandRegistry = null; private IrisCommandRegistry commandRegistry = null;
@@ -166,12 +166,12 @@ public class IrisEntity extends IrisRegistrant {
@Desc("Set to true if you want to apply all of the settings here to the mob, even though an external plugin has already done so. Scripts are always applied.") @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; private boolean applySettingsToCustomMobAnyways = false;
@Desc("Set the entity type to UNKNOWN, then define a script here which ends with the entity variable (the result). You can use Iris.getLocation() to find the target location. You can spawn any entity this way.") @Desc("Set the entity type to UNKNOWN, then define a script here which ends with the entity variable (the result). You can use location to find the target location. You can spawn any entity this way.\nFile extension: .spawn.kts")
@RegistryListResource(IrisScript.class) @RegistryListResource(IrisScript.class)
private String spawnerScript = ""; private String spawnerScript = "";
@ArrayType(min = 1, type = String.class) @ArrayType(min = 1, type = String.class)
@Desc("Set the entity type to UNKNOWN, then define a script here. You can use Iris.getLocation() to find the target location. You can spawn any entity this way.") @Desc("Executed post spawn you can modify the entity however you want with it\nFile extension: .postspawn.kts")
@RegistryListResource(IrisScript.class) @RegistryListResource(IrisScript.class)
private KList<String> postSpawnScripts = new KList<>(); private KList<String> postSpawnScripts = new KList<>();
@@ -213,9 +213,8 @@ public class IrisEntity extends IrisRegistrant {
if (!spawnerScript.isEmpty() && ee == null) { if (!spawnerScript.isEmpty() && ee == null) {
synchronized (this) { synchronized (this) {
gen.getExecution().getAPI().setLocation(at);
try { try {
ee = (Entity) gen.getExecution().evaluate(spawnerScript); ee = (Entity) gen.getExecution().spawnMob(spawnerScript, at);
} catch (Throwable ex) { } catch (Throwable ex) {
Iris.error("You must return an Entity in your scripts to use entity scripts!"); Iris.error("You must return an Entity in your scripts to use entity scripts!");
ex.printStackTrace(); ex.printStackTrace();
@@ -355,11 +354,8 @@ public class IrisEntity extends IrisRegistrant {
if (postSpawnScripts.isNotEmpty()) { if (postSpawnScripts.isNotEmpty()) {
synchronized (this) { synchronized (this) {
gen.getExecution().getAPI().setLocation(at);
gen.getExecution().getAPI().setEntity(ee);
for (String i : postSpawnScripts) { for (String i : postSpawnScripts) {
gen.getExecution().execute(i); gen.getExecution().postSpawnMob(i, at, ee);
} }
} }
} }
@@ -18,6 +18,7 @@
package com.volmit.iris.engine.object; package com.volmit.iris.engine.object;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.engine.object.annotations.*;
@@ -25,6 +26,7 @@ import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG; import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.noise.ExpressionNoise; import com.volmit.iris.util.noise.ExpressionNoise;
import com.volmit.iris.util.noise.ImageNoise; import com.volmit.iris.util.noise.ImageNoise;
import com.volmit.iris.util.noise.NoiseGenerator;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@@ -56,6 +58,9 @@ public class IrisGeneratorStyle {
private String expression = null; private String expression = null;
@Desc("Use an Image map instead of a generated value") @Desc("Use an Image map instead of a generated value")
private IrisImageMap imageMap = null; private IrisImageMap imageMap = null;
@Desc("Instead of using the style property, use a custom noise generator to represent this style.\nFile extension: .noise.kts")
@RegistryListResource(IrisScript.class)
private String script = null;
@MinNumber(0.00001) @MinNumber(0.00001)
@Desc("The Output multiplier. Only used if parent is fracture.") @Desc("The Output multiplier. Only used if parent is fracture.")
private double multiplier = 1; private double multiplier = 1;
@@ -93,40 +98,27 @@ public class IrisGeneratorStyle {
public CNG createNoCache(RNG rng, IrisData data, boolean actuallyCached) { public CNG createNoCache(RNG rng, IrisData data, boolean actuallyCached) {
String cacheKey = hash() + ""; String cacheKey = hash() + "";
CNG cng = null;
if (getExpression() != null) { if (getExpression() != null) {
IrisExpression e = data.getExpressionLoader().load(getExpression()); IrisExpression e = data.getExpressionLoader().load(getExpression());
if (e != null) { if (e != null) {
CNG cng = new CNG(rng, new ExpressionNoise(rng, e), 1D, 1) cng = new CNG(rng, new ExpressionNoise(rng, e), 1D, 1).bake();
.bake().scale(1D / zoom).pow(exponent).bake();
cng.setTrueFracturing(axialFracturing);
if (fracture != null) {
cng.fractureWith(fracture.create(rng.nextParallelRNG(2934), data), fracture.getMultiplier());
}
if (cellularFrequency > 0) {
return cng.cellularize(rng.nextParallelRNG(884466), cellularFrequency).scale(1D / cellularZoom).bake();
}
return cng;
} }
} else if (getImageMap() != null) { } else if (getImageMap() != null) {
CNG cng = new CNG(rng, new ImageNoise(data, getImageMap()), 1D, 1).bake().scale(1D / zoom).pow(exponent).bake(); cng = new CNG(rng, new ImageNoise(data, getImageMap()), 1D, 1).bake();
cng.setTrueFracturing(axialFracturing); } else if (getScript() != null) {
Object result = data.getEnvironment().createNoise(getScript(), rng);
if (fracture != null) { if (result == null) Iris.warn("Failed to create noise from script: " + getScript());
cng.fractureWith(fracture.create(rng.nextParallelRNG(2934), data), fracture.getMultiplier()); if (result instanceof NoiseGenerator generator) {
cng = new CNG(rng, generator, 1D, 1).bake();
} }
if (cellularFrequency > 0) {
return cng.cellularize(rng.nextParallelRNG(884466), cellularFrequency).scale(1D / cellularZoom).bake();
}
return cng;
} }
CNG cng = style.create(rng).bake().scale(1D / zoom).pow(exponent).bake(); if (cng == null) {
cng = style.create(rng).bake();
}
cng = cng.scale(1D / zoom).pow(exponent).bake();
cng.setTrueFracturing(axialFracturing); cng.setTrueFracturing(axialFracturing);
if (fracture != null) { if (fracture != null) {
@@ -50,8 +50,7 @@ public class IrisJigsawPiece extends IrisRegistrant {
@Desc("The object this piece represents") @Desc("The object this piece represents")
private String object = ""; private String object = "";
@Required @ArrayType(type = IrisJigsawPieceConnector.class)
@ArrayType(type = IrisJigsawPieceConnector.class, min = 1)
@Desc("The connectors this object contains") @Desc("The connectors this object contains")
private KList<IrisJigsawPieceConnector> connectors = new KList<>(); private KList<IrisJigsawPieceConnector> connectors = new KList<>();
@@ -1,43 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine.object;
import com.volmit.iris.engine.object.annotations.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Snippet("jigsaw-placer")
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Desc("Represents a jigsaw placement")
@Data
public class IrisJigsawPlacement {
@RegistryListResource(IrisJigsawStructure.class)
@Required
@Desc("The jigsaw structure to use")
private String structure = "";
@Required
@MinNumber(1)
@Desc("The rarity for this jigsaw structure to place on a per chunk basis")
private int rarity = 29;
}
@@ -23,6 +23,7 @@ import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.engine.object.annotations.functions.StructureKeyFunction; import com.volmit.iris.engine.object.annotations.functions.StructureKeyFunction;
import com.volmit.iris.engine.object.annotations.functions.StructureKeyOrTagFunction;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
@@ -40,6 +41,11 @@ import lombok.experimental.Accessors;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public class IrisJigsawStructure extends IrisRegistrant { public class IrisJigsawStructure extends IrisRegistrant {
@RegistryListFunction(StructureKeyFunction.class)
@ArrayType(min = 1, type = String.class)
@Desc("The datapack structures. Randomply chooses a structure to place\nIgnores every other setting")
private KList<String> datapackStructures = new KList<>();
@RegistryListResource(IrisJigsawPiece.class) @RegistryListResource(IrisJigsawPiece.class)
@Required @Required
@ArrayType(min = 1, type = String.class) @ArrayType(min = 1, type = String.class)
@@ -70,7 +76,7 @@ public class IrisJigsawStructure extends IrisRegistrant {
@Desc("Set to true to prevent rotating the initial structure piece") @Desc("Set to true to prevent rotating the initial structure piece")
private boolean disableInitialRotation = false; private boolean disableInitialRotation = false;
@RegistryListFunction(StructureKeyFunction.class) @RegistryListFunction(StructureKeyOrTagFunction.class)
@Desc("The minecraft key to use when creating treasure maps") @Desc("The minecraft key to use when creating treasure maps")
private String structureKey = null; private String structureKey = null;
@@ -117,6 +123,10 @@ public class IrisJigsawStructure extends IrisRegistrant {
public int getMaxDimension() { public int getMaxDimension() {
return maxDimension.aquire(() -> { return maxDimension.aquire(() -> {
if (datapackStructures.isNotEmpty()) {
return 0;
}
if (useMaxPieceSizeForParallaxRadius) { if (useMaxPieceSizeForParallaxRadius) {
int max = 0; int max = 0;
KList<String> pools = new KList<>(); KList<String> pools = new KList<>();
@@ -0,0 +1,25 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.engine.object.annotations.functions.ResourceLoadersFunction;
import com.volmit.iris.util.collection.KList;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Desc("Represents global preprocessors")
public class IrisPreProcessors {
@Required
@Desc("The preprocessor type")
@RegistryListFunction(ResourceLoadersFunction.class)
private String type = "dimension";
@Required
@Desc("The preprocessor scripts\nFile extension: .proc.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> scripts = new KList<>();
}
@@ -346,7 +346,7 @@ public class IrisRegion extends IrisRegistrant implements IRare {
continue; continue;
} }
IrisBiome biome = IrisData.loadAnyBiome(i); IrisBiome biome = IrisData.loadAnyBiome(i, getLoader());
names.remove(i); names.remove(i);
if (biome == null) { if (biome == null) {
@@ -0,0 +1,74 @@
package com.volmit.iris.engine.object;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineAssignedComponent;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.function.BiPredicate;
public class IrisStructurePopulator extends EngineAssignedComponent {
private final CNG cng;
private final long mantle;
private final long jigsaw;
public IrisStructurePopulator(Engine engine) {
super(engine, "Datapack Structures");
mantle = engine.getSeedManager().getMantle();
jigsaw = engine.getSeedManager().getJigsaw();
cng = NoiseStyle.STATIC.create(new RNG(jigsaw));
}
@ChunkCoordinates
public void populateStructures(int x, int z, BiPredicate<String, Boolean> placer) {
int bX = x << 4, bZ = z << 4;
var dimension = getDimension();
var region = getEngine().getRegion(bX + 8, bZ + 8);
var biome = getEngine().getSurfaceBiome(bX + 8, bZ + 8);
var loader = getData().getJigsawStructureLoader();
long seed = cng.fit(Integer.MIN_VALUE, Integer.MAX_VALUE, x, z);
if (dimension.getStronghold() != null) {
var list = getDimension().getStrongholds(mantle);
if (list != null && list.contains(new Position2(bX, bZ))) {
place(placer, loader.load(dimension.getStronghold()), new RNG(seed), true);
return;
}
}
boolean placed = place(placer, biome.getJigsawStructures(), seed, x, z);
if (!placed) placed = place(placer, region.getJigsawStructures(), seed, x, z);
if (!placed) place(placer, dimension.getJigsawStructures(), seed, x, z);
}
private boolean place(BiPredicate<String, Boolean> placer, KList<IrisJigsawStructurePlacement> placements, long seed, int x, int z) {
var placement = pick(placements, seed, x, z);
if (placement == null) return false;
return place(placer, getData().getJigsawStructureLoader().load(placement.getStructure()), new RNG(seed), false);
}
@Nullable
@ChunkCoordinates
private IrisJigsawStructurePlacement pick(List<IrisJigsawStructurePlacement> structures, long seed, int x, int z) {
return IRare.pick(structures.stream()
.filter(p -> p.shouldPlace(getData(), getDimension().getJigsawStructureDivisor(), jigsaw, x, z))
.toList(), new RNG(seed).nextDouble());
}
@ChunkCoordinates
private boolean place(BiPredicate<String, Boolean> placer, IrisJigsawStructure structure, RNG rng, boolean ignoreBiomes) {
if (structure == null || structure.getDatapackStructures().isEmpty()) return false;
var keys = structure.getDatapackStructures().shuffleCopy(rng);
while (keys.isNotEmpty()) {
String key = keys.removeFirst();
if (key != null && placer.test(key, ignoreBiomes || structure.isForcePlace()))
return true;
}
return false;
}
}
@@ -0,0 +1,12 @@
package com.volmit.iris.engine.object.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface RegistryMapBlockState {
String value();
}
@@ -6,7 +6,7 @@ import com.volmit.iris.engine.framework.ListFunction;
import com.volmit.iris.engine.mantle.ComponentFlag; import com.volmit.iris.engine.mantle.ComponentFlag;
import com.volmit.iris.engine.mantle.MantleComponent; import com.volmit.iris.engine.mantle.MantleComponent;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.mantle.flag.MantleFlag;
import java.util.Objects; import java.util.Objects;
@@ -0,0 +1,28 @@
package com.volmit.iris.engine.object.annotations.functions;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.engine.framework.ListFunction;
import com.volmit.iris.util.collection.KList;
public class ResourceLoadersFunction implements ListFunction<KList<String>> {
@Override
public String key() {
return "resource-loader";
}
@Override
public String fancyName() {
return "Resource Loader";
}
@Override
public KList<String> apply(IrisData data) {
return data.getLoaders()
.values()
.stream()
.filter(rl -> ResourceLoader.class.equals(rl.getClass()))
.map(ResourceLoader::getFolderName)
.collect(KList.collector());
}
}
@@ -18,6 +18,6 @@ public class StructureKeyFunction implements ListFunction<KList<String>> {
@Override @Override
public KList<String> apply(IrisData irisData) { public KList<String> apply(IrisData irisData) {
return INMS.get().getStructureKeys(); return INMS.get().getStructureKeys().removeWhere(t -> t.startsWith("#"));
} }
} }
@@ -0,0 +1,23 @@
package com.volmit.iris.engine.object.annotations.functions;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.engine.framework.ListFunction;
import com.volmit.iris.util.collection.KList;
public class StructureKeyOrTagFunction implements ListFunction<KList<String>> {
@Override
public String key() {
return "structure-key-or-tag";
}
@Override
public String fancyName() {
return "Structure Key or Tag";
}
@Override
public KList<String> apply(IrisData irisData) {
return INMS.get().getStructureKeys();
}
}
@@ -170,15 +170,12 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
if (dimension == null) { if (dimension == null) {
Iris.error("Oh No! There's no pack in " + data.getDataFolder().getPath() + " or... there's no dimension for the key " + dimensionKey); Iris.error("Oh No! There's no pack in " + data.getDataFolder().getPath() + " or... there's no dimension for the key " + dimensionKey);
IrisDimension test = IrisData.loadAnyDimension(dimensionKey); IrisDimension test = IrisData.loadAnyDimension(dimensionKey, null);
if (test != null) { if (test != null) {
Iris.warn("Looks like " + dimensionKey + " exists in " + test.getLoadFile().getPath() + " "); Iris.warn("Looks like " + dimensionKey + " exists in " + test.getLoadFile().getPath() + " ");
Iris.service(StudioSVC.class).installIntoWorld(Iris.getSender(), dimensionKey, dataLocation.getParentFile().getParentFile()); test = Iris.service(StudioSVC.class).installInto(Iris.getSender(), dimensionKey, dataLocation);
Iris.warn("Attempted to install into " + data.getDataFolder().getPath()); Iris.warn("Attempted to install into " + data.getDataFolder().getPath());
data.dump();
data.clearLists();
test = data.getDimensionLoader().load(dimensionKey);
if (test != null) { if (test != null) {
Iris.success("Woo! Patched the Engine!"); Iris.success("Woo! Patched the Engine!");
@@ -240,11 +237,12 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
} }
}, syncExecutor)); }, syncExecutor));
} }
futures.add(CompletableFuture.runAsync(() -> INMS.get().placeStructures(c), syncExecutor));
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenRunAsync(() -> { .thenRunAsync(() -> {
c.removePluginChunkTicket(Iris.instance); c.removePluginChunkTicket(Iris.instance);
c.unload(); engine.getWorldManager().onChunkLoad(c, true);
}, syncExecutor) }, syncExecutor)
.get(); .get();
Iris.debug("Regenerated " + x + " " + z); Iris.debug("Regenerated " + x + " " + z);
@@ -356,16 +354,16 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
@Override @Override
public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) { public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) {
try { try {
getEngine(world); Engine engine = getEngine(world);
computeStudioGenerator(); computeStudioGenerator();
TerrainChunk tc = TerrainChunk.create(d, new IrisBiomeStorage()); TerrainChunk tc = TerrainChunk.create(d, new IrisBiomeStorage());
this.world.bind(world); this.world.bind(world);
if (studioGenerator != null) { if (studioGenerator != null) {
studioGenerator.generateChunk(getEngine(), tc, x, z); studioGenerator.generateChunk(engine, tc, x, z);
} else { } else {
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc); ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight()); BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight());
getEngine().generate(x << 4, z << 4, blocks, biomes, IrisSettings.get().getGenerator().useMulticore); engine.generate(x << 4, z << 4, blocks, biomes, IrisSettings.get().getGenerator().useMulticore);
blocks.apply(); blocks.apply();
biomes.apply(); biomes.apply();
} }
@@ -1,96 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine.scripting;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.engine.IrisComplex;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisExpression;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
@Data
@EqualsAndHashCode(exclude = "engine")
@ToString(exclude = "engine")
public class IrisScriptingAPI {
private final Engine engine;
private IrisRegistrant preprocessorObject;
private double x = 0;
private double y = 0;
private double z = 0;
private Location location;
private Entity entity;
public IrisScriptingAPI(Engine engine) {
this.engine = engine;
}
public IrisData getData() {
return getEngine().getData();
}
public IrisComplex getComplex() {
return getEngine().getComplex();
}
public long getSeed() {
return getEngine().getSeedManager().getScript();
}
public double expression(String expressionName, double x, double y, double z) {
IrisExpression expression = getData().getExpressionLoader().load(expressionName);
return expression.evaluate(getComplex().getRng(), x, y, z);
}
public double expression(String expressionName, double x, double z) {
IrisExpression expression = getData().getExpressionLoader().load(expressionName);
return expression.evaluate(getComplex().getRng(), x, z);
}
public IrisBiome getBiomeAt(int x, int z) {
return getEngine().getSurfaceBiome(x, z);
}
public IrisDimension getDimension() {
return getEngine().getDimension();
}
public void info(String log) {
Iris.info(log);
}
public void debug(String log) {
Iris.debug(log);
}
public void warn(String log) {
Iris.warn(log);
}
public void error(String log) {
Iris.error(log);
}
}
@@ -23,15 +23,11 @@ import lombok.NonNull;
import lombok.Setter; import lombok.Setter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.scoreboard.DisplaySlot; import org.bukkit.scoreboard.*;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.scoreboard.Team;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
/** /**
@@ -42,7 +38,7 @@ public class Board {
private static final String[] CACHED_ENTRIES = new String[C.values().length]; private static final String[] CACHED_ENTRIES = new String[C.values().length];
private static final Function<String, String> APPLY_COLOR_TRANSLATION = s -> C.translateAlternateColorCodes('&', s); private static final UnaryOperator<String> APPLY_COLOR_TRANSLATION = s -> C.translateAlternateColorCodes('&', s);
static { static {
IntStream.range(0, 15).forEach(i -> CACHED_ENTRIES[i] = C.values()[i].toString() + C.RESET); IntStream.range(0, 15).forEach(i -> CACHED_ENTRIES[i] = C.values()[i].toString() + C.RESET);
@@ -54,13 +50,14 @@ public class Board {
private BoardSettings boardSettings; private BoardSettings boardSettings;
private boolean ready; private boolean ready;
@SuppressWarnings("deprecation")
public Board(@NonNull final Player player, final BoardSettings boardSettings) { public Board(@NonNull final Player player, final BoardSettings boardSettings) {
this.player = player; this.player = player;
this.boardSettings = boardSettings; this.boardSettings = boardSettings;
this.objective = this.getScoreboard().getObjective("board") == null ? this.getScoreboard().registerNewObjective("board", "dummy") : this.getScoreboard().getObjective("board"); var obj = getScoreboard().getObjective("board");
this.objective = obj == null ? this.getScoreboard().registerNewObjective("board", Criteria.DUMMY, "Iris") : obj;
this.objective.setDisplaySlot(DisplaySlot.SIDEBAR); this.objective.setDisplaySlot(DisplaySlot.SIDEBAR);
Team team = this.getScoreboard().getTeam("board") == null ? this.getScoreboard().registerNewTeam("board") : this.getScoreboard().getTeam("board"); Team team = getScoreboard().getTeam("board");
team = team == null ? getScoreboard().registerNewTeam("board") : team;
team.setAllowFriendlyFire(true); team.setAllowFriendlyFire(true);
team.setCanSeeFriendlyInvisibles(false); team.setCanSeeFriendlyInvisibles(false);
team.setPrefix(""); team.setPrefix("");
@@ -94,7 +91,8 @@ public class Board {
} }
// Getting their Scoreboard display from the Scoreboard Provider. // Getting their Scoreboard display from the Scoreboard Provider.
final List<String> entries = boardSettings.getBoardProvider().getLines(player).stream().map(APPLY_COLOR_TRANSLATION).collect(Collectors.toList()); final List<String> entries = boardSettings.getBoardProvider().getLines(player);
entries.replaceAll(APPLY_COLOR_TRANSLATION);
if (boardSettings.getScoreDirection() == ScoreDirection.UP) { if (boardSettings.getScoreDirection() == ScoreDirection.UP) {
Collections.reverse(entries); Collections.reverse(entries);
@@ -38,6 +38,12 @@ public class BoardUpdateTask extends BukkitRunnable {
@Override @Override
public void run() { public void run() {
boardManager.getScoreboards().entrySet().stream().filter(entrySet -> PLAYER_IS_ONLINE.test(entrySet.getKey())).forEach(entrySet -> entrySet.getValue().update()); for (var entry : boardManager.getScoreboards().entrySet()) {
if (!PLAYER_IS_ONLINE.test(entry.getKey())) {
continue;
}
entry.getValue().update();
}
} }
} }
@@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull;
import java.io.Serializable; import java.io.Serializable;
import java.util.AbstractSet; import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -30,13 +31,15 @@ public class KSet<T> extends AbstractSet<T> implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final ConcurrentHashMap<T, Boolean> map; private final ConcurrentHashMap<T, Boolean> map;
public KSet() { public KSet(Collection<? extends T> c) {
map = new ConcurrentHashMap<>(); this(c.size());
addAll(c);
} }
public KSet(Collection<? extends T> c) { @SafeVarargs
this(); public KSet(T... values) {
addAll(c); this(values.length);
addAll(Arrays.asList(values));
} }
public KSet(int initialCapacity, float loadFactor) { public KSet(int initialCapacity, float loadFactor) {
@@ -47,6 +50,13 @@ public class KSet<T> extends AbstractSet<T> implements Serializable {
map = new ConcurrentHashMap<>(initialCapacity); map = new ConcurrentHashMap<>(initialCapacity);
} }
public static <T> KSet<T> merge(Collection<? extends T> first, Collection<? extends T> second) {
var set = new KSet<T>();
set.addAll(first);
set.addAll(second);
return set;
}
@Override @Override
public int size() { public int size() {
return map.size(); return map.size();
@@ -22,6 +22,8 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.link.Identifier; import com.volmit.iris.core.link.Identifier;
import com.volmit.iris.core.link.data.DataType; import com.volmit.iris.core.link.data.DataType;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.container.BlockProperty;
import com.volmit.iris.core.service.ExternalDataSVC; import com.volmit.iris.core.service.ExternalDataSVC;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
@@ -35,10 +37,7 @@ import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.Leaves; import org.bukkit.block.data.type.Leaves;
import org.bukkit.block.data.type.PointedDripstone; import org.bukkit.block.data.type.PointedDripstone;
import java.util.Arrays; import java.util.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.bukkit.Material.*; import static org.bukkit.Material.*;
@@ -499,7 +498,7 @@ public class B {
if (!ix.startsWith("minecraft:") && ix.contains(":")) { if (!ix.startsWith("minecraft:") && ix.contains(":")) {
Identifier key = Identifier.fromString(ix); Identifier key = Identifier.fromString(ix);
Optional<BlockData> bd = Iris.service(ExternalDataSVC.class).getBlockData(key); Optional<BlockData> bd = Iris.service(ExternalDataSVC.class).getBlockData(key);
Iris.info("Loading block data " + key); Iris.debug("Loading block data " + key);
if (bd.isPresent()) if (bd.isPresent())
bx = bd.get(); bx = bd.get();
} }
@@ -680,6 +679,28 @@ public class B {
return bt.toArray(new String[0]); return bt.toArray(new String[0]);
} }
public synchronized static KMap<List<String>, List<BlockProperty>> getBlockStates() {
KMap<List<BlockProperty>, List<String>> flipped = new KMap<>();
INMS.get().getBlockProperties().forEach((k, v) -> {
flipped.computeIfAbsent(v, $ -> new KList<>()).add(k.getKey().toString());
});
var emptyStates = flipped.computeIfAbsent(new KList<>(0), $ -> new KList<>());
for (var pair : Iris.service(ExternalDataSVC.class).getAllBlockProperties()) {
if (pair.getB().isEmpty()) emptyStates.add(pair.getA().toString());
else flipped.computeIfAbsent(pair.getB(), $ -> new KList<>()).add(pair.getA().toString());
}
emptyStates.addAll(custom.k());
KMap<List<String>, List<BlockProperty>> states = new KMap<>();
flipped.forEach((k, v) -> {
var old = states.put(v, k);
if (old != null) Iris.error("Duplicate block state: " + v + " (" + old + " and " + k + ")");
});
return states;
}
public static String[] getItemTypes() { public static String[] getItemTypes() {
KList<String> bt = new KList<>(); KList<String> bt = new KList<>();
@@ -21,10 +21,16 @@ package com.volmit.iris.util.data;
import com.github.benmanes.caffeine.cache.CacheLoader; import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache; import com.github.benmanes.caffeine.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.Scheduler;
import com.volmit.iris.engine.framework.MeteredCache; import com.volmit.iris.engine.framework.MeteredCache;
import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.math.RollingSequence;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class KCache<K, V> implements MeteredCache { public class KCache<K, V> implements MeteredCache {
public static final ExecutorService EXECUTOR = Executors.newVirtualThreadPerTaskExecutor();
private final long max; private final long max;
private final LoadingCache<K, V> cache; private final LoadingCache<K, V> cache;
private final boolean fastDump; private final boolean fastDump;
@@ -46,6 +52,8 @@ public class KCache<K, V> implements MeteredCache {
return Caffeine return Caffeine
.newBuilder() .newBuilder()
.maximumSize(max) .maximumSize(max)
.scheduler(Scheduler.systemScheduler())
.executor(EXECUTOR)
.initialCapacity((int) (max)) .initialCapacity((int) (max))
.build((k) -> loader == null ? null : loader.load(k)); .build((k) -> loader == null ? null : loader.load(k));
} }
@@ -18,29 +18,20 @@
package com.volmit.iris.util.decree; package com.volmit.iris.util.decree;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.ChronoLatch;
public class DecreeContext { public class DecreeContext {
private static final ChronoLatch cl = new ChronoLatch(60000); private static final ThreadLocal<VolmitSender> context = new ThreadLocal<>();
private static final KMap<Thread, VolmitSender> context = new KMap<>();
public static VolmitSender get() { public static VolmitSender get() {
return context.get(Thread.currentThread()); return context.get();
} }
public static void touch(VolmitSender c) { public static void touch(VolmitSender c) {
synchronized (context) { context.set(c);
context.put(Thread.currentThread(), c); }
if (cl.flip()) { public static void remove() {
for (Thread i : context.k()) { context.remove();
if (!i.isAlive()) {
context.remove(i);
}
}
}
}
} }
} }
@@ -18,6 +18,7 @@
package com.volmit.iris.util.decree; package com.volmit.iris.util.decree;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.engine.platform.PlatformChunkGenerator;
@@ -34,6 +35,14 @@ public interface DecreeExecutor {
return sender().player(); return sender().player();
} }
default IrisData data() {
var access = access();
if (access != null) {
return access.getData();
}
return null;
}
default Engine engine() { default Engine engine() {
if (sender().isPlayer() && IrisToolbelt.access(sender().player().getWorld()) != null) { if (sender().isPlayer() && IrisToolbelt.access(sender().player().getWorld()) != null) {
PlatformChunkGenerator gen = IrisToolbelt.access(sender().player().getWorld()); PlatformChunkGenerator gen = IrisToolbelt.access(sender().player().getWorld());
@@ -23,7 +23,7 @@ import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
public interface DecreeParameterHandler<T> { public interface DecreeParameterHandler<T> extends DecreeExecutor {
/** /**
* Should return the possible values for this type * Should return the possible values for this type
* *
@@ -133,23 +133,32 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter {
default boolean call(VolmitSender sender, String[] args) { default boolean call(VolmitSender sender, String[] args) {
DecreeContext.touch(sender); DecreeContext.touch(sender);
return getRoot().invoke(sender, enhanceArgs(args)); try {
return getRoot().invoke(sender, enhanceArgs(args));
} finally {
DecreeContext.remove();
}
} }
@Nullable @Nullable
@Override @Override
default List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { default List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
KList<String> enhanced = new KList<>(args); DecreeContext.touch(new VolmitSender(sender));
KList<String> v = getRoot().tabComplete(enhanced, enhanced.toString(" ")); try {
v.removeDuplicates(); KList<String> enhanced = new KList<>(args);
KList<String> v = getRoot().tabComplete(enhanced, enhanced.toString(" "));
v.removeDuplicates();
if (sender instanceof Player) { if (sender instanceof Player) {
if (IrisSettings.get().getGeneral().isCommandSounds()) { if (IrisSettings.get().getGeneral().isCommandSounds()) {
((Player) sender).playSound(((Player) sender).getLocation(), Sound.BLOCK_AMETHYST_BLOCK_CHIME, 0.25f, RNG.r.f(0.125f, 1.95f)); ((Player) sender).playSound(((Player) sender).getLocation(), Sound.BLOCK_AMETHYST_BLOCK_CHIME, 0.25f, RNG.r.f(0.125f, 1.95f));
}
} }
}
return v; return v;
} finally {
DecreeContext.remove();
}
} }
@Override @Override
@@ -18,63 +18,12 @@
package com.volmit.iris.util.decree.handlers; package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import java.io.File; public class BiomeHandler extends RegistrantHandler<IrisBiome> {
import java.util.stream.Collectors; public BiomeHandler() {
super(IrisBiome.class, true);
public class BiomeHandler implements DecreeParameterHandler<IrisBiome> {
@Override
public KList<IrisBiome> getPossibilities() {
KMap<String, IrisBiome> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisBiome j : data.getBiomeLoader().loadAll(data.getBiomeLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisBiome dim) {
return dim.getLoadKey();
}
@Override
public IrisBiome parse(String in, boolean force) throws DecreeParsingException {
if (in.equals("null")) {
return null;
}
KList<IrisBiome> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Biome \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Biome \"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisBiome.class);
} }
@Override @Override
@@ -18,62 +18,12 @@
package com.volmit.iris.util.decree.handlers; package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisCave; import com.volmit.iris.engine.object.IrisCave;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import java.io.File; public class CaveHandler extends RegistrantHandler<IrisCave> {
import java.util.stream.Collectors; public CaveHandler() {
super(IrisCave.class, true);
public class CaveHandler implements DecreeParameterHandler<IrisCave> {
@Override
public KList<IrisCave> getPossibilities() {
KMap<String, IrisCave> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisCave j : data.getCaveLoader().loadAll(data.getCaveLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisCave dim) {
return dim.getLoadKey();
}
@Override
public IrisCave parse(String in, boolean force) throws DecreeParsingException {
if (in.equals("null")) {
return null;
}
KList<IrisCave> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Cave \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Cave\"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisCave.class);
} }
@Override @Override
@@ -18,65 +18,22 @@
package com.volmit.iris.util.decree.handlers; package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException; import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import java.io.File; public class DimensionHandler extends RegistrantHandler<IrisDimension> {
public DimensionHandler() {
public class DimensionHandler implements DecreeParameterHandler<IrisDimension> { super(IrisDimension.class, false);
@Override
public KList<IrisDimension> getPossibilities() {
KMap<String, IrisDimension> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisDimension j : data.getDimensionLoader().loadAll(data.getDimensionLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisDimension dim) {
return dim.getLoadKey();
} }
@Override @Override
public IrisDimension parse(String in, boolean force) throws DecreeParsingException { public IrisDimension parse(String in, boolean force) throws DecreeParsingException {
if (in.equalsIgnoreCase("default")) { if (in.equalsIgnoreCase("default")) {
return parse(IrisSettings.get().getGenerator().getDefaultWorldType()); return parse(IrisSettings.get().getGenerator().getDefaultWorldType());
} }
return super.parse(in, force);
KList<IrisDimension> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Dimension \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).toList().get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Dimension \"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisDimension.class);
} }
@Override @Override
@@ -18,84 +18,13 @@
package com.volmit.iris.util.decree.handlers; package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisEntity; import com.volmit.iris.engine.object.IrisEntity;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import java.io.File; public class EntityHandler extends RegistrantHandler<IrisEntity> {
import java.util.stream.Collectors;
public class EntityHandler implements DecreeParameterHandler<IrisEntity> { public EntityHandler() {
super(IrisEntity.class, false);
/**
* Should return the possible values for this type
*
* @return Possibilities for this type.
*/
@Override
public KList<IrisEntity> getPossibilities() {
KMap<String, IrisEntity> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisEntity j : data.getEntityLoader().loadAll(data.getEntityLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
/**
* Converting the type back to a string (inverse of the {@link #parse(String) parse} method)
*
* @param entity The input of the designated type to convert to a String
* @return The resulting string
*/
@Override
public String toString(IrisEntity entity) {
return entity.getLoadKey();
}
/**
* Should parse a String into the designated type
*
* @param in The string to parse
* @return The value extracted from the string, of the designated type
* @throws DecreeParsingException Thrown when the parsing fails (ex: "oop" translated to an integer throws this)
*/
@Override
public IrisEntity parse(String in, boolean force) throws DecreeParsingException {
KList<IrisEntity> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Entity \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Entity \"" + in + "\"");
}
}
/**
* Returns whether a certain type is supported by this handler<br>
*
* @param type The type to check
* @return True if supported, false if not
*/
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisEntity.class);
} }
@Override @Override
@@ -18,59 +18,12 @@
package com.volmit.iris.util.decree.handlers; package com.volmit.iris.util.decree.handlers;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisGenerator; import com.volmit.iris.engine.object.IrisGenerator;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeParameterHandler;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import java.io.File; public class GeneratorHandler extends RegistrantHandler<IrisGenerator> {
import java.util.stream.Collectors; public GeneratorHandler() {
super(IrisGenerator.class, false);
public class GeneratorHandler implements DecreeParameterHandler<IrisGenerator> {
@Override
public KList<IrisGenerator> getPossibilities() {
KMap<String, IrisGenerator> p = new KMap<>();
//noinspection ConstantConditions
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
if (i.isDirectory()) {
IrisData data = IrisData.get(i);
for (IrisGenerator j : data.getGeneratorLoader().loadAll(data.getGeneratorLoader().getPossibleKeys())) {
p.putIfAbsent(j.getLoadKey(), j);
}
data.close();
}
}
return p.v();
}
@Override
public String toString(IrisGenerator gen) {
return gen.getLoadKey();
}
@Override
public IrisGenerator parse(String in, boolean force) throws DecreeParsingException {
KList<IrisGenerator> options = getPossibilities(in);
if (options.isEmpty()) {
throw new DecreeParsingException("Unable to find Generator \"" + in + "\"");
}
try {
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
} catch (Throwable e) {
throw new DecreeParsingException("Unable to filter which Generator \"" + in + "\"");
}
}
@Override
public boolean supports(Class<?> type) {
return type.equals(IrisGenerator.class);
} }
@Override @Override
Loaded 100 of 178 files, more files were not shown because too many files have changed in this diff. Show more