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:
parent
badd42789a
commit
fc80f65a6d
8 changed files with 126 additions and 6 deletions
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue