[Refactoring/Fix] Some fixes and refactorings

* Fixed set parsing
* Added a way to work around lua require differences between the lua standard and the game scripts usage
* Added some more ScriptLibDefinitions
* Started moving to kotlinx.io where possible
This commit is contained in:
hartie95 2024-02-02 13:54:29 +01:00
parent 6c013a7557
commit 21b161f62b
19 changed files with 355 additions and 120 deletions

View File

@ -53,7 +53,7 @@ java {
publishing {
publications {
create<MavenPublication>("maven") {
from(components["kotlin"])
from(components["java"])
groupId = "org.anime_game_servers.lua"
artifactId = "GIlua"
}

View File

@ -20,7 +20,7 @@ public class SceneGroupInfo {
@Nullable @LuaNames("is_replaceable")
private SceneReplaceable isReplaceable;
@LuaNames("dynamic_load")
private final boolean dynamicLoad = false;
private boolean dynamicLoad = false;
@Nullable
private SceneBusiness business;
@Nullable @LuaNames("life_cycle")

View File

@ -1,5 +1,6 @@
package org.anime_game_servers.gi_lua.script_lib
import org.anime_game_servers.core.base.annotations.lua.LuaNames
import org.anime_game_servers.gi_lua.models.ScriptArgs
import org.anime_game_servers.gi_lua.models.scene.group.SceneGroup
@ -9,9 +10,11 @@ interface GroupEventLuaContext : LuaContext {
// fields used by some scripts
/*int uid();
int source_entity_id();
int target_entity_id();*/
val uid: Int
@LuaNames("source_entity_id")
val sourceEntityId: Int
@LuaNames("target_entity_id")
val targetEntityId: Int
/*override fun uid() = getArgs().uid
override fun source_entity_id() = getArgs().source_eid
override fun target_entity_id() = getArgs().target_eid*/

View File

@ -215,7 +215,7 @@ public class ScriptLib {
return context.getScriptLibHandler().GetRegionEntityCount(context, regionId, entityTypeEnum);
}
public int GetRegionConfigId(GroupEventLuaContext context, Object rawTable){
public static int GetRegionConfigId(GroupEventLuaContext context, Object rawTable){
val table = context.getEngine().getTable(rawTable);
val regionEid = table.getInt("region_eid");
return context.getScriptLibHandler().GetRegionConfigId(context, regionEid);
@ -773,7 +773,11 @@ public class ScriptLib {
return context.getScriptLibHandler().BeginCameraSceneLook(context, sceneLookParams);
}
public int ClearPlayerEyePoint(GroupEventLuaContext context, int var1){
public static int SetPlayerEyePointStream(GroupEventLuaContext context, int var1, int var2, boolean var3){
return context.getScriptLibHandler().SetPlayerEyePointStream(context, var1, var2, var3);
}
public static int ClearPlayerEyePoint(GroupEventLuaContext context, int var1){
return context.getScriptLibHandler().ClearPlayerEyePoint(context, var1);
}
@ -1073,6 +1077,10 @@ public class ScriptLib {
return context.getScriptLibHandler().AssignPlayerUidOpNotify(context, param1);
}
public static int CreateTreasureMapSpotRewardGadget(GroupEventLuaContext context, int gadgetCfgId){
return context.getScriptLibHandler().CreateTreasureMapSpotRewardGadget(context, gadgetCfgId);
}
/**
* TODO better parameter handling and verify active handling
@ -1199,12 +1207,21 @@ public class ScriptLib {
return handler.GetContextGroupId(context);
}
public static int SetGadgetEnableInteract(ControllerLuaContext<Object> context, int groupId, int configId, boolean enable) {
val handler = context.getScriptLibHandlerProvider().getGadgetControllerHandler();
if(handler == null){
return NOT_IMPLEMENTED.getValue();
public static int SetGadgetEnableInteract(LuaContext context, int groupId, int configId, boolean enable) {
if(context instanceof ControllerLuaContext cContext){
val handler = cContext.getScriptLibHandlerProvider().getGadgetControllerHandler();
if(handler == null){
return NOT_IMPLEMENTED.getValue();
}
return handler.SetGadgetEnableInteract(cContext, groupId, configId, enable);
} else if(context instanceof GroupEventLuaContext gContext){
val handler = gContext.getScriptLibHandlerProvider().getScriptLibHandler();
if(handler == null){
return NOT_IMPLEMENTED.getValue();
}
return handler.SetGadgetEnableInteract(gContext, groupId, configId, enable);
}
return handler.SetGadgetEnableInteract(context, groupId, configId, enable);
return NOT_IMPLEMENTED.getValue();
}
public static int DropSubfield(ControllerLuaContext<Object> context, Object paramsTable) {

View File

@ -22,6 +22,11 @@ public interface ScriptLibHandler<GroupEventContext extends GroupEventLuaContext
void PrintGroupWarning(LuaContext context, String msg);
int SetGadgetStateByConfigId(GroupEventContext context, int configId, int gadgetState);
int SetGroupGadgetStateByConfigId(GroupEventContext context, int groupId, int configId, int gadgetState);
/**
* Sets a gadget interacteable based on the config id and group id.
*/
int SetGadgetEnableInteract(GroupEventContext context, int groupId, int configId, boolean enable);
int SetWorktopOptionsByGroupId(GroupEventContext context, int groupId, int configId, LuaTable options);
int SetWorktopOptions(GroupEventContext context, LuaTable table);
@ -257,7 +262,8 @@ public interface ScriptLibHandler<GroupEventContext extends GroupEventLuaContext
int BeginCameraSceneLook(GroupEventContext context, LuaTable sceneLookParamsTable);
public int ClearPlayerEyePoint(GroupEventContext context, int var1);
int SetPlayerEyePointStream(GroupEventContext context, int var1, int var2, boolean var3);
int ClearPlayerEyePoint(GroupEventContext context, int var1);
int ShowReminderRadius(GroupEventContext context, int var1, LuaTable var2, int var3);
int ShowClientGuide(GroupEventContext context, String guideName);
@ -407,6 +413,8 @@ public interface ScriptLibHandler<GroupEventContext extends GroupEventLuaContext
*/
int AssignPlayerUidOpNotify(GroupEventContext context, LuaTable param1Table);
int CreateTreasureMapSpotRewardGadget(GroupEventContext context, int gadgetCfgId);
/**
* TODO better parameter handling and verify active handling
* Calls a lua function in the specified group if the group is active. The call parameters are passed to the called parameters like this:

View File

@ -24,6 +24,7 @@ dependencies {
annotationProcessor(libs.jvm.lombok)
implementation(libs.bundles.jvm.reflection)
implementation(libs.jvm.logging)
implementation(libs.jvm.kotlinx.io.core)
}
tasks.test {
@ -46,7 +47,7 @@ java {
publishing {
publications {
create<MavenPublication>("maven") {
from(components["kotlin"])
from(components["java"])
artifactId = "JNLuaEngine"
}
}

View File

@ -2,7 +2,9 @@ package org.anime_game_servers.jnlua_engine;
import io.github.oshai.kotlinlogging.KLogger;
import io.github.oshai.kotlinlogging.KotlinLogging;
import kotlinx.io.SourcesJvmKt;
import lombok.val;
import org.anime_game_servers.lua.engine.RequireMode;
import org.anime_game_servers.lua.engine.ScriptConfig;
import org.terasology.jnlua.LuaState;
import org.terasology.jnlua.NamedJavaFunction;
@ -30,21 +32,26 @@ public class JNLuaRequireCommonFunction implements NamedJavaFunction {
@Override
public int invoke(LuaState luaState) {
if(scriptConfig.getEnableIncludeWorkaround() == RequireMode.DISABLED){
return 0;
}
val requiredName = luaState.checkString(1);
luaState.remove(1);
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 {
luaState.load(includeScript, requiredName, "t");
try (val includeScript = scriptConfig.getScriptLoader().openScript(params);) {
if (includeScript == null) {
logger.error(() -> "Require script not found. " + params.getBasePath());
return 1;
}
val stream = SourcesJvmKt.asInputStream(includeScript);
luaState.load(stream, requiredName, "t");
luaState.call(0, 0);
} catch (IOException e) {
logger.error(e, ()-> "Error on loading require script. " + params.getBasePath());
return 2;
}
return 0;
}

View File

@ -1,11 +1,16 @@
package org.anime_game_servers.jnlua_engine;
import io.github.oshai.kotlinlogging.KLogger;
import io.github.oshai.kotlinlogging.KotlinLogging;
import kotlin.Pair;
import lombok.val;
import org.anime_game_servers.lua.engine.LuaEngine;
import org.anime_game_servers.lua.engine.LuaScript;
import org.anime_game_servers.lua.engine.LuaValue;
import org.anime_game_servers.lua.engine.RequireMode;
import org.anime_game_servers.lua.models.BooleanLuaValue;
import org.anime_game_servers.lua.models.IntLuaValue;
import org.anime_game_servers.lua.models.MutableBoolean;
import org.anime_game_servers.lua.models.ScriptType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -14,18 +19,23 @@ import org.terasology.jnlua.script.LuaBindings;
import org.terasology.jnlua.script.LuaScriptEngine;
import javax.script.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
public class JNLuaScript implements LuaScript {
private static KLogger logger = KotlinLogging.INSTANCE.logger(JNLuaScript.class.getName());
final Reader scriptReader;
@Nullable
private final CompiledLuaScript compiledScript;
private final String modifiedScript;
private final LuaBindings binding;
private final JNLuaEngine engine;
private final LuaScriptEngine scriptEngine;
@ -44,14 +54,60 @@ public class JNLuaScript implements LuaScript {
val requireFunction = JNLuaRequireCommonFunction.getInstance(engine.getScriptConfig());
binding.put(requireFunction.getName(), requireFunction);
scriptReader = Files.newBufferedReader(scriptPath);
val reader = Files.newBufferedReader(scriptPath);
this.scriptReader = reader;
if (engine.getScriptConfig().getEnableIncludeWorkaround() == RequireMode.ENABLED_WITH_WORKAROUND &&
(scriptType == ScriptType.EXECUTABLE || scriptType == ScriptType.STATIC_EXECUTABLE || scriptType == ScriptType.ONE_TIME_EXECUTABLE)) {
this.modifiedScript = compileScriptWithWorkaround(reader, scriptPath);
} else {
this.modifiedScript = null;
}
if(scriptType.getPrecompile()) {
this.compiledScript = (CompiledLuaScript) ((Compilable) scriptEngine).compile(scriptReader);
if(modifiedScript != null) {
this.compiledScript = (CompiledLuaScript) ((Compilable) scriptEngine).compile(modifiedScript);
} else {
this.compiledScript = (CompiledLuaScript) ((Compilable) scriptEngine).compile(scriptReader);
}
} else {
this.compiledScript = null;
}
}
// todo maybe caching?
private String compileScriptWithWorkaround(BufferedReader reader, Path path) throws IOException,ScriptException {
val requireRegex = Pattern.compile("\\s*require\\s+\"(.*)\"");
val changed = new MutableBoolean(false);
try {
val script = reader.lines().map(line -> {
val result = requireRegex.matcher(line);
if (result.matches()) {
val requireBasePath = engine.getScriptConfig().getScriptLoader().getRequireScriptParams(result.group(1)).getBasePath();
val requirePath = engine.getScriptConfig().getScriptLoader().getScriptPath(requireBasePath);
if(requirePath == null){
logger.warn(()->"Could not find require script "+result.group(1)+" for script "+ path);
return line;
}
try {
try (val requireReader = Files.newBufferedReader(requirePath)){
val requireScript = requireReader.lines().reduce((a, b) -> a + "\n" + b).orElse(line);
changed.setValue(true);
return requireScript;
}
} catch (IOException e) {
return line;
}
} else {
return line;
}
}).reduce((a, b) -> a + "\n" + b).orElse("");
return changed.getValue() ? script : null;
}
catch (Exception e) {
return null;
}
}
@Override
public boolean hasMethod(@NotNull String methodName) {
return binding.containsKey(methodName);
@ -75,7 +131,11 @@ public class JNLuaScript implements LuaScript {
if(compiledScript != null) {
compiledScript.eval(context);
} else {
scriptEngine.eval(scriptReader, context);
if(modifiedScript != null) {
scriptEngine.eval(modifiedScript, context);
} else {
scriptEngine.eval(scriptReader, context);
}
}
}

View File

@ -2,6 +2,7 @@ package org.anime_game_servers.jnlua_engine;
import io.github.oshai.kotlinlogging.KLogger;
import io.github.oshai.kotlinlogging.KotlinLogging;
import lombok.val;
import org.anime_game_servers.lua.serialize.BaseSerializer;
import org.terasology.jnlua.LuaValueProxy;
import org.terasology.jnlua.util.AbstractTableMap;
@ -10,10 +11,7 @@ import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
public class JNLuaSerializer extends BaseSerializer {
@ -52,11 +50,11 @@ public class JNLuaSerializer extends BaseSerializer {
@Override
public <T> Map<String, T> toMap(Class<T> type, Object obj) {
return serializeMap(type, (LuaValueProxy) obj);
return serializeMap(String.class, type, (LuaValueProxy) obj);
}
private <T> T objectToClass(Class<T> type, Object value) {
T object = null;
Object object = null;
if (value instanceof Integer) {
object = (T) getInt(value);
@ -69,14 +67,24 @@ public class JNLuaSerializer extends BaseSerializer {
} else {
object = serialize(type, null, (LuaValueProxy) value);
}
return object;
if(String.class.isAssignableFrom(type)){
return (T) String.valueOf(object);
} else {
return (T) object;
}
}
public <T> List<T> serializeList(Class<T> type, LuaValueProxy table) {
List<T> list = new ArrayList<>();
private <T> List<T> serializeList(Class<T> type, LuaValueProxy table) {
return serializeCollection(type, new ArrayList<>(), table);
}
private <T> Set<T> serializeSet(Class<T> type, LuaValueProxy table) {
return serializeCollection(type, new HashSet<>(), table);
}
public <T, Y extends Collection<T>> Y serializeCollection(Class<T> type, Y target, LuaValueProxy table) {
if (table == null) {
return list;
return target;
}
var tableObj = (Map<String, Object>) table;
@ -88,7 +96,7 @@ public class JNLuaSerializer extends BaseSerializer {
T object = objectToClass(type, keyValue);
if (object != null) {
list.add(object);
target.add(object);
}
} catch (Exception ex) {
@ -98,19 +106,7 @@ public class JNLuaSerializer extends BaseSerializer {
logger.error(e, () -> "Exception serializing list");
}
return list;
}
private Class<?> getListType(Class<?> type, @Nullable Field field){
if(field == null){
return type.getTypeParameters()[0].getClass();
}
Type fieldType = field.getGenericType();
if(fieldType instanceof ParameterizedType){
return (Class<?>) ((ParameterizedType) fieldType).getActualTypeArguments()[0];
}
return null;
return target;
}
public <T> T serialize(Class<T> type, @Nullable Field field, LuaValueProxy table) {
@ -118,13 +114,34 @@ public class JNLuaSerializer extends BaseSerializer {
if (type == List.class) {
try {
Class<?> listType = getListType(type, field);
Class<?> listType = getCollectionType(type, field);
return (T) serializeList(listType, table);
} catch (Exception e) {
logger.error(e, ()->"Exception serializing");
return null;
}
}
if (type == Set.class) {
try {
Class<?> listType = getCollectionType(type, field);
return (T) serializeSet(listType, table);
} catch (Exception e) {
logger.error("Exception while serializing {}", type.getName(), e);
return null;
}
}
if (type == Map.class) {
try {
val mapTypes = getMapTypes(type, field);
if(mapTypes == null){
return null;
}
return (T) serializeMap(mapTypes.component1(), mapTypes.component2(), table);
} catch (Exception e) {
logger.error("Exception while serializing {}", type.getName(), e);
return null;
}
}
try {
if (!fieldMetaCache.containsKey(type)) {
@ -161,7 +178,7 @@ public class JNLuaSerializer extends BaseSerializer {
set(object, fieldMeta, methodAccess, (boolean) keyValue);
} else if (fieldMeta.getType().equals(List.class)) {
LuaValueProxy objTable = (LuaValueProxy) tableObj.get(k.getKey());
Class<?> listType = getListType(type, fieldMeta.getField());
Class<?> listType = getCollectionType(type, fieldMeta.getField());
List<?> listObj = serializeList(listType, objTable);
set(object, fieldMeta, methodAccess, listObj);
} else {
@ -178,25 +195,31 @@ public class JNLuaSerializer extends BaseSerializer {
return object;
}
public <T> Map<String, T> serializeMap(Class<T> type, LuaValueProxy table) {
Map<String, T> map = new HashMap<>();
public <K,V> Map<K, V> serializeMap(Class<K> typeKey, Class<V> typeValue, LuaValueProxy table) {
Map<K, V> map = new HashMap<>();
if (table == null) {
return map;
}
var tableObj = (Map<String, Object>) table;
var tableObj = (Map<Object, Object>) table;
try {
for (var k : tableObj.entrySet()) {
try {
var keyValue = k.getValue();
T object = objectToClass(type, keyValue);
if (object != null) {
map.put(k.getKey(), object);
K key = objectToClass(typeKey, k.getKey());
if(key == null){
logger.warn(() -> "Can't serialize key: "+key+" to type: "+typeKey);
continue;
}
V value = objectToClass(typeValue, k.getValue());
if(value == null){
logger.warn(() -> "Can't serialize value: "+value+" to type: "+typeValue);
continue;
}
map.put(key, value);
} catch (Exception ex) {
}

View File

@ -1,10 +1,9 @@
package org.anime_game_servers.luaj_engine
import io.github.oshai.kotlinlogging.KotlinLogging.logger
import org.anime_game_servers.lua.engine.LuaEngine
import org.anime_game_servers.lua.engine.LuaScript
import org.anime_game_servers.lua.engine.LuaTable
import org.anime_game_servers.lua.engine.ScriptConfig
import kotlinx.io.asInputStream
import kotlinx.io.buffered
import org.anime_game_servers.lua.engine.*
import org.anime_game_servers.lua.models.ScriptType
import org.luaj.vm2.lib.ResourceFinder
import org.luaj.vm2.lib.jse.CoerceJavaToLua
@ -34,8 +33,11 @@ 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 {
if (scriptConfig.enableIncludeWorkaround == RequireMode.DISABLED)
return ByteArrayInputStream(ByteArray(0))
val params = scriptConfig.scriptLoader.getRequireScriptParams(filename)
val stream = scriptConfig.scriptLoader.openScript(params)
val stream = scriptConfig.scriptLoader.openScript(params)?.buffered()?.asInputStream()
return stream ?: ByteArrayInputStream(ByteArray(0))
}
@ -82,7 +84,7 @@ class LuaJEngine(override val scriptConfig: ScriptConfig) : LuaEngine {
if (!Files.exists(scriptPath)) return null
try {
return LuaJScript(this, scriptPath)
return LuaJScript(this, scriptPath, scriptType)
} catch (e: IOException) {
throw RuntimeException(e)
} catch (e: ScriptException) {

View File

@ -2,11 +2,16 @@ package org.anime_game_servers.luaj_engine;
import io.github.oshai.kotlinlogging.KLogger;
import io.github.oshai.kotlinlogging.KotlinLogging;
import kotlin.Pair;
import kotlin.text.Regex;
import lombok.val;
import org.anime_game_servers.lua.engine.LuaEngine;
import org.anime_game_servers.lua.engine.LuaScript;
import org.anime_game_servers.lua.engine.LuaValue;
import org.anime_game_servers.lua.engine.RequireMode;
import org.anime_game_servers.lua.models.BooleanLuaValue;
import org.anime_game_servers.lua.models.MutableBoolean;
import org.anime_game_servers.lua.models.ScriptType;
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import javax.annotation.Nonnull;
@ -19,19 +24,61 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
public class LuaJScript implements LuaScript {
private static KLogger logger = KotlinLogging.INSTANCE.logger(LuaJScript.class.getName());
private final CompiledScript compiledScript;
private final String modifiedScript;
private final Bindings binding;
private final LuaJEngine engine;
public LuaJScript(LuaJEngine engine, Path scriptPath) throws IOException, ScriptException {
public LuaJScript(LuaJEngine engine, Path scriptPath, ScriptType scriptType) throws IOException, ScriptException {
this.engine = engine;
this.compiledScript = ((Compilable) engine.getEngine()).compile(Files.newBufferedReader(scriptPath));
if (engine.getScriptConfig().getEnableIncludeWorkaround() == RequireMode.ENABLED_WITH_WORKAROUND && (scriptType == ScriptType.EXECUTABLE || scriptType == ScriptType.STATIC_EXECUTABLE || scriptType == ScriptType.ONE_TIME_EXECUTABLE)) {
val result = compileScriptWithWorkaround(scriptPath);
this.compiledScript = result.getFirst();
this.modifiedScript = result.getSecond();
} else {
this.compiledScript = ((Compilable) engine.getEngine()).compile(Files.newBufferedReader(scriptPath));
this.modifiedScript = null;
}
this.binding = engine.getEngine().createBindings();
}
// todo maybe caching?
private Pair<CompiledScript, String> compileScriptWithWorkaround(Path path) throws IOException,ScriptException {
val requireRegex = Pattern.compile("\\s*require\\s+\"(.*)\"");
val changed = new MutableBoolean(false);
try (val reader = Files.newBufferedReader(path)){
val script = reader.lines().map(line -> {
val result = requireRegex.matcher(line);
if (result.matches()) {
val requireBasePath = engine.getScriptConfig().getScriptLoader().getRequireScriptParams(result.group(1)).getBasePath();
val requirePath = engine.getScriptConfig().getScriptLoader().getScriptPath(requireBasePath);
if(requirePath == null){
logger.warn(()->"Could not find require script "+result.group(1)+" for script "+path);
return line;
}
try {
try (val requireReader = Files.newBufferedReader(requirePath)){
val requireScript = requireReader.lines().reduce((a, b) -> a + "\n" + b).orElse(line);
changed.setValue(true);
return requireScript;
}
} catch (IOException e) {
return line;
}
} else {
return line;
}
}).reduce((a, b) -> a + "\n" + b).orElse("");
String modifiedScript = changed.getValue() ? script : null;
return new Pair<>(((Compilable) engine.getEngine()).compile(script), modifiedScript);
}
}
@Override
public boolean hasMethod(@Nonnull String methodName) {
return binding.containsKey(methodName) && ((org.luaj.vm2.LuaValue) binding.get(methodName)).isfunction();

View File

@ -13,10 +13,7 @@ import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public class LuaJSerializer extends BaseSerializer {
private static KLogger logger = KotlinLogging.INSTANCE.logger(LuaJEngine.class.getName());
@ -101,11 +98,19 @@ public class LuaJSerializer extends BaseSerializer {
return map;
}
public <T> List<T> serializeList(Class<T> type, LuaTable table) {
List<T> list = new ArrayList<>();
private <T> List<T> serializeList(Class<T> type, LuaTable table) {
val startSize = table != null ? table.length() : 0;
return serializeCollection(type, new ArrayList<>(startSize), table);
}
private <T> Set<T> serializeSet(Class<T> type, LuaTable table) {
val startSize = table != null ? table.length() : 0;
return serializeCollection(type, new HashSet<>(startSize), table);
}
public <T, Y extends Collection<T>> Y serializeCollection(Class<T> type, Y target, LuaTable table) {
if (table == null) {
return list;
return target;
}
try {
@ -117,7 +122,7 @@ public class LuaJSerializer extends BaseSerializer {
T object = valueToType(type, keyValue);
if (object != null) {
list.add(object);
target.add(object);
}
} catch (Exception ex) {
@ -127,47 +132,7 @@ public class LuaJSerializer extends BaseSerializer {
logger.error(e, () -> "Exception while serializing list");
}
return list;
}
private Class<?> getListType(Class<?> type, @Nullable Field field) {
if (field == null) {
return type.getTypeParameters()[0].getClass();
}
Type fieldType = field.getGenericType();
if (fieldType instanceof ParameterizedType) {
return (Class<?>) ((ParameterizedType) fieldType).getActualTypeArguments()[0];
}
return null;
}
private Pair<Class<?>, Class<?>> getMapTypes(Class<?> type, @Nullable Field field) {
Class<?> key = null;
Class<?> value = null;
if (field == null) {
val types = type.getTypeParameters();
if(types.length < 2){
return null;
}
key = types.getClass();
value = types.getClass();
}
else {
Type fieldType = field.getGenericType();
if (fieldType instanceof ParameterizedType) {
val types = ((ParameterizedType) fieldType).getActualTypeArguments();
if(types.length < 2){
return null;
}
key = (Class<?>) types[0];
value = (Class<?>) types[1];
}
}
if(key!=null && value!=null){
return new Pair<>(key, value);
}
return null;
return target;
}
public <T> T serialize(Class<T> type, @Nullable Field field, LuaTable table) {
@ -175,13 +140,22 @@ public class LuaJSerializer extends BaseSerializer {
if (type == List.class) {
try {
Class<?> listType = getListType(type, field);
Class<?> listType = getCollectionType(type, field);
return (T) serializeList(listType, table);
} catch (Exception e) {
logger.error("Exception while serializing {}", type.getName(), e);
return null;
}
}
if (type == Set.class) {
try {
Class<?> listType = getCollectionType(type, field);
return (T) serializeSet(listType, table);
} catch (Exception e) {
logger.error("Exception while serializing {}", type.getName(), e);
return null;
}
}
if (type == Map.class) {
try {
val mapTypes = getMapTypes(type, field);

View File

@ -47,6 +47,7 @@ kotlin {
implementation(libs.ags.core.base)
implementation(libs.kotlin.reflect)
implementation(libs.logging)
api(libs.kotlinx.io.core)
}
}
val commonTest by getting {
@ -57,6 +58,7 @@ kotlin {
implementation(libs.bundles.jvm.reflection)
implementation(libs.findbugs.jsr305)
implementation(libs.jvm.logging)
api(libs.kotlinx.io.core)
}
}
val jvmTest by getting

View File

@ -0,0 +1,11 @@
package org.anime_game_servers.lua.models
class MutableBoolean(private var value: Boolean){
fun getValue(): Boolean {
return value
}
fun setValue(value: Boolean) {
this.value = value
}
}

View File

@ -2,8 +2,8 @@ package org.anime_game_servers.lua.engine
import io.github.oshai.kotlinlogging.KLogger
import io.github.oshai.kotlinlogging.KotlinLogging
import kotlinx.io.Source
import org.anime_game_servers.lua.models.ScriptType
import java.io.InputStream
import java.nio.file.Path
import javax.script.ScriptException
@ -11,7 +11,7 @@ import javax.script.ScriptException
interface BaseScriptLoader {
fun getScriptPath(scriptName: String): Path?
fun getRequireScriptParams(scriptName: String): ScriptLoadParams
fun openScript(params: ScriptLoadParams): InputStream?
fun openScript(params: ScriptLoadParams): Source?
fun getScript(
scriptLoadParams: ScriptLoadParams
): LuaScript?

View File

@ -2,5 +2,22 @@ package org.anime_game_servers.lua.engine
data class ScriptConfig(
val scriptLoader: BaseScriptLoader,
val enableIncludeWorkaround: Boolean = false,
val enableIncludeWorkaround: RequireMode = RequireMode.DISABLED,
)
enum class RequireMode {
/**
* The include/require function is disabled.
*/
DISABLED,
/**
* The include/require function is enabled.
*/
ENABLED,
/**
* The include/require function is enabled and the workaround is enabled.
*/
ENABLED_WITH_WORKAROUND,
}

View File

@ -5,6 +5,8 @@ import com.esotericsoftware.reflectasm.MethodAccess
import io.github.oshai.kotlinlogging.KotlinLogging.logger
import org.anime_game_servers.core.base.annotations.lua.LuaNames
import java.lang.reflect.Field
import java.lang.reflect.ParameterizedType
import java.lang.reflect.TypeVariable
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import javax.annotation.Nonnull
@ -163,6 +165,47 @@ abstract class BaseSerializer : Serializer {
}
}
protected fun getCollectionType(type: Class<*>, field: Field?): Class<*>? {
if (field == null) {
return type.typeParameters[0].javaClass
}
val fieldType = field.genericType
if (fieldType is ParameterizedType) {
return (fieldType as ParameterizedType).actualTypeArguments[0] as Class<*>
}
return null
}
protected fun getMapTypes(type: Class<*>, field: Field?): Pair<Class<*>, Class<*>>? {
var key: Class<*>? = null
var value: Class<*>? = null
if (field == null) {
val types = type.getTypeParameters()
if (types.size < 2) {
return null
}
key = types.javaClass
value = types.javaClass
} else {
val fieldType = field.genericType
if (fieldType is ParameterizedType) {
val types = fieldType.actualTypeArguments
if (types.size < 2) {
return null
}
key = types[0] as Class<*>
value = types[1] as Class<*>
}
}
if (key != null && value != null) {
return Pair(key, value)
}
return null
}
companion object {
private val logger = logger(BaseSerializer::class.java.name)

View File

@ -0,0 +1,19 @@
package org.anime_game_servers.lua.utils
import kotlinx.io.Source
import kotlinx.io.asSource
import kotlinx.io.buffered
import java.io.IOException
import java.io.InputStream
import java.nio.file.Files
import java.nio.file.Path
fun InputStream.asSource(): Source {
return this.asSource().buffered()
}
@Throws(IOException::class)
fun Path.asSource(): Source {
val stream = Files.newInputStream(this)
return stream.asSource().buffered()
}

View File

@ -35,6 +35,7 @@ anime_game_lua = "0.1"
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
jvm-kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
kotlinx-io-core = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kx_io" }
jvm-kotlinx-io-core = { module = "org.jetbrains.kotlinx:kotlinx-io-core-jvm", version.ref = "kx_io" }
logging = { module = "io.github.oshai:kotlin-logging", version.ref = "logger" }
jvm-logging = { module = "io.github.oshai:kotlin-logging-jvm", version.ref = "logger" }
reflectasm = { module = "com.esotericsoftware:reflectasm", version.ref = "reflectasm" }