mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-12-19 15:09:18 +00:00
Merge pull request #1221 from VolmitSoftware/feat/kts
Kotlin script engine
This commit is contained in:
@@ -62,7 +62,7 @@ val serverMinHeap = "2G"
|
||||
val serverMaxHeap = "8G"
|
||||
//Valid values are: none, truecolor, indexed256, indexed16, indexed8
|
||||
val color = "truecolor"
|
||||
val errorReporting = false
|
||||
val errorReporting = findProperty("errorReporting") as Boolean? ?: false
|
||||
|
||||
val nmsBindings = mapOf(
|
||||
"v1_21_R5" to "1.21.7-R0.1-SNAPSHOT",
|
||||
|
||||
@@ -28,6 +28,8 @@ plugins {
|
||||
alias(libs.plugins.sentry)
|
||||
alias(libs.plugins.slimjar)
|
||||
alias(libs.plugins.grgit)
|
||||
alias(libs.plugins.kotlin.jvm)
|
||||
alias(libs.plugins.kotlin.lombok)
|
||||
}
|
||||
|
||||
val apiVersion = "1.19"
|
||||
@@ -88,11 +90,23 @@ dependencies {
|
||||
slim(libs.zip)
|
||||
slim(libs.gson)
|
||||
slim(libs.asm)
|
||||
slim(libs.bsf)
|
||||
slim(libs.rhino)
|
||||
slim(libs.caffeine)
|
||||
slim(libs.byteBuddy.core)
|
||||
slim(libs.byteBuddy.agent)
|
||||
slim(libs.dom4j)
|
||||
slim(libs.jaxen)
|
||||
|
||||
// Script Engine
|
||||
slim(libs.kotlin.stdlib)
|
||||
slim(libs.kotlin.coroutines)
|
||||
slim(libs.kotlin.scripting.common)
|
||||
slim(libs.kotlin.scripting.jvm)
|
||||
slim(libs.kotlin.scripting.jvm.host)
|
||||
slim(libs.kotlin.scripting.dependencies.maven) {
|
||||
constraints {
|
||||
slim(libs.mavenCore)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
@@ -120,6 +134,11 @@ slimJar {
|
||||
relocate("net.kyori", "$lib.kyori")
|
||||
relocate("org.bstats", "$lib.metrics")
|
||||
relocate("io.sentry", "$lib.sentry")
|
||||
relocate("org.apache.maven", "$lib.maven")
|
||||
relocate("org.codehaus.plexus", "$lib.plexus")
|
||||
relocate("org.eclipse.sisu", "$lib.sisu")
|
||||
relocate("org.eclipse.aether", "$lib.aether")
|
||||
relocate("com.google.inject", "$lib.guice")
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
||||
@@ -47,7 +47,6 @@ import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.json.JSONArray;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.mantle.MantleChunk;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
@@ -233,9 +232,7 @@ public class CommandStudio implements DecreeExecutor {
|
||||
chunkMap.forEach((pos, chunk) -> {
|
||||
var c = mantle.getChunk(pos.getX(), pos.getZ()).use();
|
||||
try {
|
||||
for (MantleFlag flag : MantleFlag.values()) {
|
||||
c.flag(flag, chunk.isFlagged(flag));
|
||||
}
|
||||
c.copyFlags(chunk);
|
||||
c.clear();
|
||||
for (int y = 0; y < sections; y++) {
|
||||
var slice = chunk.get(y);
|
||||
@@ -370,7 +367,7 @@ public class CommandStudio implements DecreeExecutor {
|
||||
var sender = sender();
|
||||
int d = radius * 2;
|
||||
KMap<String, KList<Position2>> data = new KMap<>();
|
||||
var multiBurst = new MultiBurst("Distance Sampler", Thread.MIN_PRIORITY);
|
||||
var multiBurst = new MultiBurst("Distance Sampler");
|
||||
var executor = multiBurst.burst(radius * radius);
|
||||
|
||||
sender.sendMessage(C.GRAY + "Generating data...");
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.scripting.environment.PackEnvironment;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.object.*;
|
||||
@@ -33,6 +34,8 @@ import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.context.IrisContext;
|
||||
import com.volmit.iris.util.format.C;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlagAdapter;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
@@ -54,6 +57,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
private static final KMap<File, IrisData> dataLoaders = new KMap<>();
|
||||
private final File dataFolder;
|
||||
private final int id;
|
||||
private final PackEnvironment environment;
|
||||
private boolean closed = false;
|
||||
private ResourceLoader<IrisBiome> biomeLoader;
|
||||
private ResourceLoader<IrisLootTable> lootLoader;
|
||||
@@ -87,6 +91,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
this.engine = null;
|
||||
this.dataFolder = dataFolder;
|
||||
this.id = RNG.r.imax();
|
||||
this.environment = PackEnvironment.create(this);
|
||||
hotloaded();
|
||||
}
|
||||
|
||||
@@ -252,12 +257,20 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
}
|
||||
}
|
||||
|
||||
if (engine != null && t.getPreprocessors().isNotEmpty()) {
|
||||
if (engine == null) return;
|
||||
var global = engine.getDimension().getPreProcessors(t.getFolderName());
|
||||
var local = t.getPreprocessors();
|
||||
if ((global != null && global.isNotEmpty()) || local.isNotEmpty()) {
|
||||
synchronized (this) {
|
||||
engine.getExecution().getAPI().setPreprocessorObject(t);
|
||||
if (global != null) {
|
||||
for (String i : global) {
|
||||
engine.getExecution().preprocessObject(i, t);
|
||||
Iris.debug("Loader<" + C.GREEN + t.getTypeName() + C.LIGHT_PURPLE + "> iprocess " + C.YELLOW + t.getLoadKey() + C.LIGHT_PURPLE + " in <rainbow>" + i);
|
||||
}
|
||||
}
|
||||
|
||||
for (String i : t.getPreprocessors()) {
|
||||
engine.getExecution().execute(i);
|
||||
for (String i : local) {
|
||||
engine.getExecution().preprocessObject(i, t);
|
||||
Iris.debug("Loader<" + C.GREEN + t.getTypeName() + C.LIGHT_PURPLE + "> iprocess " + C.YELLOW + t.getLoadKey() + C.LIGHT_PURPLE + " in <rainbow>" + i);
|
||||
}
|
||||
}
|
||||
@@ -271,6 +284,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
public void close() {
|
||||
closed = true;
|
||||
dump();
|
||||
dataLoaders.remove(dataFolder);
|
||||
}
|
||||
|
||||
public IrisData copy() {
|
||||
@@ -311,12 +325,14 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
}
|
||||
|
||||
public synchronized void hotloaded() {
|
||||
environment.close();
|
||||
possibleSnippets = new KMap<>();
|
||||
builder = new GsonBuilder()
|
||||
.addDeserializationExclusionStrategy(this)
|
||||
.addSerializationExclusionStrategy(this)
|
||||
.setLenient()
|
||||
.registerTypeAdapterFactory(this)
|
||||
.registerTypeAdapter(MantleFlag.class, new MantleFlagAdapter())
|
||||
.setPrettyPrinting();
|
||||
loaders.clear();
|
||||
File packs = dataFolder;
|
||||
@@ -344,6 +360,10 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
builder.registerTypeAdapterFactory(KeyedType::createTypeAdapter);
|
||||
|
||||
gson = builder.create();
|
||||
dimensionLoader.streamAll()
|
||||
.map(IrisDimension::getDataScripts)
|
||||
.flatMap(KList::stream)
|
||||
.forEach(environment::execute);
|
||||
}
|
||||
|
||||
public void dump() {
|
||||
|
||||
@@ -45,6 +45,7 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
@@ -215,6 +216,10 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
|
||||
return j;
|
||||
}
|
||||
|
||||
public Stream<T> streamAll() {
|
||||
return streamAll(Arrays.stream(getPossibleKeys()));
|
||||
}
|
||||
|
||||
public Stream<T> streamAll(Stream<String> s) {
|
||||
return s.map(this::load);
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ public class ScriptResourceLoader extends ResourceLoader<IrisScript> {
|
||||
private Set<String> getKeysInDirectory(File directory) {
|
||||
Set<String> keys = new HashSet<>();
|
||||
for (File file : directory.listFiles()) {
|
||||
if (file.isFile() && file.getName().endsWith(".js")) {
|
||||
keys.add(file.getName().replaceAll("\\Q.js\\E", ""));
|
||||
if (file.isFile() && file.getName().endsWith(".kts")) {
|
||||
keys.add(file.getName().replaceAll("\\Q.kts\\E", ""));
|
||||
} else if (file.isDirectory()) {
|
||||
keys.addAll(getKeysInDirectory(file));
|
||||
}
|
||||
@@ -127,12 +127,12 @@ public class ScriptResourceLoader extends ResourceLoader<IrisScript> {
|
||||
public File findFile(String name) {
|
||||
for (File i : getFolders(name)) {
|
||||
for (File j : i.listFiles()) {
|
||||
if (j.isFile() && j.getName().endsWith(".js") && j.getName().split("\\Q.\\E")[0].equals(name)) {
|
||||
if (j.isFile() && j.getName().endsWith(".kts") && j.getName().split("\\Q.\\E")[0].equals(name)) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
|
||||
File file = new File(i, name + ".js");
|
||||
File file = new File(i, name + ".kts");
|
||||
|
||||
if (file.exists()) {
|
||||
return file;
|
||||
@@ -147,12 +147,12 @@ public class ScriptResourceLoader extends ResourceLoader<IrisScript> {
|
||||
private IrisScript loadRaw(String name) {
|
||||
for (File i : getFolders(name)) {
|
||||
for (File j : i.listFiles()) {
|
||||
if (j.isFile() && j.getName().endsWith(".js") && j.getName().split("\\Q.\\E")[0].equals(name)) {
|
||||
if (j.isFile() && j.getName().endsWith(".kts") && j.getName().split("\\Q.\\E")[0].equals(name)) {
|
||||
return loadFile(j, name);
|
||||
}
|
||||
}
|
||||
|
||||
File file = new File(i, name + ".js");
|
||||
File file = new File(i, name + ".kts");
|
||||
|
||||
if (file.exists()) {
|
||||
return loadFile(file, name);
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.volmit.iris.engine.data.cache.Cache;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RollingSequence;
|
||||
|
||||
@@ -14,12 +14,10 @@ import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.annotation.concurrent.NotThreadSafe;
|
||||
import java.io.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@NotThreadSafe
|
||||
@RequiredArgsConstructor
|
||||
class PregenCacheImpl implements PregenCache {
|
||||
private static final int SIZE = 32;
|
||||
|
||||
@@ -192,7 +192,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
||||
private class ServiceExecutor implements Executor {
|
||||
private final ExecutorService service = IrisSettings.get().getPregen().isUseVirtualThreads() ?
|
||||
Executors.newVirtualThreadPerTaskExecutor() :
|
||||
new MultiBurst("Iris Async Pregen", Thread.MIN_PRIORITY);
|
||||
new MultiBurst("Iris Async Pregen");
|
||||
|
||||
public void generate(int x, int z, PregenListener listener) {
|
||||
service.submit(() -> {
|
||||
|
||||
104
core/src/main/java/com/volmit/iris/core/project/Gradle.java
Normal file
104
core/src/main/java/com/volmit/iris/core/project/Gradle.java
Normal file
@@ -0,0 +1,104 @@
|
||||
package com.volmit.iris.core.project;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
import org.zeroturnaround.zip.ZipUtil;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class Gradle {
|
||||
private static final boolean WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
|
||||
private static final String[] ENVIRONMENT = createEnvironment();
|
||||
private static final String VERSION = "8.14.2";
|
||||
private static final String DISTRIBUTION_URL = "https://services.gradle.org/distributions/gradle-" + VERSION + "-bin.zip";
|
||||
private static final String HASH = IO.hash(DISTRIBUTION_URL);
|
||||
|
||||
public static synchronized void wrapper(File projectDir) {
|
||||
try {
|
||||
File settings = new File(projectDir, "settings.gradle.kts");
|
||||
if (!settings.exists()) settings.createNewFile();
|
||||
runGradle(projectDir, "wrapper");
|
||||
} catch (Throwable e) {
|
||||
Iris.error("Failed to install gradle wrapper!");
|
||||
e.printStackTrace();
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void runGradle(File projectDir, String... args) throws IOException, InterruptedException {
|
||||
File gradle = downloadGradle(false);
|
||||
String[] cmd = new String[args.length + 1];
|
||||
cmd[0] = gradle.getAbsolutePath();
|
||||
System.arraycopy(args, 0, cmd, 1, args.length);
|
||||
var process = Runtime.getRuntime().exec(cmd, ENVIRONMENT, projectDir);
|
||||
attach(process.getInputStream());
|
||||
attach(process.getErrorStream());
|
||||
var code = process.waitFor();
|
||||
if (code == 0) return;
|
||||
throw new RuntimeException("Gradle exited with code " + code);
|
||||
}
|
||||
|
||||
private static synchronized File downloadGradle(boolean force) {
|
||||
var folder = Iris.instance.getDataFolder("cache", HASH.substring(0, 2), HASH);
|
||||
if (force) {
|
||||
IO.delete(folder);
|
||||
folder.mkdirs();
|
||||
}
|
||||
|
||||
var bin = new File(folder, "gradle-" + VERSION + "/bin/gradle" + (WINDOWS ? ".bat" : ""));
|
||||
if (bin.exists()) {
|
||||
bin.setExecutable(true);
|
||||
return bin;
|
||||
}
|
||||
|
||||
try (var input = new BufferedInputStream(URI.create(DISTRIBUTION_URL).toURL().openStream())) {
|
||||
ZipUtil.unpack(input, folder);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("Failed to download gradle", e);
|
||||
}
|
||||
|
||||
bin.setExecutable(true);
|
||||
return bin;
|
||||
}
|
||||
|
||||
private static String[] createEnvironment() {
|
||||
var env = new HashMap<>(System.getenv());
|
||||
env.put("JAVA_HOME", findJavaHome());
|
||||
return env.entrySet()
|
||||
.stream()
|
||||
.map(e -> e.getKey() + "=" + e.getValue())
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
private static String findJavaHome() {
|
||||
String javaHome = System.getProperty("java.home");
|
||||
if (javaHome != null && new File(javaHome + "/bin/java" + (WINDOWS ? ".exe" : "")).exists()) {
|
||||
return javaHome;
|
||||
}
|
||||
|
||||
return ProcessHandle.current()
|
||||
.info()
|
||||
.command()
|
||||
.map(s -> new File(s).getAbsoluteFile().getParentFile().getParentFile())
|
||||
.flatMap(f -> f.exists() ? Optional.of(f.getAbsolutePath()) : Optional.empty())
|
||||
.orElseThrow(() -> new RuntimeException("Failed to find java home, please set java.home system property"));
|
||||
}
|
||||
|
||||
private static void attach(InputStream stream) {
|
||||
Thread.ofVirtual().start(() -> {
|
||||
try (var in = new Scanner(stream)) {
|
||||
while (in.hasNextLine()) {
|
||||
String line = in.nextLine();
|
||||
Iris.debug("[GRADLE] " + line);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.core.loader.IrisRegistrant;
|
||||
import com.volmit.iris.core.loader.ResourceLoader;
|
||||
import com.volmit.iris.core.scripting.environment.SimpleEnvironment;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
import com.volmit.iris.engine.object.*;
|
||||
import com.volmit.iris.engine.object.annotations.Snippet;
|
||||
@@ -49,6 +50,8 @@ import lombok.Data;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.World;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.Element;
|
||||
import org.zeroturnaround.zip.ZipUtil;
|
||||
|
||||
import java.awt.*;
|
||||
@@ -217,12 +220,7 @@ public class IrisProject {
|
||||
close();
|
||||
}
|
||||
|
||||
boolean hasError = false;
|
||||
|
||||
if (hasError) {
|
||||
return;
|
||||
}
|
||||
|
||||
J.a(() -> {
|
||||
IrisDimension d = IrisData.loadAnyDimension(getName());
|
||||
if (d == null) {
|
||||
sender.sendMessage("Can't find dimension: " + getName());
|
||||
@@ -231,10 +229,6 @@ public class IrisProject {
|
||||
sender.player().setGameMode(GameMode.SPECTATOR);
|
||||
}
|
||||
|
||||
openVSCode(sender);
|
||||
|
||||
|
||||
J.a(() -> {
|
||||
try {
|
||||
activeProvider = (PlatformChunkGenerator) IrisToolbelt.createWorld()
|
||||
.seed(seed)
|
||||
@@ -247,6 +241,8 @@ public class IrisProject {
|
||||
} catch (IrisException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
openVSCode(sender);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -359,6 +355,74 @@ public class IrisProject {
|
||||
settings.put("json.schemas", schemas);
|
||||
ws.put("settings", settings);
|
||||
|
||||
dm.getEnvironment().configureProject();
|
||||
File schemasFile = new File(path, ".idea" + File.separator + "jsonSchemas.xml");
|
||||
Document doc = IO.read(schemasFile);
|
||||
Element mappings = (Element) doc.selectSingleNode("//component[@name='JsonSchemaMappingsProjectConfiguration']");
|
||||
if (mappings == null) {
|
||||
mappings = doc.getRootElement()
|
||||
.addElement("component")
|
||||
.addAttribute("name", "JsonSchemaMappingsProjectConfiguration");
|
||||
}
|
||||
|
||||
Element state = (Element) mappings.selectSingleNode("state");
|
||||
if (state == null) state = mappings.addElement("state");
|
||||
|
||||
Element map = (Element) state.selectSingleNode("map");
|
||||
if (map == null) map = state.addElement("map");
|
||||
var schemaMap = new KMap<String, String>();
|
||||
schemas.forEach(element -> {
|
||||
if (!(element instanceof JSONObject obj))
|
||||
return;
|
||||
|
||||
String url = obj.getString("url");
|
||||
String dir = obj.getJSONArray("fileMatch").getString(0);
|
||||
schemaMap.put(url, dir.substring(1, dir.indexOf("/*")));
|
||||
});
|
||||
|
||||
map.selectNodes("entry/value/SchemaInfo/option[@name='relativePathToSchema']")
|
||||
.stream()
|
||||
.map(node -> node.valueOf("@value"))
|
||||
.forEach(schemaMap::remove);
|
||||
|
||||
var ideaSchemas = map;
|
||||
schemaMap.forEach((url, dir) -> {
|
||||
var genName = UUID.randomUUID().toString();
|
||||
|
||||
var info = ideaSchemas.addElement("entry")
|
||||
.addAttribute("key", genName)
|
||||
.addElement("value")
|
||||
.addElement("SchemaInfo");
|
||||
info.addElement("option")
|
||||
.addAttribute("name", "generatedName")
|
||||
.addAttribute("value", genName);
|
||||
info.addElement("option")
|
||||
.addAttribute("name", "name")
|
||||
.addAttribute("value", dir);
|
||||
info.addElement("option")
|
||||
.addAttribute("name", "relativePathToSchema")
|
||||
.addAttribute("value", url);
|
||||
|
||||
|
||||
var item = info.addElement("option")
|
||||
.addAttribute("name", "patterns")
|
||||
.addElement("list")
|
||||
.addElement("Item");
|
||||
item.addElement("option")
|
||||
.addAttribute("name", "directory")
|
||||
.addAttribute("value", "true");
|
||||
item.addElement("option")
|
||||
.addAttribute("name", "path")
|
||||
.addAttribute("value", dir);
|
||||
item.addElement("option")
|
||||
.addAttribute("name", "mappingKind")
|
||||
.addAttribute("value", "Directory");
|
||||
});
|
||||
if (!schemaMap.isEmpty()) {
|
||||
IO.write(schemasFile, doc);
|
||||
}
|
||||
Gradle.wrapper(path);
|
||||
|
||||
return ws;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,9 @@ public class SchemaBuilder {
|
||||
private JSONObject buildProperties(Class<?> c) {
|
||||
JSONObject o = new JSONObject();
|
||||
JSONObject properties = new JSONObject();
|
||||
o.put("description", getDescription(c));
|
||||
String desc = getDescription(c);
|
||||
o.put("description", desc);
|
||||
o.put("x-intellij-html-description", desc.replace("\n", "<br>"));
|
||||
o.put("type", getType(c));
|
||||
JSONArray required = new JSONArray();
|
||||
|
||||
@@ -520,11 +522,12 @@ public class SchemaBuilder {
|
||||
}
|
||||
|
||||
KList<String> d = new KList<>();
|
||||
d.add(k.getName());
|
||||
d.add(getFieldDescription(k));
|
||||
d.add(" ");
|
||||
d.add(fancyType);
|
||||
d.add(getDescription(k.getType()));
|
||||
d.add("<h>" + k.getName() + "</h>");
|
||||
d.add(getFieldDescription(k) + "<hr></hr>");
|
||||
d.add("<h>" + fancyType + "</h>");
|
||||
String typeDesc = getDescription(k.getType());
|
||||
boolean present = !typeDesc.isBlank();
|
||||
if (present) d.add(typeDesc);
|
||||
|
||||
Snippet snippet = k.getType().getDeclaredAnnotation(Snippet.class);
|
||||
if (snippet == null) {
|
||||
@@ -536,8 +539,9 @@ public class SchemaBuilder {
|
||||
|
||||
if (snippet != null) {
|
||||
String sm = snippet.value();
|
||||
d.add(" ");
|
||||
if (present) d.add(" ");
|
||||
d.add("You can instead specify \"snippet/" + sm + "/some-name.json\" to use a snippet file instead of specifying it here.");
|
||||
present = false;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -545,15 +549,13 @@ public class SchemaBuilder {
|
||||
Object value = k.get(cl.newInstance());
|
||||
|
||||
if (value != null) {
|
||||
if (present) d.add(" ");
|
||||
if (value instanceof List) {
|
||||
d.add(" ");
|
||||
d.add("* Default Value is an empty list");
|
||||
d.add(SYMBOL_LIMIT__N + " Default Value is an empty list");
|
||||
} else if (!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum()) && !KeyedType.isKeyed(cl)) {
|
||||
d.add(" ");
|
||||
d.add("* Default Value is a default object (create this object to see default properties)");
|
||||
d.add(SYMBOL_LIMIT__N + " Default Value is a default object (create this object to see default properties)");
|
||||
} else {
|
||||
d.add(" ");
|
||||
d.add("* Default Value is " + value);
|
||||
d.add(SYMBOL_LIMIT__N + " Default Value is " + value);
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
@@ -561,8 +563,14 @@ public class SchemaBuilder {
|
||||
}
|
||||
|
||||
description.forEach((g) -> d.add(g.trim()));
|
||||
String desc = d.toString("\n")
|
||||
.replace("<hr></hr>", "\n")
|
||||
.replace("<h>", "")
|
||||
.replace("</h>", "");
|
||||
String hDesc = d.toString("<br>");
|
||||
prop.put("type", type);
|
||||
prop.put("description", d.toString("\n"));
|
||||
prop.put("description", desc);
|
||||
prop.put("x-intellij-html-description", hDesc);
|
||||
return buildSnippet(prop, k.getType());
|
||||
}
|
||||
|
||||
@@ -588,8 +596,10 @@ public class SchemaBuilder {
|
||||
arr.put(prop);
|
||||
arr.put(str);
|
||||
str.put("description", prop.getString("description"));
|
||||
str.put("x-intellij-html-description", prop.getString("x-intellij-html-description"));
|
||||
anyOf.put("anyOf", arr);
|
||||
anyOf.put("description", prop.getString("description"));
|
||||
anyOf.put("x-intellij-html-description", prop.getString("x-intellij-html-description"));
|
||||
anyOf.put("!required", type.isAnnotationPresent(Required.class));
|
||||
|
||||
return anyOf;
|
||||
@@ -615,7 +625,9 @@ public class SchemaBuilder {
|
||||
String name = function.apply(gg);
|
||||
j.put("const", name);
|
||||
Desc dd = type.getField(name).getAnnotation(Desc.class);
|
||||
j.put("description", dd == null ? ("No Description for " + name) : dd.value());
|
||||
String desc = dd == null ? ("No Description for " + name) : dd.value();
|
||||
j.put("description", desc);
|
||||
j.put("x-intellij-html-description", desc.replace("\n", "<br>"));
|
||||
a.put(j);
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.volmit.iris.core.scripting.environment;
|
||||
|
||||
import com.volmit.iris.core.loader.IrisRegistrant;
|
||||
import com.volmit.iris.core.scripting.kotlin.environment.IrisExecutionEnvironment;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import lombok.NonNull;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface EngineEnvironment extends PackEnvironment {
|
||||
static EngineEnvironment create(@NonNull Engine engine) {
|
||||
return new IrisExecutionEnvironment(engine);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
Engine getEngine();
|
||||
|
||||
@Nullable
|
||||
Object spawnMob(@NonNull String script, @NonNull Location location);
|
||||
|
||||
void postSpawnMob(@NonNull String script, @NonNull Location location, @NonNull Entity mob);
|
||||
|
||||
void preprocessObject(@NonNull String script, @NonNull IrisRegistrant object);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -28,12 +28,12 @@ import com.volmit.iris.core.loader.ResourceLoader;
|
||||
import com.volmit.iris.core.nms.container.BlockPos;
|
||||
import com.volmit.iris.core.nms.container.Pair;
|
||||
import com.volmit.iris.core.project.IrisProject;
|
||||
import com.volmit.iris.core.scripting.environment.EngineEnvironment;
|
||||
import com.volmit.iris.core.service.PreservationSVC;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.engine.framework.*;
|
||||
import com.volmit.iris.engine.mantle.EngineMantle;
|
||||
import com.volmit.iris.engine.object.*;
|
||||
import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
|
||||
import com.volmit.iris.util.atomics.AtomicRollingSequence;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.context.ChunkContext;
|
||||
@@ -43,7 +43,7 @@ import com.volmit.iris.util.format.C;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.hunk.Hunk;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.matter.MatterStructurePOI;
|
||||
@@ -94,7 +94,7 @@ public class IrisEngine implements Engine {
|
||||
private CompletableFuture<Long> hash32;
|
||||
private EngineMode mode;
|
||||
private EngineEffects effects;
|
||||
private EngineExecutionEnvironment execution;
|
||||
private EngineEnvironment execution;
|
||||
private EngineWorldManager worldManager;
|
||||
private volatile int parallelism;
|
||||
private boolean failing;
|
||||
@@ -170,10 +170,11 @@ public class IrisEngine implements Engine {
|
||||
cacheId = RNG.r.nextInt();
|
||||
worldManager = new IrisWorldManager(this);
|
||||
complex = new IrisComplex(this);
|
||||
execution = new IrisExecutionEnvironment(this);
|
||||
execution = EngineEnvironment.create(this);
|
||||
effects = new IrisEngineEffects(this);
|
||||
hash32 = new CompletableFuture<>();
|
||||
setupMode();
|
||||
getDimension().getEngineScripts().forEach(execution::execute);
|
||||
J.a(this::computeBiomeMaxes);
|
||||
J.a(() -> {
|
||||
File[] roots = getData().getLoaders()
|
||||
@@ -199,7 +200,7 @@ public class IrisEngine implements Engine {
|
||||
mode.close();
|
||||
}
|
||||
|
||||
mode = getDimension().getMode().getType().create(this);
|
||||
mode = getDimension().getMode().create(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import lombok.*;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
|
||||
@@ -29,13 +29,13 @@ import com.volmit.iris.core.loader.IrisRegistrant;
|
||||
import com.volmit.iris.core.nms.container.BlockPos;
|
||||
import com.volmit.iris.core.nms.container.Pair;
|
||||
import com.volmit.iris.core.pregenerator.ChunkUpdater;
|
||||
import com.volmit.iris.core.scripting.environment.EngineEnvironment;
|
||||
import com.volmit.iris.core.service.ExternalDataSVC;
|
||||
import com.volmit.iris.engine.IrisComplex;
|
||||
import com.volmit.iris.engine.data.cache.Cache;
|
||||
import com.volmit.iris.engine.data.chunk.TerrainChunk;
|
||||
import com.volmit.iris.engine.mantle.EngineMantle;
|
||||
import com.volmit.iris.engine.object.*;
|
||||
import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.context.ChunkContext;
|
||||
@@ -48,7 +48,7 @@ import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.format.C;
|
||||
import com.volmit.iris.util.function.Function2;
|
||||
import com.volmit.iris.util.hunk.Hunk;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.BlockPosition;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
@@ -110,7 +110,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
|
||||
IrisContext getContext();
|
||||
|
||||
EngineExecutionEnvironment getExecution();
|
||||
EngineEnvironment getExecution();
|
||||
|
||||
double getMaxBiomeObjectDensity();
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@ import com.volmit.iris.engine.object.IrisObject;
|
||||
import com.volmit.iris.engine.object.IrisObjectPlacement;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.volmit.iris.engine.mantle;
|
||||
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.ReservedFlag;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -10,5 +10,5 @@ import java.lang.annotation.Target;
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ComponentFlag {
|
||||
MantleFlag value();
|
||||
ReservedFlag value();
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.hunk.Hunk;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.mantle.MantleChunk;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.matter.*;
|
||||
import com.volmit.iris.util.matter.slices.UpdateMatter;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
package com.volmit.iris.engine.mantle;
|
||||
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.volmit.iris.engine.object.IrisDimension;
|
||||
import com.volmit.iris.util.context.ChunkContext;
|
||||
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
@@ -28,17 +28,17 @@ import com.volmit.iris.engine.object.IrisCarving;
|
||||
import com.volmit.iris.engine.object.IrisRegion;
|
||||
import com.volmit.iris.util.context.ChunkContext;
|
||||
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.ReservedFlag;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ComponentFlag(MantleFlag.CARVED)
|
||||
@ComponentFlag(ReservedFlag.CARVED)
|
||||
public class MantleCarvingComponent extends IrisMantleComponent {
|
||||
private final int radius = computeRadius();
|
||||
|
||||
public MantleCarvingComponent(EngineMantle engineMantle) {
|
||||
super(engineMantle, MantleFlag.CARVED, 0);
|
||||
super(engineMantle, ReservedFlag.CARVED, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,17 +28,17 @@ import com.volmit.iris.engine.object.IrisFluidBodies;
|
||||
import com.volmit.iris.engine.object.IrisRegion;
|
||||
import com.volmit.iris.util.context.ChunkContext;
|
||||
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.ReservedFlag;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ComponentFlag(MantleFlag.FLUID_BODIES)
|
||||
@ComponentFlag(ReservedFlag.FLUID_BODIES)
|
||||
public class MantleFluidBodyComponent extends IrisMantleComponent {
|
||||
private final int radius = computeRadius();
|
||||
|
||||
public MantleFluidBodyComponent(EngineMantle engineMantle) {
|
||||
super(engineMantle, MantleFlag.FLUID_BODIES, 0);
|
||||
super(engineMantle, ReservedFlag.FLUID_BODIES, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,7 +30,7 @@ import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.context.ChunkContext;
|
||||
import com.volmit.iris.util.documentation.BlockCoordinates;
|
||||
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.ReservedFlag;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.matter.slices.container.JigsawStructuresContainer;
|
||||
@@ -40,14 +40,14 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ComponentFlag(MantleFlag.JIGSAW)
|
||||
@ComponentFlag(ReservedFlag.JIGSAW)
|
||||
public class MantleJigsawComponent extends IrisMantleComponent {
|
||||
@Getter
|
||||
private final int radius = computeRadius();
|
||||
private final CNG cng;
|
||||
|
||||
public MantleJigsawComponent(EngineMantle engineMantle) {
|
||||
super(engineMantle, MantleFlag.JIGSAW, 2);
|
||||
super(engineMantle, ReservedFlag.JIGSAW, 2);
|
||||
cng = NoiseStyle.STATIC.create(new RNG(jigsaw()));
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import com.volmit.iris.util.data.B;
|
||||
import com.volmit.iris.util.documentation.BlockCoordinates;
|
||||
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.ReservedFlag;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.matter.MatterStructurePOI;
|
||||
import com.volmit.iris.util.noise.CNG;
|
||||
@@ -48,12 +48,12 @@ import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Getter
|
||||
@ComponentFlag(MantleFlag.OBJECT)
|
||||
@ComponentFlag(ReservedFlag.OBJECT)
|
||||
public class MantleObjectComponent extends IrisMantleComponent {
|
||||
private final int radius = computeRadius();
|
||||
|
||||
public MantleObjectComponent(EngineMantle engineMantle) {
|
||||
super(engineMantle, MantleFlag.OBJECT, 1);
|
||||
super(engineMantle, ReservedFlag.OBJECT, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.volmit.iris.engine.framework.EngineAssignedModifier;
|
||||
import com.volmit.iris.util.context.ChunkContext;
|
||||
import com.volmit.iris.util.data.IrisCustomData;
|
||||
import com.volmit.iris.util.hunk.Hunk;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
@@ -30,11 +30,12 @@ import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.engine.object.annotations.*;
|
||||
import com.volmit.iris.engine.object.annotations.functions.ComponentFlagFunction;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.data.DataProvider;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.noise.CNG;
|
||||
@@ -68,6 +69,7 @@ public class IrisDimension extends IrisRegistrant {
|
||||
private final transient AtomicCache<Double> rad = new AtomicCache<>();
|
||||
private final transient AtomicCache<Boolean> featuresUsed = new AtomicCache<>();
|
||||
private final transient AtomicCache<KList<Position2>> strongholdsCache = new AtomicCache<>();
|
||||
private final transient AtomicCache<KMap<String, KList<String>>> cachedPreProcessors = new AtomicCache<>();
|
||||
@MinNumber(2)
|
||||
@Required
|
||||
@Desc("The human readable name of this dimension")
|
||||
@@ -241,9 +243,20 @@ public class IrisDimension extends IrisRegistrant {
|
||||
@Desc("The Subterrain Fluid Layer Height")
|
||||
private int caveLavaHeight = 8;
|
||||
@RegistryListFunction(ComponentFlagFunction.class)
|
||||
@ArrayType(type = MantleFlag.class)
|
||||
@ArrayType(type = String.class)
|
||||
@Desc("Collection of disabled components")
|
||||
private KList<MantleFlag> disabledComponents = new KList<>();
|
||||
@Desc("A list of globally applied pre-processors")
|
||||
@ArrayType(type = IrisPreProcessors.class)
|
||||
private KList<IrisPreProcessors> globalPreProcessors = new KList<>();
|
||||
@Desc("A list of scripts executed on engine setup")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@ArrayType(type = String.class, min = 1)
|
||||
private KList<String> engineScripts = new KList<>();
|
||||
@Desc("A list of scripts executed on data setup")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@ArrayType(type = String.class, min = 1)
|
||||
private KList<String> dataScripts = new KList<>();
|
||||
|
||||
public int getMaxHeight() {
|
||||
return (int) getDimensionHeight().getMax();
|
||||
@@ -364,6 +377,17 @@ public class IrisDimension extends IrisRegistrant {
|
||||
return r;
|
||||
}
|
||||
|
||||
public KList<String> getPreProcessors(String type) {
|
||||
return cachedPreProcessors.aquire(() -> {
|
||||
KMap<String, KList<String>> preProcessors = new KMap<>();
|
||||
for (var entry : globalPreProcessors) {
|
||||
preProcessors.computeIfAbsent(entry.getType(), k -> new KList<>())
|
||||
.addAll(entry.getScripts());
|
||||
}
|
||||
return preProcessors;
|
||||
}).get(type);
|
||||
}
|
||||
|
||||
public IrisGeneratorStyle getBiomeStyle(InferredType type) {
|
||||
switch (type) {
|
||||
case CAVE:
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
|
||||
package com.volmit.iris.engine.object;
|
||||
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.framework.EngineMode;
|
||||
import com.volmit.iris.engine.object.annotations.Desc;
|
||||
import com.volmit.iris.engine.object.annotations.RegistryListResource;
|
||||
import com.volmit.iris.engine.object.annotations.Snippet;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@@ -35,4 +38,19 @@ public class IrisDimensionMode {
|
||||
@Desc("The dimension type")
|
||||
private IrisDimensionModeType type = IrisDimensionModeType.OVERWORLD;
|
||||
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@Desc("The script to create the dimension mode instead of using provided types")
|
||||
private String script;
|
||||
|
||||
public EngineMode create(Engine engine) {
|
||||
if (script == null) {
|
||||
return type.create(engine);
|
||||
}
|
||||
Object result = engine.getExecution().evaluate(script);
|
||||
if (result instanceof EngineMode) {
|
||||
return (EngineMode) result;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("The script '" + script + "' did not return an engine mode!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,9 +213,8 @@ public class IrisEntity extends IrisRegistrant {
|
||||
|
||||
if (!spawnerScript.isEmpty() && ee == null) {
|
||||
synchronized (this) {
|
||||
gen.getExecution().getAPI().setLocation(at);
|
||||
try {
|
||||
ee = (Entity) gen.getExecution().evaluate(spawnerScript);
|
||||
ee = (Entity) gen.getExecution().spawnMob(spawnerScript, at);
|
||||
} catch (Throwable ex) {
|
||||
Iris.error("You must return an Entity in your scripts to use entity scripts!");
|
||||
ex.printStackTrace();
|
||||
@@ -355,11 +354,8 @@ public class IrisEntity extends IrisRegistrant {
|
||||
|
||||
if (postSpawnScripts.isNotEmpty()) {
|
||||
synchronized (this) {
|
||||
gen.getExecution().getAPI().setLocation(at);
|
||||
gen.getExecution().getAPI().setEntity(ee);
|
||||
|
||||
for (String i : postSpawnScripts) {
|
||||
gen.getExecution().execute(i);
|
||||
gen.getExecution().postSpawnMob(i, at, ee);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
package com.volmit.iris.engine.object;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.engine.object.annotations.*;
|
||||
@@ -25,6 +26,7 @@ import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.noise.CNG;
|
||||
import com.volmit.iris.util.noise.ExpressionNoise;
|
||||
import com.volmit.iris.util.noise.ImageNoise;
|
||||
import com.volmit.iris.util.noise.NoiseGenerator;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@@ -56,6 +58,9 @@ public class IrisGeneratorStyle {
|
||||
private String expression = null;
|
||||
@Desc("Use an Image map instead of a generated value")
|
||||
private IrisImageMap imageMap = null;
|
||||
@Desc("Instead of using the style property, use a custom noise generator to represent this style.")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
private String script = null;
|
||||
@MinNumber(0.00001)
|
||||
@Desc("The Output multiplier. Only used if parent is fracture.")
|
||||
private double multiplier = 1;
|
||||
@@ -93,40 +98,27 @@ public class IrisGeneratorStyle {
|
||||
public CNG createNoCache(RNG rng, IrisData data, boolean actuallyCached) {
|
||||
String cacheKey = hash() + "";
|
||||
|
||||
CNG cng = null;
|
||||
if (getExpression() != null) {
|
||||
IrisExpression e = data.getExpressionLoader().load(getExpression());
|
||||
|
||||
if (e != null) {
|
||||
CNG cng = new CNG(rng, new ExpressionNoise(rng, e), 1D, 1)
|
||||
.bake().scale(1D / zoom).pow(exponent).bake();
|
||||
cng.setTrueFracturing(axialFracturing);
|
||||
|
||||
if (fracture != null) {
|
||||
cng.fractureWith(fracture.create(rng.nextParallelRNG(2934), data), fracture.getMultiplier());
|
||||
}
|
||||
|
||||
if (cellularFrequency > 0) {
|
||||
return cng.cellularize(rng.nextParallelRNG(884466), cellularFrequency).scale(1D / cellularZoom).bake();
|
||||
}
|
||||
|
||||
return cng;
|
||||
cng = new CNG(rng, new ExpressionNoise(rng, e), 1D, 1).bake();
|
||||
}
|
||||
} else if (getImageMap() != null) {
|
||||
CNG cng = new CNG(rng, new ImageNoise(data, getImageMap()), 1D, 1).bake().scale(1D / zoom).pow(exponent).bake();
|
||||
cng.setTrueFracturing(axialFracturing);
|
||||
|
||||
if (fracture != null) {
|
||||
cng.fractureWith(fracture.create(rng.nextParallelRNG(2934), data), fracture.getMultiplier());
|
||||
cng = new CNG(rng, new ImageNoise(data, getImageMap()), 1D, 1).bake();
|
||||
} else if (getScript() != null) {
|
||||
Object result = data.getEnvironment().createNoise(getScript(), rng);
|
||||
if (result == null) Iris.warn("Failed to create noise from script: " + getScript());
|
||||
if (result instanceof NoiseGenerator generator) {
|
||||
cng = new CNG(rng, generator, 1D, 1).bake();
|
||||
}
|
||||
}
|
||||
|
||||
if (cellularFrequency > 0) {
|
||||
return cng.cellularize(rng.nextParallelRNG(884466), cellularFrequency).scale(1D / cellularZoom).bake();
|
||||
if (cng == null) {
|
||||
cng = style.create(rng).bake();
|
||||
}
|
||||
|
||||
return cng;
|
||||
}
|
||||
|
||||
CNG cng = style.create(rng).bake().scale(1D / zoom).pow(exponent).bake();
|
||||
cng = cng.scale(1D / zoom).pow(exponent).bake();
|
||||
cng.setTrueFracturing(axialFracturing);
|
||||
|
||||
if (fracture != null) {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.volmit.iris.engine.object;
|
||||
|
||||
import com.volmit.iris.engine.object.annotations.*;
|
||||
import com.volmit.iris.engine.object.annotations.functions.ResourceLoadersFunction;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Desc("Represents global preprocessors")
|
||||
public class IrisPreProcessors {
|
||||
@Required
|
||||
@Desc("The preprocessor type")
|
||||
@RegistryListFunction(ResourceLoadersFunction.class)
|
||||
private String type = "dimension";
|
||||
|
||||
@Required
|
||||
@Desc("The preprocessor scripts")
|
||||
@RegistryListResource(IrisScript.class)
|
||||
@ArrayType(type = String.class, min = 1)
|
||||
private KList<String> scripts = new KList<>();
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import com.volmit.iris.engine.framework.ListFunction;
|
||||
import com.volmit.iris.engine.mantle.ComponentFlag;
|
||||
import com.volmit.iris.engine.mantle.MantleComponent;
|
||||
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;
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -1,38 +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.engine.framework.Engine;
|
||||
import org.apache.bsf.BSFManager;
|
||||
|
||||
public interface EngineExecutionEnvironment {
|
||||
Engine getEngine();
|
||||
|
||||
IrisScriptingAPI getAPI();
|
||||
|
||||
BSFManager getManager();
|
||||
|
||||
void execute(String script);
|
||||
|
||||
Object evaluate(String script);
|
||||
|
||||
default void close() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,12 @@ import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import org.apache.commons.io.function.IOConsumer;
|
||||
import org.apache.commons.io.function.IOFunction;
|
||||
import lombok.SneakyThrows;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentHelper;
|
||||
import org.dom4j.io.OutputFormat;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.channels.Channels;
|
||||
@@ -1669,6 +1675,24 @@ public class IO {
|
||||
return (ch2 == -1);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static void write(File file, Document doc) {
|
||||
file.getParentFile().mkdirs();
|
||||
try (var writer = new FileWriter(file)) {
|
||||
new XMLWriter(writer, OutputFormat.createPrettyPrint())
|
||||
.write(doc);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static Document read(File file) {
|
||||
if (file.exists()) return new SAXReader().read(file);
|
||||
var doc = DocumentHelper.createDocument();
|
||||
doc.addElement("project")
|
||||
.addAttribute("version", "4");
|
||||
return doc;
|
||||
}
|
||||
|
||||
public static <T extends Closeable> void write(File file, IOFunction<FileOutputStream, T> builder, IOConsumer<T> action) throws IOException {
|
||||
File dir = new File(file.getParentFile(), ".tmp");
|
||||
dir.mkdirs();
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.function.Consumer4;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.mantle.io.IOWorker;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.matter.Matter;
|
||||
import com.volmit.iris.util.matter.MatterSlice;
|
||||
|
||||
@@ -24,9 +24,11 @@ import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||
import com.volmit.iris.util.documentation.ChunkRelativeBlockCoordinates;
|
||||
import com.volmit.iris.util.function.Consumer4;
|
||||
import com.volmit.iris.util.io.CountingDataInputStream;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.matter.IrisMatter;
|
||||
import com.volmit.iris.util.matter.Matter;
|
||||
import com.volmit.iris.util.matter.MatterSlice;
|
||||
import com.volmit.iris.util.parallel.AtomicBooleanArray;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -36,7 +38,6 @@ import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicIntegerArray;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
/**
|
||||
@@ -48,7 +49,7 @@ public class MantleChunk {
|
||||
private final int x;
|
||||
@Getter
|
||||
private final int z;
|
||||
private final AtomicIntegerArray flags;
|
||||
private final AtomicBooleanArray flags;
|
||||
private final Object[] flagLocks;
|
||||
private final AtomicReferenceArray<Matter> sections;
|
||||
private final Semaphore ref = new Semaphore(Integer.MAX_VALUE, true);
|
||||
@@ -62,13 +63,12 @@ public class MantleChunk {
|
||||
@ChunkCoordinates
|
||||
public MantleChunk(int sectionHeight, int x, int z) {
|
||||
sections = new AtomicReferenceArray<>(sectionHeight);
|
||||
flags = new AtomicIntegerArray(MantleFlag.values().length);
|
||||
flagLocks = new Object[MantleFlag.values().length];
|
||||
flags = new AtomicBooleanArray(MantleFlag.MAX_ORDINAL + 1);
|
||||
flagLocks = new Object[flags.length()];
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
|
||||
for (int i = 0; i < flags.length(); i++) {
|
||||
flags.set(i, 0);
|
||||
flagLocks[i] = new Object();
|
||||
}
|
||||
}
|
||||
@@ -84,10 +84,19 @@ public class MantleChunk {
|
||||
public MantleChunk(int version, int sectionHeight, CountingDataInputStream din) throws IOException {
|
||||
this(sectionHeight, din.readByte(), din.readByte());
|
||||
int s = din.readByte();
|
||||
int l = version < 0 ? flags.length() : Varint.readUnsignedVarInt(din);
|
||||
int l = version < 0 ? MantleFlag.RESERVED_FLAGS : Varint.readUnsignedVarInt(din);
|
||||
|
||||
if (version >= 1) {
|
||||
for (int i = 0; i < l;) {
|
||||
byte f = din.readByte();
|
||||
for (int j = 0; j < Byte.SIZE && i < flags.length(); j++, i++) {
|
||||
flags.set(i, (f & (1 << j)) != 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < flags.length() && i < l; i++) {
|
||||
flags.set(i, din.readBoolean() ? 1 : 0);
|
||||
flags.set(i, din.readBoolean());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < s; i++) {
|
||||
@@ -145,9 +154,17 @@ public class MantleChunk {
|
||||
ref.release();
|
||||
}
|
||||
|
||||
public void copyFlags(MantleChunk chunk) {
|
||||
use();
|
||||
for (int i = 0; i < flags.length(); i++) {
|
||||
flags.set(i, chunk.flags.get(i));
|
||||
}
|
||||
release();
|
||||
}
|
||||
|
||||
public void flag(MantleFlag flag, boolean f) {
|
||||
if (closed.get()) throw new IllegalStateException("Chunk is closed!");
|
||||
flags.set(flag.ordinal(), f ? 1 : 0);
|
||||
flags.set(flag.ordinal(), f);
|
||||
}
|
||||
|
||||
public void raiseFlag(MantleFlag flag, Runnable r) {
|
||||
@@ -158,14 +175,14 @@ public class MantleChunk {
|
||||
if (closed.get()) throw new IllegalStateException("Chunk is closed!");
|
||||
if (guard != null && isFlagged(guard)) return;
|
||||
synchronized (flagLocks[flag.ordinal()]) {
|
||||
if (flags.getAndSet(flag.ordinal(), 1) == 0) {
|
||||
if (flags.compareAndSet(flag.ordinal(), false, true)) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFlagged(MantleFlag flag) {
|
||||
return flags.get(flag.ordinal()) == 1;
|
||||
return flags.get(flag.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,10 +266,15 @@ public class MantleChunk {
|
||||
dos.writeByte(x);
|
||||
dos.writeByte(z);
|
||||
dos.writeByte(sections.length());
|
||||
Varint.writeUnsignedVarInt(flags.length(), dos);
|
||||
Varint.writeUnsignedVarInt(Math.ceilDiv(flags.length(), Byte.SIZE), dos);
|
||||
|
||||
for (int i = 0; i < flags.length(); i++) {
|
||||
dos.writeBoolean(flags.get(i) == 1);
|
||||
int count = flags.length();
|
||||
for (int i = 0; i < count;) {
|
||||
int f = 0;
|
||||
for (int j = 0; j < Byte.SIZE && i < flags.length(); j++, i++) {
|
||||
f |= flags.get(i) ? (1 << j) : 0;
|
||||
}
|
||||
dos.write(f);
|
||||
}
|
||||
|
||||
var bytes = new ByteArrayOutputStream(8192);
|
||||
|
||||
@@ -1,44 +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.util.mantle;
|
||||
|
||||
import com.volmit.iris.util.collection.StateList;
|
||||
|
||||
public enum MantleFlag {
|
||||
OBJECT,
|
||||
UPDATE,
|
||||
JIGSAW,
|
||||
FEATURE,
|
||||
INITIAL_SPAWNED,
|
||||
REAL,
|
||||
CARVED,
|
||||
FLUID_BODIES,
|
||||
INITIAL_SPAWNED_MARKER,
|
||||
CLEANED,
|
||||
PLANNED,
|
||||
ETCHED,
|
||||
TILE,
|
||||
CUSTOM,
|
||||
DISCOVERED,
|
||||
CUSTOM_ACTIVE;
|
||||
|
||||
static StateList getStateList() {
|
||||
return new StateList(MantleFlag.values());
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
public class TectonicPlate {
|
||||
private static final ThreadLocal<Boolean> errors = ThreadLocal.withInitial(() -> false);
|
||||
public static final int MISSING = -1;
|
||||
public static final int CURRENT = 0;
|
||||
public static final int CURRENT = 1;
|
||||
|
||||
private final int sectionHeight;
|
||||
private final AtomicReferenceArray<MantleChunk> chunks;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.volmit.iris.util.mantle.flag;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
record CustomFlag(String name, int ordinal) implements MantleFlag {
|
||||
|
||||
@Override
|
||||
public @NotNull String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCustom() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (!(object instanceof CustomFlag that))
|
||||
return false;
|
||||
return ordinal == that.ordinal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ordinal;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.util.mantle.flag;
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
public sealed interface MantleFlag permits CustomFlag, ReservedFlag {
|
||||
int MIN_ORDINAL = 64;
|
||||
int MAX_ORDINAL = 255;
|
||||
|
||||
MantleFlag OBJECT = ReservedFlag.OBJECT;
|
||||
MantleFlag UPDATE = ReservedFlag.UPDATE;
|
||||
MantleFlag JIGSAW = ReservedFlag.JIGSAW;
|
||||
MantleFlag FEATURE = ReservedFlag.FEATURE;
|
||||
MantleFlag INITIAL_SPAWNED = ReservedFlag.INITIAL_SPAWNED;
|
||||
MantleFlag REAL = ReservedFlag.REAL;
|
||||
MantleFlag CARVED = ReservedFlag.CARVED;
|
||||
MantleFlag FLUID_BODIES = ReservedFlag.FLUID_BODIES;
|
||||
MantleFlag INITIAL_SPAWNED_MARKER = ReservedFlag.INITIAL_SPAWNED_MARKER;
|
||||
MantleFlag CLEANED = ReservedFlag.CLEANED;
|
||||
MantleFlag PLANNED = ReservedFlag.PLANNED;
|
||||
MantleFlag ETCHED = ReservedFlag.ETCHED;
|
||||
MantleFlag TILE = ReservedFlag.TILE;
|
||||
MantleFlag CUSTOM = ReservedFlag.CUSTOM;
|
||||
MantleFlag DISCOVERED = ReservedFlag.DISCOVERED;
|
||||
MantleFlag CUSTOM_ACTIVE = ReservedFlag.CUSTOM_ACTIVE;
|
||||
|
||||
int RESERVED_FLAGS = ReservedFlag.values().length;
|
||||
|
||||
String name();
|
||||
int ordinal();
|
||||
|
||||
boolean isCustom();
|
||||
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
static MantleFlag of(int ordinal) {
|
||||
if (ordinal < MIN_ORDINAL || ordinal > MAX_ORDINAL)
|
||||
throw new IllegalArgumentException("Ordinal must be between " + MIN_ORDINAL + " and " + MAX_ORDINAL);
|
||||
return new CustomFlag("CUSTOM:"+ordinal, ordinal);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.volmit.iris.util.mantle.flag;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class MantleFlagAdapter extends TypeAdapter<MantleFlag> {
|
||||
private static final String CUSTOM = "CUSTOM:";
|
||||
private static final int CUSTOM_LENGTH = CUSTOM.length();
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, MantleFlag value) throws IOException {
|
||||
if (value == null) out.nullValue();
|
||||
else out.value(value.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MantleFlag read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
String s = in.nextString();
|
||||
if (s.startsWith(CUSTOM) && s.length() > CUSTOM_LENGTH)
|
||||
return MantleFlag.of(Integer.parseInt(s.substring(CUSTOM_LENGTH)));
|
||||
return ReservedFlag.valueOf(s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.volmit.iris.util.mantle.flag;
|
||||
|
||||
public enum ReservedFlag implements MantleFlag {
|
||||
OBJECT,
|
||||
UPDATE,
|
||||
JIGSAW,
|
||||
FEATURE,
|
||||
INITIAL_SPAWNED,
|
||||
REAL,
|
||||
CARVED,
|
||||
FLUID_BODIES,
|
||||
INITIAL_SPAWNED_MARKER,
|
||||
CLEANED,
|
||||
PLANNED,
|
||||
ETCHED,
|
||||
TILE,
|
||||
CUSTOM,
|
||||
DISCOVERED,
|
||||
CUSTOM_ACTIVE;
|
||||
|
||||
@Override
|
||||
public boolean isCustom() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.volmit.iris.util.parallel;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
|
||||
public class AtomicBooleanArray implements Serializable {
|
||||
private static final VarHandle AA = MethodHandles.arrayElementVarHandle(boolean[].class);
|
||||
private final boolean[] array;
|
||||
|
||||
public AtomicBooleanArray(int length) {
|
||||
array = new boolean[length];
|
||||
}
|
||||
|
||||
public final int length() {
|
||||
return array.length;
|
||||
}
|
||||
|
||||
public final boolean get(int index) {
|
||||
return (boolean) AA.getVolatile(array, index);
|
||||
}
|
||||
|
||||
public final void set(int index, boolean newValue) {
|
||||
AA.setVolatile(array, index, newValue);
|
||||
}
|
||||
|
||||
public final boolean compareAndSet(int index, boolean expectedValue, boolean newValue) {
|
||||
return (boolean) AA.compareAndSet(array, index, expectedValue, newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
int iMax = array.length - 1;
|
||||
if (iMax == -1)
|
||||
return "[]";
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append('[');
|
||||
for (int i = 0; ; i++) {
|
||||
b.append(get(i));
|
||||
if (i == iMax)
|
||||
return b.append(']').toString();
|
||||
b.append(',').append(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,11 @@ public class MultiBurst implements ExecutorService {
|
||||
private ExecutorService service;
|
||||
|
||||
public MultiBurst() {
|
||||
this("Iris", Thread.MIN_PRIORITY, () -> IrisSettings.get().getConcurrency().getParallelism());
|
||||
this("Iris");
|
||||
}
|
||||
|
||||
public MultiBurst(String name) {
|
||||
this(name, Thread.MIN_PRIORITY, () -> IrisSettings.get().getConcurrency().getParallelism());
|
||||
}
|
||||
|
||||
public MultiBurst(String name, IntSupplier parallelism) {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.base
|
||||
|
||||
import com.volmit.iris.core.loader.IrisData
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.providedProperties
|
||||
|
||||
@KotlinScript(fileExtension = "data.kts", compilationConfiguration = DataScriptDefinition::class)
|
||||
abstract class DataScript
|
||||
|
||||
object DataScriptDefinition : ScriptCompilationConfiguration(listOf(SimpleScriptDefinition), {
|
||||
providedProperties("data" to IrisData::class)
|
||||
}) {
|
||||
private fun readResolve(): Any = DataScriptDefinition
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.base
|
||||
|
||||
import com.volmit.iris.core.scripting.func.BiomeLookup
|
||||
import com.volmit.iris.engine.IrisComplex
|
||||
import com.volmit.iris.engine.framework.Engine
|
||||
import com.volmit.iris.engine.`object`.IrisDimension
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.providedProperties
|
||||
|
||||
@KotlinScript(fileExtension = "engine.kts", compilationConfiguration = EngineScriptDefinition::class)
|
||||
abstract class EngineScript
|
||||
|
||||
object EngineScriptDefinition : ScriptCompilationConfiguration(listOf(DataScriptDefinition), {
|
||||
providedProperties(
|
||||
"engine" to Engine::class,
|
||||
"complex" to IrisComplex::class,
|
||||
"seed" to Long::class,
|
||||
"dimension" to IrisDimension::class,
|
||||
"biome" to BiomeLookup::class,
|
||||
)
|
||||
}) {
|
||||
|
||||
private fun readResolve(): Any = EngineScriptDefinition
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.base
|
||||
|
||||
import org.bukkit.Location
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.providedProperties
|
||||
|
||||
@KotlinScript(fileExtension = "spawn.kts", compilationConfiguration = MobSpawningScriptDefinition::class)
|
||||
abstract class MobSpawningScript
|
||||
|
||||
object MobSpawningScriptDefinition : ScriptCompilationConfiguration(listOf(EngineScriptDefinition), {
|
||||
providedProperties("location" to Location::class)
|
||||
}) {
|
||||
private fun readResolve(): Any = MobSpawningScriptDefinition
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.base
|
||||
|
||||
import com.volmit.iris.util.math.RNG
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.providedProperties
|
||||
|
||||
@KotlinScript(fileExtension = "noise.kts", compilationConfiguration = NoiseScriptDefinition::class)
|
||||
abstract class NoiseScript
|
||||
|
||||
object NoiseScriptDefinition : ScriptCompilationConfiguration(listOf(DataScriptDefinition), {
|
||||
providedProperties("rng" to RNG::class)
|
||||
}) {
|
||||
|
||||
private fun readResolve(): Any = NoiseScriptDefinition
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.base
|
||||
|
||||
import org.bukkit.entity.Entity
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.providedProperties
|
||||
|
||||
@KotlinScript(fileExtension = "postspawn.kts", compilationConfiguration = PostMobSpawningScriptDefinition::class)
|
||||
abstract class PostMobSpawningScript
|
||||
|
||||
object PostMobSpawningScriptDefinition : ScriptCompilationConfiguration(listOf(MobSpawningScriptDefinition), {
|
||||
providedProperties("entity" to Entity::class)
|
||||
}) {
|
||||
private fun readResolve(): Any = PostMobSpawningScriptDefinition
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.base
|
||||
|
||||
import com.volmit.iris.core.loader.IrisRegistrant
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.providedProperties
|
||||
|
||||
@KotlinScript(fileExtension = "proc.kts", compilationConfiguration = PreprocessorScriptDefinition::class)
|
||||
abstract class PreprocessorScript
|
||||
|
||||
object PreprocessorScriptDefinition : ScriptCompilationConfiguration(listOf(EngineScriptDefinition), {
|
||||
providedProperties("object" to IrisRegistrant::class)
|
||||
}) {
|
||||
private fun readResolve(): Any = PreprocessorScriptDefinition
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.base
|
||||
|
||||
import com.volmit.iris.core.scripting.kotlin.runner.configureMavenDepsOnAnnotations
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.defaultImports
|
||||
import kotlin.script.experimental.api.refineConfiguration
|
||||
import kotlin.script.experimental.dependencies.DependsOn
|
||||
import kotlin.script.experimental.dependencies.Repository
|
||||
import kotlin.script.experimental.jvm.dependenciesFromClassContext
|
||||
import kotlin.script.experimental.jvm.jvm
|
||||
|
||||
@KotlinScript(fileExtension = "simple.kts", compilationConfiguration = SimpleScriptDefinition::class)
|
||||
abstract class SimpleScript
|
||||
|
||||
object SimpleScriptDefinition : ScriptCompilationConfiguration({
|
||||
defaultImports(
|
||||
DependsOn::class.qualifiedName!!,
|
||||
Repository::class.qualifiedName!!,
|
||||
"com.volmit.iris.Iris.info",
|
||||
"com.volmit.iris.Iris.debug",
|
||||
"com.volmit.iris.Iris.warn",
|
||||
"com.volmit.iris.Iris.error"
|
||||
)
|
||||
|
||||
jvm {
|
||||
dependenciesFromClassContext(KotlinScript::class, wholeClasspath = true)
|
||||
dependenciesFromClassContext(SimpleScript::class, wholeClasspath = true)
|
||||
}
|
||||
|
||||
refineConfiguration {
|
||||
onAnnotations(DependsOn::class, Repository::class, handler = ::configureMavenDepsOnAnnotations)
|
||||
}
|
||||
}) {
|
||||
private fun readResolve(): Any = SimpleScriptDefinition
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.environment
|
||||
|
||||
import com.volmit.iris.core.loader.IrisRegistrant
|
||||
import com.volmit.iris.core.scripting.environment.EngineEnvironment
|
||||
import com.volmit.iris.core.scripting.func.BiomeLookup
|
||||
import com.volmit.iris.core.scripting.kotlin.base.EngineScript
|
||||
import com.volmit.iris.core.scripting.kotlin.base.MobSpawningScript
|
||||
import com.volmit.iris.core.scripting.kotlin.base.PostMobSpawningScript
|
||||
import com.volmit.iris.core.scripting.kotlin.base.PreprocessorScript
|
||||
import com.volmit.iris.engine.framework.Engine
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.entity.Entity
|
||||
|
||||
data class IrisExecutionEnvironment(
|
||||
private val engine: Engine
|
||||
) : IrisPackExecutionEnvironment(engine.data), EngineEnvironment {
|
||||
override fun getEngine() = engine
|
||||
|
||||
override fun execute(script: String) =
|
||||
execute(script, EngineScript::class.java, engine.parameters())
|
||||
|
||||
override fun evaluate(script: String) =
|
||||
evaluate(script, EngineScript::class.java, engine.parameters())
|
||||
|
||||
override fun spawnMob(script: String, location: Location) =
|
||||
evaluate(script, MobSpawningScript::class.java, engine.parameters("location" to location))
|
||||
|
||||
override fun postSpawnMob(script: String, location: Location, mob: Entity) =
|
||||
execute(script, PostMobSpawningScript::class.java, engine.parameters("location" to location, "entity" to mob))
|
||||
|
||||
override fun preprocessObject(script: String, `object`: IrisRegistrant) =
|
||||
execute(script, PreprocessorScript::class.java, engine.parameters("object" to `object`))
|
||||
|
||||
private fun Engine.parameters(vararg values: Pair<String, Any?>): Map<String, Any?> {
|
||||
return mapOf(
|
||||
"data" to data,
|
||||
"engine" to this,
|
||||
"complex" to complex,
|
||||
"seed" to seedManager.seed,
|
||||
"dimension" to dimension,
|
||||
"biome" to BiomeLookup(::getSurfaceBiome),
|
||||
*values,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.environment
|
||||
|
||||
import com.volmit.iris.core.loader.IrisData
|
||||
import com.volmit.iris.core.scripting.environment.PackEnvironment
|
||||
import com.volmit.iris.core.scripting.kotlin.base.DataScript
|
||||
import com.volmit.iris.core.scripting.kotlin.base.NoiseScript
|
||||
import com.volmit.iris.core.scripting.kotlin.runner.Script
|
||||
import com.volmit.iris.core.scripting.kotlin.runner.valueOrThrow
|
||||
import com.volmit.iris.util.math.RNG
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
open class IrisPackExecutionEnvironment(
|
||||
private val data: IrisData
|
||||
) : IrisSimpleExecutionEnvironment(data.dataFolder), PackEnvironment {
|
||||
|
||||
override fun getData() = data
|
||||
|
||||
override fun compile(script: String, type: KClass<*>): Script {
|
||||
val loaded = data.scriptLoader.load(script)
|
||||
return compileCache.get(script)
|
||||
.computeIfAbsent(type) { _ -> runner.compile(type, loaded.loadFile, loaded.source) }
|
||||
.valueOrThrow("Failed to compile script $script")
|
||||
}
|
||||
|
||||
override fun execute(script: String) =
|
||||
execute(script, DataScript::class.java, data.parameters())
|
||||
|
||||
override fun evaluate(script: String) =
|
||||
evaluate(script, DataScript::class.java, data.parameters())
|
||||
|
||||
override fun createNoise(script: String, rng: RNG) =
|
||||
evaluate(script, NoiseScript::class.java, data.parameters("rng" to rng))
|
||||
|
||||
private fun IrisData.parameters(vararg values: Pair<String, Any?>): Map<String, Any?> {
|
||||
return mapOf(
|
||||
"data" to this,
|
||||
*values,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.environment
|
||||
|
||||
import com.volmit.iris.Iris
|
||||
import com.volmit.iris.core.IrisSettings
|
||||
import com.volmit.iris.core.scripting.environment.SimpleEnvironment
|
||||
import com.volmit.iris.core.scripting.kotlin.base.*
|
||||
import com.volmit.iris.core.scripting.kotlin.runner.Script
|
||||
import com.volmit.iris.core.scripting.kotlin.runner.ScriptRunner
|
||||
import com.volmit.iris.core.scripting.kotlin.runner.classpath
|
||||
import com.volmit.iris.core.scripting.kotlin.runner.valueOrNull
|
||||
import com.volmit.iris.core.scripting.kotlin.runner.valueOrThrow
|
||||
import com.volmit.iris.util.collection.KMap
|
||||
import com.volmit.iris.util.data.KCache
|
||||
import com.volmit.iris.util.format.C
|
||||
import java.io.File
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.ResultWithDiagnostics
|
||||
import kotlin.text.split
|
||||
|
||||
open class IrisSimpleExecutionEnvironment(
|
||||
baseDir: File = File(".").absoluteFile
|
||||
) : SimpleEnvironment {
|
||||
protected val compileCache = KCache<String, KMap<KClass<*>, ResultWithDiagnostics<Script>>>({ _ -> KMap() }, IrisSettings.get().performance.cacheSize.toLong())
|
||||
protected val runner = ScriptRunner(baseDir)
|
||||
|
||||
override fun execute(
|
||||
script: String
|
||||
) = execute(script, SimpleScript::class.java, null)
|
||||
|
||||
override fun execute(
|
||||
script: String,
|
||||
type: Class<*>,
|
||||
vars: Map<String, Any?>?
|
||||
) {
|
||||
Iris.debug("Execute Script (void) " + C.DARK_GREEN + script)
|
||||
evaluate0(script, type.kotlin, vars)
|
||||
}
|
||||
|
||||
override fun evaluate(
|
||||
script: String
|
||||
): Any? = evaluate(script, SimpleScript::class.java, null)
|
||||
|
||||
override fun evaluate(
|
||||
script: String,
|
||||
type: Class<*>,
|
||||
vars: Map<String, Any?>?
|
||||
): Any? {
|
||||
Iris.debug("Execute Script (for result) " + C.DARK_GREEN + script)
|
||||
return evaluate0(script, type.kotlin, vars)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
compileCache.invalidate()
|
||||
runner.clear()
|
||||
}
|
||||
|
||||
protected open fun compile(script: String, type: KClass<*>) =
|
||||
compileCache.get(script)
|
||||
.computeIfAbsent(type) { _ -> runner.compile(type, script) }
|
||||
.valueOrThrow("Failed to compile script")
|
||||
|
||||
private fun evaluate0(name: String, type: KClass<*>, properties: Map<String, Any?>? = null): Any? {
|
||||
val current = Thread.currentThread()
|
||||
val loader = current.contextClassLoader
|
||||
current.contextClassLoader = this.javaClass.classLoader
|
||||
try {
|
||||
return compile(name, type)
|
||||
.evaluate(properties)
|
||||
.valueOrThrow("Failed to evaluate script")
|
||||
.valueOrNull()
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
current.contextClassLoader = loader
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun configureProject() {
|
||||
runner.baseDir.mkdirs()
|
||||
val libs = listOf(javaClass.classLoader.classpath, KotlinScript::class.java.classLoader.classpath)
|
||||
.flatMap { it }
|
||||
.sortedBy { it.absolutePath }
|
||||
.toMutableList()
|
||||
|
||||
File(runner.baseDir, "build.gradle.kts")
|
||||
.updateClasspath(libs)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val CLASSPATH = "val classpath = files("
|
||||
|
||||
private fun File.updateClasspath(classpath: List<File>) {
|
||||
val test = if (exists()) readLines() else BASE_GRADLE
|
||||
writeText(test.updateClasspath(classpath))
|
||||
}
|
||||
|
||||
private fun List<String>.updateClasspath(classpath: List<File>): String {
|
||||
val classpath = classpath.joinToString(",", CLASSPATH, ")") { "\"${it.escapedPath}\"" }
|
||||
val index = indexOfFirst { it.startsWith(CLASSPATH) }
|
||||
if (index == -1) {
|
||||
return "$classpath\n${joinToString("\n")}"
|
||||
}
|
||||
|
||||
val mod = toMutableList()
|
||||
mod[index] = classpath
|
||||
return mod.joinToString("\n")
|
||||
}
|
||||
|
||||
private val File.escapedPath
|
||||
get() = absolutePath.replace("\\", "\\\\").replace("\"", "\\\"")
|
||||
|
||||
private val BASE_GRADLE = """
|
||||
val classpath = files()
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version("2.2.0")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
val script by configurations.creating
|
||||
configurations.compileOnly { extendsFrom(script) }
|
||||
configurations.kotlinScriptDef { extendsFrom(script) }
|
||||
configurations.kotlinScriptDefExtensions { extendsFrom(script) }
|
||||
configurations.kotlinCompilerClasspath { extendsFrom(script) }
|
||||
configurations.kotlinCompilerPluginClasspath { extendsFrom(script) }
|
||||
|
||||
dependencies {
|
||||
script(classpath)
|
||||
}""".trimIndent().split("\n")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.runner
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
import kotlin.script.experimental.host.createEvaluationConfigurationFromTemplate
|
||||
import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost
|
||||
|
||||
data class CachedScript(
|
||||
private val base: CompiledScript,
|
||||
private val host: BasicJvmScriptingHost,
|
||||
private val hostConfig: ScriptingHostConfiguration
|
||||
) : Script, CompiledScript {
|
||||
private val scripts = base.otherScripts.map { CachedScript(it, host, hostConfig) }
|
||||
private val evalConfig = createEvaluationConfiguration()
|
||||
private val lock = ReentrantLock()
|
||||
|
||||
@Volatile
|
||||
private var value: ResultWithDiagnostics<KClass<*>>? = null
|
||||
|
||||
override val otherScripts: List<CompiledScript>
|
||||
get() = scripts
|
||||
|
||||
override val sourceLocationId: String?
|
||||
get() = base.sourceLocationId
|
||||
|
||||
override val compilationConfiguration: ScriptCompilationConfiguration
|
||||
get() = base.compilationConfiguration
|
||||
|
||||
override val resultField: Pair<String, KotlinType>?
|
||||
get() = base.resultField
|
||||
|
||||
|
||||
override suspend fun getClass(scriptEvaluationConfiguration: ScriptEvaluationConfiguration?) = value ?: run {
|
||||
lock.lock()
|
||||
try {
|
||||
value ?: base.getClass(scriptEvaluationConfiguration).also { value = it }
|
||||
} finally {
|
||||
lock.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
override fun evaluate(properties: Map<String, Any?>?) = host.runInCoroutineContext {
|
||||
host.evaluator(this, createEvaluationConfiguration(properties))
|
||||
}
|
||||
|
||||
private fun createEvaluationConfiguration(properties: Map<String, Any?>?): ScriptEvaluationConfiguration {
|
||||
if (properties == null || properties.isEmpty())
|
||||
return evalConfig
|
||||
|
||||
return evalConfig.with {
|
||||
providedProperties(properties)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEvaluationConfiguration(): ScriptEvaluationConfiguration {
|
||||
val type = compilationConfiguration[ScriptCompilationConfiguration.baseClass]?.fromClass!!
|
||||
return createEvaluationConfigurationFromTemplate(
|
||||
KotlinType(type),
|
||||
hostConfig,
|
||||
type)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.runner
|
||||
|
||||
import kotlin.script.experimental.api.EvaluationResult
|
||||
import kotlin.script.experimental.api.ResultWithDiagnostics
|
||||
|
||||
interface Script {
|
||||
fun evaluate(properties: Map<String, Any?>?): ResultWithDiagnostics<EvaluationResult>
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.runner
|
||||
|
||||
import com.volmit.iris.core.scripting.kotlin.base.SimpleScript
|
||||
import java.io.File
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.dependencies.DependsOn
|
||||
import kotlin.script.experimental.dependencies.Repository
|
||||
import kotlin.script.experimental.host.FileScriptSource
|
||||
import kotlin.script.experimental.host.createCompilationConfigurationFromTemplate
|
||||
import kotlin.script.experimental.host.toScriptSource
|
||||
import kotlin.script.experimental.host.withDefaultsFrom
|
||||
import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration
|
||||
import kotlin.script.experimental.jvm.dependenciesFromClassContext
|
||||
import kotlin.script.experimental.jvm.jvm
|
||||
import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost
|
||||
|
||||
class ScriptRunner(
|
||||
private val host: BasicJvmScriptingHost,
|
||||
val baseDir: File
|
||||
) {
|
||||
constructor(baseDir: File) : this(BasicJvmScriptingHost(), baseDir)
|
||||
|
||||
private val configs = ConcurrentHashMap<KClass<*>, ScriptCompilationConfiguration>()
|
||||
private val hostConfig = host.baseHostConfiguration.withDefaultsFrom(defaultJvmScriptingHostConfiguration)
|
||||
private var resolver = createResolver(baseDir)
|
||||
|
||||
fun compile(type: KClass<*>, raw: String, name: String? = null) = compile(type, raw.toScriptSource(name))
|
||||
fun compile(type: KClass<*>, file: File, preloaded: String? = null) = compile(type, FileScriptSource(file, preloaded))
|
||||
|
||||
fun clear() {
|
||||
configs.clear()
|
||||
resolver = createResolver(baseDir)
|
||||
}
|
||||
|
||||
private fun compile(
|
||||
type: KClass<*>,
|
||||
code: SourceCode
|
||||
): ResultWithDiagnostics<Script> = host.runInCoroutineContext {
|
||||
host.compiler(code, configs.computeIfAbsent(type, ::createConfig))
|
||||
.map { CachedScript(it, host, hostConfig) }
|
||||
}
|
||||
|
||||
private fun createConfig(type: KClass<*>) = createCompilationConfigurationFromTemplate(
|
||||
KotlinType(type),
|
||||
hostConfig,
|
||||
type
|
||||
) {
|
||||
dependencyResolver(resolver)
|
||||
packDirectory(baseDir)
|
||||
|
||||
if (SimpleScript::class.java.isAssignableFrom(type.java))
|
||||
return@createCompilationConfigurationFromTemplate
|
||||
|
||||
jvm {
|
||||
dependenciesFromClassContext(type, wholeClasspath = true)
|
||||
dependenciesFromClassContext(this::class, wholeClasspath = true)
|
||||
dependenciesFromClassContext(KotlinScript::class, wholeClasspath = true)
|
||||
}
|
||||
|
||||
refineConfiguration {
|
||||
onAnnotations(DependsOn::class, Repository::class, handler = ::configureMavenDepsOnAnnotations)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.runner
|
||||
|
||||
import com.volmit.iris.core.scripting.kotlin.runner.resolver.CompoundDependenciesResolver
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.dependencies.resolveFromScriptSourceAnnotations
|
||||
import kotlin.script.experimental.jvm.updateClasspath
|
||||
import kotlin.script.experimental.jvm.util.classpathFromClassloader
|
||||
import kotlin.script.experimental.util.PropertiesCollection
|
||||
|
||||
internal fun <T, R> ResultWithDiagnostics<T>.map(transformer: (T) -> R): ResultWithDiagnostics<R> = when (this) {
|
||||
is ResultWithDiagnostics.Success -> ResultWithDiagnostics.Success(transformer(value), reports)
|
||||
is ResultWithDiagnostics.Failure -> this
|
||||
}
|
||||
|
||||
internal fun EvaluationResult.valueOrNull() = returnValue.valueOrNull()
|
||||
internal fun ResultValue.valueOrNull(): Any? =
|
||||
when (this) {
|
||||
is ResultValue.Value -> value
|
||||
else -> null
|
||||
}
|
||||
|
||||
private val workDir = File(".").normalize()
|
||||
internal fun createResolver(baseDir: File = workDir) = CompoundDependenciesResolver(baseDir)
|
||||
|
||||
private val resolver = createResolver()
|
||||
internal fun configureMavenDepsOnAnnotations(context: ScriptConfigurationRefinementContext): ResultWithDiagnostics<ScriptCompilationConfiguration> {
|
||||
val annotations = context.collectedData?.get(ScriptCollectedData.collectedAnnotations)?.takeIf { it.isNotEmpty() }
|
||||
?: return context.compilationConfiguration.asSuccess()
|
||||
|
||||
val reports = mutableListOf<ScriptDiagnostic>()
|
||||
val resolver = context.compilationConfiguration[ScriptCompilationConfiguration.dependencyResolver] ?: resolver
|
||||
context.compilationConfiguration[ScriptCompilationConfiguration.packDirectory]
|
||||
?.addPack(resolver)
|
||||
?: context.script.locationId
|
||||
?.let(::File)
|
||||
?.takeIf { it.exists() }
|
||||
?.run {
|
||||
val location = SourceCode.LocationWithId(context.script.locationId!!, SourceCode.Location(SourceCode.Position(0, 0)))
|
||||
val parts = normalize().absolutePath.split(File.separatorChar)
|
||||
for (i in parts.size - 1 downTo 1) {
|
||||
if (parts[i] != "scripts") continue
|
||||
val pack = File(parts.subList(0, i).joinToString(File.separator))
|
||||
if (!File(pack, "dimensions${File.separator}${parts[i - 1]}.json").exists())
|
||||
continue
|
||||
pack.addPack(resolver)
|
||||
reports.add(ScriptDiagnostic(
|
||||
ScriptDiagnostic.unspecifiedInfo,
|
||||
"Adding pack \"$pack\"",
|
||||
ScriptDiagnostic.Severity.INFO,
|
||||
location
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
return runBlocking {
|
||||
resolver.resolveFromScriptSourceAnnotations(annotations)
|
||||
}.onSuccess {
|
||||
context.compilationConfiguration.with {
|
||||
updateClasspath(it)
|
||||
}.asSuccess()
|
||||
}.appendReports(reports)
|
||||
}
|
||||
|
||||
internal val ClassLoader.classpath get() = classpathFromClassloader(this) ?: emptyList()
|
||||
|
||||
fun <R> ResultWithDiagnostics<R>.valueOrThrow(message: CharSequence): R = valueOr {
|
||||
throw RuntimeException(it.reports.joinToString("\n", "$message\n") { r -> r.render(withStackTrace = true) })
|
||||
}
|
||||
|
||||
val ScriptCompilationConfigurationKeys.dependencyResolver by PropertiesCollection.key(resolver)
|
||||
val ScriptCompilationConfigurationKeys.packDirectory by PropertiesCollection.key<File>()
|
||||
|
||||
private fun File.addPack(resolver: CompoundDependenciesResolver) = resolver.addPack(this)
|
||||
private fun <R> ResultWithDiagnostics<R>.appendReports(reports : Collection<ScriptDiagnostic>) =
|
||||
if (reports.isEmpty()) this
|
||||
else when (this) {
|
||||
is ResultWithDiagnostics.Success -> ResultWithDiagnostics.Success(value, this.reports + reports)
|
||||
is ResultWithDiagnostics.Failure -> ResultWithDiagnostics.Failure(this.reports + reports)
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.runner.resolver
|
||||
|
||||
import java.io.File
|
||||
import kotlin.collections.component1
|
||||
import kotlin.collections.component2
|
||||
import kotlin.collections.iterator
|
||||
import kotlin.collections.set
|
||||
import kotlin.script.experimental.api.IterableResultsCollector
|
||||
import kotlin.script.experimental.api.ResultWithDiagnostics
|
||||
import kotlin.script.experimental.api.ScriptDiagnostic
|
||||
import kotlin.script.experimental.api.SourceCode
|
||||
import kotlin.script.experimental.api.asErrorDiagnostics
|
||||
import kotlin.script.experimental.api.asSuccess
|
||||
import kotlin.script.experimental.dependencies.ArtifactWithLocation
|
||||
import kotlin.script.experimental.dependencies.ExternalDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.RepositoryCoordinates
|
||||
import kotlin.script.experimental.dependencies.impl.makeResolveFailureResult
|
||||
|
||||
class CompoundDependenciesResolver(
|
||||
private val baseDir: File
|
||||
) : DependenciesResolver {
|
||||
private val resolvers = listOf(FileDependenciesResolver(baseDir), LocalMavenDependenciesResolver())
|
||||
|
||||
override fun acceptsRepository(repositoryCoordinates: RepositoryCoordinates): Boolean {
|
||||
return resolvers.any { it.acceptsRepository(repositoryCoordinates) }
|
||||
}
|
||||
|
||||
override fun acceptsArtifact(artifactCoordinates: String): Boolean {
|
||||
return resolvers.any { it.acceptsArtifact(artifactCoordinates) }
|
||||
}
|
||||
|
||||
override fun addRepository(
|
||||
repositoryCoordinates: RepositoryCoordinates,
|
||||
options: ExternalDependenciesResolver.Options,
|
||||
sourceCodeLocation: SourceCode.LocationWithId?
|
||||
): ResultWithDiagnostics<Boolean> {
|
||||
var success = false
|
||||
var repositoryAdded = false
|
||||
val reports = mutableListOf<ScriptDiagnostic>()
|
||||
|
||||
for (resolver in resolvers) {
|
||||
when (val result = resolver.addRepository(repositoryCoordinates, options, sourceCodeLocation)) {
|
||||
is ResultWithDiagnostics.Success -> {
|
||||
success = true
|
||||
repositoryAdded = repositoryAdded || result.value
|
||||
reports.addAll(result.reports)
|
||||
}
|
||||
is ResultWithDiagnostics.Failure -> reports.addAll(result.reports)
|
||||
}
|
||||
}
|
||||
|
||||
return when {
|
||||
success -> repositoryAdded.asSuccess(reports)
|
||||
reports.isEmpty() -> makeResolveFailureResult(
|
||||
"No dependency resolver found that recognizes the repository coordinates '$repositoryCoordinates'",
|
||||
sourceCodeLocation
|
||||
)
|
||||
else -> ResultWithDiagnostics.Failure(reports)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun resolve(
|
||||
artifactsWithLocations: List<ArtifactWithLocation>,
|
||||
options: ExternalDependenciesResolver.Options
|
||||
): ResultWithDiagnostics<List<File>> {
|
||||
val resultsCollector = IterableResultsCollector<File>()
|
||||
|
||||
val artifactToResolverIndex = mutableMapOf<ArtifactWithLocation, Int>().apply {
|
||||
for (artifactWithLocation in artifactsWithLocations) {
|
||||
put(artifactWithLocation, -1)
|
||||
}
|
||||
}
|
||||
|
||||
while (artifactToResolverIndex.isNotEmpty()) {
|
||||
val resolverGroups = mutableMapOf<Int, MutableList<ArtifactWithLocation>>()
|
||||
|
||||
for ((artifactWithLocation, resolverIndex) in artifactToResolverIndex) {
|
||||
val (artifact, sourceCodeLocation) = artifactWithLocation
|
||||
|
||||
var currentIndex = resolverIndex + 1
|
||||
while (currentIndex < resolvers.size) {
|
||||
if (resolvers[currentIndex].acceptsArtifact(artifact)) break
|
||||
++currentIndex
|
||||
}
|
||||
if (currentIndex == resolvers.size) {
|
||||
if (resolverIndex == -1) {
|
||||
resultsCollector.addDiagnostic(
|
||||
"No suitable dependency resolver found for artifact '$artifact'"
|
||||
.asErrorDiagnostics(locationWithId = sourceCodeLocation)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
resolverGroups
|
||||
.getOrPut(currentIndex) { mutableListOf() }
|
||||
.add(artifactWithLocation)
|
||||
}
|
||||
}
|
||||
|
||||
artifactToResolverIndex.clear()
|
||||
for ((resolverIndex, artifacts) in resolverGroups) {
|
||||
val resolver = resolvers[resolverIndex]
|
||||
val resolveResult = resolver.resolve(artifacts, options)
|
||||
resultsCollector.add(resolveResult)
|
||||
if (resolveResult.reports.isNotEmpty()) {
|
||||
for (artifact in artifacts) {
|
||||
artifactToResolverIndex[artifact] = resolverIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resultsCollector.getResult()
|
||||
}
|
||||
|
||||
override fun addPack(directory: File) {
|
||||
if (!directory.normalize().absolutePath.startsWith(baseDir.normalize().absolutePath))
|
||||
return
|
||||
resolvers.forEach { it.addPack(directory) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.runner.resolver
|
||||
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.dependencies.ExternalDependenciesResolver
|
||||
|
||||
interface DependenciesResolver : ExternalDependenciesResolver {
|
||||
fun addPack(directory: File)
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.runner.resolver
|
||||
|
||||
import java.io.File
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.script.experimental.api.ResultWithDiagnostics
|
||||
import kotlin.script.experimental.api.SourceCode
|
||||
import kotlin.script.experimental.api.asSuccess
|
||||
import kotlin.script.experimental.dependencies.ExternalDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.RepositoryCoordinates
|
||||
import kotlin.script.experimental.dependencies.impl.makeResolveFailureResult
|
||||
import kotlin.script.experimental.dependencies.impl.toRepositoryUrlOrNull
|
||||
|
||||
class FileDependenciesResolver(
|
||||
private val baseDir: File,
|
||||
) : DependenciesResolver {
|
||||
private val localRepos = ConcurrentHashMap.newKeySet<File>(1).also { it.add(baseDir) }
|
||||
|
||||
private fun String.toRepositoryFileOrNull(): File? =
|
||||
File(baseDir, this).takeIf { it.exists() && it.isDirectory }
|
||||
|
||||
private fun RepositoryCoordinates.toFilePath() =
|
||||
(this.toRepositoryUrlOrNull()?.takeIf { it.protocol == "file" }?.path ?: string).toRepositoryFileOrNull()
|
||||
|
||||
override fun addRepository(
|
||||
repositoryCoordinates: RepositoryCoordinates,
|
||||
options: ExternalDependenciesResolver.Options,
|
||||
sourceCodeLocation: SourceCode.LocationWithId?
|
||||
): ResultWithDiagnostics<Boolean> {
|
||||
if (!acceptsRepository(repositoryCoordinates)) return false.asSuccess()
|
||||
|
||||
val repoDir = repositoryCoordinates.toFilePath()
|
||||
?: return makeResolveFailureResult("Invalid repository location: '${repositoryCoordinates}'", sourceCodeLocation)
|
||||
|
||||
localRepos.add(repoDir)
|
||||
|
||||
return true.asSuccess()
|
||||
}
|
||||
|
||||
override suspend fun resolve(
|
||||
artifactCoordinates: String,
|
||||
options: ExternalDependenciesResolver.Options,
|
||||
sourceCodeLocation: SourceCode.LocationWithId?
|
||||
): ResultWithDiagnostics<List<File>> {
|
||||
if (!acceptsArtifact(artifactCoordinates)) throw IllegalArgumentException("Path is invalid")
|
||||
|
||||
val messages = mutableListOf<String>()
|
||||
|
||||
for (repo in localRepos) {
|
||||
// TODO: add coordinates and wildcard matching
|
||||
val file = File(repo, artifactCoordinates)
|
||||
when {
|
||||
!file.exists() -> messages.add("File '$file' not found")
|
||||
!file.isFile && !file.isDirectory -> messages.add("Path '$file' is neither file nor directory")
|
||||
else -> return ResultWithDiagnostics.Success(listOf(file))
|
||||
}
|
||||
}
|
||||
return makeResolveFailureResult(messages.joinToString("; "), sourceCodeLocation)
|
||||
}
|
||||
|
||||
override fun acceptsArtifact(artifactCoordinates: String) =
|
||||
!artifactCoordinates.isBlank() // TODO: make check stronger, e.g. using NIO's Path
|
||||
|
||||
override fun acceptsRepository(repositoryCoordinates: RepositoryCoordinates): Boolean = repositoryCoordinates.toFilePath() != null
|
||||
|
||||
override fun addPack(directory: File) {
|
||||
localRepos.add(directory)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.volmit.iris.core.scripting.kotlin.runner.resolver
|
||||
|
||||
import com.volmit.iris.util.io.IO
|
||||
import org.dom4j.Document
|
||||
import org.dom4j.DocumentFactory
|
||||
import org.dom4j.io.SAXReader
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.api.ResultWithDiagnostics
|
||||
import kotlin.script.experimental.api.SourceCode
|
||||
import kotlin.script.experimental.dependencies.ArtifactWithLocation
|
||||
import kotlin.script.experimental.dependencies.ExternalDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.RepositoryCoordinates
|
||||
import kotlin.script.experimental.dependencies.maven.MavenDependenciesResolver
|
||||
|
||||
class LocalMavenDependenciesResolver : DependenciesResolver {
|
||||
private lateinit var localRepo: File
|
||||
private val maven = MavenDependenciesResolver(true)
|
||||
|
||||
override fun acceptsRepository(repositoryCoordinates: RepositoryCoordinates) = maven.acceptsRepository(repositoryCoordinates)
|
||||
override fun acceptsArtifact(artifactCoordinates: String) = maven.acceptsArtifact(artifactCoordinates)
|
||||
|
||||
override fun addRepository(
|
||||
repositoryCoordinates: RepositoryCoordinates,
|
||||
options: ExternalDependenciesResolver.Options,
|
||||
sourceCodeLocation: SourceCode.LocationWithId?
|
||||
) = maven.addRepository(repositoryCoordinates, options, sourceCodeLocation)
|
||||
|
||||
override suspend fun resolve(
|
||||
artifactsWithLocations: List<ArtifactWithLocation>,
|
||||
options: ExternalDependenciesResolver.Options
|
||||
): ResultWithDiagnostics<List<File>> {
|
||||
val userOld: String? = System.getProperty("org.apache.maven.user-settings")
|
||||
val globalOld: String? = System.getProperty("org.apache.maven.global-settings")
|
||||
|
||||
try {
|
||||
System.setProperty("org.apache.maven.user-settings", createSettings(userOld))
|
||||
System.clearProperty("org.apache.maven.global-settings")
|
||||
|
||||
return maven.resolve(artifactsWithLocations, options)
|
||||
} finally {
|
||||
setProperty("org.apache.maven.user-settings", userOld)
|
||||
setProperty("org.apache.maven.global-settings", globalOld)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSettings(user: String?): String {
|
||||
val settingsFile = File(localRepo, "settings.xml")
|
||||
val document = readSettings(user)
|
||||
val node = document.selectSingleNode("//localRepository")
|
||||
?: document.rootElement.addElement("localRepository")
|
||||
|
||||
if (node.text != localRepo.absolutePath) {
|
||||
node.text = localRepo.absolutePath
|
||||
|
||||
IO.write(settingsFile, document)
|
||||
}
|
||||
return settingsFile.absolutePath
|
||||
}
|
||||
|
||||
private fun readSettings(user: String?): Document {
|
||||
val baseFile = user?.let(::File)?.takeIf { it.exists() } ?: File(
|
||||
System.getProperty("user.home"),
|
||||
".m2/settings.xml"
|
||||
).takeIf { it.exists() }?.let { return SAXReader().read(it) }
|
||||
return if (baseFile != null) SAXReader().read(baseFile) else DocumentFactory.getInstance().createDocument().also {
|
||||
it.addElement("settings")
|
||||
.addAttribute("xmlns", "http://maven.apache.org/SETTINGS/1.0.0")
|
||||
.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
|
||||
.addAttribute("xsi:schemaLocation", "http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd")
|
||||
}
|
||||
}
|
||||
|
||||
private fun setProperty(name: String, value: String?) {
|
||||
when(value) {
|
||||
null -> System.clearProperty(name)
|
||||
else -> System.setProperty(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addPack(directory: File) {
|
||||
if (!::localRepo.isInitialized) {
|
||||
localRepo = directory.resolve(".iris/m2")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,10 +33,15 @@ lru = "1.4.2" # https://central.sonatype.com/artifact/com.googlecode.concurrentl
|
||||
zip = "1.17" # https://central.sonatype.com/artifact/org.zeroturnaround/zt-zip
|
||||
gson = "2.13.1" # https://central.sonatype.com/artifact/com.google.code.gson/gson
|
||||
asm = "9.8" # https://central.sonatype.com/artifact/org.ow2.asm/asm
|
||||
bsf = "2.4.0" # https://central.sonatype.com/artifact/bsf/bsf
|
||||
rhino = "1.7R2" # https://central.sonatype.com/artifact/rhino/js
|
||||
caffeine = "3.2.1" # https://central.sonatype.com/artifact/com.github.ben-manes.caffeine/caffeine
|
||||
byte-buddy = "1.17.6" # https://central.sonatype.com/artifact/net.bytebuddy/byte-buddy
|
||||
dom4j = "2.2.0" # https://central.sonatype.com/artifact/org.dom4j/dom4j
|
||||
jaxen = "2.0.0" # https://central.sonatype.com/artifact/jaxen/jaxen
|
||||
|
||||
# Script Engine
|
||||
kotlin = "2.2.0"
|
||||
kotlin-coroutines = "1.10.2"
|
||||
maven-core = "3.9.10"
|
||||
|
||||
# Third Party Integrations
|
||||
nexo = "1.8.0" # https://repo.nexomc.com/#/releases/com/nexomc/nexo
|
||||
@@ -77,11 +82,20 @@ lru = { module = "com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap
|
||||
zip = { module = "org.zeroturnaround:zt-zip", version.ref = "zip" }
|
||||
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
|
||||
asm = { module = "org.ow2.asm:asm", version.ref = "asm" }
|
||||
bsf = { module = "bsf:bsf", version.ref = "bsf" }
|
||||
rhino = { module = "rhino:js", version.ref = "rhino" }
|
||||
caffeine = { module = "com.github.ben-manes.caffeine:caffeine", version.ref = "caffeine" }
|
||||
byteBuddy-core = { module = "net.bytebuddy:byte-buddy", version.ref = "byte-buddy" }
|
||||
byteBuddy-agent = { module = "net.bytebuddy:byte-buddy-agent", version.ref = "byte-buddy" }
|
||||
dom4j = { module = "org.dom4j:dom4j", version.ref = "dom4j" }
|
||||
jaxen = { module = "jaxen:jaxen", version.ref = "jaxen" }
|
||||
|
||||
# Script Engine
|
||||
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
|
||||
kotlin-scripting-common = { module = "org.jetbrains.kotlin:kotlin-scripting-common", version.ref = "kotlin" }
|
||||
kotlin-scripting-jvm = { module = "org.jetbrains.kotlin:kotlin-scripting-jvm", version.ref = "kotlin" }
|
||||
kotlin-scripting-jvm-host = { module = "org.jetbrains.kotlin:kotlin-scripting-jvm-host", version.ref = "kotlin" }
|
||||
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
|
||||
kotlin-scripting-dependencies-maven = { module = "org.jetbrains.kotlin:kotlin-scripting-dependencies-maven", version.ref = "kotlin" }
|
||||
mavenCore = { module = "org.apache.maven:maven-core", version.ref = "maven-core" }
|
||||
|
||||
# Third Party Integrations
|
||||
nexo = { module = "com.nexomc:nexo", version.ref = "nexo" }
|
||||
@@ -101,4 +115,6 @@ slimjar = { id = "de.crazydev22.slimjar", version.ref = "slimjar" }
|
||||
download = { id = "de.undercouch.download", version.ref = "download" }
|
||||
runPaper = { id = "xyz.jpenilla.run-paper", version.ref = "runPaper" }
|
||||
sentry = { id = "io.sentry.jvm.gradle", version.ref = "sentryPlugin" }
|
||||
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
kotlin-lombok = { id = "org.jetbrains.kotlin.plugin.lombok", version.ref = "kotlin" }
|
||||
grgit = { id = "org.ajoberstar.grgit", version.ref = "grgit" }
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.reflect.WrappedField;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.reflect.WrappedField;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
@@ -11,10 +11,9 @@ import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.reflect.WrappedField;
|
||||
import com.volmit.iris.util.scheduling.S;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderSet;
|
||||
@@ -28,7 +27,6 @@ import net.minecraft.tags.StructureTags;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.util.random.WeightedRandomList;
|
||||
import net.minecraft.world.entity.MobCategory;
|
||||
import net.minecraft.world.item.EnderEyeItem;
|
||||
import net.minecraft.world.level.LevelHeightAccessor;
|
||||
import net.minecraft.world.level.NoiseColumn;
|
||||
import net.minecraft.world.level.StructureManager;
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.reflect.WrappedField;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.reflect.WrappedField;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.reflect.WrappedField;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.reflect.WrappedField;
|
||||
import net.minecraft.core.*;
|
||||
@@ -24,7 +24,6 @@ import net.minecraft.tags.StructureTags;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.util.random.WeightedRandomList;
|
||||
import net.minecraft.world.entity.MobCategory;
|
||||
import net.minecraft.world.item.EnderEyeItem;
|
||||
import net.minecraft.world.level.*;
|
||||
import net.minecraft.world.level.biome.*;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
@@ -33,7 +32,6 @@ import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.levelgen.RandomState;
|
||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||
import net.minecraft.world.level.levelgen.structure.BuiltinStructures;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import net.minecraft.world.level.levelgen.structure.StructureSet;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.reflect.WrappedField;
|
||||
import net.minecraft.core.*;
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.reflect.WrappedField;
|
||||
import net.minecraft.core.*;
|
||||
|
||||
Reference in New Issue
Block a user