#include "build/generated/sources/headers/java/main/ru_dbotthepony_kstarbound_lua_LuaJNI.h" #include "lua-5.3.6/src/lapi.h" #include "lua-5.3.6/src/lua.h" #include "lua-5.3.6/src/lauxlib.h" #include static int lua_jniFunc(lua_State *state) { JNIEnv *env = (JNIEnv *) lua_touserdata(state, lua_upvalueindex(1)); jmethodID callback = (jmethodID) lua_touserdata(state, lua_upvalueindex(2)); jobject* lua_JCClosure = (jobject*) lua_touserdata(state, lua_upvalueindex(3)); jint result = (*env)->CallIntMethod(env, *lua_JCClosure, callback, (long long) state); if (result <= -1) { return lua_error(state); } return result; } static int remove_gc_root(lua_State *state) { JNIEnv *env = (JNIEnv *) lua_touserdata(state, lua_upvalueindex(1)); jobject* obj = (jobject*) lua_touserdata(state, 1); if (obj == NULL) { printf("Lua Glue: remove_gc_root: obj is NULL! This is VERY LIKELY is going to result into a memory leak!\n"); return 0; } (*env)->DeleteGlobalRef(env, *obj); return 0; } static JNIEXPORT void JNICALL Java_ru_dbotthepony_kstarbound_lua_LuaJNI_lua_1pushcclosure(JNIEnv *env, jclass interface, jlong luaState, jobject lua_JCClosure) { lua_State* LluaState = (lua_State*) luaState; jclass clazz = (*env)->GetObjectClass(env, lua_JCClosure); if (clazz == NULL) return; jmethodID callback = (*env)->GetMethodID(env, clazz, "invoke", "(J)I"); if (callback == NULL) return; lua_pushlightuserdata(LluaState, env); lua_pushlightuserdata(LluaState, callback); void *umemory = lua_newuserdata(LluaState, sizeof(jobject)); jobject* rawBlock = (jobject*) umemory; *rawBlock = (*env)->NewGlobalRef(env, lua_JCClosure); int userdataIndex = lua_gettop(LluaState); // local table = {} lua_createtable(LluaState, 0, 1); int tableIndex = lua_gettop(LluaState); // function() lua_pushlightuserdata(LluaState, env); lua_pushcclosure(LluaState, remove_gc_root, 1); // table.__gc = fn lua_setfield(LluaState, tableIndex, "__gc"); // setmetatable(userdata, table) lua_setmetatable(LluaState, userdataIndex); lua_pushcclosure(LluaState, lua_jniFunc, 3); } // pushes Java object to Lua state, creating new GC root // Created reference is full userdata, hence it can have metatables attached to it // IT IS EXPECTED that before pushing object, at top of stack there is a table which is to be attached as metatable to newly created object // After this function returns, freshly created userdata will replace metatable static JNIEXPORT void JNICALL Java_ru_dbotthepony_kstarbound_lua_LuaJNI_lua_1pushjobject(JNIEnv *env, jclass interface, jlong luaState, jobject obj) { lua_State* LluaState = (lua_State*) luaState; jobject *umemory = (jobject *) lua_newuserdata(LluaState, sizeof(jobject)); *umemory = (*env)->NewGlobalRef(env, obj); lua_pushlightuserdata(LluaState, env); lua_pushcclosure(LluaState, remove_gc_root, 1); lua_setfield(LluaState, -3, "__gc"); lua_pushnil(LluaState); lua_copy(LluaState, -3, -1); lua_setmetatable(LluaState, -2); lua_copy(LluaState, -1, -2); lua_settop(LluaState, -2); } // returns NULL if index is invalid or doesn't contain userdata static JNIEXPORT jobject JNICALL Java_ru_dbotthepony_kstarbound_lua_LuaJNI_lua_1tojobject(JNIEnv *env, jclass interface, jlong luaState, jint stackIndex) { lua_State* LluaState = (lua_State*) luaState; jobject *data = lua_touserdata(LluaState, stackIndex); if (data == NULL) return NULL; return *data; }