[Refactoring] Refactored ScriptLoader handling to make it more flexible

This commit is contained in:
hartie95 2024-01-08 20:32:25 +01:00
parent 44caa6d85d
commit 4daa7f98a4
12 changed files with 197 additions and 125 deletions

View File

@ -25,6 +25,11 @@ dependencies {
implementation("com.github.davidmoten:rtree-multi:0.1")
implementation("io.github.oshai:kotlin-logging-jvm:5.1.0")
}
tasks.withType<KotlinCompile>().configureEach {
compilerOptions {
freeCompilerArgs.add("-Xjvm-default=all")
}
}
tasks.test {
useJUnitPlatform()

View File

@ -0,0 +1,82 @@
package org.anime_game_servers.gi_lua.models.loader
import org.anime_game_servers.lua.engine.BaseScriptLoader
import org.anime_game_servers.lua.models.ScriptType
interface SceneScriptParams : BaseScriptLoader.ScriptLoadParams {
val scriptSource: ScriptSource
val targetId: Int
override fun getBaseDirectory() = if(scriptSource == ScriptSource.ACTIVITY)
"Activity/$targetId/"
else "Scene/$targetId/"
}
data class SceneGroupScriptLoadParams(
override val scriptSource: ScriptSource,
override val targetId: Int,
val groupId: Int
) : SceneScriptParams {
override fun getScriptName(): String = if(scriptSource == ScriptSource.ACTIVITY)
"activity${targetId}_group${groupId}.lua"
else "scene${targetId}_group${groupId}.lua"
override fun getScriptType(): ScriptType = ScriptType.EXECUTABLE
}
data class SceneBlockScriptLoadParams(
override val scriptSource: ScriptSource,
override val targetId: Int,
val blockId: Int
) : SceneScriptParams {
override fun getScriptName(): String = if(scriptSource == ScriptSource.ACTIVITY)
"activity${targetId}_block${blockId}.lua"
else "scene${targetId}_block${blockId}.lua"
}
data class SceneDummyPointScriptLoadParams(
val sceneId: Int
) : BaseScriptLoader.ScriptLoadParams {
override fun getBaseDirectory() = "Scene/$sceneId/"
override fun getScriptName(): String = "scene${sceneId}_dummy_points.lua"
}
data class SceneMetaScriptLoadParams(
val sceneId: Int
) : BaseScriptLoader.ScriptLoadParams {
override fun getBaseDirectory() = "Scene/$sceneId/"
override fun getScriptName(): String = "scene$sceneId.lua"
}
data class ActivityMetaScriptLoadParams(
val activityId: Int
) : BaseScriptLoader.ScriptLoadParams {
override fun getBaseDirectory() = "Activity/$activityId/"
override fun getScriptName(): String = "activity$activityId.lua"
}
class SceneReplacementScriptLoadParams : BaseScriptLoader.ScriptLoadParams {
override fun getBaseDirectory() = "Scene/"
override fun getScriptName(): String = "groups_replacement.lua"
}
data class ShardQuestScriptLoadParams(
val questId: Int
) : BaseScriptLoader.ScriptLoadParams {
override fun getBaseDirectory() = "Quest/Share/"
override fun getScriptName(): String = "Q${questId}ShareConfig.lua"
}
data class GadgetScriptLoadParams(
val gadgetScript: String
) : BaseScriptLoader.ScriptLoadParams {
override fun getBaseDirectory() = "Gadget/"
override fun getScriptName(): String = gadgetScript
override fun getScriptType(): ScriptType = ScriptType.EXECUTABLE
}
data class CommonScriptLoadParams(
val commonPath: String,
val commonScript: String
) : BaseScriptLoader.ScriptLoadParams {
// TODO constructor that accepts a single common parameter from lua
override fun getBaseDirectory() = "Common/$commonPath"
override fun getScriptName(): String = commonScript
override fun getScriptType(): ScriptType = ScriptType.EXECUTABLE
}

View File

@ -1,111 +0,0 @@
package org.anime_game_servers.gi_lua.models.loader;
import io.github.oshai.kotlinlogging.KLogger;
import io.github.oshai.kotlinlogging.KotlinLogging;
import lombok.val;
import org.anime_game_servers.lua.engine.BaseScriptLoader;
import org.anime_game_servers.lua.engine.LuaEngine;
import org.anime_game_servers.lua.engine.LuaScript;
import org.anime_game_servers.lua.engine.ScriptConfig;
import org.anime_game_servers.lua.models.ScriptType;
import javax.script.ScriptException;
import java.nio.file.Path;
public interface GIScriptLoader extends BaseScriptLoader {
KLogger logger = KotlinLogging.INSTANCE.logger(GIScriptLoader.class.getName());
LuaScript getScript(ScriptSource scriptSource, int typeId, String scriptName, Path scriptPath, ScriptType scriptType);
ScriptConfig getScriptConfig();
default LuaScript getScript(ScriptSource scriptSource, String scriptName, Path scriptPath, ScriptType scriptType){
if (scriptSource.getNeedsId())
throw new IllegalArgumentException("ScriptSource "+scriptSource.name()+" needs an id");
return getScript(scriptSource, 0, scriptName, scriptPath, scriptType);
}
default Path getScriptPath(ScriptSource type, String scriptName){
if (type.getNeedsId())
throw new IllegalArgumentException("ScriptSource "+type.name()+" needs an id");
return getScriptPath(type, 0, scriptName);
}
default Path getScriptPath(ScriptSource type, int typeId, String scriptName){
val basePath = switch (type) {
case SCENE -> "Scene/" + typeId + "/" + scriptName;
case SCENE_REPLACEMENT -> "Scene/" + scriptName;
case ACTIVITY-> "Activity/" + typeId + "/" + scriptName;
case COMMON -> "Common/" + scriptName;
case GADGET -> "Gadget/" + scriptName;
case SHARED_QUESTS -> "Quest/Share/" + scriptName;
};
return getScriptPath(basePath);
}
default boolean loadData(ScriptSource type, int typeId, String scriptName, ScriptType scriptType, ScriptParser parser) {
val path = getScriptPath(type, typeId, scriptName);
val cs = getScript(type, typeId, scriptName, path, scriptType);
if (cs == null) {
logger.warn(() -> "No script found for "+type.name()+" " + typeId);
return false;
}
// Eval script
try {
cs.evaluate();
parser.parse(cs);
} catch (ScriptException exception) {
logger.error(exception, () -> "An error occurred while running the script "+scriptName);
return false;
}
return true;
}
default void addDefaultsForEngine(LuaEngine luaEngine){
LuaEngine.registerNamespace("org.anime_game_servers.core.gi");
LuaEngine.registerNamespace("org.anime_game_servers.gi_lua");
luaEngine.addGlobals();
}
default boolean loadSceneReplacementScript(ScriptParser parser){
return loadData(ScriptSource.SCENE_REPLACEMENT, 0, "groups_replacement.lua", ScriptType.DATA_STORAGE, parser);
}
default boolean loadSharedQuestScript(ScriptParser parser, int questId){
return loadData(ScriptSource.SHARED_QUESTS, questId, "Q"+questId+"ShareConfig.lua", ScriptType.DATA_STORAGE, parser);
}
default boolean loadSceneMetaScript(int sceneId, ScriptParser parser){
return loadData(ScriptSource.SCENE, sceneId, "scene"+sceneId+".lua", ScriptType.DATA_STORAGE, parser);
}
default boolean loadSceneBlockScript(ScriptSource scriptSource, int targetId, int blockId, ScriptParser parser){
if(scriptSource == ScriptSource.SCENE)
return loadData(scriptSource, targetId, "scene"+targetId+"_block"+blockId+".lua", ScriptType.DATA_STORAGE, parser);
else
return loadData(scriptSource, targetId, "activity"+targetId+"_block"+blockId+".lua", ScriptType.DATA_STORAGE, parser);
}
default boolean loadSceneGroupScript(ScriptSource scriptSource, int targetId, int groupId, ScriptParser parser){
if(scriptSource == ScriptSource.SCENE)
return loadData(scriptSource, targetId, "scene"+targetId+"_group"+groupId+".lua", ScriptType.EXECUTABLE, parser);
else
return loadData(scriptSource, targetId, "activity"+targetId+"_group"+groupId+".lua", ScriptType.EXECUTABLE, parser);
}
default boolean loadSceneDummyPoints(int sceneId, ScriptParser parser){
return loadData(ScriptSource.SCENE, sceneId, "scene"+sceneId+"_dummy_points.lua", ScriptType.DATA_STORAGE, parser);
}
default boolean loadActivityMetaScript(int activityId, ScriptParser parser){
return loadData(ScriptSource.ACTIVITY, activityId, "activity"+activityId+".lua", ScriptType.DATA_STORAGE, parser);
}
default boolean loadActivityBlockScript(int activityId, int blockId, ScriptParser parser){
return loadData(ScriptSource.ACTIVITY, activityId, "activity"+activityId+"_block"+blockId+".lua", ScriptType.DATA_STORAGE, parser);
}
interface ScriptParser {
void parse(LuaScript script) throws ScriptException;
}
}

View File

@ -0,0 +1,30 @@
package org.anime_game_servers.gi_lua.models.loader
import io.github.oshai.kotlinlogging.KLogger
import io.github.oshai.kotlinlogging.KotlinLogging.logger
import org.anime_game_servers.lua.engine.BaseScriptLoader
import org.anime_game_servers.lua.engine.LuaEngine
@JvmDefaultWithCompatibility
interface GIScriptLoader : BaseScriptLoader {
fun addDefaultsForEngine(luaEngine: LuaEngine) {
LuaEngine.registerNamespace("org.anime_game_servers.core.gi")
LuaEngine.registerNamespace("org.anime_game_servers.gi_lua")
luaEngine.addGlobals()
}
override fun getRequireScriptParams(scriptName: String): BaseScriptLoader.ScriptLoadParams {
val path = scriptName.substringBeforeLast('/', "").let {
if (it.isEmpty()) "" else "$it/"
}
val file = scriptName.substringAfterLast('/').let {
if(!it.endsWith(".lua")) "${it}.lua" else it
}
return CommonScriptLoadParams(path, file)
}
companion object {
val logger: KLogger = logger(GIScriptLoader::class.java.name)
}
}

View File

@ -5,6 +5,7 @@ import io.github.oshai.kotlinlogging.KotlinLogging;
import lombok.Getter;
import lombok.ToString;
import lombok.val;
import org.anime_game_servers.gi_lua.models.loader.ActivityMetaScriptLoadParams;
import org.anime_game_servers.gi_lua.models.loader.GIScriptLoader;
import org.anime_game_servers.gi_lua.models.scene.block.SceneBlock;
import org.anime_game_servers.gi_lua.models.scene.block.SceneGroupInfo;
@ -48,7 +49,8 @@ public class ActivityMeta {
}
private boolean loadActivityMeta(GIScriptLoader scriptLoader){
return scriptLoader.loadActivityMetaScript(activityId, (cs -> {
val metaParams = new ActivityMetaScriptLoadParams(activityId);
return scriptLoader.loadData(metaParams, (cs -> {
// Create blocks
this.blockIds = cs.getGlobalVariableList("blocks", Integer.class);
}));

View File

@ -5,6 +5,8 @@ import io.github.oshai.kotlinlogging.KotlinLogging;
import lombok.Getter;
import lombok.ToString;
import lombok.val;
import org.anime_game_servers.gi_lua.models.loader.SceneDummyPointScriptLoadParams;
import org.anime_game_servers.gi_lua.models.loader.SceneMetaScriptLoadParams;
import org.anime_game_servers.gi_lua.models.scene.block.SceneBlock;
import org.anime_game_servers.gi_lua.models.scene.block.SceneGroupInfo;
import org.anime_game_servers.gi_lua.models.scene.group.SceneGroup;
@ -54,7 +56,8 @@ public class SceneMeta {
}
private boolean loadSceneMeta(GIScriptLoader scriptLoader){
return scriptLoader.loadSceneMetaScript(sceneId, (cs -> {
val sceneData = new SceneMetaScriptLoadParams(sceneId);
return scriptLoader.loadData(sceneData, (cs -> {
this.config = cs.getGlobalVariable("scene_config", SceneConfig.class);
// TODO optimize later
@ -69,7 +72,8 @@ public class SceneMeta {
}
private void loadDummyPoints(GIScriptLoader scriptLoader){
scriptLoader.loadSceneDummyPoints(sceneId, (cs -> {
val scriptParams = new SceneDummyPointScriptLoadParams(sceneId);
scriptLoader.loadData(scriptParams, (cs -> {
this.dummyPoints = cs.getGlobalVariableMap("dummy_points", DummyPoint.class);
}));
}

View File

@ -5,6 +5,7 @@ import io.github.oshai.kotlinlogging.KLogger;
import io.github.oshai.kotlinlogging.KotlinLogging;
import lombok.*;
import org.anime_game_servers.gi_lua.models.PositionImpl;
import org.anime_game_servers.gi_lua.models.loader.SceneBlockScriptLoadParams;
import org.anime_game_servers.gi_lua.models.loader.ScriptSource;
import org.anime_game_servers.gi_lua.models.scene.ActivityMeta;
import org.anime_game_servers.gi_lua.models.scene.SceneMeta;
@ -58,7 +59,8 @@ public class SceneBlock {
val scriptType = activityId == 0 ? ScriptSource.SCENE : ScriptSource.ACTIVITY;
val typeId = activityId == 0 ? sceneId : activityId;
if( !scriptLoader.loadSceneBlockScript(scriptType, typeId, id, (cs -> {
val sceneBlockParams = new SceneBlockScriptLoadParams(scriptType, typeId, id);
if( !scriptLoader.loadData(sceneBlockParams, (cs -> {
// Set groups
this.groupInfo = cs.getGlobalVariableList("groups", SceneGroupInfo.class).stream()
.collect(Collectors.toMap(x -> x.getId(), y -> y, (a, b) -> a));

View File

@ -5,6 +5,7 @@ import io.github.oshai.kotlinlogging.KotlinLogging;
import lombok.Getter;
import lombok.ToString;
import lombok.val;
import org.anime_game_servers.gi_lua.models.loader.SceneGroupScriptLoadParams;
import org.anime_game_servers.gi_lua.models.scene.SceneMeta;
import org.anime_game_servers.gi_lua.models.loader.ScriptSource;
import org.anime_game_servers.gi_lua.models.scene.block.SceneGroupInfo;
@ -95,7 +96,8 @@ public class SceneGroup {
val scriptType = activityId == 0 ? ScriptSource.SCENE : ScriptSource.ACTIVITY;
val typeId = activityId == 0 ? sceneId : activityId;
if (!scriptLoader.loadSceneGroupScript(scriptType, typeId, groupId, cs -> {
val groupParams = new SceneGroupScriptLoadParams(scriptType, typeId, groupId);
if (!scriptLoader.loadData(groupParams, cs -> {
this.script = cs;
// Set
this.monsters = cs.getGlobalVariableList("monsters", SceneMonster.class).stream()

View File

@ -32,18 +32,17 @@ public class JNLuaRequireCommonFunction implements NamedJavaFunction {
public int invoke(LuaState luaState) {
val requiredName = luaState.checkString(1);
luaState.remove(1);
val path = "Common/" + requiredName + ".lua";
val includePath = scriptConfig.getScriptLoader().getScriptPath(path);
if (!Files.exists(includePath)) {
logger.error(() -> "Require script not found. " + path);
val params = scriptConfig.getScriptLoader().getRequireScriptParams(requiredName);
val includeScript = scriptConfig.getScriptLoader().openScript(params);
if (includeScript == null) {
logger.error(() -> "Require script not found. " + params.getBasePath());
return 1;
}
try {
val includeScript = Files.newInputStream(includePath);
luaState.load(includeScript, requiredName, "t");
luaState.call(0, 0);
} catch (IOException e) {
logger.error(e, ()-> "Error on loading require script. " + path);
logger.error(e, ()-> "Error on loading require script. " + params.getBasePath());
return 2;
}
return 0;

View File

@ -34,8 +34,8 @@ class LuaJEngine(override val scriptConfig: ScriptConfig) : LuaEngine {
// Set engine to replace require as a temporary fix to missing scripts
context.globals.finder = object : ResourceFinder {
override fun findResource(filename: String): InputStream {
val scriptPath = scriptConfig.scriptLoader.getScriptPath(filename)
val stream = scriptConfig.scriptLoader.openScript(scriptPath!!)
val params = scriptConfig.scriptLoader.getRequireScriptParams(filename)
val stream = scriptConfig.scriptLoader.openScript(params)
return stream ?: ByteArrayInputStream(ByteArray(0))
}

View File

@ -12,6 +12,13 @@ kotlin {
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
compilations.all {
compileTaskProvider.configure {
compilerOptions {
freeCompilerArgs.add("-Xjvm-default=all")
}
}
}
}
js(IR) {
browser {
@ -22,6 +29,7 @@ kotlin {
}
}
}
val hostOs = System.getProperty("os.name")
val isMingwX64 = hostOs.startsWith("Windows")
val nativeTarget = when {

View File

@ -1,9 +1,58 @@
package org.anime_game_servers.lua.engine
import io.github.oshai.kotlinlogging.KLogger
import io.github.oshai.kotlinlogging.KotlinLogging
import org.anime_game_servers.lua.models.ScriptType
import java.io.InputStream
import java.nio.file.Path
import javax.script.ScriptException
@JvmDefaultWithCompatibility
interface BaseScriptLoader {
fun openScript(scriptPath: Path): InputStream?
fun getScriptPath(scriptName: String): Path?
fun getRequireScriptParams(scriptName: String): ScriptLoadParams
fun openScript(params: ScriptLoadParams): InputStream?
fun getScript(
scriptLoadParams: ScriptLoadParams
): LuaScript?
fun loadData(
scriptLoadParams: ScriptLoadParams,
parser: ScriptParser
): Boolean {
val cs = getScript(scriptLoadParams)
if (cs == null) {
logger.warn { "No script found for " + scriptLoadParams.getBaseDirectory() }
return false
}
// Eval script
try {
cs.evaluate()
parser.parse(cs)
} catch (exception: ScriptException) {
logger.error(exception) { "An error occurred while running the script ${scriptLoadParams.getScriptName()}" }
return false
}
return true
}
interface ScriptLoadParams {
fun getBaseDirectory(): String
fun getScriptName(): String
fun getBasePath(): String = getBaseDirectory() + getScriptName()
fun getScriptType(): ScriptType = ScriptType.DATA_STORAGE
}
interface ScriptParser {
@Throws(ScriptException::class)
fun parse(script: LuaScript)
}
companion object {
val logger: KLogger = KotlinLogging.logger(BaseScriptLoader::class.java.name)
}
}