diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 1c8cc1022..b58c75d11 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -4879,6 +4879,18 @@ Utilities or checking if a mod is enabled. * `minetest.get_modnames()`: returns a list of enabled mods, sorted alphabetically. * Does not include disabled mods, even if they are installed. +* `minetest.get_game_info()`: returns a table containing information about the + current game. Note that other meta information (e.g. version/release number) + can be manually read from `game.conf` in the game's root directory. + + { + id = string, + title = string, + author = string, + -- The root directory of the game + path = string, + } + * `minetest.get_worldpath()`: returns e.g. `"/home/user/.minetest/world"` * Useful for storing custom data * `minetest.is_singleplayer()` diff --git a/games/devtest/mods/unittests/misc.lua b/games/devtest/mods/unittests/misc.lua index 8ac3ed110..7c16b7c82 100644 --- a/games/devtest/mods/unittests/misc.lua +++ b/games/devtest/mods/unittests/misc.lua @@ -103,3 +103,10 @@ local function test_compress() end unittests.register("test_compress", test_compress) +local function test_game_info() + local info = minetest.get_game_info() + local game_conf = Settings(info.path .. "/game.conf") + assert(info.id == "devtest") + assert(info.title == game_conf:get("title")) +end +unittests.register("test_game_info", test_game_info) diff --git a/src/gamedef.h b/src/gamedef.h index e32d10509..df1fa2458 100644 --- a/src/gamedef.h +++ b/src/gamedef.h @@ -40,6 +40,7 @@ namespace irr { namespace scene { class ISceneManager; }} +struct SubgameSpec; struct ModSpec; /* An interface for fetching game-global definitions like tool and @@ -72,6 +73,7 @@ public: virtual const std::vector &getMods() const = 0; virtual const ModSpec* getModSpec(const std::string &modname) const = 0; + virtual const SubgameSpec* getGameSpec() const { return nullptr; } virtual std::string getWorldPath() const { return ""; } virtual ModStorageDatabase *getModStorageDatabase() = 0; diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index 0d989ae04..09e971007 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -579,6 +579,17 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, } lua_pop(L, 1); // Pop mod name + // Allow read-only access to game directory + if (!write_required) { + const SubgameSpec *game_spec = gamedef->getGameSpec(); + if (game_spec && !game_spec->path.empty()) { + str = fs::AbsolutePath(game_spec->path); + if (!str.empty() && fs::PathStartsWith(abs_path, str)) { + return true; + } + } + } + // Allow read-only access to all mod directories if (!write_required) { const std::vector &mods = gamedef->getMods(); diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index a5daae346..fb2018aac 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -424,6 +424,20 @@ int ModApiServer::l_get_modnames(lua_State *L) return 1; } +// get_game_info() +int ModApiServer::l_get_game_info(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + const SubgameSpec *game_spec = getGameDef(L)->getGameSpec(); + assert(game_spec); + lua_newtable(L); + setstringfield(L, -1, "id", game_spec->id); + setstringfield(L, -1, "title", game_spec->title); + setstringfield(L, -1, "author", game_spec->author); + setstringfield(L, -1, "path", game_spec->path); + return 1; +} + // get_worldpath() int ModApiServer::l_get_worldpath(lua_State *L) { @@ -608,6 +622,7 @@ void ModApiServer::Initialize(lua_State *L, int top) API_FCT(get_current_modname); API_FCT(get_modpath); API_FCT(get_modnames); + API_FCT(get_game_info); API_FCT(print); @@ -643,4 +658,5 @@ void ModApiServer::InitializeAsync(lua_State *L, int top) API_FCT(get_current_modname); API_FCT(get_modpath); API_FCT(get_modnames); + API_FCT(get_game_info); } diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h index a4f38c34e..15d61669e 100644 --- a/src/script/lua_api/l_server.h +++ b/src/script/lua_api/l_server.h @@ -52,6 +52,9 @@ private: // the returned list is sorted alphabetically for you static int l_get_modnames(lua_State *L); + // get_game_info() + static int l_get_game_info(lua_State *L); + // print(text) static int l_print(lua_State *L); diff --git a/src/server.h b/src/server.h index 06da14a9a..365fdf625 100644 --- a/src/server.h +++ b/src/server.h @@ -284,6 +284,7 @@ public: virtual const std::vector &getMods() const; virtual const ModSpec* getModSpec(const std::string &modname) const; + virtual const SubgameSpec* getGameSpec() const { return &m_gamespec; } static std::string getBuiltinLuaPath(); virtual std::string getWorldPath() const { return m_path_world; }