1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-07-02 16:38:41 +00:00

Try to preserve metatable when exchanging data with the async env (#14369)

Co-authored-by: sfan5 <sfan5@live.de>
Co-authored-by: Lars Mueller <appgurulars@gmx.de>
This commit is contained in:
y5nw 2024-03-06 18:04:49 +01:00 committed by GitHub
parent badd42789a
commit fc80f65a6d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 126 additions and 6 deletions

View file

@ -99,6 +99,27 @@ static inline bool suitable_key(lua_State *L, int idx)
}
}
/**
* Push core.known_metatables to the stack if it exists.
* @param L Lua state
* @return true if core.known_metatables exists, false otherwise.
*/
static inline bool get_known_lua_metatables(lua_State *L)
{
lua_getglobal(L, "core");
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
return false;
}
lua_getfield(L, -1, "known_metatables");
if (lua_istable(L, -1)) {
lua_remove(L, -2);
return true;
}
lua_pop(L, 2);
return false;
}
namespace {
// checks if you left any values on the stack, for debugging
class StackChecker {
@ -450,6 +471,18 @@ static VectorRef<PackedInstr> pack_inner(lua_State *L, int idx, int vidx, Packed
lua_pop(L, 1);
}
// try to preserve metatable information
if (lua_getmetatable(L, idx) && get_known_lua_metatables(L)) {
lua_insert(L, -2);
lua_gettable(L, -2);
if (lua_isstring(L, -1)) {
auto r = emplace(pv, INSTR_SETMETATABLE);
r->sdata = std::string(lua_tostring(L, -1));
r->set_into = vi_table;
}
lua_pop(L, 2);
}
// exactly the table should be left on stack
assert(vidx == vi_table + 1);
return rtable;
@ -514,6 +547,16 @@ void script_unpack(lua_State *L, PackedValue *pv)
lua_pushinteger(L, i.sidata1);
lua_rawget(L, top);
break;
case INSTR_SETMETATABLE:
if (get_known_lua_metatables(L)) {
lua_getfield(L, -1, i.sdata.c_str());
lua_remove(L, -2);
if (lua_istable(L, -1))
lua_setmetatable(L, top + i.set_into);
else
lua_pop(L, 1);
}
continue;
/* Lua types */
case LUA_TNIL:
@ -614,6 +657,9 @@ void script_dump_packed(const PackedValue *val)
case INSTR_PUSHREF:
printf("PUSHREF(%d)", i.sidata1);
break;
case INSTR_SETMETATABLE:
printf("SETMETATABLE(%s)", i.sdata.c_str());
break;
case LUA_TNIL:
printf("nil");
break;
@ -636,7 +682,7 @@ void script_dump_packed(const PackedValue *val)
printf("userdata %s %p", i.sdata.c_str(), i.ptrdata);
break;
default:
printf("!!UNKNOWN!!");
FATAL_ERROR("unknown type");
break;
}
if (i.set_into) {

View file

@ -34,9 +34,10 @@ extern "C" {
states and cannot be used for persistence or network transfer.
*/
#define INSTR_SETTABLE (-10)
#define INSTR_POP (-11)
#define INSTR_PUSHREF (-12)
#define INSTR_SETTABLE (-10)
#define INSTR_POP (-11)
#define INSTR_PUSHREF (-12)
#define INSTR_SETMETATABLE (-13)
/**
* Represents a single instruction that pushes a new value or operates with existing ones.
@ -70,6 +71,7 @@ struct PackedInstr
- function: buffer
- w/ set_into: string key (no null bytes!)
- userdata: name in registry
- INSTR_SETMETATABLE: name of the metatable
*/
std::string sdata;