Browse Source

Implement vector and node conversion in Lua (#12609)

Co-authored-by: sfan5 <sfan5@live.de>
Jude Melton-Houghton 1 year ago
parent
commit
b38ffdec27

+ 1 - 0
builtin/client/init.lua

@@ -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 - 0
builtin/common/item_s.lua

@@ -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

+ 0 - 1
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")
 

+ 0 - 1
builtin/common/tests/serialize_spec.lua

@@ -1,5 +1,4 @@
 _G.core = {}
-_G.vector = {metatable = {}}
 
 _G.setfenv = require 'busted.compatibility'.setfenv
 

+ 1 - 1
builtin/common/tests/vector_spec.lua

@@ -1,4 +1,4 @@
-_G.vector = {metatable = {}}
+_G.vector = {}
 dofile("builtin/common/vector.lua")
 
 describe("vector", function()

+ 23 - 2
builtin/common/vector.lua

@@ -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"}
 
@@ -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

+ 0 - 1
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 = {}
 

+ 1 - 0
src/client/client.cpp

@@ -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;
 	{

+ 1 - 0
src/gui/guiEngine.cpp

@@ -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) {

+ 14 - 30
src/script/common/c_content.cpp

@@ -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);
 }
 
 /******************************************************************************/

+ 2 - 4
src/script/common/c_content.h

@@ -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,

+ 43 - 77
src/script/common/c_converter.cpp

@@ -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
@@ -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)
@@ -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);
@@ -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)
@@ -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)

+ 7 - 1
src/script/common/c_internal.h

@@ -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,
 };
 
 

+ 1 - 0
src/script/cpp_api/s_async.cpp

@@ -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;

+ 47 - 8
src/script/cpp_api/s_base.cpp

@@ -120,16 +120,32 @@ ScriptApiBase::ScriptApiBase(ScriptingType type):
 #endif
 
 	// Add basic globals
-	lua_newtable(m_luastack);
-	lua_setglobal(m_luastack, "core");
 
-	// vector.metatable is stored in the registry for quick access from C++.
+	// "core" table:
 	lua_newtable(m_luastack);
-	lua_rawseti(m_luastack, LUA_REGISTRYINDEX, CUSTOM_RIDX_VECTOR_METATABLE);
-	lua_newtable(m_luastack);
-	lua_rawgeti(m_luastack, LUA_REGISTRYINDEX, CUSTOM_RIDX_VECTOR_METATABLE);
-	lua_setfield(m_luastack, -2, "metatable");
-	lua_setglobal(m_luastack, "vector");
+	// Populate with some internal functions which will be removed in Lua:
+	lua_pushcfunction(m_luastack, [](lua_State *L) -> int {
+		lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_READ_VECTOR);
+		return 0;
+	});
+	lua_setfield(m_luastack, -2, "set_read_vector");
+	lua_pushcfunction(m_luastack, [](lua_State *L) -> int {
+		lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_VECTOR);
+		return 0;
+	});
+	lua_setfield(m_luastack, -2, "set_push_vector");
+	lua_pushcfunction(m_luastack, [](lua_State *L) -> int {
+		lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_READ_NODE);
+		return 0;
+	});
+	lua_setfield(m_luastack, -2, "set_read_node");
+	lua_pushcfunction(m_luastack, [](lua_State *L) -> int {
+		lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_NODE);
+		return 0;
+	});
+	lua_setfield(m_luastack, -2, "set_push_node");
+	// Finally, put the table into the global environment:
+	lua_setglobal(m_luastack, "core");
 
 	if (m_type == ScriptingType::Client)
 		lua_pushstring(m_luastack, "/");
@@ -180,6 +196,29 @@ void ScriptApiBase::clientOpenLibs(lua_State *L)
 	}
 }
 
+void ScriptApiBase::checkSetByBuiltin()
+{
+	lua_State *L = getStack();
+
+	if (m_gamedef) {
+		lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_READ_VECTOR);
+		FATAL_ERROR_IF(lua_type(L, -1) != LUA_TFUNCTION, "missing read_vector");
+		lua_pop(L, 1);
+
+		lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_VECTOR);
+		FATAL_ERROR_IF(lua_type(L, -1) != LUA_TFUNCTION, "missing push_vector");
+		lua_pop(L, 1);
+
+		lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_READ_NODE);
+		FATAL_ERROR_IF(lua_type(L, -1) != LUA_TFUNCTION, "missing read_node");
+		lua_pop(L, 1);
+
+		lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_NODE);
+		FATAL_ERROR_IF(lua_type(L, -1) != LUA_TFUNCTION, "missing push_node");
+		lua_pop(L, 1);
+	}
+}
+
 void ScriptApiBase::loadMod(const std::string &script_path,
 		const std::string &mod_name)
 {

+ 3 - 0
src/script/cpp_api/s_base.h

@@ -115,6 +115,9 @@ public:
 
 	void clientOpenLibs(lua_State *L);
 
+	// Check things that should be set by the builtin mod.
+	void checkSetByBuiltin();
+
 protected:
 	friend class LuaABM;
 	friend class LuaLBM;

+ 2 - 6
src/script/cpp_api/s_client.cpp

@@ -186,15 +186,13 @@ bool ScriptApiClient::on_dignode(v3s16 p, MapNode node)
 {
 	SCRIPTAPI_PRECHECKHEADER
 
-	const NodeDefManager *ndef = getClient()->ndef();
-
 	// Get core.registered_on_dignode
 	lua_getglobal(L, "core");
 	lua_getfield(L, -1, "registered_on_dignode");
 
 	// Push data
 	push_v3s16(L, p);
-	pushnode(L, node, ndef);
+	pushnode(L, node);
 
 	// Call functions
 	try {
@@ -210,15 +208,13 @@ bool ScriptApiClient::on_punchnode(v3s16 p, MapNode node)
 {
 	SCRIPTAPI_PRECHECKHEADER
 
-	const NodeDefManager *ndef = getClient()->ndef();
-
 	// Get core.registered_on_punchgnode
 	lua_getglobal(L, "core");
 	lua_getfield(L, -1, "registered_on_punchnode");
 
 	// Push data
 	push_v3s16(L, p);
-	pushnode(L, node, ndef);
+	pushnode(L, node);
 
 	// Call functions
 	try {

+ 1 - 2
src/script/cpp_api/s_env.cpp

@@ -274,7 +274,6 @@ void ScriptApiEnv::on_liquid_transformed(
 
 	// Convert the list to a pos array and a node array for lua
 	int index = 1;
-	const NodeDefManager *ndef = getEnv()->getGameDef()->ndef();
 	lua_createtable(L, list.size(), 0);
 	lua_createtable(L, list.size(), 0);
 	for(std::pair<v3s16, MapNode> p : list) {
@@ -282,7 +281,7 @@ void ScriptApiEnv::on_liquid_transformed(
 		push_v3s16(L, p.first);
 		lua_rawset(L, -4);
 		lua_pushnumber(L, index++);
-		pushnode(L, p.second, ndef);
+		pushnode(L, p.second);
 		lua_rawset(L, -3);
 	}
 

+ 5 - 5
src/script/cpp_api/s_node.cpp

@@ -119,7 +119,7 @@ bool ScriptApiNode::node_on_punch(v3s16 p, MapNode node,
 
 	// Call function
 	push_v3s16(L, p);
-	pushnode(L, node, ndef);
+	pushnode(L, node);
 	objectrefGetOrCreate(L, puncher);
 	pushPointedThing(pointed);
 	PCALL_RES(lua_pcall(L, 4, 0, error_handler));
@@ -142,7 +142,7 @@ bool ScriptApiNode::node_on_dig(v3s16 p, MapNode node,
 
 	// Call function
 	push_v3s16(L, p);
-	pushnode(L, node, ndef);
+	pushnode(L, node);
 	objectrefGetOrCreate(L, digger);
 	PCALL_RES(lua_pcall(L, 3, 1, error_handler));
 
@@ -204,8 +204,8 @@ bool ScriptApiNode::node_on_flood(v3s16 p, MapNode node, MapNode newnode)
 
 	// Call function
 	push_v3s16(L, p);
-	pushnode(L, node, ndef);
-	pushnode(L, newnode, ndef);
+	pushnode(L, node);
+	pushnode(L, newnode);
 	PCALL_RES(lua_pcall(L, 3, 1, error_handler));
 	lua_remove(L, error_handler);
 	return readParam<bool>(L, -1, false);
@@ -225,7 +225,7 @@ void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node)
 
 	// Call function
 	push_v3s16(L, p);
-	pushnode(L, node, ndef);
+	pushnode(L, node);
 	PCALL_RES(lua_pcall(L, 2, 0, error_handler));
 	lua_pop(L, 1);  // Pop error handler
 }

+ 0 - 6
src/script/cpp_api/s_security.cpp

@@ -98,7 +98,6 @@ void ScriptApiSecurity::initializeSecurity()
 		"type",
 		"unpack",
 		"_VERSION",
-		"vector",
 		"xpcall",
 	};
 	static const char *whitelist_tables[] = {
@@ -253,10 +252,6 @@ void ScriptApiSecurity::initializeSecurity()
 	lua_pushnil(L);
 	lua_setfield(L, old_globals, "core");
 
-	// 'vector' as well.
-	lua_pushnil(L);
-	lua_setfield(L, old_globals, "vector");
-
 	lua_pop(L, 1); // Pop globals_backup
 
 
@@ -299,7 +294,6 @@ void ScriptApiSecurity::initializeSecurityClient()
 		"type",
 		"unpack",
 		"_VERSION",
-		"vector",
 		"xpcall",
 		// Completely safe libraries
 		"coroutine",

+ 1 - 1
src/script/lua_api/l_client.cpp

@@ -220,7 +220,7 @@ int ModApiClient::l_get_node_or_nil(lua_State *L)
 	MapNode n = getClient(L)->CSMGetNode(pos, &pos_ok);
 	if (pos_ok) {
 		// Return node
-		pushnode(L, n, getClient(L)->ndef());
+		pushnode(L, n);
 	} else {
 		lua_pushnil(L);
 	}

+ 8 - 11
src/script/lua_api/l_env.cpp

@@ -98,7 +98,7 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
 	luaL_checktype(L, -1, LUA_TFUNCTION);
 	lua_remove(L, -2); // Remove registered_abms[m_id]
 	push_v3s16(L, p);
-	pushnode(L, n, env->getGameDef()->ndef());
+	pushnode(L, n);
 	lua_pushnumber(L, active_object_count);
 	lua_pushnumber(L, active_object_count_wider);
 
@@ -140,7 +140,7 @@ void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n)
 	luaL_checktype(L, -1, LUA_TFUNCTION);
 	lua_remove(L, -2); // Remove registered_lbms[m_id]
 	push_v3s16(L, p);
-	pushnode(L, n, env->getGameDef()->ndef());
+	pushnode(L, n);
 
 	int result = lua_pcall(L, 2, 0, error_handler);
 	if (result)
@@ -247,10 +247,9 @@ int ModApiEnvMod::l_set_node(lua_State *L)
 {
 	GET_ENV_PTR;
 
-	const NodeDefManager *ndef = env->getGameDef()->ndef();
 	// parameters
 	v3s16 pos = read_v3s16(L, 1);
-	MapNode n = readnode(L, 2, ndef);
+	MapNode n = readnode(L, 2);
 	// Do it
 	bool succeeded = env->setNode(pos, n);
 	lua_pushboolean(L, succeeded);
@@ -263,7 +262,6 @@ int ModApiEnvMod::l_bulk_set_node(lua_State *L)
 {
 	GET_ENV_PTR;
 
-	const NodeDefManager *ndef = env->getGameDef()->ndef();
 	// parameters
 	if (!lua_istable(L, 1)) {
 		return 0;
@@ -275,7 +273,7 @@ int ModApiEnvMod::l_bulk_set_node(lua_State *L)
 		return 1;
 	}
 
-	MapNode n = readnode(L, 2, ndef);
+	MapNode n = readnode(L, 2);
 
 	// Do it
 	bool succeeded = true;
@@ -315,10 +313,9 @@ int ModApiEnvMod::l_swap_node(lua_State *L)
 {
 	GET_ENV_PTR;
 
-	const NodeDefManager *ndef = env->getGameDef()->ndef();
 	// parameters
 	v3s16 pos = read_v3s16(L, 1);
-	MapNode n = readnode(L, 2, ndef);
+	MapNode n = readnode(L, 2);
 	// Do it
 	bool succeeded = env->swapNode(pos, n);
 	lua_pushboolean(L, succeeded);
@@ -336,7 +333,7 @@ int ModApiEnvMod::l_get_node(lua_State *L)
 	// Do it
 	MapNode n = env->getMap().getNode(pos);
 	// Return node
-	pushnode(L, n, env->getGameDef()->ndef());
+	pushnode(L, n);
 	return 1;
 }
 
@@ -353,7 +350,7 @@ int ModApiEnvMod::l_get_node_or_nil(lua_State *L)
 	MapNode n = env->getMap().getNode(pos, &pos_ok);
 	if (pos_ok) {
 		// Return node
-		pushnode(L, n, env->getGameDef()->ndef());
+		pushnode(L, n);
 	} else {
 		lua_pushnil(L);
 	}
@@ -438,7 +435,7 @@ int ModApiEnvMod::l_place_node(lua_State *L)
 	IItemDefManager *idef = server->idef();
 
 	v3s16 pos = read_v3s16(L, 1);
-	MapNode n = readnode(L, 2, ndef);
+	MapNode n = readnode(L, 2);
 
 	// Don't attempt to load non-loaded area as of now
 	MapNode n_old = env->getMap().getNode(pos);

+ 7 - 0
src/script/lua_api/l_item.cpp

@@ -721,3 +721,10 @@ void ModApiItemMod::InitializeAsync(lua_State *L, int top)
 	API_FCT(get_content_id);
 	API_FCT(get_name_from_content_id);
 }
+
+void ModApiItemMod::InitializeClient(lua_State *L, int top)
+{
+	// all read-only functions
+	API_FCT(get_content_id);
+	API_FCT(get_name_from_content_id);
+}

+ 1 - 0
src/script/lua_api/l_item.h

@@ -174,4 +174,5 @@ private:
 public:
 	static void Initialize(lua_State *L, int top);
 	static void InitializeAsync(lua_State *L, int top);
+	static void InitializeClient(lua_State *L, int top);
 };

+ 2 - 2
src/script/lua_api/l_particles.cpp

@@ -138,7 +138,7 @@ int ModApiParticles::l_add_particle(lua_State *L)
 
 		lua_getfield(L, 1, "node");
 		if (lua_istable(L, -1))
-			p.node = readnode(L, -1, getGameDef(L)->ndef());
+			p.node = readnode(L, -1);
 		lua_pop(L, 1);
 
 		p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile);
@@ -289,7 +289,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
 
 		lua_getfield(L, 1, "node");
 		if (lua_istable(L, -1))
-			p.node = readnode(L, -1, getGameDef(L)->ndef());
+			p.node = readnode(L, -1);
 		lua_pop(L, 1);
 
 		p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile);

+ 2 - 2
src/script/lua_api/l_particles_local.cpp

@@ -87,7 +87,7 @@ int ModApiParticlesLocal::l_add_particle(lua_State *L)
 
 	lua_getfield(L, 1, "node");
 	if (lua_istable(L, -1))
-		p.node = readnode(L, -1, getGameDef(L)->ndef());
+		p.node = readnode(L, -1);
 	lua_pop(L, 1);
 
 	p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile);
@@ -185,7 +185,7 @@ int ModApiParticlesLocal::l_add_particlespawner(lua_State *L)
 
 	lua_getfield(L, 1, "node");
 	if (lua_istable(L, -1))
-		p.node = readnode(L, -1, getGameDef(L)->ndef());
+		p.node = readnode(L, -1);
 	lua_pop(L, 1);
 
 	p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile);

+ 2 - 6
src/script/lua_api/l_vmanip.cpp

@@ -139,12 +139,10 @@ int LuaVoxelManip::l_get_node_at(lua_State *L)
 {
 	NO_MAP_LOCK_REQUIRED;
 
-	const NodeDefManager *ndef = getServer(L)->getNodeDefManager();
-
 	LuaVoxelManip *o = checkObject<LuaVoxelManip>(L, 1);
 	v3s16 pos        = check_v3s16(L, 2);
 
-	pushnode(L, o->vm->getNodeNoExNoEmerge(pos), ndef);
+	pushnode(L, o->vm->getNodeNoExNoEmerge(pos));
 	return 1;
 }
 
@@ -152,11 +150,9 @@ int LuaVoxelManip::l_set_node_at(lua_State *L)
 {
 	NO_MAP_LOCK_REQUIRED;
 
-	const NodeDefManager *ndef = getServer(L)->getNodeDefManager();
-
 	LuaVoxelManip *o = checkObject<LuaVoxelManip>(L, 1);
 	v3s16 pos        = check_v3s16(L, 2);
-	MapNode n        = readnode(L, 3, ndef);
+	MapNode n        = readnode(L, 3);
 
 	o->vm->setNodeNoEmerge(pos, n);
 

+ 1 - 0
src/script/scripting_client.cpp

@@ -78,6 +78,7 @@ void ClientScripting::InitializeModApi(lua_State *L, int top)
 
 	ModApiUtil::InitializeClient(L, top);
 	ModApiClient::Initialize(L, top);
+	ModApiItemMod::InitializeClient(L, top);
 	ModApiStorage::Initialize(L, top);
 	ModApiEnvMod::InitializeClient(L, top);
 	ModApiChannels::Initialize(L, top);

+ 1 - 0
src/server.cpp

@@ -447,6 +447,7 @@ void Server::init()
 	m_inventory_mgr = std::make_unique<ServerInventoryManager>();
 
 	m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
+	m_script->checkSetByBuiltin();
 
 	m_gamespec.checkAndLog();
 	m_modmgr->loadMods(m_script);