]> git.lizzy.rs Git - dragonfireclient.git/commitdiff
Add "MINETEST_MOD_PATH" environment variable (#11515)
authoremixa-d <85313564+emixa-d@users.noreply.github.com>
Wed, 6 Oct 2021 22:19:41 +0000 (22:19 +0000)
committerGitHub <noreply@github.com>
Wed, 6 Oct 2021 22:19:41 +0000 (00:19 +0200)
This adds an environment variable MINETEST_MOD_PATH.
When it exists, Minetest will look there for mods in addition to ~/.minetest/mods/.

12 files changed:
builtin/mainmenu/pkgmgr.lua
doc/menu_lua_api.txt
doc/minetest.6
src/content/subgames.cpp
src/content/subgames.h
src/script/lua_api/l_mainmenu.cpp
src/script/lua_api/l_mainmenu.h
src/unittest/CMakeLists.txt
src/unittest/test_config.h.in
src/unittest/test_mod/test_mod/init.lua [new file with mode: 0644]
src/unittest/test_mod/test_mod/mod.conf [new file with mode: 0644]
src/unittest/test_servermodmanager.cpp

index 787936e318b6ab9689544956e5247c35c480dfeb..76d4a4123f22ed0227b14ba10a91a40fd1553434 100644 (file)
@@ -682,11 +682,9 @@ function pkgmgr.preparemodlist(data)
        local game_mods = {}
 
        --read global mods
-       local modpath = core.get_modpath()
-
-       if modpath ~= nil and
-               modpath ~= "" then
-               get_mods(modpath,global_mods)
+       local modpaths = core.get_modpaths()
+       for _, modpath in ipairs(modpaths) do
+               get_mods(modpath, global_mods)
        end
 
        for i=1,#global_mods,1 do
index f4dfff2613f77963ce5a773d405066fb865670b2..b4b6eaba2a4e306d3fb56eb203aeb5a48f539876 100644 (file)
@@ -219,7 +219,13 @@ Package - content which is downloadable from the content db, may or may not be i
     * returns path to global user data,
       the directory that contains user-provided mods, worlds, games, and texture packs.
 * core.get_modpath() (possible in async calls)
-    * returns path to global modpath
+    * returns path to global modpath, where mods can be installed
+* core.get_modpaths() (possible in async calls)
+    * returns list of paths to global modpaths, where mods have been installed
+
+      The difference with "core.get_modpath" is that no mods should be installed in these
+      directories by Minetest -- they might be read-only.
+
 * core.get_clientmodpath() (possible in async calls)
     * returns path to global client-side modpath
 * core.get_gamepath() (possible in async calls)
index bac70fe1a1125dde465f35e6b9b3fa181301cf37..42ed1a45f435d770f00847a06538a34bf7d5fe06 100644 (file)
@@ -119,6 +119,9 @@ Display an interactive terminal over ncurses during execution.
 .TP
 .B MINETEST_SUBGAME_PATH
 Colon delimited list of directories to search for games.
+.TP
+.B MINETEST_MOD_PATH
+Colon delimited list of directories to search for mods.
 
 .SH BUGS
 Please report all bugs at https://github.com/minetest/minetest/issues.
index e9dc609b0a231b467de0b571874a7ee52425400f..30447c838d0fa0d94668ace1586bdb2d033a6c4c 100644 (file)
@@ -113,6 +113,10 @@ SubgameSpec findSubgame(const std::string &id)
        if (user != share || user_game)
                mods_paths.insert(user + DIR_DELIM + "mods");
 
+       for (const std::string &mod_path : getEnvModPaths()) {
+               mods_paths.insert(mod_path);
+       }
+
        // Get meta
        std::string conf_path = game_path + DIR_DELIM + "game.conf";
        Settings conf;
@@ -384,3 +388,13 @@ void loadGameConfAndInitWorld(const std::string &path, const std::string &name,
        if (new_game_settings)
                delete game_settings;
 }
+
+std::vector<std::string> getEnvModPaths()
+{
+       const char *c_mod_path = getenv("MINETEST_MOD_PATH");
+       std::vector<std::string> paths;
+       Strfnd search_paths(c_mod_path ? c_mod_path : "");
+       while (!search_paths.at_end())
+               paths.push_back(search_paths.next(PATH_DELIM));
+       return paths;
+}
index 60392639b51d823bcc56fd5473822041a7806256..4a50803e8305a4cc82ab4e9c41b66c09ae44f2cc 100644 (file)
@@ -58,6 +58,8 @@ SubgameSpec findWorldSubgame(const std::string &world_path);
 
 std::set<std::string> getAvailableGameIds();
 std::vector<SubgameSpec> getAvailableGames();
+// Get the list of paths to mods in the environment variable $MINETEST_MOD_PATH
+std::vector<std::string> getEnvModPaths();
 
 bool getWorldExists(const std::string &world_path);
 //! Try to get the displayed name of a world
index 6e9a5c34f8b7d2d314d5509dd0bef3960595e121..57fddc0be32d96f930128199dcf09bb52cc1825b 100644 (file)
@@ -502,6 +502,21 @@ int ModApiMainMenu::l_get_modpath(lua_State *L)
        return 1;
 }
 
+/******************************************************************************/
+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)
 {
@@ -856,6 +871,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);
@@ -889,6 +905,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);
index ec2d20da2630ed59c44217335f62337b745d74f9..781185425196b7f9931f0c4d3f46a10d2de739e4 100644 (file)
@@ -112,6 +112,8 @@ class ModApiMainMenu: public ModApiBase
 
        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);
index 5703b890629684a40856d361911ab54858ee006a..52f8709014473b1fdc593b3269903a9af15dd78f 100644 (file)
@@ -44,6 +44,7 @@ set (UNITTEST_CLIENT_SRCS
 
 set (TEST_WORLDDIR ${CMAKE_CURRENT_SOURCE_DIR}/test_world)
 set (TEST_SUBGAME_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../games/devtest)
+set (TEST_MOD_PATH ${CMAKE_CURRENT_SOURCE_DIR}/test_mod)
 
 configure_file(
        "${CMAKE_CURRENT_SOURCE_DIR}/test_config.h.in"
index 36850b00d618aff31d28495f2d49f1a2adc13464..50d2398e459e53399173a5ef8a0ba3a11ceebfa1 100644 (file)
@@ -4,3 +4,4 @@
 
 #define TEST_WORLDDIR "@TEST_WORLDDIR@"
 #define TEST_SUBGAME_PATH "@TEST_SUBGAME_PATH@"
+#define TEST_MOD_PATH "@TEST_MOD_PATH@"
diff --git a/src/unittest/test_mod/test_mod/init.lua b/src/unittest/test_mod/test_mod/init.lua
new file mode 100644 (file)
index 0000000..724a863
--- /dev/null
@@ -0,0 +1 @@
+-- deliberately empty
diff --git a/src/unittest/test_mod/test_mod/mod.conf b/src/unittest/test_mod/test_mod/mod.conf
new file mode 100644 (file)
index 0000000..56c64b2
--- /dev/null
@@ -0,0 +1,2 @@
+name = test_mod
+description = A mod doing nothing, to test if MINETEST_MOD_PATH is recognised
index e3edb0c32f6fadc6e32d5c209f33156f26c39b71..4c473d8b5c677faa4f72811ee37863c062287c33 100644 (file)
@@ -48,14 +48,20 @@ static TestServerModManager g_test_instance;
 void TestServerModManager::runTests(IGameDef *gamedef)
 {
        const char *saved_env_mt_subgame_path = getenv("MINETEST_SUBGAME_PATH");
+       const char *saved_env_mt_mod_path = getenv("MINETEST_MOD_PATH");
 #ifdef WIN32
        {
                std::string subgame_path("MINETEST_SUBGAME_PATH=");
                subgame_path.append(TEST_SUBGAME_PATH);
                _putenv(subgame_path.c_str());
+
+               std::string mod_path("MINETEST_MOD_PATH=");
+               mod_path.append(TEST_MOD_PATH);
+               _putenv(mod_path.c_str());
        }
 #else
        setenv("MINETEST_SUBGAME_PATH", TEST_SUBGAME_PATH, 1);
+       setenv("MINETEST_MOD_PATH", TEST_MOD_PATH, 1);
 #endif
 
        TEST(testCreation);
@@ -75,12 +81,21 @@ void TestServerModManager::runTests(IGameDef *gamedef)
                if (saved_env_mt_subgame_path)
                        subgame_path.append(saved_env_mt_subgame_path);
                _putenv(subgame_path.c_str());
+
+               std::string mod_path("MINETEST_MOD_PATH=");
+               if (saved_env_mt_mod_path)
+                       mod_path.append(saved_env_mt_mod_path);
+               _putenv(mod_path.c_str());
        }
 #else
        if (saved_env_mt_subgame_path)
                setenv("MINETEST_SUBGAME_PATH", saved_env_mt_subgame_path, 1);
        else
                unsetenv("MINETEST_SUBGAME_PATH");
+       if (saved_env_mt_mod_path)
+               setenv("MINETEST_MOD_PATH", saved_env_mt_mod_path, 1);
+       else
+               unsetenv("MINETEST_MOD_PATH");
 #endif
 }
 
@@ -89,6 +104,7 @@ void TestServerModManager::testCreation()
        std::string path = std::string(TEST_WORLDDIR) + DIR_DELIM + "world.mt";
        Settings world_config;
        world_config.set("gameid", "devtest");
+       world_config.set("load_mod_test_mod", "true");
        UASSERTEQ(bool, world_config.updateConfigFile(path.c_str()), true);
        ServerModManager sm(TEST_WORLDDIR);
 }
@@ -119,16 +135,21 @@ void TestServerModManager::testGetMods()
        UASSERTEQ(bool, mods.empty(), false);
 
        // Ensure we found basenodes mod (part of devtest)
+       // and test_mod (for testing MINETEST_MOD_PATH).
        bool default_found = false;
+       bool test_mod_found = false;
        for (const auto &m : mods) {
                if (m.name == "basenodes")
                        default_found = true;
+               if (m.name == "test_mod")
+                       test_mod_found = true;
 
                // Verify if paths are not empty
                UASSERTEQ(bool, m.path.empty(), false);
        }
 
        UASSERTEQ(bool, default_found, true);
+       UASSERTEQ(bool, test_mod_found, true);
 }
 
 void TestServerModManager::testGetModspec()