merge kts engine into this codebase

This commit is contained in:
Julian Krings 2025-07-09 15:16:11 +02:00
parent 4b0766c097
commit 1bc6192c8b
No known key found for this signature in database
GPG Key ID: 208C6E08C3B718D2
24 changed files with 591 additions and 57 deletions

View File

@ -26,6 +26,8 @@ plugins {
alias(libs.plugins.shadow) alias(libs.plugins.shadow)
alias(libs.plugins.sentry) alias(libs.plugins.sentry)
alias(libs.plugins.slimjar) alias(libs.plugins.slimjar)
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.lombok)
} }
val apiVersion = "1.19" val apiVersion = "1.19"
@ -91,6 +93,14 @@ dependencies {
slim(libs.byteBuddy.agent) slim(libs.byteBuddy.agent)
slim(libs.dom4j) slim(libs.dom4j)
slim(libs.jaxen) 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)
} }
java { java {
@ -117,6 +127,9 @@ slimJar {
relocate("net.kyori", "$lib.kyori") relocate("net.kyori", "$lib.kyori")
relocate("org.bstats", "$lib.metrics") relocate("org.bstats", "$lib.metrics")
relocate("io.sentry", "$lib.sentry") relocate("io.sentry", "$lib.sentry")
relocate("org.apache.maven", "$lib.maven")
relocate("org.codehaus.plexus", "$lib.plexus")
relocate("org.eclipse.sisu", "$lib.sisu")
} }
tasks { tasks {

View File

@ -53,6 +53,7 @@ import com.volmit.iris.util.io.JarScanner;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.misc.Bindings; import com.volmit.iris.util.misc.Bindings;
import com.volmit.iris.util.misc.SlimJar;
import com.volmit.iris.util.misc.getHardware; import com.volmit.iris.util.misc.getHardware;
import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.IrisService; import com.volmit.iris.util.plugin.IrisService;
@ -438,13 +439,7 @@ public class Iris extends VolmitPlugin implements Listener {
} }
public Iris() { public Iris() {
ApplicationBuilder.appending("Iris") SlimJar.load(getDataFolder("cache", "libraries"));
.downloadDirectoryPath(getDataFolder("cache", "libraries").toPath())
.logger((message, args) -> {
if (!message.startsWith("Loaded library ")) return;
getLogger().info(message.formatted(args));
})
.build();
} }
private void enable() { private void enable() {

View File

@ -1,81 +1,37 @@
package com.volmit.iris.core.scripting; package com.volmit.iris.core.scripting;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant; import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.util.io.IO; import com.volmit.iris.core.scripting.kotlin.environment.IrisExecutionEnvironment;
import com.volmit.iris.core.scripting.kotlin.environment.IrisPackExecutionEnvironment;
import com.volmit.iris.core.scripting.kotlin.environment.IrisSimpleExecutionEnvironment;
import lombok.NonNull; import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
import java.util.*; import java.util.*;
@UtilityClass @UtilityClass
public class ExecutionEnvironment { public class ExecutionEnvironment {
private static final String VERSION = System.getProperty("iris.scriptVersion", "master-ffbf167eba-1");
private static final String BASE_URL = "https://jitpack.io/com/github/VolmitSoftware/Iris-Scripts/" + VERSION + "/Iris-Scripts-" + VERSION + "-all.jar";
private static final Provider PROVIDER = ServiceLoader.load(Provider.class, buildLoader())
.findFirst()
.orElseThrow()
.init(Iris.instance.getDataFolder("cache", "libraries").toPath());
@NonNull @NonNull
public static Engine createEngine(@NonNull com.volmit.iris.engine.framework.Engine engine) { public static Engine createEngine(@NonNull com.volmit.iris.engine.framework.Engine engine) {
return PROVIDER.createEngine(engine); return new IrisExecutionEnvironment(engine);
} }
@NonNull @NonNull
public static Pack createPack(@NonNull IrisData data) { public static Pack createPack(@NonNull IrisData data) {
return PROVIDER.createPack(data); return new IrisPackExecutionEnvironment(data);
} }
@NonNull @NonNull
public static Simple createSimple() { public static Simple createSimple() {
return PROVIDER.createSimple(); return new IrisSimpleExecutionEnvironment();
} }
@SneakyThrows
private static URLClassLoader buildLoader() {
try (HttpClient client = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.ALWAYS).build()) {
var resolved = client.send(HttpRequest.newBuilder(URI.create(BASE_URL)).build(), HttpResponse.BodyHandlers.discarding())
.request();
String hash = IO.hash(resolved.uri().getPath());
File file = Iris.instance.getDataFile("cache", hash.substring(0, 2), hash.substring(3, 5), hash + ".jar");
if (!file.exists()) {
file.getParentFile().mkdirs();
Iris.info("Downloading Script Engine...");
client.send(resolved, HttpResponse.BodyHandlers.ofFile(file.toPath()));
Iris.info("Downloaded Script Engine!");
}
return new URLClassLoader(new URL[]{file.toURI().toURL()}, Provider.class.getClassLoader());
}
}
public interface Provider {
Provider init(Path localRepository);
@NonNull
Engine createEngine(@NonNull com.volmit.iris.engine.framework.Engine engine);
@NonNull
Pack createPack(@NonNull IrisData data);
@NonNull
Simple createSimple();
}
public interface Simple { public interface Simple {
void configureProject(@NonNull File projectDir); void configureProject(@NonNull File projectDir);

View File

@ -0,0 +1,37 @@
package com.volmit.iris.util.misc;
import io.github.slimjar.app.builder.ApplicationBuilder;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;
public class SlimJar {
private static final Logger LOGGER = Logger.getLogger("Iris");
private static final ReentrantLock lock = new ReentrantLock();
private static final AtomicBoolean loaded = new AtomicBoolean();
public static void load(@Nullable File localRepository) {
if (loaded.get()) return;
lock.lock();
try {
if (loaded.getAndSet(true)) return;
if (localRepository == null) {
localRepository = new File(".iris/libraries");
}
ApplicationBuilder.appending("Iris")
.downloadDirectoryPath(localRepository.toPath())
.logger((message, args) -> {
if (!message.startsWith("Loaded library ")) return;
LOGGER.info(message.formatted(args));
})
.build();
} finally {
lock.unlock();
}
}
}

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,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,40 @@
package com.volmit.iris.core.scripting.kotlin.base
import com.volmit.iris.core.scripting.kotlin.runner.configureMavenDepsOnAnnotations
import com.volmit.iris.util.misc.SlimJar
import kotlin.script.experimental.annotations.KotlinScript
import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.defaultImports
import kotlin.script.experimental.api.isStandalone
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({
SlimJar.load(null)
isStandalone(false)
defaultImports(
"kotlin.script.experimental.dependencies.DependsOn",
"kotlin.script.experimental.dependencies.Repository",
"com.volmit.iris.Iris.info",
"com.volmit.iris.Iris.debug",
"com.volmit.iris.Iris.warn",
"com.volmit.iris.Iris.error"
)
jvm {
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.ExecutionEnvironment
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), ExecutionEnvironment.Engine {
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,35 @@
package com.volmit.iris.core.scripting.kotlin.environment
import com.volmit.iris.core.loader.IrisData
import com.volmit.iris.core.scripting.ExecutionEnvironment
import com.volmit.iris.core.scripting.kotlin.base.DataScript
import com.volmit.iris.core.scripting.kotlin.runner.Script
import kotlin.reflect.KClass
import kotlin.script.experimental.api.valueOrThrow
open class IrisPackExecutionEnvironment(
private val data: IrisData
) : IrisSimpleExecutionEnvironment(), ExecutionEnvironment.Pack {
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.compileText(type, loaded.source, script) }
.valueOrThrow()
}
override fun execute(script: String) =
execute(script, DataScript::class.java, data.parameters())
override fun evaluate(script: String) =
evaluate(script, DataScript::class.java, data.parameters())
private fun IrisData.parameters(vararg values: Pair<String, Any?>): Map<String, Any?> {
return mapOf(
"data" to this,
*values,
)
}
}

View File

@ -0,0 +1,135 @@
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.ExecutionEnvironment
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.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.api.ResultWithDiagnostics
import kotlin.script.experimental.api.valueOrThrow
import kotlin.text.split
open class IrisSimpleExecutionEnvironment : ExecutionEnvironment.Simple {
protected val compileCache = KCache<String, KMap<KClass<*>, ResultWithDiagnostics<Script>>>({ _ -> KMap() }, IrisSettings.get().performance.cacheSize.toLong())
protected val runner = ScriptRunner()
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.clearConfigurations()
}
protected open fun compile(script: String, type: KClass<*>) =
compileCache.get(script)
.computeIfAbsent(type) { _ -> runner.compileText(type, script) }
.valueOrThrow()
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()
.valueOrNull()
} catch (e: Throwable) {
e.printStackTrace()
}
current.contextClassLoader = loader
return null
}
override fun configureProject(projectDir: File) {
projectDir.mkdirs()
val libs = javaClass.classLoader.parent.classpath
.sortedBy { it.absolutePath }
.toMutableList()
libs.add(codeSource)
libs.removeIf { libs.count { f -> f.name == it.name } > 1 }
File(projectDir, "build.gradle.kts")
.updateClasspath(libs)
}
companion object {
private const val CLASSPATH = "val classpath = files("
private val codeSource = File(IrisSimpleExecutionEnvironment::class.java.protectionDomain.codeSource.location.toURI())
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.1.20")
}
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 {
add("script", classpath)
}""".trimIndent().split("\n")
}
}

View File

@ -0,0 +1,64 @@
package com.volmit.iris.core.scripting.kotlin.runner
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater
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()
@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 {
val cached = base.getClass(scriptEvaluationConfiguration)
updater.set(this, cached)
return cached
}
override fun evaluate(properties: Map<String, Any?>?) = host.runInCoroutineContext {
host.evaluator.invoke(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)
}
companion object {
private val updater = AtomicReferenceFieldUpdater.newUpdater(CachedScript::class.java, ResultWithDiagnostics::class.java, "value")
}
}

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,53 @@
package com.volmit.iris.core.scripting.kotlin.runner
import com.volmit.iris.core.scripting.kotlin.base.EngineScript
import java.util.concurrent.ConcurrentHashMap
import kotlin.reflect.KClass
import kotlin.script.experimental.api.*
import kotlin.script.experimental.dependencies.DependsOn
import kotlin.script.experimental.dependencies.Repository
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
) {
constructor() : this(BasicJvmScriptingHost())
private val configs = ConcurrentHashMap<KClass<*>, ScriptCompilationConfiguration>()
private val hostConfig = host.baseHostConfiguration.withDefaultsFrom(defaultJvmScriptingHostConfiguration)
fun compileText(type: KClass<*>, raw: String, name: String? = null) = compile(type, raw.toScriptSource(name))
fun clearConfigurations() = configs.clear()
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
) {
if (EngineScript::class.java.isAssignableFrom(type.java))
return@createCompilationConfigurationFromTemplate
jvm {
dependenciesFromClassContext(type, wholeClasspath = true)
}
refineConfiguration {
onAnnotations(DependsOn::class, Repository::class, handler = ::configureMavenDepsOnAnnotations)
}
}
}

View File

@ -0,0 +1,54 @@
package com.volmit.iris.core.scripting.kotlin.runner
import kotlinx.coroutines.runBlocking
import java.io.File
import kotlin.script.experimental.api.*
import kotlin.script.experimental.dependencies.CompoundDependenciesResolver
import kotlin.script.experimental.dependencies.FileSystemDependenciesResolver
import kotlin.script.experimental.dependencies.maven.MavenDependenciesResolver
import kotlin.script.experimental.dependencies.resolveFromScriptSourceAnnotations
import kotlin.script.experimental.jvm.updateClasspath
import kotlin.script.experimental.jvm.util.classpathFromClassloader
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
}
internal val resolver = CompoundDependenciesResolver(FileSystemDependenciesResolver(), MavenDependenciesResolver())
internal fun configureMavenDepsOnAnnotations(context: ScriptConfigurationRefinementContext): ResultWithDiagnostics<ScriptCompilationConfiguration> {
val annotations = context.collectedData?.get(ScriptCollectedData.collectedAnnotations)?.takeIf { it.isNotEmpty() }
?: return context.compilationConfiguration.asSuccess()
return runBlocking {
resolver.resolveFromScriptSourceAnnotations(annotations)
}.onSuccess {
context.compilationConfiguration.with {
updateClasspath(it)
}.asSuccess()
}
}
internal fun Collection<File>.format(projectDir: File): Collection<String> {
val projectDir = projectDir.absolutePath
val home = File(System.getProperty("user.home")).absolutePath
return map { format(it, projectDir, home) }.toSet()
}
internal val ClassLoader.classpath get() = classpathFromClassloader(this) ?: emptyList()
private fun format(file: File, projectDir: String, home: String): String {
val path = file.absolutePath
return when {
path.startsWith(projectDir) -> $$"$PROJECT_DIR$/$${path.substring(projectDir.length + 1)}"
path.startsWith(home) -> $$"$USER_HOME$/$${path.substring(home.length + 1)}"
else -> path
}
}

View File

@ -37,6 +37,10 @@ byte-buddy = "1.17.6" # https://central.sonatype.com/artifact/net.bytebuddy/byte
dom4j = "2.2.0" # https://central.sonatype.com/artifact/org.dom4j/dom4j dom4j = "2.2.0" # https://central.sonatype.com/artifact/org.dom4j/dom4j
jaxen = "2.0.0" # https://central.sonatype.com/artifact/jaxen/jaxen jaxen = "2.0.0" # https://central.sonatype.com/artifact/jaxen/jaxen
# Script Engine
kotlin = "2.2.0"
kotlin-coroutines = "1.10.2"
# Third Party Integrations # Third Party Integrations
nexo = "1.8.0" # https://repo.nexomc.com/#/releases/com/nexomc/nexo nexo = "1.8.0" # https://repo.nexomc.com/#/releases/com/nexomc/nexo
itemsadder = "4.0.10" # https://github.com/LoneDev6/API-ItemsAdder itemsadder = "4.0.10" # https://github.com/LoneDev6/API-ItemsAdder
@ -82,6 +86,14 @@ byteBuddy-agent = { module = "net.bytebuddy:byte-buddy-agent", version.ref = "by
dom4j = { module = "org.dom4j:dom4j", version.ref = "dom4j" } dom4j = { module = "org.dom4j:dom4j", version.ref = "dom4j" }
jaxen = { module = "jaxen:jaxen", version.ref = "jaxen" } 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"}
# Third Party Integrations # Third Party Integrations
nexo = { module = "com.nexomc:nexo", version.ref = "nexo" } nexo = { module = "com.nexomc:nexo", version.ref = "nexo" }
itemsadder = { module = "dev.lone:api-itemsadder", version.ref = "itemsadder" } itemsadder = { module = "dev.lone:api-itemsadder", version.ref = "itemsadder" }
@ -100,3 +112,5 @@ slimjar = { id = "de.crazydev22.slimjar", version.ref = "slimjar" }
download = { id = "de.undercouch.download", version.ref = "download" } download = { id = "de.undercouch.download", version.ref = "download" }
runPaper = { id = "xyz.jpenilla.run-paper", version.ref = "runPaper" } runPaper = { id = "xyz.jpenilla.run-paper", version.ref = "runPaper" }
sentry = { id = "io.sentry.jvm.gradle", version.ref = "sentryPlugin" } 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" }