replace rhino scripting engine with kotlin scripting

This commit is contained in:
Julian Krings 2025-04-23 14:21:09 +02:00
parent f1c72974fd
commit c597c55c2c
No known key found for this signature in database
GPG Key ID: 208C6E08C3B718D2
14 changed files with 188 additions and 242 deletions

View File

@ -168,8 +168,6 @@ allprojects {
compileOnly 'com.google.code.gson:gson:2.10.1'
compileOnly 'org.ow2.asm:asm:9.2'
compileOnly 'com.google.guava:guava:33.0.0-jre'
compileOnly 'bsf:bsf:2.4.0'
compileOnly 'rhino:js:1.7R2'
compileOnly 'com.github.ben-manes.caffeine:caffeine:3.0.6'
compileOnly 'org.apache.commons:commons-lang3:3.12.0'
compileOnly 'com.github.oshi:oshi-core:6.6.5'

View File

@ -30,6 +30,7 @@ import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import com.volmit.iris.core.pregenerator.LazyPregenerator;
import com.volmit.iris.core.scripting.ExecutionEnvironment;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.core.tools.IrisWorldCreator;
@ -462,6 +463,7 @@ public class Iris extends VolmitPlugin implements Listener {
compat = IrisCompat.configured(getDataFile("compat.json"));
ServerConfigurator.configure();
new IrisContextInjector();
ExecutionEnvironment.createSimple();
IrisSafeguard.IrisSafeguardSystem();
getSender().setTag(getTag());
IrisSafeguard.earlySplash();

View File

@ -252,10 +252,8 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
if (engine != null && t.getPreprocessors().isNotEmpty()) {
synchronized (this) {
engine.getExecution().getAPI().setPreprocessorObject(t);
for (String i : t.getPreprocessors()) {
engine.getExecution().execute(i);
engine.getExecution().preprocessObject(i, t);
Iris.debug("Loader<" + C.GREEN + t.getTypeName() + C.LIGHT_PURPLE + "> iprocess " + C.YELLOW + t.getLoadKey() + C.LIGHT_PURPLE + " in <rainbow>" + i);
}
}

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

@ -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.ExecutionEnvironment;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.object.annotations.Snippet;
@ -274,6 +275,7 @@ public class IrisProject {
PrecisionStopwatch p = PrecisionStopwatch.start();
JSONObject j = createCodeWorkspaceConfig();
IO.writeAll(ws, j.toString(4));
ExecutionEnvironment.createPack(IrisData.get(path)).buildProject();
p.end();
return true;
} catch (Throwable e) {

View File

@ -0,0 +1,160 @@
package com.volmit.iris.core.scripting;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.io.IO;
import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.util.*;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
@UtilityClass
public class ExecutionEnvironment {
private static final String BASE_URL = "https://jitpack.io/com/github/VolmitSoftware/Iris-Scripts/%s/Iris-Scripts-%s-all.jar";
private static final Provider PROVIDER = ServiceLoader.load(Provider.class, buildLoader())
.findFirst()
.orElseThrow();
@NonNull
public static Engine createEngine(@NonNull com.volmit.iris.engine.framework.Engine engine) {
return PROVIDER.createEngine(engine);
}
@NonNull
public static Pack createPack(@NonNull IrisData data) {
return PROVIDER.createPack(data);
}
@NonNull
public static Simple createSimple() {
return PROVIDER.createSimple();
}
@SneakyThrows
private static URLClassLoader buildLoader() {
String version = "ac94c94427";
String url = BASE_URL.formatted(version, version);
String hash = IO.hash("Iris-Scripts.jar@" + version);
var file = Iris.instance.getDataFile("cache", hash.substring(0, 2), hash.substring(3, 5), hash);
var libsDir = new File(file.getParentFile(), "libs");
KList<String> libs = null;
if (!file.exists()) {
libsDir.mkdirs();
Iris.info("Downloading Script Engine...");
var tempFile = Iris.getNonCachedFile(UUID.randomUUID().toString(), url);
try (var jar = new JarFile(tempFile); var out = new JarOutputStream(new FileOutputStream(file)) ) {
libs = getLibraries(jar);
for (var it = jar.entries().asIterator(); it.hasNext(); ) {
var entry = it.next();
if (entry.isDirectory()) {
out.putNextEntry(entry);
out.closeEntry();
continue;
}
try (var in = jar.getInputStream(entry)) {
if (libs.contains(entry.getName())) {
var target = new File(libsDir, entry.getName());
target.getParentFile().mkdirs();
Files.copy(in, target.toPath());
continue;
}
out.putNextEntry(entry);
IO.copy(in, out);
out.closeEntry();
}
}
}
IO.deleteUp(tempFile);
Iris.info("Downloaded Script Engine!");
}
if (libs == null) {
try (var jar = new JarFile(file)) {
libs = getLibraries(jar);
}
}
var urls = new URL[libs.size() + 1];
urls[0] = file.toURI().toURL();
for (int i = 0; i < libs.size(); i++) {
File lib = new File(libsDir, libs.get(i));
if (!lib.exists()) {
Iris.warn("Missing library: " + lib.getAbsolutePath());
continue;
}
urls[i + 1] = lib.toURI().toURL();
}
return new URLClassLoader(urls, Provider.class.getClassLoader());
}
private static KList<String> getLibraries(JarFile jar) throws IOException {
return new KList<>(jar.getManifest()
.getMainAttributes()
.getValue("Libraries")
.split(";"));
}
public interface Provider {
@NonNull
Engine createEngine(@NonNull com.volmit.iris.engine.framework.Engine engine);
@NonNull
Pack createPack(@NonNull IrisData data);
@NonNull
Simple createSimple();
}
public interface Simple {
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() {
}
}
public interface Pack extends Simple {
@NonNull
IrisData getData();
void buildProject();
}
public interface Engine extends Pack {
@NonNull
com.volmit.iris.engine.framework.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,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.ExecutionEnvironment;
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;
@ -93,7 +93,7 @@ public class IrisEngine implements Engine {
private CompletableFuture<Long> hash32;
private EngineMode mode;
private EngineEffects effects;
private EngineExecutionEnvironment execution;
private ExecutionEnvironment.Engine execution;
private EngineWorldManager worldManager;
private volatile int parallelism;
private volatile int minHeight;
@ -171,7 +171,7 @@ public class IrisEngine implements Engine {
cacheId = RNG.r.nextInt();
worldManager = new IrisWorldManager(this);
complex = new IrisComplex(this);
execution = new IrisExecutionEnvironment(this);
execution = ExecutionEnvironment.createEngine(this);
effects = new IrisEngineEffects(this);
hash32 = new CompletableFuture<>();
setupMode();

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,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.ExecutionEnvironment;
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;
@ -111,7 +111,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
IrisContext getContext();
EngineExecutionEnvironment getExecution();
ExecutionEnvironment.Engine getExecution();
double getMaxBiomeObjectDensity();

View File

@ -211,9 +211,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();
@ -353,11 +352,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

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

@ -16,8 +16,6 @@ libraries:
- org.zeroturnaround:zt-zip:1.14
- it.unimi.dsi:fastutil:8.5.6
- org.ow2.asm:asm:9.2
- rhino:js:1.7R2
- bsf:bsf:2.4.0
- org.lz4:lz4-java:1.8.0
- com.github.oshi:oshi-core:6.6.5
commands: