9
0
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:
Julian Krings
2025-09-04 13:43:08 +02:00
committed by GitHub
88 changed files with 1654 additions and 415 deletions

View File

@@ -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",

View File

@@ -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 {

View File

@@ -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...");

View File

@@ -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;

View File

@@ -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() {

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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(() -> {

View 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);
}
}
});
}
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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() {
}
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;

View 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;
}
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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()));
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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:

View File

@@ -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!");
}
}

View File

@@ -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);
}
}
}

View File

@@ -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) {

View File

@@ -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<>();
}

View File

@@ -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;

View File

@@ -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());
}
}

View File

@@ -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() {
}
}

View File

@@ -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);
}
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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);

View File

@@ -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());
}
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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(' ');
}
}
}

View File

@@ -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) {

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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,
)
}
}

View File

@@ -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,
)
}
}

View File

@@ -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")
}
}

View File

@@ -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)
}
}

View File

@@ -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>
}

View File

@@ -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)
}
}
}

View File

@@ -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)
}

View File

@@ -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) }
}
}

View File

@@ -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)
}

View 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)
}
}

View File

@@ -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")
}
}
}

View File

@@ -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" }

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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.*;

View File

@@ -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.*;