diff options
Diffstat (limited to 'src/script/lua_api')
31 files changed, 700 insertions, 596 deletions
diff --git a/src/script/lua_api/l_areastore.cpp b/src/script/lua_api/l_areastore.cpp index 908c766b0..45724e604 100644 --- a/src/script/lua_api/l_areastore.cpp +++ b/src/script/lua_api/l_areastore.cpp @@ -372,7 +372,7 @@ void LuaAreaStore::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Can be created from Lua (AreaStore()) diff --git a/src/script/lua_api/l_auth.cpp b/src/script/lua_api/l_auth.cpp index 0fc57ba3a..32d8a7411 100644 --- a/src/script/lua_api/l_auth.cpp +++ b/src/script/lua_api/l_auth.cpp @@ -32,8 +32,11 @@ AuthDatabase *ModApiAuth::getAuthDb(lua_State *L) { ServerEnvironment *server_environment = dynamic_cast<ServerEnvironment *>(getEnv(L)); - if (!server_environment) + if (!server_environment) { + luaL_error(L, "Attempt to access an auth function but the auth" + " system is yet not initialized. This causes bugs."); return nullptr; + } return server_environment->getAuthDatabase(); } diff --git a/src/script/lua_api/l_camera.cpp b/src/script/lua_api/l_camera.cpp index 40251154c..d85d16283 100644 --- a/src/script/lua_api/l_camera.cpp +++ b/src/script/lua_api/l_camera.cpp @@ -219,7 +219,7 @@ void LuaCamera::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); } diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index c75fc8dc7..18ee3a521 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -46,13 +46,22 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/client.h" #endif -struct EnumString ModApiEnvMod::es_ClearObjectsMode[] = +const EnumString ModApiEnvMod::es_ClearObjectsMode[] = { {CLEAR_OBJECTS_MODE_FULL, "full"}, {CLEAR_OBJECTS_MODE_QUICK, "quick"}, {0, NULL}, }; +const EnumString ModApiEnvMod::es_BlockStatusType[] = +{ + {ServerEnvironment::BS_UNKNOWN, "unknown"}, + {ServerEnvironment::BS_EMERGING, "emerging"}, + {ServerEnvironment::BS_LOADED, "loaded"}, + {ServerEnvironment::BS_ACTIVE, "active"}, + {0, NULL}, +}; + /////////////////////////////////////////////////////////////////////////////// @@ -228,7 +237,7 @@ void LuaRaycast::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); lua_register(L, className, create_object); @@ -468,7 +477,7 @@ int ModApiEnvMod::l_place_node(lua_State *L) return 1; } // Create item to place - ItemStack item(ndef->get(n).name, 1, 0, idef); + Optional<ItemStack> item = ItemStack(ndef->get(n).name, 1, 0, idef); // Make pointed position PointedThing pointed; pointed.type = POINTEDTHING_NODE; @@ -871,6 +880,21 @@ int ModApiEnvMod::l_find_node_near(lua_State *L) return 0; } +static void checkArea(v3s16 &minp, v3s16 &maxp) +{ + auto volume = VoxelArea(minp, maxp).getVolume(); + // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000 + if (volume > 4096000) { + throw LuaError("Area volume exceeds allowed value of 4096000"); + } + + // Clamp to map range to avoid problems +#define CLAMP(arg) core::clamp(arg, (s16)-MAX_MAP_GENERATION_LIMIT, (s16)MAX_MAP_GENERATION_LIMIT) + minp = v3s16(CLAMP(minp.X), CLAMP(minp.Y), CLAMP(minp.Z)); + maxp = v3s16(CLAMP(maxp.X), CLAMP(maxp.Y), CLAMP(maxp.Z)); +#undef CLAMP +} + // find_nodes_in_area(minp, maxp, nodenames, [grouped]) int ModApiEnvMod::l_find_nodes_in_area(lua_State *L) { @@ -890,13 +914,7 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L) } #endif - v3s16 cube = maxp - minp + 1; - // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000 - if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) { - luaL_error(L, "find_nodes_in_area(): area volume" - " exceeds allowed value of 4096000"); - return 0; - } + checkArea(minp, maxp); std::vector<content_t> filter; collectNodeIds(L, 3, ndef, filter); @@ -1001,13 +1019,7 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L) } #endif - v3s16 cube = maxp - minp + 1; - // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000 - if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) { - luaL_error(L, "find_nodes_in_area_under_air(): area volume" - " exceeds allowed value of 4096000"); - return 0; - } + checkArea(minp, maxp); std::vector<content_t> filter; collectNodeIds(L, 3, ndef, filter); @@ -1389,6 +1401,24 @@ int ModApiEnvMod::l_forceload_block(lua_State *L) return 0; } +// compare_block_status(nodepos) +int ModApiEnvMod::l_compare_block_status(lua_State *L) +{ + GET_ENV_PTR; + + v3s16 nodepos = check_v3s16(L, 1); + std::string condition_s = luaL_checkstring(L, 2); + auto status = env->getBlockStatus(getNodeBlockPos(nodepos)); + + int condition_i = -1; + if (!string_to_enum(es_BlockStatusType, condition_i, condition_s)) + return 0; // Unsupported + + lua_pushboolean(L, status >= condition_i); + return 1; +} + + // forceload_free_block(blockpos) // blockpos = {x=num, y=num, z=num} int ModApiEnvMod::l_forceload_free_block(lua_State *L) @@ -1462,6 +1492,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top) API_FCT(transforming_liquid_add); API_FCT(forceload_block); API_FCT(forceload_free_block); + API_FCT(compare_block_status); API_FCT(get_translated_string); } diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index 42c2d64f8..67c76faae 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -195,6 +195,9 @@ private: // stops forceloading a position static int l_forceload_free_block(lua_State *L); + // compare_block_status(nodepos) + static int l_compare_block_status(lua_State *L); + // Get a string translated server side static int l_get_translated_string(lua_State * L); @@ -207,7 +210,8 @@ public: static void Initialize(lua_State *L, int top); static void InitializeClient(lua_State *L, int top); - static struct EnumString es_ClearObjectsMode[]; + static const EnumString es_ClearObjectsMode[]; + static const EnumString es_BlockStatusType[]; }; class LuaABM : public ActiveBlockModifier { @@ -219,17 +223,21 @@ private: float m_trigger_interval; u32 m_trigger_chance; bool m_simple_catch_up; + s16 m_min_y; + s16 m_max_y; public: LuaABM(lua_State *L, int id, const std::vector<std::string> &trigger_contents, const std::vector<std::string> &required_neighbors, - float trigger_interval, u32 trigger_chance, bool simple_catch_up): + float trigger_interval, u32 trigger_chance, bool simple_catch_up, s16 min_y, s16 max_y): m_id(id), m_trigger_contents(trigger_contents), m_required_neighbors(required_neighbors), m_trigger_interval(trigger_interval), m_trigger_chance(trigger_chance), - m_simple_catch_up(simple_catch_up) + m_simple_catch_up(simple_catch_up), + m_min_y(min_y), + m_max_y(max_y) { } virtual const std::vector<std::string> &getTriggerContents() const @@ -252,6 +260,14 @@ public: { return m_simple_catch_up; } + virtual s16 getMinY() + { + return m_min_y; + } + virtual s16 getMaxY() + { + return m_max_y; + } virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, u32 active_object_count, u32 active_object_count_wider); }; diff --git a/src/script/lua_api/l_http.cpp b/src/script/lua_api/l_http.cpp index 5ea3b3f99..bd359b3cc 100644 --- a/src/script/lua_api/l_http.cpp +++ b/src/script/lua_api/l_http.cpp @@ -21,14 +21,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_converter.h" #include "common/c_content.h" #include "lua_api/l_http.h" +#include "cpp_api/s_security.h" #include "httpfetch.h" #include "settings.h" #include "debug.h" #include "log.h" -#include <algorithm> #include <iomanip> -#include <cctype> #define HTTP_API(name) \ lua_pushstring(L, #name); \ @@ -42,12 +41,10 @@ void ModApiHttp::read_http_fetch_request(lua_State *L, HTTPFetchRequest &req) req.caller = httpfetch_caller_alloc_secure(); getstringfield(L, 1, "url", req.url); - lua_getfield(L, 1, "user_agent"); - if (lua_isstring(L, -1)) - req.useragent = getstringfield_default(L, 1, "user_agent", ""); - lua_pop(L, 1); + getstringfield(L, 1, "user_agent", req.useragent); req.multipart = getboolfield_default(L, 1, "multipart", false); - req.timeout = getintfield_default(L, 1, "timeout", 3) * 1000; + if (getintfield(L, 1, "timeout", req.timeout)) + req.timeout *= 1000; lua_getfield(L, 1, "method"); if (lua_isstring(L, -1)) { @@ -165,58 +162,40 @@ int ModApiHttp::l_http_fetch_async_get(lua_State *L) return 1; } -int ModApiHttp::l_request_http_api(lua_State *L) +int ModApiHttp::l_set_http_api_lua(lua_State *L) { NO_MAP_LOCK_REQUIRED; - // We have to make sure that this function is being called directly by - // a mod, otherwise a malicious mod could override this function and - // steal its return value. - lua_Debug info; - - // Make sure there's only one item below this function on the stack... - if (lua_getstack(L, 2, &info)) { - return 0; - } - FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed"); - FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed"); - - // ...and that that item is the main file scope. - if (strcmp(info.what, "main") != 0) { - return 0; - } - - // Mod must be listed in secure.http_mods or secure.trusted_mods - lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); - if (!lua_isstring(L, -1)) { - return 0; - } + // This is called by builtin to give us a function that will later + // populate the http_api table with additional method(s). + // We need this because access to the HTTP api is security-relevant and + // any mod could just mess with a global variable. + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_HTTP_API_LUA); - std::string mod_name = readParam<std::string>(L, -1); - std::string http_mods = g_settings->get("secure.http_mods"); - http_mods.erase(std::remove(http_mods.begin(), http_mods.end(), ' '), http_mods.end()); - std::vector<std::string> mod_list_http = str_split(http_mods, ','); + return 0; +} - std::string trusted_mods = g_settings->get("secure.trusted_mods"); - trusted_mods.erase(std::remove(trusted_mods.begin(), trusted_mods.end(), ' '), trusted_mods.end()); - std::vector<std::string> mod_list_trusted = str_split(trusted_mods, ','); +int ModApiHttp::l_request_http_api(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; - mod_list_http.insert(mod_list_http.end(), mod_list_trusted.begin(), mod_list_trusted.end()); - if (std::find(mod_list_http.begin(), mod_list_http.end(), mod_name) == mod_list_http.end()) { + if (!ScriptApiSecurity::checkWhitelisted(L, "secure.http_mods") && + !ScriptApiSecurity::checkWhitelisted(L, "secure.trusted_mods")) { lua_pushnil(L); return 1; } - lua_getglobal(L, "core"); - lua_getfield(L, -1, "http_add_fetch"); + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_HTTP_API_LUA); + assert(lua_isfunction(L, -1)); lua_newtable(L); HTTP_API(fetch_async); HTTP_API(fetch_async_get); // Stack now looks like this: - // <core.http_add_fetch> <table with fetch_async, fetch_async_get> - // Now call core.http_add_fetch to append .fetch(request, callback) to table + // <function> <table with fetch_async, fetch_async_get> + // Now call it to append .fetch(request, callback) to table lua_call(L, 1, 1); return 1; @@ -249,6 +228,7 @@ void ModApiHttp::Initialize(lua_State *L, int top) API_FCT(get_http_api); } else { API_FCT(request_http_api); + API_FCT(set_http_api_lua); } #endif diff --git a/src/script/lua_api/l_http.h b/src/script/lua_api/l_http.h index c3a2a5276..17fa283ba 100644 --- a/src/script/lua_api/l_http.h +++ b/src/script/lua_api/l_http.h @@ -41,6 +41,9 @@ private: // http_fetch_async_get(handle) static int l_http_fetch_async_get(lua_State *L); + // set_http_api_lua() [internal] + static int l_set_http_api_lua(lua_State *L); + // request_http_api() static int l_request_http_api(lua_State *L); diff --git a/src/script/lua_api/l_inventory.cpp b/src/script/lua_api/l_inventory.cpp index 434d0a76c..b0a4ee194 100644 --- a/src/script/lua_api/l_inventory.cpp +++ b/src/script/lua_api/l_inventory.cpp @@ -421,19 +421,6 @@ void InvRef::create(lua_State *L, const InventoryLocation &loc) luaL_getmetatable(L, className); lua_setmetatable(L, -2); } -void InvRef::createPlayer(lua_State *L, RemotePlayer *player) -{ - NO_MAP_LOCK_REQUIRED; - InventoryLocation loc; - loc.setPlayer(player->getName()); - create(L, loc); -} -void InvRef::createNodeMeta(lua_State *L, v3s16 p) -{ - InventoryLocation loc; - loc.setNodeMeta(p); - create(L, loc); -} void InvRef::Register(lua_State *L) { @@ -456,7 +443,7 @@ void InvRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Cannot be created from Lua diff --git a/src/script/lua_api/l_inventory.h b/src/script/lua_api/l_inventory.h index 94f670c9d..6a75bac0f 100644 --- a/src/script/lua_api/l_inventory.h +++ b/src/script/lua_api/l_inventory.h @@ -111,8 +111,6 @@ public: // Creates an InvRef and leaves it on top of stack // Not callable from Lua; all references are created on the C side. static void create(lua_State *L, const InventoryLocation &loc); - static void createPlayer(lua_State *L, RemotePlayer *player); - static void createNodeMeta(lua_State *L, v3s16 p); static void Register(lua_State *L); }; diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp index 9e0da4034..794d8a6e5 100644 --- a/src/script/lua_api/l_item.cpp +++ b/src/script/lua_api/l_item.cpp @@ -483,7 +483,7 @@ void LuaItemStack::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Can be created from Lua (ItemStack(itemstack or itemstring or table or nil)) diff --git a/src/script/lua_api/l_itemstackmeta.cpp b/src/script/lua_api/l_itemstackmeta.cpp index d1ba1bda4..739fb9221 100644 --- a/src/script/lua_api/l_itemstackmeta.cpp +++ b/src/script/lua_api/l_itemstackmeta.cpp @@ -114,7 +114,7 @@ void ItemStackMetaRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Cannot be created from Lua diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp index 33fa27c8b..2efb976c7 100644 --- a/src/script/lua_api/l_localplayer.cpp +++ b/src/script/lua_api/l_localplayer.cpp @@ -128,11 +128,11 @@ int LuaLocalPlayer::l_is_in_liquid_stable(lua_State *L) return 1; } -int LuaLocalPlayer::l_get_liquid_viscosity(lua_State *L) +int LuaLocalPlayer::l_get_move_resistance(lua_State *L) { LocalPlayer *player = getobject(L, 1); - lua_pushinteger(L, player->liquid_viscosity); + lua_pushinteger(L, player->move_resistance); return 1; } @@ -223,16 +223,22 @@ int LuaLocalPlayer::l_get_control(lua_State *L) }; lua_createtable(L, 0, 12); - set("up", c.up); - set("down", c.down); - set("left", c.left); - set("right", c.right); - set("jump", c.jump); - set("aux1", c.aux1); + set("jump", c.jump); + set("aux1", c.aux1); set("sneak", c.sneak); - set("zoom", c.zoom); - set("dig", c.dig); + set("zoom", c.zoom); + set("dig", c.dig); set("place", c.place); + // Player movement in polar coordinates and non-binary speed + lua_pushnumber(L, c.movement_speed); + lua_setfield(L, -2, "movement_speed"); + lua_pushnumber(L, c.movement_direction); + lua_setfield(L, -2, "movement_direction"); + // Provide direction keys to ensure compatibility + set("up", c.direction_keys & (1 << 0)); + set("down", c.direction_keys & (1 << 1)); + set("left", c.direction_keys & (1 << 2)); + set("right", c.direction_keys & (1 << 3)); return 1; } @@ -369,10 +375,11 @@ int LuaLocalPlayer::l_hud_change(lua_State *L) if (!element) return 0; + HudElementStat stat; void *unused; - read_hud_change(L, element, &unused); + bool ok = read_hud_change(L, stat, element, &unused); - lua_pushboolean(L, true); + lua_pushboolean(L, ok); return 1; } @@ -446,7 +453,7 @@ void LuaLocalPlayer::Register(lua_State *L) lua_pop(L, 1); // Drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // Drop methodtable } @@ -461,7 +468,6 @@ const luaL_Reg LuaLocalPlayer::methods[] = { luamethod(LuaLocalPlayer, is_touching_ground), luamethod(LuaLocalPlayer, is_in_liquid), luamethod(LuaLocalPlayer, is_in_liquid_stable), - luamethod(LuaLocalPlayer, get_liquid_viscosity), luamethod(LuaLocalPlayer, is_climbing), luamethod(LuaLocalPlayer, swimming_vertical), luamethod(LuaLocalPlayer, get_physics_override), @@ -483,5 +489,7 @@ const luaL_Reg LuaLocalPlayer::methods[] = { luamethod(LuaLocalPlayer, hud_change), luamethod(LuaLocalPlayer, hud_get), + luamethod(LuaLocalPlayer, get_move_resistance), + {0, 0} }; diff --git a/src/script/lua_api/l_localplayer.h b/src/script/lua_api/l_localplayer.h index 4413f2bdb..041545a49 100644 --- a/src/script/lua_api/l_localplayer.h +++ b/src/script/lua_api/l_localplayer.h @@ -51,7 +51,6 @@ private: static int l_is_touching_ground(lua_State *L); static int l_is_in_liquid(lua_State *L); static int l_is_in_liquid_stable(lua_State *L); - static int l_get_liquid_viscosity(lua_State *L); static int l_is_climbing(lua_State *L); static int l_swimming_vertical(lua_State *L); @@ -96,6 +95,8 @@ private: // hud_get(self, id) static int l_hud_get(lua_State *L); + static int l_get_move_resistance(lua_State *L); + LocalPlayer *m_localplayer = nullptr; public: diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 3e9709bde..736ad022f 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_internal.h" #include "common/c_content.h" #include "cpp_api/s_async.h" +#include "scripting_mainmenu.h" #include "gui/guiEngine.h" #include "gui/guiMainMenu.h" #include "gui/guiKeyChangeMenu.h" @@ -34,9 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "serverlist.h" #include "mapgen/mapgen.h" #include "settings.h" - -#include <IFileArchive.h> -#include <IFileSystem.h> +#include "client/client.h" #include "client/renderingengine.h" #include "network/networkprotocol.h" @@ -399,7 +398,8 @@ int ModApiMainMenu::l_show_keys_menu(lua_State *L) GUIEngine* engine = getGuiEngine(L); sanity_check(engine != NULL); - GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu(RenderingEngine::get_gui_env(), + GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu( + engine->m_rendering_engine->get_gui_env(), engine->m_parent, -1, engine->m_menumanager, @@ -414,25 +414,53 @@ int ModApiMainMenu::l_create_world(lua_State *L) const char *name = luaL_checkstring(L, 1); int gameidx = luaL_checkinteger(L,2) -1; + StringMap use_settings; + luaL_checktype(L, 3, LUA_TTABLE); + lua_pushnil(L); + while (lua_next(L, 3) != 0) { + // key at index -2 and value at index -1 + use_settings[luaL_checkstring(L, -2)] = luaL_checkstring(L, -1); + lua_pop(L, 1); + } + lua_pop(L, 1); + std::string path = porting::path_user + DIR_DELIM "worlds" + DIR_DELIM + sanitizeDirName(name, "world_"); std::vector<SubgameSpec> games = getAvailableGames(); + if (gameidx < 0 || gameidx >= (int) games.size()) { + lua_pushstring(L, "Invalid game index"); + return 1; + } - if ((gameidx >= 0) && - (gameidx < (int) games.size())) { + // Set the settings for world creation + // this is a bad hack but the best we have right now.. + StringMap backup; + for (auto it : use_settings) { + if (g_settings->existsLocal(it.first)) + backup[it.first] = g_settings->get(it.first); + g_settings->set(it.first, it.second); + } - // Create world if it doesn't exist - try { - loadGameConfAndInitWorld(path, name, games[gameidx], true); - lua_pushnil(L); - } catch (const BaseException &e) { - lua_pushstring(L, (std::string("Failed to initialize world: ") + e.what()).c_str()); - } - } else { - lua_pushstring(L, "Invalid game index"); + // Create world if it doesn't exist + try { + loadGameConfAndInitWorld(path, name, games[gameidx], true); + lua_pushnil(L); + } catch (const BaseException &e) { + auto err = std::string("Failed to initialize world: ") + e.what(); + lua_pushstring(L, err.c_str()); + } + + // Restore previous settings + for (auto it : use_settings) { + auto it2 = backup.find(it.first); + if (it2 == backup.end()) + g_settings->remove(it.first); // wasn't set before + else + g_settings->set(it.first, it2->second); // was set before } + return 1; } @@ -503,6 +531,21 @@ int ModApiMainMenu::l_get_modpath(lua_State *L) } /******************************************************************************/ +int ModApiMainMenu::l_get_modpaths(lua_State *L) +{ + int index = 1; + lua_newtable(L); + ModApiMainMenu::l_get_modpath(L); + lua_rawseti(L, -2, index); + for (const std::string &component : getEnvModPaths()) { + index++; + lua_pushstring(L, component.c_str()); + lua_rawseti(L, -2, index); + } + return 1; +} + +/******************************************************************************/ int ModApiMainMenu::l_get_clientmodpath(lua_State *L) { std::string modpath = fs::RemoveRelativePathComponents( @@ -548,7 +591,10 @@ int ModApiMainMenu::l_get_cache_path(lua_State *L) /******************************************************************************/ int ModApiMainMenu::l_get_temp_path(lua_State *L) { - lua_pushstring(L, fs::TempPath().c_str()); + if (lua_isnoneornil(L, 1) || !lua_toboolean(L, 1)) + lua_pushstring(L, fs::TempPath().c_str()); + else + lua_pushstring(L, fs::CreateTempFile().c_str()); return 1; } @@ -588,26 +634,24 @@ int ModApiMainMenu::l_copy_dir(lua_State *L) const char *destination = luaL_checkstring(L, 2); bool keep_source = true; + if (!lua_isnoneornil(L, 3)) + keep_source = readParam<bool>(L, 3); - if ((!lua_isnone(L,3)) && - (!lua_isnil(L,3))) { - keep_source = readParam<bool>(L,3); - } - - std::string absolute_destination = fs::RemoveRelativePathComponents(destination); - std::string absolute_source = fs::RemoveRelativePathComponents(source); - - if ((ModApiMainMenu::mayModifyPath(absolute_destination))) { - bool retval = fs::CopyDir(absolute_source,absolute_destination); - - if (retval && (!keep_source)) { + std::string abs_destination = fs::RemoveRelativePathComponents(destination); + std::string abs_source = fs::RemoveRelativePathComponents(source); - retval &= fs::RecursiveDelete(absolute_source); - } - lua_pushboolean(L,retval); + if (!ModApiMainMenu::mayModifyPath(abs_destination) || + (!keep_source && !ModApiMainMenu::mayModifyPath(abs_source))) { + lua_pushboolean(L, false); return 1; } - lua_pushboolean(L,false); + + bool retval; + if (keep_source) + retval = fs::CopyDir(abs_source, abs_destination); + else + retval = fs::MoveDir(abs_source, abs_destination); + lua_pushboolean(L, retval); return 1; } @@ -629,75 +673,9 @@ int ModApiMainMenu::l_extract_zip(lua_State *L) std::string absolute_destination = fs::RemoveRelativePathComponents(destination); if (ModApiMainMenu::mayModifyPath(absolute_destination)) { - fs::CreateAllDirs(absolute_destination); - - io::IFileSystem *fs = RenderingEngine::get_filesystem(); - - if (!fs->addFileArchive(zipfile, false, false, io::EFAT_ZIP)) { - lua_pushboolean(L,false); - return 1; - } - - sanity_check(fs->getFileArchiveCount() > 0); - - /**********************************************************************/ - /* WARNING this is not threadsafe!! */ - /**********************************************************************/ - io::IFileArchive* opened_zip = - fs->getFileArchive(fs->getFileArchiveCount()-1); - - const io::IFileList* files_in_zip = opened_zip->getFileList(); - - unsigned int number_of_files = files_in_zip->getFileCount(); - - for (unsigned int i=0; i < number_of_files; i++) { - std::string fullpath = destination; - fullpath += DIR_DELIM; - fullpath += files_in_zip->getFullFileName(i).c_str(); - std::string fullpath_dir = fs::RemoveLastPathComponent(fullpath); - - if (!files_in_zip->isDirectory(i)) { - if (!fs::PathExists(fullpath_dir) && !fs::CreateAllDirs(fullpath_dir)) { - fs->removeFileArchive(fs->getFileArchiveCount()-1); - lua_pushboolean(L,false); - return 1; - } - - io::IReadFile* toread = opened_zip->createAndOpenFile(i); - - FILE *targetfile = fopen(fullpath.c_str(),"wb"); - - if (targetfile == NULL) { - fs->removeFileArchive(fs->getFileArchiveCount()-1); - lua_pushboolean(L,false); - return 1; - } - - char read_buffer[1024]; - long total_read = 0; - - while (total_read < toread->getSize()) { - - unsigned int bytes_read = - toread->read(read_buffer,sizeof(read_buffer)); - if ((bytes_read == 0 ) || - (fwrite(read_buffer, 1, bytes_read, targetfile) != bytes_read)) - { - fclose(targetfile); - fs->removeFileArchive(fs->getFileArchiveCount()-1); - lua_pushboolean(L,false); - return 1; - } - total_read += bytes_read; - } - - fclose(targetfile); - } - - } - - fs->removeFileArchive(fs->getFileArchiveCount()-1); - lua_pushboolean(L,true); + auto fs = RenderingEngine::get_raw_device()->getFileSystem(); + bool ok = fs::extractZipFile(fs, zipfile, destination); + lua_pushboolean(L, ok); return 1; } @@ -763,7 +741,7 @@ int ModApiMainMenu::l_show_path_select_dialog(lua_State *L) bool is_file_select = readParam<bool>(L, 3); GUIFileSelectMenu* fileOpenMenu = - new GUIFileSelectMenu(RenderingEngine::get_gui_env(), + new GUIFileSelectMenu(engine->m_rendering_engine->get_gui_env(), engine->m_parent, -1, engine->m_menumanager, @@ -804,13 +782,12 @@ int ModApiMainMenu::l_get_video_drivers(lua_State *L) lua_newtable(L); for (u32 i = 0; i != drivers.size(); i++) { - const char *name = RenderingEngine::getVideoDriverName(drivers[i]); - const char *fname = RenderingEngine::getVideoDriverFriendlyName(drivers[i]); + auto &info = RenderingEngine::getVideoDriverInfo(drivers[i]); lua_newtable(L); - lua_pushstring(L, name); + lua_pushstring(L, info.name.c_str()); lua_setfield(L, -2, "name"); - lua_pushstring(L, fname); + lua_pushstring(L, info.friendly_name.c_str()); lua_setfield(L, -2, "friendly_name"); lua_rawseti(L, -2, i + 1); @@ -820,32 +797,11 @@ int ModApiMainMenu::l_get_video_drivers(lua_State *L) } /******************************************************************************/ -int ModApiMainMenu::l_get_video_modes(lua_State *L) -{ - std::vector<core::vector3d<u32> > videomodes - = RenderingEngine::getSupportedVideoModes(); - - lua_newtable(L); - for (u32 i = 0; i != videomodes.size(); i++) { - lua_newtable(L); - lua_pushnumber(L, videomodes[i].X); - lua_setfield(L, -2, "w"); - lua_pushnumber(L, videomodes[i].Y); - lua_setfield(L, -2, "h"); - lua_pushnumber(L, videomodes[i].Z); - lua_setfield(L, -2, "depth"); - - lua_rawseti(L, -2, i + 1); - } - - return 1; -} - -/******************************************************************************/ int ModApiMainMenu::l_gettext(lua_State *L) { - std::string text = strgettext(std::string(luaL_checkstring(L, 1))); - lua_pushstring(L, text.c_str()); + const char *srctext = luaL_checkstring(L, 1); + const char *text = *srctext ? gettext(srctext) : ""; + lua_pushstring(L, text); return 1; } @@ -859,15 +815,7 @@ int ModApiMainMenu::l_get_screen_info(lua_State *L) lua_pushnumber(L,RenderingEngine::getDisplayDensity()); lua_settable(L, top); - lua_pushstring(L,"display_width"); - lua_pushnumber(L,RenderingEngine::getDisplaySize().X); - lua_settable(L, top); - - lua_pushstring(L,"display_height"); - lua_pushnumber(L,RenderingEngine::getDisplaySize().Y); - lua_settable(L, top); - - const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); + const v2u32 &window_size = RenderingEngine::getWindowSize(); lua_pushstring(L,"window_width"); lua_pushnumber(L, window_size.X); lua_settable(L, top); @@ -875,6 +823,10 @@ int ModApiMainMenu::l_get_screen_info(lua_State *L) lua_pushstring(L,"window_height"); lua_pushnumber(L, window_size.Y); lua_settable(L, top); + + lua_pushstring(L, "render_info"); + lua_pushstring(L, wide_to_utf8(RenderingEngine::get_video_driver()->getName()).c_str()); + lua_settable(L, top); return 1; } @@ -910,20 +862,20 @@ int ModApiMainMenu::l_open_dir(lua_State *L) /******************************************************************************/ int ModApiMainMenu::l_do_async_callback(lua_State *L) { - GUIEngine* engine = getGuiEngine(L); + MainMenuScripting *script = getScriptApi<MainMenuScripting>(L); size_t func_length, param_length; const char* serialized_func_raw = luaL_checklstring(L, 1, &func_length); - const char* serialized_param_raw = luaL_checklstring(L, 2, ¶m_length); sanity_check(serialized_func_raw != NULL); sanity_check(serialized_param_raw != NULL); - std::string serialized_func = std::string(serialized_func_raw, func_length); - std::string serialized_param = std::string(serialized_param_raw, param_length); + u32 jobId = script->queueAsync( + std::string(serialized_func_raw, func_length), + std::string(serialized_param_raw, param_length)); - lua_pushinteger(L, engine->queueAsync(serialized_func, serialized_param)); + lua_pushinteger(L, jobId); return 1; } @@ -949,6 +901,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top) API_FCT(get_mapgen_names); API_FCT(get_user_path); API_FCT(get_modpath); + API_FCT(get_modpaths); API_FCT(get_clientmodpath); API_FCT(get_gamepath); API_FCT(get_texturepath); @@ -966,7 +919,6 @@ void ModApiMainMenu::Initialize(lua_State *L, int top) API_FCT(download_file); API_FCT(gettext); API_FCT(get_video_drivers); - API_FCT(get_video_modes); API_FCT(get_screen_info); API_FCT(get_min_supp_proto); API_FCT(get_max_supp_proto); @@ -983,6 +935,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top) API_FCT(get_mapgen_names); API_FCT(get_user_path); API_FCT(get_modpath); + API_FCT(get_modpaths); API_FCT(get_clientmodpath); API_FCT(get_gamepath); API_FCT(get_texturepath); @@ -993,10 +946,10 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top) API_FCT(delete_dir); API_FCT(copy_dir); API_FCT(is_dir); - //API_FCT(extract_zip); //TODO remove dependency to GuiEngine + API_FCT(extract_zip); API_FCT(may_modify_path); API_FCT(download_file); API_FCT(get_min_supp_proto); API_FCT(get_max_supp_proto); - //API_FCT(gettext); (gettext lib isn't threadsafe) + API_FCT(gettext); } diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index 33ac9e721..781185425 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -112,6 +112,8 @@ private: static int l_get_modpath(lua_State *L); + static int l_get_modpaths(lua_State *L); + static int l_get_clientmodpath(lua_State *L); static int l_get_gamepath(lua_State *L); @@ -140,8 +142,6 @@ private: static int l_get_video_drivers(lua_State *L); - static int l_get_video_modes(lua_State *L); - //version compatibility static int l_get_min_supp_proto(lua_State *L); diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 12a497b1e..f173bd162 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -482,9 +482,7 @@ int ModApiMapgen::l_get_biome_id(lua_State *L) { NO_MAP_LOCK_REQUIRED; - const char *biome_str = lua_tostring(L, 1); - if (!biome_str) - return 0; + const char *biome_str = luaL_checkstring(L, 1); const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); if (!bmgr) @@ -527,30 +525,12 @@ int ModApiMapgen::l_get_heat(lua_State *L) v3s16 pos = read_v3s16(L, 1); - NoiseParams np_heat; - NoiseParams np_heat_blend; - - MapSettingsManager *settingsmgr = - getServer(L)->getEmergeManager()->map_settings_mgr; - - if (!settingsmgr->getMapSettingNoiseParams("mg_biome_np_heat", - &np_heat) || - !settingsmgr->getMapSettingNoiseParams("mg_biome_np_heat_blend", - &np_heat_blend)) - return 0; + const BiomeGen *biomegen = getServer(L)->getEmergeManager()->getBiomeGen(); - std::string value; - if (!settingsmgr->getMapSetting("seed", &value)) - return 0; - std::istringstream ss(value); - u64 seed; - ss >> seed; - - const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); - if (!bmgr) + if (!biomegen || biomegen->getType() != BIOMEGEN_ORIGINAL) return 0; - float heat = bmgr->getHeatAtPosOriginal(pos, np_heat, np_heat_blend, seed); + float heat = ((BiomeGenOriginal*) biomegen)->calcHeatAtPoint(pos); lua_pushnumber(L, heat); @@ -566,31 +546,12 @@ int ModApiMapgen::l_get_humidity(lua_State *L) v3s16 pos = read_v3s16(L, 1); - NoiseParams np_humidity; - NoiseParams np_humidity_blend; + const BiomeGen *biomegen = getServer(L)->getEmergeManager()->getBiomeGen(); - MapSettingsManager *settingsmgr = - getServer(L)->getEmergeManager()->map_settings_mgr; - - if (!settingsmgr->getMapSettingNoiseParams("mg_biome_np_humidity", - &np_humidity) || - !settingsmgr->getMapSettingNoiseParams("mg_biome_np_humidity_blend", - &np_humidity_blend)) - return 0; - - std::string value; - if (!settingsmgr->getMapSetting("seed", &value)) - return 0; - std::istringstream ss(value); - u64 seed; - ss >> seed; - - const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); - if (!bmgr) + if (!biomegen || biomegen->getType() != BIOMEGEN_ORIGINAL) return 0; - float humidity = bmgr->getHumidityAtPosOriginal(pos, np_humidity, - np_humidity_blend, seed); + float humidity = ((BiomeGenOriginal*) biomegen)->calcHumidityAtPoint(pos); lua_pushnumber(L, humidity); @@ -606,45 +567,11 @@ int ModApiMapgen::l_get_biome_data(lua_State *L) v3s16 pos = read_v3s16(L, 1); - NoiseParams np_heat; - NoiseParams np_heat_blend; - NoiseParams np_humidity; - NoiseParams np_humidity_blend; - - MapSettingsManager *settingsmgr = - getServer(L)->getEmergeManager()->map_settings_mgr; - - if (!settingsmgr->getMapSettingNoiseParams("mg_biome_np_heat", - &np_heat) || - !settingsmgr->getMapSettingNoiseParams("mg_biome_np_heat_blend", - &np_heat_blend) || - !settingsmgr->getMapSettingNoiseParams("mg_biome_np_humidity", - &np_humidity) || - !settingsmgr->getMapSettingNoiseParams("mg_biome_np_humidity_blend", - &np_humidity_blend)) - return 0; - - std::string value; - if (!settingsmgr->getMapSetting("seed", &value)) - return 0; - std::istringstream ss(value); - u64 seed; - ss >> seed; - - const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); - if (!bmgr) + const BiomeGen *biomegen = getServer(L)->getEmergeManager()->getBiomeGen(); + if (!biomegen) return 0; - float heat = bmgr->getHeatAtPosOriginal(pos, np_heat, np_heat_blend, seed); - if (!heat) - return 0; - - float humidity = bmgr->getHumidityAtPosOriginal(pos, np_humidity, - np_humidity_blend, seed); - if (!humidity) - return 0; - - const Biome *biome = bmgr->getBiomeFromNoiseOriginal(heat, humidity, pos); + const Biome *biome = biomegen->calcBiomeAtPoint(pos); if (!biome || biome->index == OBJDEF_INVALID_INDEX) return 0; @@ -653,11 +580,16 @@ int ModApiMapgen::l_get_biome_data(lua_State *L) lua_pushinteger(L, biome->index); lua_setfield(L, -2, "biome"); - lua_pushnumber(L, heat); - lua_setfield(L, -2, "heat"); + if (biomegen->getType() == BIOMEGEN_ORIGINAL) { + float heat = ((BiomeGenOriginal*) biomegen)->calcHeatAtPoint(pos); + float humidity = ((BiomeGenOriginal*) biomegen)->calcHumidityAtPoint(pos); - lua_pushnumber(L, humidity); - lua_setfield(L, -2, "humidity"); + lua_pushnumber(L, heat); + lua_setfield(L, -2, "heat"); + + lua_pushnumber(L, humidity); + lua_setfield(L, -2, "humidity"); + } return 1; } @@ -820,9 +752,7 @@ int ModApiMapgen::l_get_mapgen_params(lua_State *L) lua_setfield(L, -2, "mgname"); settingsmgr->getMapSetting("seed", &value); - std::istringstream ss(value); - u64 seed; - ss >> seed; + u64 seed = from_string<u64>(value); lua_pushinteger(L, seed); lua_setfield(L, -2, "seed"); @@ -1493,9 +1423,12 @@ int ModApiMapgen::l_generate_ores(lua_State *L) NO_MAP_LOCK_REQUIRED; EmergeManager *emerge = getServer(L)->getEmergeManager(); + if (!emerge || !emerge->mgparams) + return 0; Mapgen mg; - mg.seed = emerge->mgparams->seed; + // Intentionally truncates to s32, see Mapgen::Mapgen() + mg.seed = (s32)emerge->mgparams->seed; mg.vm = LuaVoxelManip::checkobject(L, 1)->vm; mg.ndef = getServer(L)->getNodeDefManager(); @@ -1519,9 +1452,12 @@ int ModApiMapgen::l_generate_decorations(lua_State *L) NO_MAP_LOCK_REQUIRED; EmergeManager *emerge = getServer(L)->getEmergeManager(); + if (!emerge || !emerge->mgparams) + return 0; Mapgen mg; - mg.seed = emerge->mgparams->seed; + // Intentionally truncates to s32, see Mapgen::Mapgen() + mg.seed = (s32)emerge->mgparams->seed; mg.vm = LuaVoxelManip::checkobject(L, 1)->vm; mg.ndef = getServer(L)->getNodeDefManager(); @@ -1734,11 +1670,10 @@ int ModApiMapgen::l_serialize_schematic(lua_State *L) std::ostringstream os(std::ios_base::binary); switch (schem_format) { case SCHEM_FMT_MTS: - schem->serializeToMts(&os, schem->m_nodenames); + schem->serializeToMts(&os); break; case SCHEM_FMT_LUA: - schem->serializeToLua(&os, schem->m_nodenames, - use_comments, indent_spaces); + schem->serializeToLua(&os, use_comments, indent_spaces); break; default: return 0; diff --git a/src/script/lua_api/l_metadata.cpp b/src/script/lua_api/l_metadata.cpp index 21002e6a7..d00cb4daa 100644 --- a/src/script/lua_api/l_metadata.cpp +++ b/src/script/lua_api/l_metadata.cpp @@ -82,9 +82,10 @@ int MetaDataRef::l_get(lua_State *L) std::string str; if (meta->getStringToRef(name, str)) { lua_pushlstring(L, str.c_str(), str.size()); - return 1; + } else { + lua_pushnil(L); } - return 0; + return 1; } // get_string(self, name) diff --git a/src/script/lua_api/l_minimap.cpp b/src/script/lua_api/l_minimap.cpp index 3bbb6e5e3..a135e0bd5 100644 --- a/src/script/lua_api/l_minimap.cpp +++ b/src/script/lua_api/l_minimap.cpp @@ -211,7 +211,7 @@ void LuaMinimap::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable } diff --git a/src/script/lua_api/l_modchannels.cpp b/src/script/lua_api/l_modchannels.cpp index 0485b276a..931c2749c 100644 --- a/src/script/lua_api/l_modchannels.cpp +++ b/src/script/lua_api/l_modchannels.cpp @@ -107,7 +107,7 @@ void ModChannelRef::Register(lua_State *L) lua_pop(L, 1); // Drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // Drop methodtable } diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp index 57052cb42..34760157d 100644 --- a/src/script/lua_api/l_nodemeta.cpp +++ b/src/script/lua_api/l_nodemeta.cpp @@ -89,7 +89,10 @@ int NodeMetaRef::l_get_inventory(lua_State *L) NodeMetaRef *ref = checkobject(L, 1); ref->getmeta(true); // try to ensure the metadata exists - InvRef::createNodeMeta(L, ref->m_p); + + InventoryLocation loc; + loc.setNodeMeta(ref->m_p); + InvRef::create(L, loc); return 1; } @@ -234,7 +237,7 @@ void NodeMetaRef::RegisterCommon(lua_State *L) void NodeMetaRef::Register(lua_State *L) { RegisterCommon(L); - luaL_openlib(L, 0, methodsServer, 0); // fill methodtable + luaL_register(L, nullptr, methodsServer); // fill methodtable lua_pop(L, 1); // drop methodtable } @@ -260,7 +263,7 @@ const luaL_Reg NodeMetaRef::methodsServer[] = { void NodeMetaRef::RegisterClient(lua_State *L) { RegisterCommon(L); - luaL_openlib(L, 0, methodsClient, 0); // fill methodtable + luaL_register(L, nullptr, methodsClient); // fill methodtable lua_pop(L, 1); // drop methodtable } diff --git a/src/script/lua_api/l_nodetimer.cpp b/src/script/lua_api/l_nodetimer.cpp index c2df52c05..8a302149f 100644 --- a/src/script/lua_api/l_nodetimer.cpp +++ b/src/script/lua_api/l_nodetimer.cpp @@ -122,7 +122,7 @@ void NodeTimerRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Cannot be created from Lua diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp index e0861126a..f43ba837a 100644 --- a/src/script/lua_api/l_noise.cpp +++ b/src/script/lua_api/l_noise.cpp @@ -122,7 +122,7 @@ void LuaPerlinNoise::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); lua_register(L, className, create_object); @@ -380,7 +380,7 @@ void LuaPerlinNoiseMap::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); lua_register(L, className, create_object); @@ -485,7 +485,7 @@ void LuaPseudoRandom::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); lua_register(L, className, create_object); @@ -584,7 +584,7 @@ void LuaPcgRandom::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); lua_register(L, className, create_object); @@ -699,7 +699,7 @@ void LuaSecureRandom::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); lua_register(L, className, create_object); diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 8ae99b929..407b48db0 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -172,27 +172,11 @@ int ObjectRef::l_punch(lua_State *L) float time_from_last_punch = readParam<float>(L, 3, 1000000.0f); ToolCapabilities toolcap = read_tool_capabilities(L, 4); v3f dir = readParam<v3f>(L, 5, sao->getBasePosition() - puncher->getBasePosition()); - dir.normalize(); - u16 src_original_hp = sao->getHP(); - u16 dst_origin_hp = puncher->getHP(); - u16 wear = sao->punch(dir, &toolcap, puncher, time_from_last_punch); + u32 wear = sao->punch(dir, &toolcap, puncher, time_from_last_punch); lua_pushnumber(L, wear); - // If the punched is a player, and its HP changed - if (src_original_hp != sao->getHP() && - sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) { - getServer(L)->SendPlayerHPOrDie((PlayerSAO *)sao, - PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, puncher)); - } - - // If the puncher is a player, and its HP changed - if (dst_origin_hp != puncher->getHP() && - puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) { - getServer(L)->SendPlayerHPOrDie((PlayerSAO *)puncher, - PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, sao)); - } return 1; } @@ -238,8 +222,6 @@ int ObjectRef::l_set_hp(lua_State *L) } sao->setHP(hp, reason); - if (sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) - getServer(L)->SendPlayerHPOrDie((PlayerSAO *)sao, reason); if (reason.hasLuaReference()) luaL_unref(L, LUA_REGISTRYINDEX, reason.lua_reference); return 0; @@ -685,6 +667,7 @@ int ObjectRef::l_set_properties(lua_State *L) return 0; read_object_properties(L, 2, sao, prop, getServer(L)->idef()); + prop->validate(); sao->notifyObjectPropertiesModified(); return 0; } @@ -752,6 +735,7 @@ int ObjectRef::l_set_nametag_attributes(lua_State *L) std::string nametag = getstringfield_default(L, 2, "text", ""); prop->nametag = nametag; + prop->validate(); sao->notifyObjectPropertiesModified(); lua_pushboolean(L, true); return 1; @@ -1383,20 +1367,19 @@ int ObjectRef::l_get_player_control(lua_State *L) NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); RemotePlayer *player = getplayer(ref); - if (player == nullptr) { - lua_pushlstring(L, "", 0); - return 1; - } - const PlayerControl &control = player->getPlayerControl(); lua_newtable(L); - lua_pushboolean(L, control.up); + if (player == nullptr) + return 1; + + const PlayerControl &control = player->getPlayerControl(); + lua_pushboolean(L, control.direction_keys & (1 << 0)); lua_setfield(L, -2, "up"); - lua_pushboolean(L, control.down); + lua_pushboolean(L, control.direction_keys & (1 << 1)); lua_setfield(L, -2, "down"); - lua_pushboolean(L, control.left); + lua_pushboolean(L, control.direction_keys & (1 << 2)); lua_setfield(L, -2, "left"); - lua_pushboolean(L, control.right); + lua_pushboolean(L, control.direction_keys & (1 << 3)); lua_setfield(L, -2, "right"); lua_pushboolean(L, control.jump); lua_setfield(L, -2, "jump"); @@ -1425,11 +1408,25 @@ int ObjectRef::l_get_player_control_bits(lua_State *L) ObjectRef *ref = checkobject(L, 1); RemotePlayer *player = getplayer(ref); if (player == nullptr) { - lua_pushlstring(L, "", 0); + lua_pushinteger(L, 0); return 1; } - lua_pushnumber(L, player->keyPressed); + const auto &c = player->getPlayerControl(); + + // This is very close to PlayerControl::getKeysPressed() but duplicated + // here so the encoding in the API is not inadvertedly changed. + u32 keypress_bits = + c.direction_keys | + ( (u32)(c.jump & 1) << 4) | + ( (u32)(c.aux1 & 1) << 5) | + ( (u32)(c.sneak & 1) << 6) | + ( (u32)(c.dig & 1) << 7) | + ( (u32)(c.place & 1) << 8) | + ( (u32)(c.zoom & 1) << 9) + ; + + lua_pushinteger(L, keypress_bits); return 1; } @@ -1553,12 +1550,14 @@ int ObjectRef::l_hud_change(lua_State *L) if (elem == nullptr) return 0; + HudElementStat stat; void *value = nullptr; - HudElementStat stat = read_hud_change(L, elem, &value); + bool ok = read_hud_change(L, stat, elem, &value); - getServer(L)->hudChange(player, id, stat, value); + if (ok) + getServer(L)->hudChange(player, id, stat, value); - lua_pushboolean(L, true); + lua_pushboolean(L, ok); return 1; } @@ -1736,9 +1735,11 @@ int ObjectRef::l_set_sky(lua_State *L) return 0; SkyboxParams sky_params = player->getSkyParams(); - bool is_colorspec = is_color_table(L, 2); - if (lua_istable(L, 2) && !is_colorspec) { + // reset if empty + if (lua_isnoneornil(L, 2) && lua_isnone(L, 3)) { + sky_params = SkyboxDefaults::getSkyDefaults(); + } else if (lua_istable(L, 2) && !is_color_table(L, 2)) { lua_getfield(L, 2, "base_color"); if (!lua_isnil(L, -1)) read_color(L, -1, &sky_params.bgcolor); @@ -1762,17 +1763,11 @@ int ObjectRef::l_set_sky(lua_State *L) } lua_pop(L, 1); - /* - We want to avoid crashes, so we're checking even if we're not using them. - However, we want to ensure that the skybox can be set to nil when - using "regular" or "plain" skybox modes as textures aren't needed. - */ - - if (sky_params.textures.size() != 6 && sky_params.textures.size() > 0) + // Validate that we either have six or zero textures + if (sky_params.textures.size() != 6 && !sky_params.textures.empty()) throw LuaError("Skybox expects 6 textures!"); - sky_params.clouds = getboolfield_default(L, 2, - "clouds", sky_params.clouds); + sky_params.clouds = getboolfield_default(L, 2, "clouds", sky_params.clouds); lua_getfield(L, 2, "sky_color"); if (lua_istable(L, -1)) { @@ -1820,7 +1815,7 @@ int ObjectRef::l_set_sky(lua_State *L) sky_params.fog_tint_type = luaL_checkstring(L, -1); lua_pop(L, 1); - // Because we need to leave the "sky_color" table. + // pop "sky_color" table lua_pop(L, 1); } } else { @@ -1856,11 +1851,8 @@ int ObjectRef::l_set_sky(lua_State *L) if (lua_istable(L, 4)) { lua_pushnil(L); while (lua_next(L, 4) != 0) { - // Key at index -2, and value at index -1 - if (lua_isstring(L, -1)) - sky_params.textures.emplace_back(readParam<std::string>(L, -1)); - else - sky_params.textures.emplace_back(""); + // Key at index -2, and value at index -1 + sky_params.textures.emplace_back(readParam<std::string>(L, -1)); // Remove the value, keep the key for the next iteration lua_pop(L, 1); } @@ -1876,6 +1868,7 @@ int ObjectRef::l_set_sky(lua_State *L) getServer(L)->setMoon(player, moon_params); getServer(L)->setStars(player, star_params); } + getServer(L)->setSky(player, sky_params); lua_pushboolean(L, true); return 1; @@ -1951,21 +1944,20 @@ int ObjectRef::l_set_sun(lua_State *L) if (player == nullptr) return 0; - luaL_checktype(L, 2, LUA_TTABLE); SunParams sun_params = player->getSunParams(); - sun_params.visible = getboolfield_default(L, 2, - "visible", sun_params.visible); - sun_params.texture = getstringfield_default(L, 2, - "texture", sun_params.texture); - sun_params.tonemap = getstringfield_default(L, 2, - "tonemap", sun_params.tonemap); - sun_params.sunrise = getstringfield_default(L, 2, - "sunrise", sun_params.sunrise); - sun_params.sunrise_visible = getboolfield_default(L, 2, - "sunrise_visible", sun_params.sunrise_visible); - sun_params.scale = getfloatfield_default(L, 2, - "scale", sun_params.scale); + // reset if empty + if (lua_isnoneornil(L, 2)) { + sun_params = SkyboxDefaults::getSunDefaults(); + } else { + luaL_checktype(L, 2, LUA_TTABLE); + sun_params.visible = getboolfield_default(L, 2, "visible", sun_params.visible); + sun_params.texture = getstringfield_default(L, 2, "texture", sun_params.texture); + sun_params.tonemap = getstringfield_default(L, 2, "tonemap", sun_params.tonemap); + sun_params.sunrise = getstringfield_default(L, 2, "sunrise", sun_params.sunrise); + sun_params.sunrise_visible = getboolfield_default(L, 2, "sunrise_visible", sun_params.sunrise_visible); + sun_params.scale = getfloatfield_default(L, 2, "scale", sun_params.scale); + } getServer(L)->setSun(player, sun_params); lua_pushboolean(L, true); @@ -2008,17 +2000,18 @@ int ObjectRef::l_set_moon(lua_State *L) if (player == nullptr) return 0; - luaL_checktype(L, 2, LUA_TTABLE); MoonParams moon_params = player->getMoonParams(); - moon_params.visible = getboolfield_default(L, 2, - "visible", moon_params.visible); - moon_params.texture = getstringfield_default(L, 2, - "texture", moon_params.texture); - moon_params.tonemap = getstringfield_default(L, 2, - "tonemap", moon_params.tonemap); - moon_params.scale = getfloatfield_default(L, 2, - "scale", moon_params.scale); + // reset if empty + if (lua_isnoneornil(L, 2)) { + moon_params = SkyboxDefaults::getMoonDefaults(); + } else { + luaL_checktype(L, 2, LUA_TTABLE); + moon_params.visible = getboolfield_default(L, 2, "visible", moon_params.visible); + moon_params.texture = getstringfield_default(L, 2, "texture", moon_params.texture); + moon_params.tonemap = getstringfield_default(L, 2, "tonemap", moon_params.tonemap); + moon_params.scale = getfloatfield_default(L, 2, "scale", moon_params.scale); + } getServer(L)->setMoon(player, moon_params); lua_pushboolean(L, true); @@ -2057,21 +2050,24 @@ int ObjectRef::l_set_stars(lua_State *L) if (player == nullptr) return 0; - luaL_checktype(L, 2, LUA_TTABLE); StarParams star_params = player->getStarParams(); - star_params.visible = getboolfield_default(L, 2, - "visible", star_params.visible); - star_params.count = getintfield_default(L, 2, - "count", star_params.count); + // reset if empty + if (lua_isnoneornil(L, 2)) { + star_params = SkyboxDefaults::getStarDefaults(); + } else { + luaL_checktype(L, 2, LUA_TTABLE); + star_params.visible = getboolfield_default(L, 2, "visible", star_params.visible); + star_params.count = getintfield_default(L, 2, "count", star_params.count); - lua_getfield(L, 2, "star_color"); - if (!lua_isnil(L, -1)) - read_color(L, -1, &star_params.starcolor); - lua_pop(L, 1); + lua_getfield(L, 2, "star_color"); + if (!lua_isnil(L, -1)) + read_color(L, -1, &star_params.starcolor); + lua_pop(L, 1); - star_params.scale = getfloatfield_default(L, 2, - "scale", star_params.scale); + star_params.scale = getfloatfield_default(L, 2, + "scale", star_params.scale); + } getServer(L)->setStars(player, star_params); lua_pushboolean(L, true); @@ -2110,31 +2106,36 @@ int ObjectRef::l_set_clouds(lua_State *L) if (player == nullptr) return 0; - luaL_checktype(L, 2, LUA_TTABLE); CloudParams cloud_params = player->getCloudParams(); - cloud_params.density = getfloatfield_default(L, 2, "density", cloud_params.density); + // reset if empty + if (lua_isnoneornil(L, 2)) { + cloud_params = SkyboxDefaults::getCloudDefaults(); + } else { + luaL_checktype(L, 2, LUA_TTABLE); + cloud_params.density = getfloatfield_default(L, 2, "density", cloud_params.density); - lua_getfield(L, 2, "color"); - if (!lua_isnil(L, -1)) - read_color(L, -1, &cloud_params.color_bright); - lua_pop(L, 1); - lua_getfield(L, 2, "ambient"); - if (!lua_isnil(L, -1)) - read_color(L, -1, &cloud_params.color_ambient); - lua_pop(L, 1); + lua_getfield(L, 2, "color"); + if (!lua_isnil(L, -1)) + read_color(L, -1, &cloud_params.color_bright); + lua_pop(L, 1); + lua_getfield(L, 2, "ambient"); + if (!lua_isnil(L, -1)) + read_color(L, -1, &cloud_params.color_ambient); + lua_pop(L, 1); - cloud_params.height = getfloatfield_default(L, 2, "height", cloud_params.height ); - cloud_params.thickness = getfloatfield_default(L, 2, "thickness", cloud_params.thickness); + cloud_params.height = getfloatfield_default(L, 2, "height", cloud_params.height); + cloud_params.thickness = getfloatfield_default(L, 2, "thickness", cloud_params.thickness); - lua_getfield(L, 2, "speed"); - if (lua_istable(L, -1)) { - v2f new_speed; - new_speed.X = getfloatfield_default(L, -1, "x", 0); - new_speed.Y = getfloatfield_default(L, -1, "z", 0); - cloud_params.speed = new_speed; + lua_getfield(L, 2, "speed"); + if (lua_istable(L, -1)) { + v2f new_speed; + new_speed.X = getfloatfield_default(L, -1, "x", 0); + new_speed.Y = getfloatfield_default(L, -1, "z", 0); + cloud_params.speed = new_speed; + } + lua_pop(L, 1); } - lua_pop(L, 1); getServer(L)->setClouds(player, cloud_params); lua_pushboolean(L, true); @@ -2311,7 +2312,7 @@ void ObjectRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable } diff --git a/src/script/lua_api/l_playermeta.cpp b/src/script/lua_api/l_playermeta.cpp index 558672e38..2706c99df 100644 --- a/src/script/lua_api/l_playermeta.cpp +++ b/src/script/lua_api/l_playermeta.cpp @@ -97,7 +97,7 @@ void PlayerMetaRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); // Cannot be created from Lua diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index bf5292521..88ab5e16b 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_content.h" #include "cpp_api/s_base.h" #include "cpp_api/s_security.h" +#include "scripting_server.h" #include "server.h" #include "environment.h" #include "remoteplayer.h" @@ -56,6 +57,17 @@ int ModApiServer::l_get_server_uptime(lua_State *L) return 1; } +// get_server_max_lag() +int ModApiServer::l_get_server_max_lag(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ServerEnvironment *s_env = dynamic_cast<ServerEnvironment *>(getEnv(L)); + if (!s_env) + lua_pushnil(L); + else + lua_pushnumber(L, s_env->getMaxLagEstimate()); + return 1; +} // print(text) int ModApiServer::l_print(lua_State *L) @@ -281,8 +293,10 @@ int ModApiServer::l_ban_player(lua_State *L) { NO_MAP_LOCK_REQUIRED; - Server *server = getServer(L); + if (!getEnv(L)) + throw LuaError("Can't ban player before server has started up"); + Server *server = getServer(L); const char *name = luaL_checkstring(L, 1); RemotePlayer *player = server->getEnv().getPlayer(name); if (!player) { @@ -296,16 +310,20 @@ int ModApiServer::l_ban_player(lua_State *L) return 1; } -// kick_player(name, [reason]) -> success -int ModApiServer::l_kick_player(lua_State *L) +// disconnect_player(name, [reason]) -> success +int ModApiServer::l_disconnect_player(lua_State *L) { NO_MAP_LOCK_REQUIRED; + + if (!getEnv(L)) + throw LuaError("Can't kick player before server has started up"); + const char *name = luaL_checkstring(L, 1); - std::string message("Kicked"); + std::string message; if (lua_isstring(L, 2)) - message.append(": ").append(readParam<std::string>(L, 2)); + message.append(readParam<std::string>(L, 2)); else - message.append("."); + message.append("Disconnected."); RemotePlayer *player = dynamic_cast<ServerEnvironment *>(getEnv(L))->getPlayer(name); if (player == NULL) { @@ -322,7 +340,8 @@ int ModApiServer::l_remove_player(lua_State *L) NO_MAP_LOCK_REQUIRED; std::string name = luaL_checkstring(L, 1); ServerEnvironment *s_env = dynamic_cast<ServerEnvironment *>(getEnv(L)); - assert(s_env); + if (!s_env) + throw LuaError("Can't remove player before server has started up"); RemotePlayer *player = s_env->getPlayer(name.c_str()); if (!player) @@ -452,29 +471,37 @@ int ModApiServer::l_sound_fade(lua_State *L) } // dynamic_add_media(filepath) -int ModApiServer::l_dynamic_add_media_raw(lua_State *L) +int ModApiServer::l_dynamic_add_media(lua_State *L) { NO_MAP_LOCK_REQUIRED; if (!getEnv(L)) throw LuaError("Dynamic media cannot be added before server has started up"); + Server *server = getServer(L); - std::string filepath = readParam<std::string>(L, 1); - CHECK_SECURE_PATH(L, filepath.c_str(), false); + std::string filepath; + std::string to_player; + bool ephemeral = false; - std::vector<RemotePlayer*> sent_to; - bool ok = getServer(L)->dynamicAddMedia(filepath, sent_to); - if (ok) { - // (see wrapper code in builtin) - lua_createtable(L, sent_to.size(), 0); - int i = 0; - for (RemotePlayer *player : sent_to) { - lua_pushstring(L, player->getName()); - lua_rawseti(L, -2, ++i); - } + if (lua_istable(L, 1)) { + getstringfield(L, 1, "filepath", filepath); + getstringfield(L, 1, "to_player", to_player); + getboolfield(L, 1, "ephemeral", ephemeral); } else { - lua_pushboolean(L, false); + filepath = readParam<std::string>(L, 1); } + if (filepath.empty()) + luaL_typerror(L, 1, "non-empty string"); + luaL_checktype(L, 2, LUA_TFUNCTION); + + CHECK_SECURE_PATH(L, filepath.c_str(), false); + + u32 token = server->getScriptIface()->allocateDynamicMediaCallback(L, 2); + + bool ok = server->dynamicAddMedia(filepath, token, to_player, ephemeral); + if (!ok) + server->getScriptIface()->freeDynamicMediaCallback(token); + lua_pushboolean(L, ok); return 1; } @@ -498,36 +525,12 @@ int ModApiServer::l_notify_authentication_modified(lua_State *L) return 0; } -// get_last_run_mod() -int ModApiServer::l_get_last_run_mod(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; - lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); - std::string current_mod = readParam<std::string>(L, -1, ""); - if (current_mod.empty()) { - lua_pop(L, 1); - lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str()); - } - return 1; -} - -// set_last_run_mod(modname) -int ModApiServer::l_set_last_run_mod(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; -#ifdef SCRIPTAPI_DEBUG - const char *mod = lua_tostring(L, 1); - getScriptApiBase(L)->setOriginDirect(mod); - //printf(">>>> last mod set from Lua: %s\n", mod); -#endif - return 0; -} - void ModApiServer::Initialize(lua_State *L, int top) { API_FCT(request_shutdown); API_FCT(get_server_status); API_FCT(get_server_uptime); + API_FCT(get_server_max_lag); API_FCT(get_worldpath); API_FCT(is_singleplayer); @@ -543,7 +546,7 @@ void ModApiServer::Initialize(lua_State *L, int top) API_FCT(sound_play); API_FCT(sound_stop); API_FCT(sound_fade); - API_FCT(dynamic_add_media_raw); + API_FCT(dynamic_add_media); API_FCT(get_player_information); API_FCT(get_player_privs); @@ -551,11 +554,8 @@ void ModApiServer::Initialize(lua_State *L, int top) API_FCT(get_ban_list); API_FCT(get_ban_description); API_FCT(ban_player); - API_FCT(kick_player); + API_FCT(disconnect_player); API_FCT(remove_player); API_FCT(unban_player_or_ip); API_FCT(notify_authentication_modified); - - API_FCT(get_last_run_mod); - API_FCT(set_last_run_mod); } diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h index 2df180b17..f05c0b7c9 100644 --- a/src/script/lua_api/l_server.h +++ b/src/script/lua_api/l_server.h @@ -33,6 +33,9 @@ private: // get_server_uptime() static int l_get_server_uptime(lua_State *L); + // get_server_max_lag() + static int l_get_server_max_lag(lua_State *L); + // get_worldpath() static int l_get_worldpath(lua_State *L); @@ -71,7 +74,7 @@ private: static int l_sound_fade(lua_State *L); // dynamic_add_media(filepath) - static int l_dynamic_add_media_raw(lua_State *L); + static int l_dynamic_add_media(lua_State *L); // get_player_privs(name, text) static int l_get_player_privs(lua_State *L); @@ -94,8 +97,8 @@ private: // unban_player_or_ip() static int l_unban_player_or_ip(lua_State *L); - // kick_player(name, [message]) -> success - static int l_kick_player(lua_State *L); + // disconnect_player(name, [reason]) -> success + static int l_disconnect_player(lua_State *L); // remove_player(name) static int l_remove_player(lua_State *L); @@ -103,12 +106,6 @@ private: // notify_authentication_modified(name) static int l_notify_authentication_modified(lua_State *L); - // get_last_run_mod() - static int l_get_last_run_mod(lua_State *L); - - // set_last_run_mod(modname) - static int l_set_last_run_mod(lua_State *L); - public: static void Initialize(lua_State *L, int top); }; diff --git a/src/script/lua_api/l_settings.cpp b/src/script/lua_api/l_settings.cpp index bcbaf15fa..14398dda2 100644 --- a/src/script/lua_api/l_settings.cpp +++ b/src/script/lua_api/l_settings.cpp @@ -20,18 +20,43 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_settings.h" #include "lua_api/l_internal.h" #include "cpp_api/s_security.h" +#include "threading/mutex_auto_lock.h" #include "util/string.h" // FlagDesc #include "settings.h" #include "noise.h" #include "log.h" -#define SET_SECURITY_CHECK(L, name) \ - if (o->m_settings == g_settings && ScriptApiSecurity::isSecure(L) && \ - name.compare(0, 7, "secure.") == 0) { \ - throw LuaError("Attempt to set secure setting."); \ +/* This protects: + * 'secure.*' settings from being set + * some mapgen settings from being set + * (not security-criticial, just to avoid messing up user configs) + */ +#define CHECK_SETTING_SECURITY(L, name) \ + if (o->m_settings == g_settings) { \ + if (checkSettingSecurity(L, name) == -1) \ + return 0; \ } +static inline int checkSettingSecurity(lua_State* L, const std::string &name) +{ + if (ScriptApiSecurity::isSecure(L) && name.compare(0, 7, "secure.") == 0) + throw LuaError("Attempt to set secure setting."); + + bool is_mainmenu = false; +#ifndef SERVER + is_mainmenu = ModApiBase::getGuiEngine(L) != nullptr; +#endif + if (!is_mainmenu && (name == "mg_name" || name == "mg_flags")) { + errorstream << "Tried to set global setting " << name << ", ignoring. " + "minetest.set_mapgen_setting() should be used instead." << std::endl; + infostream << script_get_backtrace(L) << std::endl; + return -1; + } + + return 0; +} + LuaSettings::LuaSettings(Settings *settings, const std::string &filename) : m_settings(settings), m_filename(filename) @@ -129,6 +154,7 @@ int LuaSettings::l_get_np_group(lua_State *L) return 1; } +// get_flags(self, key) -> table or nil int LuaSettings::l_get_flags(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -161,7 +187,7 @@ int LuaSettings::l_set(lua_State* L) std::string key = std::string(luaL_checkstring(L, 2)); const char* value = luaL_checkstring(L, 3); - SET_SECURITY_CHECK(L, key); + CHECK_SETTING_SECURITY(L, key); if (!o->m_settings->set(key, value)) throw LuaError("Invalid sequence found in setting parameters"); @@ -178,14 +204,14 @@ int LuaSettings::l_set_bool(lua_State* L) std::string key = std::string(luaL_checkstring(L, 2)); bool value = readParam<bool>(L, 3); - SET_SECURITY_CHECK(L, key); + CHECK_SETTING_SECURITY(L, key); o->m_settings->setBool(key, value); - return 1; + return 0; } -// set(self, key, value) +// set_np_group(self, key, value) int LuaSettings::l_set_np_group(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -195,7 +221,7 @@ int LuaSettings::l_set_np_group(lua_State *L) NoiseParams value; read_noiseparams(L, 3, &value); - SET_SECURITY_CHECK(L, key); + CHECK_SETTING_SECURITY(L, key); o->m_settings->setNoiseParams(key, value); @@ -210,7 +236,7 @@ int LuaSettings::l_remove(lua_State* L) std::string key = std::string(luaL_checkstring(L, 2)); - SET_SECURITY_CHECK(L, key); + CHECK_SETTING_SECURITY(L, key); bool success = o->m_settings->remove(key); lua_pushboolean(L, success); @@ -253,20 +279,36 @@ int LuaSettings::l_write(lua_State* L) return 1; } -// to_table(self) -> {[key1]=value1,...} -int LuaSettings::l_to_table(lua_State* L) +static void push_settings_table(lua_State *L, const Settings *settings) { - NO_MAP_LOCK_REQUIRED; - LuaSettings* o = checkobject(L, 1); - - std::vector<std::string> keys = o->m_settings->getNames(); - + std::vector<std::string> keys = settings->getNames(); lua_newtable(L); for (const std::string &key : keys) { - lua_pushstring(L, o->m_settings->get(key).c_str()); + std::string value; + Settings *group = nullptr; + + if (settings->getNoEx(key, value)) { + lua_pushstring(L, value.c_str()); + } else if (settings->getGroupNoEx(key, group)) { + // Recursively push tables + push_settings_table(L, group); + } else { + // Impossible case (multithreading) due to MutexAutoLock + continue; + } + lua_setfield(L, -2, key.c_str()); } +} + +// to_table(self) -> {[key1]=value1,...} +int LuaSettings::l_to_table(lua_State* L) +{ + NO_MAP_LOCK_REQUIRED; + LuaSettings* o = checkobject(L, 1); + MutexAutoLock(o->m_settings->m_mutex); + push_settings_table(L, o->m_settings); return 1; } @@ -292,7 +334,7 @@ void LuaSettings::Register(lua_State* L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Can be created from Lua (Settings(filename)) diff --git a/src/script/lua_api/l_storage.cpp b/src/script/lua_api/l_storage.cpp index cba34fb63..b8f4347a8 100644 --- a/src/script/lua_api/l_storage.cpp +++ b/src/script/lua_api/l_storage.cpp @@ -32,19 +32,23 @@ int ModApiStorage::l_get_mod_storage(lua_State *L) std::string mod_name = readParam<std::string>(L, -1); - ModMetadata *store = new ModMetadata(mod_name); + ModMetadata *store = nullptr; + if (IGameDef *gamedef = getGameDef(L)) { - store->load(gamedef->getModStoragePath()); - gamedef->registerModStorage(store); + store = new ModMetadata(mod_name, gamedef->getModStorageDatabase()); + if (gamedef->registerModStorage(store)) { + StorageRef::create(L, store); + int object = lua_gettop(L); + lua_pushvalue(L, object); + return 1; + } } else { - delete store; assert(false); // this should not happen } - StorageRef::create(L, store); - int object = lua_gettop(L); + delete store; - lua_pushvalue(L, object); + lua_pushnil(L); return 1; } @@ -110,7 +114,7 @@ void StorageRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable } diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index 203a0dd28..b04f26fda 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "irrlichttypes_extrabloated.h" #include "lua_api/l_util.h" #include "lua_api/l_internal.h" #include "lua_api/l_settings.h" @@ -39,8 +40,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "version.h" #include "util/hex.h" #include "util/sha1.h" -#include <algorithm> - +#include "util/png.h" +#include <cstdio> // log([level,] text) // Writes a line to the logger. @@ -158,28 +159,33 @@ int ModApiUtil::l_write_json(lua_State *L) return 1; } -// get_dig_params(groups, tool_capabilities) +// get_dig_params(groups, tool_capabilities[, wear]) int ModApiUtil::l_get_dig_params(lua_State *L) { NO_MAP_LOCK_REQUIRED; ItemGroupList groups; read_groups(L, 1, groups); ToolCapabilities tp = read_tool_capabilities(L, 2); - push_dig_params(L, getDigParams(groups, &tp)); + if (lua_isnoneornil(L, 3)) { + push_dig_params(L, getDigParams(groups, &tp)); + } else { + u16 wear = readParam<int>(L, 3); + push_dig_params(L, getDigParams(groups, &tp, wear)); + } return 1; } -// get_hit_params(groups, tool_capabilities[, time_from_last_punch]) +// get_hit_params(groups, tool_capabilities[, time_from_last_punch, [, wear]]) int ModApiUtil::l_get_hit_params(lua_State *L) { NO_MAP_LOCK_REQUIRED; std::unordered_map<std::string, int> groups; read_groups(L, 1, groups); ToolCapabilities tp = read_tool_capabilities(L, 2); - if(lua_isnoneornil(L, 3)) - push_hit_params(L, getHitParams(groups, &tp)); - else - push_hit_params(L, getHitParams(groups, &tp, readParam<float>(L, 3))); + float time_from_last_punch = readParam<float>(L, 3, 1000000); + int wear = readParam<int>(L, 4, 0); + push_hit_params(L, getHitParams(groups, &tp, + time_from_last_punch, wear)); return 1; } @@ -270,11 +276,11 @@ int ModApiUtil::l_compress(lua_State *L) const char *data = luaL_checklstring(L, 1, &size); int level = -1; - if (!lua_isnone(L, 3) && !lua_isnil(L, 3)) - level = readParam<float>(L, 3); + if (!lua_isnoneornil(L, 3)) + level = readParam<int>(L, 3); - std::ostringstream os; - compressZlib(std::string(data, size), os, level); + std::ostringstream os(std::ios_base::binary); + compressZlib(reinterpret_cast<const u8 *>(data), size, os, level); std::string out = os.str(); @@ -290,8 +296,8 @@ int ModApiUtil::l_decompress(lua_State *L) size_t size; const char *data = luaL_checklstring(L, 1, &size); - std::istringstream is(std::string(data, size)); - std::ostringstream os; + std::istringstream is(std::string(data, size), std::ios_base::binary); + std::ostringstream os(std::ios_base::binary); decompressZlib(is, os); std::string out = os.str(); @@ -342,6 +348,49 @@ int ModApiUtil::l_mkdir(lua_State *L) return 1; } +// rmdir(path, recursive) +int ModApiUtil::l_rmdir(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + const char *path = luaL_checkstring(L, 1); + CHECK_SECURE_PATH(L, path, true); + + bool recursive = readParam<bool>(L, 2, false); + + if (recursive) + lua_pushboolean(L, fs::RecursiveDelete(path)); + else + lua_pushboolean(L, fs::DeleteSingleFileOrEmptyDirectory(path)); + + return 1; +} + +// cpdir(source, destination) +int ModApiUtil::l_cpdir(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + const char *source = luaL_checkstring(L, 1); + const char *destination = luaL_checkstring(L, 2); + CHECK_SECURE_PATH(L, source, false); + CHECK_SECURE_PATH(L, destination, true); + + lua_pushboolean(L, fs::CopyDir(source, destination)); + return 1; +} + +// mpdir(source, destination) +int ModApiUtil::l_mvdir(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + const char *source = luaL_checkstring(L, 1); + const char *destination = luaL_checkstring(L, 2); + CHECK_SECURE_PATH(L, source, true); + CHECK_SECURE_PATH(L, destination, true); + + lua_pushboolean(L, fs::MoveDir(source, destination)); + return 1; +} + // get_dir_list(path, is_dir) int ModApiUtil::l_get_dir_list(lua_State *L) { @@ -394,36 +443,7 @@ int ModApiUtil::l_request_insecure_environment(lua_State *L) return 1; } - // We have to make sure that this function is being called directly by - // a mod, otherwise a malicious mod could override this function and - // steal its return value. - lua_Debug info; - // Make sure there's only one item below this function on the stack... - if (lua_getstack(L, 2, &info)) { - return 0; - } - FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed"); - FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed"); - // ...and that that item is the main file scope. - if (strcmp(info.what, "main") != 0) { - return 0; - } - - // Get mod name - lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); - if (!lua_isstring(L, -1)) { - return 0; - } - - // Check secure.trusted_mods - std::string mod_name = readParam<std::string>(L, -1); - std::string trusted_mods = g_settings->get("secure.trusted_mods"); - trusted_mods.erase(std::remove_if(trusted_mods.begin(), - trusted_mods.end(), static_cast<int(*)(int)>(&std::isspace)), - trusted_mods.end()); - std::vector<std::string> mod_list = str_split(trusted_mods, ','); - if (std::find(mod_list.begin(), mod_list.end(), mod_name) == - mod_list.end()) { + if (!ScriptApiSecurity::checkWhitelisted(L, "secure.trusted_mods")) { return 0; } @@ -479,6 +499,84 @@ int ModApiUtil::l_sha1(lua_State *L) return 1; } +// colorspec_to_colorstring(colorspec) +int ModApiUtil::l_colorspec_to_colorstring(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + video::SColor color(0); + if (read_color(L, 1, &color)) { + char colorstring[10]; + snprintf(colorstring, 10, "#%02X%02X%02X%02X", + color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + lua_pushstring(L, colorstring); + return 1; + } + + return 0; +} + +// colorspec_to_bytes(colorspec) +int ModApiUtil::l_colorspec_to_bytes(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + video::SColor color(0); + if (read_color(L, 1, &color)) { + u8 colorbytes[4] = { + (u8) color.getRed(), + (u8) color.getGreen(), + (u8) color.getBlue(), + (u8) color.getAlpha(), + }; + lua_pushlstring(L, (const char*) colorbytes, 4); + return 1; + } + + return 0; +} + +// encode_png(w, h, data, level) +int ModApiUtil::l_encode_png(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + // The args are already pre-validated on the lua side. + u32 width = readParam<int>(L, 1); + u32 height = readParam<int>(L, 2); + const char *data = luaL_checklstring(L, 3, NULL); + s32 compression = readParam<int>(L, 4); + + std::string out = encodePNG((const u8*)data, width, height, compression); + + lua_pushlstring(L, out.data(), out.size()); + return 1; +} + +// get_last_run_mod() +int ModApiUtil::l_get_last_run_mod(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); + std::string current_mod = readParam<std::string>(L, -1, ""); + if (current_mod.empty()) { + lua_pop(L, 1); + lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str()); + } + return 1; +} + +// set_last_run_mod(modname) +int ModApiUtil::l_set_last_run_mod(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + const char *mod = luaL_checkstring(L, 1); + getScriptApiBase(L)->setOriginDirect(mod); + return 0; +} + void ModApiUtil::Initialize(lua_State *L, int top) { API_FCT(log); @@ -503,6 +601,9 @@ void ModApiUtil::Initialize(lua_State *L, int top) API_FCT(decompress); API_FCT(mkdir); + API_FCT(rmdir); + API_FCT(cpdir); + API_FCT(mvdir); API_FCT(get_dir_list); API_FCT(safe_file_write); @@ -513,6 +614,13 @@ void ModApiUtil::Initialize(lua_State *L, int top) API_FCT(get_version); API_FCT(sha1); + API_FCT(colorspec_to_colorstring); + API_FCT(colorspec_to_bytes); + + API_FCT(encode_png); + + API_FCT(get_last_run_mod); + API_FCT(set_last_run_mod); LuaSettings::create(L, g_settings, g_settings_path); lua_setfield(L, top, "settings"); @@ -537,6 +645,8 @@ void ModApiUtil::InitializeClient(lua_State *L, int top) API_FCT(get_version); API_FCT(sha1); + API_FCT(colorspec_to_colorstring); + API_FCT(colorspec_to_bytes); } void ModApiUtil::InitializeAsync(lua_State *L, int top) @@ -557,6 +667,9 @@ void ModApiUtil::InitializeAsync(lua_State *L, int top) API_FCT(decompress); API_FCT(mkdir); + API_FCT(rmdir); + API_FCT(cpdir); + API_FCT(mvdir); API_FCT(get_dir_list); API_FCT(encode_base64); @@ -564,8 +677,12 @@ void ModApiUtil::InitializeAsync(lua_State *L, int top) API_FCT(get_version); API_FCT(sha1); + API_FCT(colorspec_to_colorstring); + API_FCT(colorspec_to_bytes); + + API_FCT(get_last_run_mod); + API_FCT(set_last_run_mod); LuaSettings::create(L, g_settings, g_settings_path); lua_setfield(L, top, "settings"); } - diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h index dbdd62b99..fcf8a1057 100644 --- a/src/script/lua_api/l_util.h +++ b/src/script/lua_api/l_util.h @@ -50,10 +50,10 @@ private: // write_json(data[, styled]) static int l_write_json(lua_State *L); - // get_dig_params(groups, tool_capabilities[, time_from_last_punch]) + // get_dig_params(groups, tool_capabilities[, wear]) static int l_get_dig_params(lua_State *L); - // get_hit_params(groups, tool_capabilities[, time_from_last_punch]) + // get_hit_params(groups, tool_capabilities[, time_from_last_punch[, wear]]) static int l_get_hit_params(lua_State *L); // check_password_entry(name, entry, password) @@ -80,6 +80,15 @@ private: // mkdir(path) static int l_mkdir(lua_State *L); + // rmdir(path, recursive) + static int l_rmdir(lua_State *L); + + // cpdir(source, destination, remove_source) + static int l_cpdir(lua_State *L); + + // mvdir(source, destination) + static int l_mvdir(lua_State *L); + // get_dir_list(path, is_dir) static int l_get_dir_list(lua_State *L); @@ -101,6 +110,21 @@ private: // sha1(string, raw) static int l_sha1(lua_State *L); + // colorspec_to_colorstring(colorspec) + static int l_colorspec_to_colorstring(lua_State *L); + + // colorspec_to_bytes(colorspec) + static int l_colorspec_to_bytes(lua_State *L); + + // encode_png(w, h, data, level) + static int l_encode_png(lua_State *L); + + // get_last_run_mod() + static int l_get_last_run_mod(lua_State *L); + + // set_last_run_mod(modname) + static int l_set_last_run_mod(lua_State *L); + public: static void Initialize(lua_State *L, int top); static void InitializeAsync(lua_State *L, int top); diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp index b99b1d98c..e040e545b 100644 --- a/src/script/lua_api/l_vmanip.cpp +++ b/src/script/lua_api/l_vmanip.cpp @@ -450,7 +450,7 @@ void LuaVoxelManip::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Can be created from Lua (VoxelManip()) |