Skip to content

Commit

Permalink
Implement vector and node conversion in Lua (#12609)
Browse files Browse the repository at this point in the history
Co-authored-by: sfan5 <sfan5@live.de>
  • Loading branch information
TurkeyMcMac and sfan5 committed Oct 18, 2022
1 parent 23e9f5d commit b38ffde
Show file tree
Hide file tree
Showing 29 changed files with 191 additions and 167 deletions.
1 change: 1 addition & 0 deletions builtin/client/init.lua
Expand Up @@ -10,3 +10,4 @@ dofile(commonpath .. "chatcommands.lua")
dofile(clientpath .. "chatcommands.lua")
dofile(clientpath .. "death_formspec.lua")
dofile(clientpath .. "misc.lua")
assert(loadfile(commonpath .. "item_s.lua"))({}) -- Just for push/read node functions
14 changes: 14 additions & 0 deletions builtin/common/item_s.lua
Expand Up @@ -223,3 +223,17 @@ function builtin_shared.cache_content_ids()
end
end
end

if core.set_read_node and core.set_push_node then
local function read_node(node)
return name2content[node.name], node.param1, node.param2
end
core.set_read_node(read_node)
core.set_read_node = nil

local function push_node(content, param1, param2)
return {name = content2name[content], param1 = param1, param2 = param2}
end
core.set_push_node(push_node)
core.set_push_node = nil
end
1 change: 0 additions & 1 deletion builtin/common/tests/misc_helpers_spec.lua
@@ -1,5 +1,4 @@
_G.core = {}
_G.vector = {metatable = {}}
dofile("builtin/common/vector.lua")
dofile("builtin/common/misc_helpers.lua")

Expand Down
1 change: 0 additions & 1 deletion builtin/common/tests/serialize_spec.lua
@@ -1,5 +1,4 @@
_G.core = {}
_G.vector = {metatable = {}}

_G.setfenv = require 'busted.compatibility'.setfenv

Expand Down
2 changes: 1 addition & 1 deletion builtin/common/tests/vector_spec.lua
@@ -1,4 +1,4 @@
_G.vector = {metatable = {}}
_G.vector = {}
dofile("builtin/common/vector.lua")

describe("vector", function()
Expand Down
25 changes: 23 additions & 2 deletions builtin/common/vector.lua
Expand Up @@ -6,8 +6,10 @@ Note: The vector.*-functions must be able to accept old vectors that had no meta
-- localize functions
local setmetatable = setmetatable

-- vector.metatable is set by C++.
local metatable = vector.metatable
vector = {}

local metatable = {}
vector.metatable = metatable

local xyz = {"x", "y", "z"}

Expand Down Expand Up @@ -366,3 +368,22 @@ function vector.dir_to_rotation(forward, up)
end
return rot
end

if rawget(_G, "core") and core.set_read_vector and core.set_push_vector then
local function read_vector(v)
return v.x, v.y, v.z
end
core.set_read_vector(read_vector)
core.set_read_vector = nil

if rawget(_G, "jit") then
-- This is necessary to prevent trace aborts.
local function push_vector(x, y, z)
return (fast_new(x, y, z))
end
core.set_push_vector(push_vector)
else
core.set_push_vector(fast_new)
end
core.set_push_vector = nil
end
1 change: 0 additions & 1 deletion builtin/mainmenu/tests/serverlistmgr_spec.lua
@@ -1,5 +1,4 @@
_G.core = {get_once = function(_) end}
_G.vector = {metatable = {}}
_G.unpack = table.unpack
_G.serverlistmgr = {}

Expand Down
1 change: 1 addition & 0 deletions src/client/client.cpp
Expand Up @@ -196,6 +196,7 @@ void Client::loadMods()
// Load builtin
scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath());
m_script->loadModFromMemory(BUILTIN_MOD_NAME);
m_script->checkSetByBuiltin();

ModConfiguration modconf;
{
Expand Down
1 change: 1 addition & 0 deletions src/gui/guiEngine.cpp
Expand Up @@ -226,6 +226,7 @@ bool GUIEngine::loadMainMenuScript()
std::string script = porting::path_share + DIR_DELIM "builtin" + DIR_DELIM "init.lua";
try {
m_script->loadScript(script);
m_script->checkSetByBuiltin();
// Menu script loaded
return true;
} catch (const ModError &e) {
Expand Down
44 changes: 14 additions & 30 deletions src/script/common/c_content.cpp
Expand Up @@ -1175,43 +1175,27 @@ NodeBox read_nodebox(lua_State *L, int index)
}

/******************************************************************************/
MapNode readnode(lua_State *L, int index, const NodeDefManager *ndef)
MapNode readnode(lua_State *L, int index)
{
lua_getfield(L, index, "name");
if (!lua_isstring(L, -1))
throw LuaError("Node name is not set or is not a string!");
std::string name = lua_tostring(L, -1);
lua_pop(L, 1);

u8 param1 = 0;
lua_getfield(L, index, "param1");
if (!lua_isnil(L, -1))
param1 = lua_tonumber(L, -1);
lua_pop(L, 1);

u8 param2 = 0;
lua_getfield(L, index, "param2");
if (!lua_isnil(L, -1))
param2 = lua_tonumber(L, -1);
lua_pop(L, 1);

content_t id = CONTENT_IGNORE;
if (!ndef->getId(name, id))
throw LuaError("\"" + name + "\" is not a registered node!");

return {id, param1, param2};
lua_pushvalue(L, index);
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_READ_NODE);
lua_insert(L, -2);
lua_call(L, 1, 3);
content_t content = lua_tointeger(L, -3);
u8 param1 = lua_tointeger(L, -2);
u8 param2 = lua_tointeger(L, -1);
lua_pop(L, 3);
return MapNode(content, param1, param2);
}

/******************************************************************************/
void pushnode(lua_State *L, const MapNode &n, const NodeDefManager *ndef)
void pushnode(lua_State *L, const MapNode &n)
{
lua_createtable(L, 0, 3);
lua_pushstring(L, ndef->get(n).name.c_str());
lua_setfield(L, -2, "name");
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_NODE);
lua_pushinteger(L, n.getContent());
lua_pushinteger(L, n.getParam1());
lua_setfield(L, -2, "param1");
lua_pushinteger(L, n.getParam2());
lua_setfield(L, -2, "param2");
lua_call(L, 3, 1);
}

/******************************************************************************/
Expand Down
6 changes: 2 additions & 4 deletions src/script/common/c_content.h
Expand Up @@ -129,10 +129,8 @@ void read_inventory_list (lua_State *L, int tableindex,
Inventory *inv, const char *name,
IGameDef *gdef, int forcesize=-1);

MapNode readnode (lua_State *L, int index,
const NodeDefManager *ndef);
void pushnode (lua_State *L, const MapNode &n,
const NodeDefManager *ndef);
MapNode readnode (lua_State *L, int index);
void pushnode (lua_State *L, const MapNode &n);


void read_groups (lua_State *L, int index,
Expand Down
120 changes: 43 additions & 77 deletions src/script/common/c_converter.cpp
Expand Up @@ -48,17 +48,19 @@ extern "C" {
} \
} while (0)

#define CHECK_POS_COORD(name) CHECK_TYPE(-1, "vector coordinate " name, LUA_TNUMBER)
#define CHECK_POS_COORD(index, name) CHECK_TYPE(index, "vector coordinate " name, LUA_TNUMBER)
#define CHECK_POS_TAB(index) CHECK_TYPE(index, "vector", LUA_TTABLE)


/**
* A helper which sets the vector metatable for the table on top of the stack
* A helper which calls CUSTOM_RIDX_READ_VECTOR with the argument at the given index
*/
static void set_vector_metatable(lua_State *L)
static void read_v3_aux(lua_State *L, int index)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_VECTOR_METATABLE);
lua_setmetatable(L, -2);
lua_pushvalue(L, index);
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_READ_VECTOR);
lua_insert(L, -2);
lua_call(L, 1, 3);
}

// Retrieve an integer vector where all components are optional
Expand All @@ -79,14 +81,11 @@ static bool getv3intfield(lua_State *L, int index,

void push_v3f(lua_State *L, v3f p)
{
lua_createtable(L, 0, 3);
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_VECTOR);
lua_pushnumber(L, p.X);
lua_setfield(L, -2, "x");
lua_pushnumber(L, p.Y);
lua_setfield(L, -2, "y");
lua_pushnumber(L, p.Z);
lua_setfield(L, -2, "z");
set_vector_metatable(L);
lua_call(L, 3, 1);
}

void push_v2f(lua_State *L, v2f p)
Expand Down Expand Up @@ -160,12 +159,12 @@ v2f check_v2f(lua_State *L, int index)
v2f p;
CHECK_POS_TAB(index);
lua_getfield(L, index, "x");
CHECK_POS_COORD("x");
CHECK_POS_COORD(-1, "x");
p.X = lua_tonumber(L, -1);
CHECK_FLOAT(p.X, "x");
lua_pop(L, 1);
lua_getfield(L, index, "y");
CHECK_POS_COORD("y");
CHECK_POS_COORD(-1, "y");
p.Y = lua_tonumber(L, -1);
CHECK_FLOAT(p.Y, "y");
lua_pop(L, 1);
Expand All @@ -174,78 +173,48 @@ v2f check_v2f(lua_State *L, int index)

v3f read_v3f(lua_State *L, int index)
{
v3f pos;
CHECK_POS_TAB(index);
lua_getfield(L, index, "x");
pos.X = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "y");
pos.Y = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "z");
pos.Z = lua_tonumber(L, -1);
lua_pop(L, 1);
return pos;
read_v3_aux(L, index);
float x = lua_tonumber(L, -3);
float y = lua_tonumber(L, -2);
float z = lua_tonumber(L, -1);
lua_pop(L, 3);
return v3f(x, y, z);
}

v3f check_v3f(lua_State *L, int index)
{
v3f pos;
CHECK_POS_TAB(index);
lua_getfield(L, index, "x");
CHECK_POS_COORD("x");
pos.X = lua_tonumber(L, -1);
CHECK_FLOAT(pos.X, "x");
lua_pop(L, 1);
lua_getfield(L, index, "y");
CHECK_POS_COORD("y");
pos.Y = lua_tonumber(L, -1);
CHECK_FLOAT(pos.Y, "y");
lua_pop(L, 1);
lua_getfield(L, index, "z");
CHECK_POS_COORD("z");
pos.Z = lua_tonumber(L, -1);
CHECK_FLOAT(pos.Z, "z");
lua_pop(L, 1);
return pos;
read_v3_aux(L, index);
CHECK_POS_COORD(-3, "x");
CHECK_POS_COORD(-2, "y");
CHECK_POS_COORD(-1, "z");
float x = lua_tonumber(L, -3);
float y = lua_tonumber(L, -2);
float z = lua_tonumber(L, -1);
lua_pop(L, 3);
return v3f(x, y, z);
}

v3d read_v3d(lua_State *L, int index)
{
v3d pos;
CHECK_POS_TAB(index);
lua_getfield(L, index, "x");
pos.X = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "y");
pos.Y = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "z");
pos.Z = lua_tonumber(L, -1);
lua_pop(L, 1);
return pos;
read_v3_aux(L, index);
double x = lua_tonumber(L, -3);
double y = lua_tonumber(L, -2);
double z = lua_tonumber(L, -1);
lua_pop(L, 3);
return v3d(x, y, z);
}

v3d check_v3d(lua_State *L, int index)
{
v3d pos;
CHECK_POS_TAB(index);
lua_getfield(L, index, "x");
CHECK_POS_COORD("x");
pos.X = lua_tonumber(L, -1);
CHECK_FLOAT(pos.X, "x");
lua_pop(L, 1);
lua_getfield(L, index, "y");
CHECK_POS_COORD("y");
pos.Y = lua_tonumber(L, -1);
CHECK_FLOAT(pos.Y, "y");
lua_pop(L, 1);
lua_getfield(L, index, "z");
CHECK_POS_COORD("z");
pos.Z = lua_tonumber(L, -1);
CHECK_FLOAT(pos.Z, "z");
lua_pop(L, 1);
return pos;
read_v3_aux(L, index);
CHECK_POS_COORD(-3, "x");
CHECK_POS_COORD(-2, "y");
CHECK_POS_COORD(-1, "z");
double x = lua_tonumber(L, -3);
double y = lua_tonumber(L, -2);
double z = lua_tonumber(L, -1);
lua_pop(L, 3);
return v3d(x, y, z);
}

void push_ARGB8(lua_State *L, video::SColor color)
Expand Down Expand Up @@ -274,14 +243,11 @@ v3f checkFloatPos(lua_State *L, int index)

void push_v3s16(lua_State *L, v3s16 p)
{
lua_createtable(L, 0, 3);
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_VECTOR);
lua_pushinteger(L, p.X);
lua_setfield(L, -2, "x");
lua_pushinteger(L, p.Y);
lua_setfield(L, -2, "y");
lua_pushinteger(L, p.Z);
lua_setfield(L, -2, "z");
set_vector_metatable(L);
lua_call(L, 3, 1);
}

v3s16 read_v3s16(lua_State *L, int index)
Expand Down
8 changes: 7 additions & 1 deletion src/script/common/c_internal.h
Expand Up @@ -56,8 +56,14 @@ enum {
CUSTOM_RIDX_CURRENT_MOD_NAME,
CUSTOM_RIDX_BACKTRACE,
CUSTOM_RIDX_HTTP_API_LUA,
CUSTOM_RIDX_VECTOR_METATABLE,
CUSTOM_RIDX_METATABLE_MAP,

// The following four functions are implemented in Lua because LuaJIT can
// trace them and optimize tables/string better than from the C API.
CUSTOM_RIDX_READ_VECTOR,
CUSTOM_RIDX_PUSH_VECTOR,
CUSTOM_RIDX_READ_NODE,
CUSTOM_RIDX_PUSH_NODE,
};


Expand Down
1 change: 1 addition & 0 deletions src/script/cpp_api/s_async.cpp
Expand Up @@ -247,6 +247,7 @@ bool AsyncEngine::prepareEnvironment(lua_State* L, int top)
try {
script->loadMod(Server::getBuiltinLuaPath() + DIR_DELIM + "init.lua",
BUILTIN_MOD_NAME);
script->checkSetByBuiltin();
} catch (const ModError &e) {
errorstream << "Execution of async base environment failed: "
<< e.what() << std::endl;
Expand Down

0 comments on commit b38ffde

Please sign in to comment.