mirror of
https://github.com/Anime-Game-Servers/AnimeGamesLua.git
synced 2024-11-23 04:19:41 +00:00
[Fix] Fix LuaName being ignored for fields passed to the Lua engine
* Also added a test to verfiy it working and updated some other tests * Improved LuaValue support for values returned from lua function calls
This commit is contained in:
parent
631cf4f080
commit
457378f83c
@ -26,6 +26,9 @@ dependencies {
|
|||||||
compileOnly(libs.jvm.lombok)
|
compileOnly(libs.jvm.lombok)
|
||||||
annotationProcessor(libs.jvm.lombok)
|
annotationProcessor(libs.jvm.lombok)
|
||||||
implementation(libs.jvm.rtree.multi)
|
implementation(libs.jvm.rtree.multi)
|
||||||
|
testImplementation(project(":base"))
|
||||||
|
testImplementation(project(":LuaJEngine"))
|
||||||
|
testImplementation(project(":JNLuaEngine"))
|
||||||
}
|
}
|
||||||
tasks.withType<KotlinCompile>().configureEach {
|
tasks.withType<KotlinCompile>().configureEach {
|
||||||
compilerOptions {
|
compilerOptions {
|
||||||
|
@ -0,0 +1,150 @@
|
|||||||
|
package org.anime_game_servers.gi_lua.test.models
|
||||||
|
|
||||||
|
import kotlinx.io.Source
|
||||||
|
import org.anime_game_servers.core.base.annotations.lua.LuaStatic
|
||||||
|
import org.anime_game_servers.gi_lua.models.ScriptArgs
|
||||||
|
import org.anime_game_servers.gi_lua.models.loader.GIScriptLoader
|
||||||
|
import org.anime_game_servers.jnlua_engine.JNLuaEngine
|
||||||
|
import org.anime_game_servers.lua.engine.*
|
||||||
|
import org.anime_game_servers.lua.models.ScriptType
|
||||||
|
import org.anime_game_servers.lua.utils.asSource
|
||||||
|
import org.anime_game_servers.luaj_engine.LuaJEngine
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
data class LuaContext(val engine: LuaEngine)
|
||||||
|
|
||||||
|
@LuaStatic
|
||||||
|
object KotlinFunctions{
|
||||||
|
@JvmStatic
|
||||||
|
fun checkScriptArgs(context:LuaContext, luaTable:Any) : Any{
|
||||||
|
// retrieve the int array as lua table from the lua side
|
||||||
|
val table = context.engine.getTable(luaTable)
|
||||||
|
val array = table.getAsIntArray()
|
||||||
|
val result = context.engine.createTable()
|
||||||
|
|
||||||
|
assert(array.size == 5)
|
||||||
|
array.forEachIndexed { index, value ->
|
||||||
|
assert(index+1 == value)
|
||||||
|
result.set(index, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert the int array back to a luaTable for lua and return it
|
||||||
|
return result.getRawTable()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getScriptArgs(context:LuaContext) : Any{
|
||||||
|
// retrieve the int array as lua table from the lua side
|
||||||
|
/*val table = context.engine.getTable(luaTable)
|
||||||
|
val x = table.optInt("x",0)
|
||||||
|
val y = table.optInt("y",0)
|
||||||
|
val z = table.optInt("z",0)*/
|
||||||
|
|
||||||
|
val result = context.engine.createTable()
|
||||||
|
/*result.set("x", x)
|
||||||
|
result.set("y", y)
|
||||||
|
result.set("z", z)*/
|
||||||
|
|
||||||
|
// convert the int array back to a luaTable for lua and return it
|
||||||
|
return result.getRawTable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class TestScriptLoader : GIScriptLoader {
|
||||||
|
abstract val engine: LuaEngine
|
||||||
|
override fun getScriptPath(scriptName: String): Path? {
|
||||||
|
val uri = ClassLoader.getSystemResource(scriptName).toURI()
|
||||||
|
return Path.of(uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openScript(params: BaseScriptLoader.ScriptLoadParams): Source? {
|
||||||
|
val basePath: String = params.getBasePath()
|
||||||
|
val scriptPath = getScriptPath(basePath) ?: return null
|
||||||
|
if(Files.exists(scriptPath)){
|
||||||
|
return scriptPath.asSource()
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getScript(scriptLoadParams: BaseScriptLoader.ScriptLoadParams): LuaScript? {
|
||||||
|
val basePath: String = scriptLoadParams.getBasePath()
|
||||||
|
val scriptPath = getScriptPath(basePath) ?: return null
|
||||||
|
return engine.getScript(scriptPath, scriptLoadParams.getScriptType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LuaJTest : ScriptArgsTest() {
|
||||||
|
|
||||||
|
override val scriptLoader = object : TestScriptLoader(){
|
||||||
|
override val engine: LuaEngine = LuaJEngine(ScriptConfig(this, RequireMode.DISABLED))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun runTest(){
|
||||||
|
checkScriptArgs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class JNLuaTest : ScriptArgsTest() {
|
||||||
|
|
||||||
|
override val scriptLoader = object : TestScriptLoader(){
|
||||||
|
override val engine: LuaEngine = JNLuaEngine(ScriptConfig(this, RequireMode.DISABLED))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun runTest(){
|
||||||
|
checkScriptArgs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class ScriptArgsTest{
|
||||||
|
abstract val scriptLoader : TestScriptLoader
|
||||||
|
|
||||||
|
fun getEngine(): LuaEngine {
|
||||||
|
return scriptLoader.engine
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkScriptArgs() {
|
||||||
|
val engine = getEngine()
|
||||||
|
LuaEngine.registerNamespace(this::class.java.packageName)
|
||||||
|
engine.addGlobals()
|
||||||
|
val uri = ClassLoader.getSystemResource("ScriptArgsTest.lua").toURI()
|
||||||
|
val path = Path.of(uri);
|
||||||
|
val script = engine.getScript(path, ScriptType.EXECUTABLE)
|
||||||
|
|
||||||
|
assert(script != null)
|
||||||
|
|
||||||
|
script!!.evaluate()
|
||||||
|
val context = LuaContext(engine)
|
||||||
|
val args = ScriptArgs(7,8).apply {
|
||||||
|
param1 = 1
|
||||||
|
param2 = 2
|
||||||
|
param3 = 3
|
||||||
|
param4 = 4
|
||||||
|
sourceEid = 5
|
||||||
|
targetEid = 6
|
||||||
|
uid = 9
|
||||||
|
paramString1 = "paramString1"
|
||||||
|
source = "source"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(script.hasMethod("testScriptArgs"))
|
||||||
|
val luaValue = script.callMethod("testScriptArgs", context, args)!!
|
||||||
|
assert(luaValue.isTable())
|
||||||
|
val result = luaValue.asObject(ScriptArgs::class.java)
|
||||||
|
assert(result != null)
|
||||||
|
assert(result!!.param1 == args.param1)
|
||||||
|
assert(result.param2 == args.param2)
|
||||||
|
assert(result.param3 == args.param3)
|
||||||
|
assert(result.param4 == args.param4)
|
||||||
|
assert(result.sourceEid == args.sourceEid)
|
||||||
|
assert(result.targetEid == args.targetEid)
|
||||||
|
assert(result.groupId == args.groupId)
|
||||||
|
assert(result.uid == args.uid)
|
||||||
|
assert(result.type == args.type)
|
||||||
|
assert(result.paramString1 == args.paramString1)
|
||||||
|
assert(result.source == args.source)
|
||||||
|
}
|
||||||
|
}
|
39
GILua/src/test/resources/ScriptArgsTest.lua
Normal file
39
GILua/src/test/resources/ScriptArgsTest.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
function testScriptArgs(ctx, evt)
|
||||||
|
if(evt.param1 ~= 1) then
|
||||||
|
return -1
|
||||||
|
end
|
||||||
|
if(evt.param2 ~= 2) then
|
||||||
|
return -2
|
||||||
|
end
|
||||||
|
if(evt.param3 ~= 3) then
|
||||||
|
return -3
|
||||||
|
end
|
||||||
|
if(evt.param4 ~= 4) then
|
||||||
|
return -4
|
||||||
|
end
|
||||||
|
if(evt.source_eid ~= 5) then
|
||||||
|
return -5
|
||||||
|
end
|
||||||
|
if(evt.target_eid ~= 6) then
|
||||||
|
return -6
|
||||||
|
end
|
||||||
|
if(evt.group_id ~= 7) then
|
||||||
|
return -7
|
||||||
|
end
|
||||||
|
if(evt.type ~= 8) then
|
||||||
|
return -8
|
||||||
|
end
|
||||||
|
if(evt.uid ~= 9) then
|
||||||
|
return -9
|
||||||
|
end
|
||||||
|
|
||||||
|
if(evt.param_str1 ~= "paramString1") then
|
||||||
|
return -10
|
||||||
|
end
|
||||||
|
if(evt.source_name ~= "source") then
|
||||||
|
return -11
|
||||||
|
end
|
||||||
|
|
||||||
|
return evt
|
||||||
|
end
|
@ -0,0 +1,153 @@
|
|||||||
|
package org.anime_game_servers.jnlua_engine;
|
||||||
|
|
||||||
|
import io.github.oshai.kotlinlogging.KLogger;
|
||||||
|
import io.github.oshai.kotlinlogging.KotlinLogging;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.anime_game_servers.lua.utils.LuaHelpersJvmKt;
|
||||||
|
import org.terasology.jnlua.*;
|
||||||
|
|
||||||
|
import java.beans.BeanInfo;
|
||||||
|
import java.beans.IntrospectionException;
|
||||||
|
import java.beans.Introspector;
|
||||||
|
import java.beans.PropertyDescriptor;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class JNLuaReflector extends DefaultJavaReflector {
|
||||||
|
private static KLogger logger = KotlinLogging.INSTANCE.logger(JNLuaReflector.class.getName());
|
||||||
|
@Getter
|
||||||
|
private static final JNLuaReflector INSTANCE = new JNLuaReflector();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<String, Accessor> createClassAccessors(Class<?> clazz) {
|
||||||
|
Map<String, Accessor> result = new HashMap<String, Accessor>();
|
||||||
|
|
||||||
|
// Fields
|
||||||
|
Field[] fields = clazz.getFields();
|
||||||
|
for (int i = 0; i < fields.length; i++) {
|
||||||
|
var field = fields[i];
|
||||||
|
var luaNames = LuaHelpersJvmKt.getLuaNames(field);
|
||||||
|
for (var luaName : luaNames) {
|
||||||
|
result.put(luaName, new FieldAccessor(field));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
Map<String, Map<List<Class<?>>, Invocable>> accessibleMethods = new HashMap<String, Map<List<Class<?>>, Invocable>>();
|
||||||
|
Method[] methods = clazz.getMethods();
|
||||||
|
for (int i = 0; i < methods.length; i++) {
|
||||||
|
// Do not overwrite fields
|
||||||
|
Method method = methods[i];
|
||||||
|
if (result.containsKey(method.getName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to find the method in a public class if the declaring
|
||||||
|
// class is not public
|
||||||
|
if (!Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
|
||||||
|
method = getPublicClassMethod(clazz, method.getName(),
|
||||||
|
method.getParameterTypes());
|
||||||
|
if (method == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each method name and parameter type list, keep
|
||||||
|
// only the method declared by the most specific class
|
||||||
|
Map<List<Class<?>>, Invocable> overloaded = accessibleMethods
|
||||||
|
.get(method.getName());
|
||||||
|
if (overloaded == null) {
|
||||||
|
overloaded = new HashMap<List<Class<?>>, Invocable>();
|
||||||
|
accessibleMethods.put(method.getName(), overloaded);
|
||||||
|
}
|
||||||
|
List<Class<?>> parameterTypes = Arrays.asList(method
|
||||||
|
.getParameterTypes());
|
||||||
|
Invocable currentInvocable = overloaded.get(parameterTypes);
|
||||||
|
if (currentInvocable != null
|
||||||
|
&& method.getDeclaringClass().isAssignableFrom(
|
||||||
|
currentInvocable.getDeclaringClass())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
overloaded.put(parameterTypes, new InvocableMethod(method));
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, Map<List<Class<?>>, Invocable>> entry : accessibleMethods
|
||||||
|
.entrySet()) {
|
||||||
|
result.put(entry.getKey(), new InvocableAccessor(clazz, entry
|
||||||
|
.getValue().values()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
Constructor<?>[] constructors = clazz.getConstructors();
|
||||||
|
List<Invocable> accessibleConstructors = new ArrayList<Invocable>(
|
||||||
|
constructors.length);
|
||||||
|
for (int i = 0; i < constructors.length; i++) {
|
||||||
|
// Ignore constructor if the declaring class is not public
|
||||||
|
if (!Modifier.isPublic(constructors[i].getDeclaringClass()
|
||||||
|
.getModifiers())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
accessibleConstructors
|
||||||
|
.add(new InvocableConstructor(constructors[i]));
|
||||||
|
}
|
||||||
|
if (clazz.isInterface()) {
|
||||||
|
accessibleConstructors.add(new InvocableProxy(clazz));
|
||||||
|
}
|
||||||
|
if (!accessibleConstructors.isEmpty()) {
|
||||||
|
result.put("new", new InvocableAccessor(clazz,
|
||||||
|
accessibleConstructors));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
BeanInfo beanInfo;
|
||||||
|
try {
|
||||||
|
beanInfo = Introspector.getBeanInfo(clazz);
|
||||||
|
} catch (IntrospectionException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
PropertyDescriptor[] propertyDescriptors = beanInfo
|
||||||
|
.getPropertyDescriptors();
|
||||||
|
for (int i = 0; i < propertyDescriptors.length; i++) {
|
||||||
|
// Do not overwrite fields or methods
|
||||||
|
if (result.containsKey(propertyDescriptors[i].getName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to find the read/write methods in a public class if the
|
||||||
|
// declaring class is not public
|
||||||
|
Method method = propertyDescriptors[i].getReadMethod();
|
||||||
|
if (method != null
|
||||||
|
&& !Modifier.isPublic(method.getDeclaringClass()
|
||||||
|
.getModifiers())) {
|
||||||
|
method = getPublicClassMethod(clazz, method.getName(),
|
||||||
|
method.getParameterTypes());
|
||||||
|
try {
|
||||||
|
propertyDescriptors[i].setReadMethod(method);
|
||||||
|
} catch (IntrospectionException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
method = propertyDescriptors[i].getWriteMethod();
|
||||||
|
if (method != null
|
||||||
|
&& !Modifier.isPublic(method.getDeclaringClass()
|
||||||
|
.getModifiers())) {
|
||||||
|
method = getPublicClassMethod(clazz, method.getName(),
|
||||||
|
method.getParameterTypes());
|
||||||
|
try {
|
||||||
|
propertyDescriptors[i].setWriteMethod(method);
|
||||||
|
} catch (IntrospectionException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not process properties without a read and a write method
|
||||||
|
if (propertyDescriptors[i].getReadMethod() == null
|
||||||
|
&& propertyDescriptors[i].getWriteMethod() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.put(propertyDescriptors[i].getName(), new PropertyAccessor(
|
||||||
|
clazz, propertyDescriptors[i]));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -8,10 +8,7 @@ import org.anime_game_servers.lua.engine.LuaEngine;
|
|||||||
import org.anime_game_servers.lua.engine.LuaScript;
|
import org.anime_game_servers.lua.engine.LuaScript;
|
||||||
import org.anime_game_servers.lua.engine.LuaValue;
|
import org.anime_game_servers.lua.engine.LuaValue;
|
||||||
import org.anime_game_servers.lua.engine.RequireMode;
|
import org.anime_game_servers.lua.engine.RequireMode;
|
||||||
import org.anime_game_servers.lua.models.BooleanLuaValue;
|
import org.anime_game_servers.lua.models.*;
|
||||||
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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.terasology.jnlua.script.CompiledLuaScript;
|
import org.terasology.jnlua.script.CompiledLuaScript;
|
||||||
@ -51,6 +48,7 @@ public class JNLuaScript implements LuaScript {
|
|||||||
context.setBindings(binding, ScriptContext.ENGINE_SCOPE);
|
context.setBindings(binding, ScriptContext.ENGINE_SCOPE);
|
||||||
val luaState = binding.getLuaState();
|
val luaState = binding.getLuaState();
|
||||||
luaState.setConverter(JNLuaConverter.getINSTANCE());
|
luaState.setConverter(JNLuaConverter.getINSTANCE());
|
||||||
|
luaState.setJavaReflector(JNLuaReflector.getINSTANCE());
|
||||||
|
|
||||||
val requireFunction = JNLuaRequireCommonFunction.getInstance(engine.getScriptConfig());
|
val requireFunction = JNLuaRequireCommonFunction.getInstance(engine.getScriptConfig());
|
||||||
binding.put(requireFunction.getName(), requireFunction);
|
binding.put(requireFunction.getName(), requireFunction);
|
||||||
@ -121,13 +119,11 @@ public class JNLuaScript implements LuaScript {
|
|||||||
@Override
|
@Override
|
||||||
public LuaValue callMethod(@NotNull String methodName, Object... args) throws ScriptException, NoSuchMethodException {
|
public LuaValue callMethod(@NotNull String methodName, Object... args) throws ScriptException, NoSuchMethodException {
|
||||||
val result = ((Invocable) scriptEngine).invokeFunction(methodName, args);
|
val result = ((Invocable) scriptEngine).invokeFunction(methodName, args);
|
||||||
if (result instanceof Boolean) {
|
if (result instanceof Boolean boolVal) {
|
||||||
return ((Boolean) result) ? BooleanLuaValue.TRUE : BooleanLuaValue.FALSE;
|
return boolVal ? BooleanLuaValue.TRUE : BooleanLuaValue.FALSE;
|
||||||
} else if (result instanceof Integer) {
|
|
||||||
return new IntLuaValue((Integer) result);
|
|
||||||
}
|
}
|
||||||
//TODO
|
|
||||||
return null;
|
return new JNLuaValue(engine, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,104 @@
|
|||||||
|
package org.anime_game_servers.jnlua_engine
|
||||||
|
|
||||||
|
import org.anime_game_servers.lua.engine.LuaValue
|
||||||
|
|
||||||
|
class JNLuaValue internal constructor(private val engine: JNLuaEngine, private val value: Any?) : LuaValue {
|
||||||
|
override fun isNull(): Boolean {
|
||||||
|
return value == null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isBoolean(): Boolean {
|
||||||
|
return value is Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isInteger(): Boolean {
|
||||||
|
return value is Int
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isLong(): Boolean {
|
||||||
|
return value is Long
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isDouble(): Boolean {
|
||||||
|
return value is Double
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isFloat(): Boolean {
|
||||||
|
return value is Float
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isString(): Boolean {
|
||||||
|
return value is String
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isTable(): Boolean {
|
||||||
|
return value is Map<*, *> || value is JNLuaTable || value is Collection<*> || value != null && value !is Number && value !is Boolean && value !is String
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun asBoolean(): Boolean {
|
||||||
|
return when(value){
|
||||||
|
is Boolean -> value
|
||||||
|
is Number -> value.toInt() != 0
|
||||||
|
is String -> value.toBoolean()
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun asInteger(): Int {
|
||||||
|
return when(value){
|
||||||
|
is Number -> value.toInt()
|
||||||
|
is Boolean -> if(value) 1 else 0
|
||||||
|
is String -> value.toInt()
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun asLong(): Long {
|
||||||
|
return when(value){
|
||||||
|
is Number -> value.toLong()
|
||||||
|
is Boolean -> if(value) 1L else 0L
|
||||||
|
is String -> value.toLong()
|
||||||
|
else -> 0L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun asDouble(): Double {
|
||||||
|
return when(value){
|
||||||
|
is Number -> value.toDouble()
|
||||||
|
is Boolean -> if(value) 1.0 else 0.0
|
||||||
|
is String -> value.toDouble()
|
||||||
|
else -> 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun asFloat(): Float {
|
||||||
|
return when(value){
|
||||||
|
is Number -> value.toFloat()
|
||||||
|
is Boolean -> if(value) 1f else 0f
|
||||||
|
is String -> value.toFloat()
|
||||||
|
else -> 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun asString(): String? {
|
||||||
|
return when(value){
|
||||||
|
is String -> value
|
||||||
|
is Number -> value.toString()
|
||||||
|
is Boolean -> value.toString()
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T> asObject(type: Class<T>): T? {
|
||||||
|
if (value == null || !isTable()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type.isAssignableFrom(value.javaClass)){
|
||||||
|
return value as T
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO expects LuaValueProxy
|
||||||
|
return engine.serializer.toObject(type, value)
|
||||||
|
}
|
||||||
|
}
|
@ -5,8 +5,8 @@ import kotlinx.io.asInputStream
|
|||||||
import kotlinx.io.buffered
|
import kotlinx.io.buffered
|
||||||
import org.anime_game_servers.lua.engine.*
|
import org.anime_game_servers.lua.engine.*
|
||||||
import org.anime_game_servers.lua.models.ScriptType
|
import org.anime_game_servers.lua.models.ScriptType
|
||||||
|
import org.anime_game_servers.luaj_engine.coerse.CoerceJavaToLua
|
||||||
import org.luaj.vm2.lib.ResourceFinder
|
import org.luaj.vm2.lib.ResourceFinder
|
||||||
import org.luaj.vm2.lib.jse.CoerceJavaToLua
|
|
||||||
import org.luaj.vm2.script.LuajContext
|
import org.luaj.vm2.script.LuajContext
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
@ -3,7 +3,6 @@ package org.anime_game_servers.luaj_engine;
|
|||||||
import io.github.oshai.kotlinlogging.KLogger;
|
import io.github.oshai.kotlinlogging.KLogger;
|
||||||
import io.github.oshai.kotlinlogging.KotlinLogging;
|
import io.github.oshai.kotlinlogging.KotlinLogging;
|
||||||
import kotlin.Pair;
|
import kotlin.Pair;
|
||||||
import kotlin.text.Regex;
|
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import org.anime_game_servers.lua.engine.LuaEngine;
|
import org.anime_game_servers.lua.engine.LuaEngine;
|
||||||
import org.anime_game_servers.lua.engine.LuaScript;
|
import org.anime_game_servers.lua.engine.LuaScript;
|
||||||
@ -12,7 +11,7 @@ import org.anime_game_servers.lua.engine.RequireMode;
|
|||||||
import org.anime_game_servers.lua.models.BooleanLuaValue;
|
import org.anime_game_servers.lua.models.BooleanLuaValue;
|
||||||
import org.anime_game_servers.lua.models.MutableBoolean;
|
import org.anime_game_servers.lua.models.MutableBoolean;
|
||||||
import org.anime_game_servers.lua.models.ScriptType;
|
import org.anime_game_servers.lua.models.ScriptType;
|
||||||
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
import org.anime_game_servers.luaj_engine.coerse.CoerceJavaToLua;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.script.Bindings;
|
import javax.script.Bindings;
|
||||||
@ -24,7 +23,6 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class LuaJScript implements LuaScript {
|
public class LuaJScript implements LuaScript {
|
||||||
|
@ -48,7 +48,7 @@ public class LuaJValue implements LuaValue {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTable() {
|
public boolean isTable() {
|
||||||
return value.istable();
|
return value.istable() || value.isuserdata();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -83,10 +83,14 @@ public class LuaJValue implements LuaValue {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T asObject(Class<T> type) {
|
public <T> T asObject(Class<T> type) {
|
||||||
if (!value.istable()) {
|
if (!value.istable() && !value.isuserdata()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(value.isuserdata()) {
|
||||||
|
return (T) value.checkuserdata(type);
|
||||||
|
}
|
||||||
|
|
||||||
return engine.getSerializer().toObject(type, value.checktable());
|
return engine.getSerializer().toObject(type, value.checktable());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,170 @@
|
|||||||
|
package org.anime_game_servers.luaj_engine.coerse;
|
||||||
|
|
||||||
|
import org.luaj.vm2.*;
|
||||||
|
import org.luaj.vm2.lib.jse.JavaArray;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to coerce values from Java to lua within the luajava library.
|
||||||
|
* <p>
|
||||||
|
* This class is primarily used by the {@link org.luaj.vm2.lib.jse.LuajavaLib},
|
||||||
|
* but can also be used directly when working with Java/lua bindings.
|
||||||
|
* <p>
|
||||||
|
* To coerce scalar types, the various, generally the {@code valueOf(type)} methods
|
||||||
|
* on {@link LuaValue} may be used:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link LuaValue#valueOf(boolean)}</li>
|
||||||
|
* <li>{@link LuaValue#valueOf(byte[])}</li>
|
||||||
|
* <li>{@link LuaValue#valueOf(double)}</li>
|
||||||
|
* <li>{@link LuaValue#valueOf(int)}</li>
|
||||||
|
* <li>{@link LuaValue#valueOf(String)}</li>
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* To coerce arrays of objects and lists, the {@code listOf(..)} and {@code tableOf(...)} methods
|
||||||
|
* on {@link LuaValue} may be used:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link LuaValue#listOf(LuaValue[])}</li>
|
||||||
|
* <li>{@link LuaValue#listOf(LuaValue[], org.luaj.vm2.Varargs)}</li>
|
||||||
|
* <li>{@link LuaValue#tableOf(LuaValue[])}</li>
|
||||||
|
* <li>{@link LuaValue#tableOf(LuaValue[], LuaValue[], org.luaj.vm2.Varargs)}</li>
|
||||||
|
* </ul>
|
||||||
|
* The method {@link org.luaj.vm2.lib.jse.CoerceJavaToLua#coerce(Object)} looks as the type and dimesioning
|
||||||
|
* of the argument and tries to guess the best fit for corrsponding lua scalar,
|
||||||
|
* table, or table of tables.
|
||||||
|
*
|
||||||
|
* @see org.luaj.vm2.lib.jse.CoerceJavaToLua#coerce(Object)
|
||||||
|
* @see org.luaj.vm2.lib.jse.LuajavaLib
|
||||||
|
*/
|
||||||
|
public class CoerceJavaToLua {
|
||||||
|
|
||||||
|
static final Map<Class<?>, Coercion> COERCIONS = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
|
||||||
|
static final Coercion instanceCoercion = new InstanceCoercion();
|
||||||
|
static final Coercion arrayCoercion = new ArrayCoercion();
|
||||||
|
static final Coercion luaCoercion = new LuaCoercion();
|
||||||
|
|
||||||
|
static {
|
||||||
|
Coercion boolCoercion = new BoolCoercion();
|
||||||
|
Coercion intCoercion = new IntCoercion();
|
||||||
|
Coercion charCoercion = new CharCoercion();
|
||||||
|
Coercion doubleCoercion = new DoubleCoercion();
|
||||||
|
Coercion stringCoercion = new StringCoercion();
|
||||||
|
Coercion bytesCoercion = new BytesCoercion();
|
||||||
|
Coercion classCoercion = new ClassCoercion();
|
||||||
|
COERCIONS.put(Boolean.class, boolCoercion);
|
||||||
|
COERCIONS.put(Byte.class, intCoercion);
|
||||||
|
COERCIONS.put(Character.class, charCoercion);
|
||||||
|
COERCIONS.put(Short.class, intCoercion);
|
||||||
|
COERCIONS.put(Integer.class, intCoercion);
|
||||||
|
COERCIONS.put(Long.class, doubleCoercion);
|
||||||
|
COERCIONS.put(Float.class, doubleCoercion);
|
||||||
|
COERCIONS.put(Double.class, doubleCoercion);
|
||||||
|
COERCIONS.put(String.class, stringCoercion);
|
||||||
|
COERCIONS.put(byte[].class, bytesCoercion);
|
||||||
|
COERCIONS.put(Class.class, classCoercion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coerse a Java object to a corresponding lua value.
|
||||||
|
* <p>
|
||||||
|
* Integral types {@code boolean}, {@code byte}, {@code char}, and {@code int}
|
||||||
|
* will become {@link LuaInteger};
|
||||||
|
* {@code long}, {@code float}, and {@code double} will become {@link LuaDouble};
|
||||||
|
* {@code String} and {@code byte[]} will become {@link LuaString};
|
||||||
|
* types inheriting from {@link LuaValue} will be returned without coercion;
|
||||||
|
* other types will become {@link LuaUserdata}.
|
||||||
|
*
|
||||||
|
* @param o Java object needing conversion
|
||||||
|
* @return {@link LuaValue} corresponding to the supplied Java value.
|
||||||
|
* @see LuaValue
|
||||||
|
* @see LuaInteger
|
||||||
|
* @see LuaDouble
|
||||||
|
* @see LuaString
|
||||||
|
* @see LuaUserdata
|
||||||
|
*/
|
||||||
|
public static LuaValue coerce(Object o) {
|
||||||
|
if (o == null)
|
||||||
|
return LuaValue.NIL;
|
||||||
|
Class<?> clazz = o.getClass();
|
||||||
|
Coercion c = COERCIONS.get(clazz);
|
||||||
|
if (c == null) {
|
||||||
|
c = clazz.isArray() ? arrayCoercion :
|
||||||
|
o instanceof LuaValue ? luaCoercion :
|
||||||
|
instanceCoercion;
|
||||||
|
COERCIONS.put(clazz, c);
|
||||||
|
}
|
||||||
|
return c.coerce(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Coercion {
|
||||||
|
LuaValue coerce(Object javaValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class BoolCoercion implements Coercion {
|
||||||
|
public LuaValue coerce(Object javaValue) {
|
||||||
|
boolean b = (Boolean) javaValue;
|
||||||
|
return b ? LuaValue.TRUE : LuaValue.FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class IntCoercion implements Coercion {
|
||||||
|
public LuaValue coerce(Object javaValue) {
|
||||||
|
Number n = (Number) javaValue;
|
||||||
|
return LuaInteger.valueOf(n.intValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class CharCoercion implements Coercion {
|
||||||
|
public LuaValue coerce(Object javaValue) {
|
||||||
|
Character c = (Character) javaValue;
|
||||||
|
return LuaInteger.valueOf(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class DoubleCoercion implements Coercion {
|
||||||
|
public LuaValue coerce(Object javaValue) {
|
||||||
|
Number n = (Number) javaValue;
|
||||||
|
return LuaDouble.valueOf(n.doubleValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class StringCoercion implements Coercion {
|
||||||
|
public LuaValue coerce(Object javaValue) {
|
||||||
|
return LuaString.valueOf(javaValue.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class BytesCoercion implements Coercion {
|
||||||
|
public LuaValue coerce(Object javaValue) {
|
||||||
|
return LuaValue.valueOf((byte[]) javaValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class ClassCoercion implements Coercion {
|
||||||
|
public LuaValue coerce(Object javaValue) {
|
||||||
|
return JavaClass.forClass((Class<?>) javaValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class InstanceCoercion implements Coercion {
|
||||||
|
public LuaValue coerce(Object javaValue) {
|
||||||
|
return new JavaInstance(javaValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class ArrayCoercion implements Coercion {
|
||||||
|
public LuaValue coerce(Object javaValue) {
|
||||||
|
// should be userdata?
|
||||||
|
return new JavaArray(javaValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class LuaCoercion implements Coercion {
|
||||||
|
public LuaValue coerce(Object javaValue) {
|
||||||
|
return (LuaValue) javaValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package org.anime_game_servers.luaj_engine.coerse;
|
||||||
|
|
||||||
|
import org.anime_game_servers.lua.utils.LuaHelpersJvmKt;
|
||||||
|
import org.luaj.vm2.LuaValue;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class JavaClass extends org.luaj.vm2.lib.jse.JavaClass {
|
||||||
|
|
||||||
|
protected static final Map<Class<?>, JavaClass> classes = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
JavaClass(Class c) {
|
||||||
|
super(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JavaClass forClass(Class<?> c) {
|
||||||
|
return classes.computeIfAbsent(c, JavaClass::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addField(Field fi, Map<LuaValue, Field> m) {
|
||||||
|
if (Modifier.isPublic(fi.getModifiers())) {
|
||||||
|
var names = LuaHelpersJvmKt.getLuaNames(fi);
|
||||||
|
for (var name : names) {
|
||||||
|
m.put(LuaValue.valueOf(name), fi);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (!fi.isAccessible())
|
||||||
|
fi.setAccessible(true);
|
||||||
|
} catch (SecurityException s) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package org.anime_game_servers.luaj_engine.coerse;
|
||||||
|
|
||||||
|
import org.luaj.vm2.LuaError;
|
||||||
|
import org.luaj.vm2.LuaUserdata;
|
||||||
|
import org.luaj.vm2.LuaValue;
|
||||||
|
import org.luaj.vm2.lib.jse.CoerceLuaToJava;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
public class JavaInstance extends LuaUserdata {
|
||||||
|
JavaClass jclass;
|
||||||
|
|
||||||
|
public JavaInstance(Object instance) {
|
||||||
|
super(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LuaValue get(LuaValue key) {
|
||||||
|
if (jclass == null)
|
||||||
|
jclass = JavaClass.forClass(m_instance.getClass());
|
||||||
|
Field f = jclass.getField(key);
|
||||||
|
if (f != null)
|
||||||
|
try {
|
||||||
|
return CoerceJavaToLua.coerce(f.get(m_instance));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new LuaError(e);
|
||||||
|
}
|
||||||
|
LuaValue m = jclass.getMethod(key);
|
||||||
|
if (m != null)
|
||||||
|
return m;
|
||||||
|
Class<?> c = jclass.getInnerClass(key);
|
||||||
|
if (c != null)
|
||||||
|
return JavaClass.forClass(c);
|
||||||
|
return super.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(LuaValue key, LuaValue value) {
|
||||||
|
if (jclass == null)
|
||||||
|
jclass = JavaClass.forClass(m_instance.getClass());
|
||||||
|
Field f = jclass.getField(key);
|
||||||
|
if (f != null)
|
||||||
|
try {
|
||||||
|
f.set(m_instance, CoerceLuaToJava.coerce(value, f.getType()));
|
||||||
|
return;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new LuaError(e);
|
||||||
|
}
|
||||||
|
super.set(key, value);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package org.anime_game_servers.lua.models
|
||||||
|
|
||||||
|
import org.anime_game_servers.lua.engine.Class
|
||||||
|
import kotlin.jvm.JvmField
|
||||||
|
|
||||||
|
open class StringLuaValue(protected val value: String) : MockLuaValue {
|
||||||
|
override fun isInteger() = true
|
||||||
|
|
||||||
|
override fun asBoolean() = when(value.lowercase()){
|
||||||
|
"true" -> true
|
||||||
|
"false" -> false
|
||||||
|
else -> try {
|
||||||
|
value.toInt() != 0
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun asInteger() = value.toInt()
|
||||||
|
override fun asLong() = value.toLong()
|
||||||
|
override fun asDouble() = value.toDouble()
|
||||||
|
override fun asFloat() = value.toFloat()
|
||||||
|
override fun asString() = value
|
||||||
|
|
||||||
|
override fun <T> asObject(type: Class<T>): T? = null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmField
|
||||||
|
val EMPTY = StringLuaValue("")
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ import org.anime_game_servers.core.base.interfaces.IntKey
|
|||||||
import org.anime_game_servers.core.base.interfaces.IntValueEnum
|
import org.anime_game_servers.core.base.interfaces.IntValueEnum
|
||||||
import org.anime_game_servers.lua.models.ScriptType
|
import org.anime_game_servers.lua.models.ScriptType
|
||||||
import org.anime_game_servers.lua.serialize.Serializer
|
import org.anime_game_servers.lua.serialize.Serializer
|
||||||
|
import org.anime_game_servers.lua.utils.getLuaName
|
||||||
import org.reflections.Reflections
|
import org.reflections.Reflections
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
@ -44,19 +45,13 @@ interface LuaEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getLuaName(classObject: Class<*>): String {
|
|
||||||
return classObject.getAnnotation(LuaNames::class.java)?.let {
|
|
||||||
it.value.firstOrNull() ?: classObject.simpleName
|
|
||||||
} ?: classObject.simpleName
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addGlobals() {
|
fun addGlobals() {
|
||||||
registeredEnums.forEach { enumClass ->
|
registeredEnums.forEach { enumClass ->
|
||||||
val enumArray = enumClass.enumConstants
|
val enumArray = enumClass.enumConstants
|
||||||
addGlobalEnum(getLuaName(enumClass), enumArray)
|
addGlobalEnum(enumClass.getLuaName(), enumArray)
|
||||||
}
|
}
|
||||||
registeredStaticClasses.forEach { staticClass ->
|
registeredStaticClasses.forEach { staticClass ->
|
||||||
addGlobalStaticClass(getLuaName(staticClass), staticClass)
|
addGlobalStaticClass(staticClass.getLuaName(), staticClass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import com.esotericsoftware.reflectasm.ConstructorAccess
|
|||||||
import com.esotericsoftware.reflectasm.MethodAccess
|
import com.esotericsoftware.reflectasm.MethodAccess
|
||||||
import io.github.oshai.kotlinlogging.KotlinLogging.logger
|
import io.github.oshai.kotlinlogging.KotlinLogging.logger
|
||||||
import org.anime_game_servers.core.base.annotations.lua.LuaNames
|
import org.anime_game_servers.core.base.annotations.lua.LuaNames
|
||||||
|
import org.anime_game_servers.lua.utils.getLuaNames
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
import java.lang.reflect.ParameterizedType
|
import java.lang.reflect.ParameterizedType
|
||||||
import java.lang.reflect.TypeVariable
|
import java.lang.reflect.TypeVariable
|
||||||
@ -47,7 +48,7 @@ abstract class BaseSerializer : Serializer {
|
|||||||
Arrays.stream(classtype.declaredFields)
|
Arrays.stream(classtype.declaredFields)
|
||||||
.forEach { field: Field ->
|
.forEach { field: Field ->
|
||||||
val name = field.name
|
val name = field.name
|
||||||
val luaNames = getLuaNames(field)
|
val luaNames = field.getLuaNames()
|
||||||
val fieldMeta = if (methodNameSet.contains(getSetterName(name))) {
|
val fieldMeta = if (methodNameSet.contains(getSetterName(name))) {
|
||||||
val setter = getSetterName(name)
|
val setter = getSetterName(name)
|
||||||
val index = methodAccess.getIndex(setter)
|
val index = methodAccess.getIndex(setter)
|
||||||
@ -68,7 +69,7 @@ abstract class BaseSerializer : Serializer {
|
|||||||
.filter { field: Field -> methodNameSet.contains(getSetterName(field.name)) }
|
.filter { field: Field -> methodNameSet.contains(getSetterName(field.name)) }
|
||||||
.forEach { field: Field ->
|
.forEach { field: Field ->
|
||||||
val name = field.name
|
val name = field.name
|
||||||
val luaNames = getLuaNames(field)
|
val luaNames = field.getLuaNames()
|
||||||
val setter = getSetterName(name)
|
val setter = getSetterName(name)
|
||||||
val index = methodAccess.getIndex(setter)
|
val index = methodAccess.getIndex(setter)
|
||||||
val fieldMeta = FieldMeta(name, luaNames, setter, index, field.type, field)
|
val fieldMeta = FieldMeta(name, luaNames, setter, index, field.type, field)
|
||||||
@ -81,18 +82,6 @@ abstract class BaseSerializer : Serializer {
|
|||||||
return fieldMetaMap
|
return fieldMetaMap
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun getLuaNames(field: Field): List<String> {
|
|
||||||
val luaName: MutableList<String> = mutableListOf(field.name)
|
|
||||||
field.annotations
|
|
||||||
.filterIsInstance<LuaNames>()
|
|
||||||
.forEach { luaNames: LuaNames ->
|
|
||||||
if (luaNames.value.isNotEmpty()) {
|
|
||||||
luaName.addAll(luaNames.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return luaName
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun set(`object`: Any?, @Nonnull fieldMeta: FieldMeta, methodAccess: MethodAccess?, value: Int) {
|
protected fun set(`object`: Any?, @Nonnull fieldMeta: FieldMeta, methodAccess: MethodAccess?, value: Int) {
|
||||||
try {
|
try {
|
||||||
if (methodAccess != null && fieldMeta.setter != null) {
|
if (methodAccess != null && fieldMeta.setter != null) {
|
||||||
|
@ -3,8 +3,12 @@ package org.anime_game_servers.lua.utils
|
|||||||
import kotlinx.io.Source
|
import kotlinx.io.Source
|
||||||
import kotlinx.io.asSource
|
import kotlinx.io.asSource
|
||||||
import kotlinx.io.buffered
|
import kotlinx.io.buffered
|
||||||
|
import org.anime_game_servers.core.base.annotations.lua.LuaNames
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
import java.lang.reflect.AnnotatedElement
|
||||||
|
import java.lang.reflect.Field
|
||||||
|
import java.lang.reflect.Member
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
@ -17,3 +21,21 @@ fun Path.asSource(): Source {
|
|||||||
val stream = Files.newInputStream(this)
|
val stream = Files.newInputStream(this)
|
||||||
return stream.asSource().buffered()
|
return stream.asSource().buffered()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Member.getLuaNames(): List<String> {
|
||||||
|
val luaName: MutableList<String> = mutableListOf(name)
|
||||||
|
(this as? AnnotatedElement)?.let {
|
||||||
|
annotations
|
||||||
|
.filterIsInstance<LuaNames>()
|
||||||
|
.forEach { luaNames: LuaNames ->
|
||||||
|
if (luaNames.value.isNotEmpty()) {
|
||||||
|
luaName.addAll(luaNames.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return luaName
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Class<*>.getLuaName()= getAnnotation(LuaNames::class.java)?.let {
|
||||||
|
it.value.firstOrNull() ?: simpleName
|
||||||
|
} ?: simpleName
|
@ -133,11 +133,12 @@ abstract class ParsingTest{
|
|||||||
val context = LuaContext(engine)
|
val context = LuaContext(engine)
|
||||||
|
|
||||||
assert(script.hasMethod("expectIntArray"))
|
assert(script.hasMethod("expectIntArray"))
|
||||||
val luaValue = script.callMethod("expectIntArray", context)
|
val luaValue = script.callMethod("expectIntArray", context)!!
|
||||||
luaValue?.isLong()
|
assert(luaValue.isTable())
|
||||||
|
|
||||||
assert(script.hasMethod("expectObjectTable"))
|
assert(script.hasMethod("expectObjectTable"))
|
||||||
val objectTableResult = script.callMethod("expectObjectTable", context)
|
val objectTableResult = script.callMethod("expectObjectTable", context)!!
|
||||||
objectTableResult?.isLong()
|
assert(objectTableResult.isTable())
|
||||||
|
|
||||||
// TODO test nested tables
|
// TODO test nested tables
|
||||||
// TODO test mixed tables (int+string keys)
|
// TODO test mixed tables (int+string keys)
|
||||||
|
@ -5,7 +5,7 @@ function expectIntArray(context)
|
|||||||
local array = KotlinFunctions.expectIntArray(context, param)
|
local array = KotlinFunctions.expectIntArray(context, param)
|
||||||
for i,v in ipairs(array) do
|
for i,v in ipairs(array) do
|
||||||
if v == Nil then
|
if v == Nil then
|
||||||
return Nil
|
return i
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return array
|
return array
|
||||||
@ -17,14 +17,14 @@ function expectObjectTable(context)
|
|||||||
local z = 3
|
local z = 3
|
||||||
local result = KotlinFunctions.expectObjectTable(context, {x=x, y=y, z=z})
|
local result = KotlinFunctions.expectObjectTable(context, {x=x, y=y, z=z})
|
||||||
|
|
||||||
if(result.x ~= x) then
|
if result.x ~= x then
|
||||||
return Nil
|
return "X"
|
||||||
end
|
end
|
||||||
if(result.y ~= y) then
|
if result.y ~= y then
|
||||||
return Nil
|
return "Y"
|
||||||
end
|
end
|
||||||
if(result.z ~= z) then
|
if result.z ~= z then
|
||||||
return Nil
|
return "Z"
|
||||||
end
|
end
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
Loading…
Reference in New Issue
Block a user