aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoremixa-d <85313564+emixa-d@users.noreply.github.com>2021-10-06 22:19:41 +0000
committerGitHub <noreply@github.com>2021-10-07 00:19:41 +0200
commit9fab5d594cab4c0a027f0aecf356382f3a37c1de (patch)
treea5bed4dfac50fcd76464dfb2010713fa4265e5e2
parent53e126ac49807d066328377c7c06352b0fc1a380 (diff)
downloadminetest-9fab5d594cab4c0a027f0aecf356382f3a37c1de.tar.gz
minetest-9fab5d594cab4c0a027f0aecf356382f3a37c1de.tar.bz2
minetest-9fab5d594cab4c0a027f0aecf356382f3a37c1de.zip
Add "MINETEST_MOD_PATH" environment variable (#11515)
This adds an environment variable MINETEST_MOD_PATH. When it exists, Minetest will look there for mods in addition to ~/.minetest/mods/.
-rw-r--r--builtin/mainmenu/pkgmgr.lua8
-rw-r--r--doc/menu_lua_api.txt8
-rw-r--r--doc/minetest.63
-rw-r--r--src/content/subgames.cpp14
-rw-r--r--src/content/subgames.h2
-rw-r--r--src/script/lua_api/l_mainmenu.cpp17
-rw-r--r--src/script/lua_api/l_mainmenu.h2
-rw-r--r--src/unittest/CMakeLists.txt1
-rw-r--r--src/unittest/test_config.h.in1
-rw-r--r--src/unittest/test_mod/test_mod/init.lua1
-rw-r--r--src/unittest/test_mod/test_mod/mod.conf2
-rw-r--r--src/unittest/test_servermodmanager.cpp21
12 files changed, 74 insertions, 6 deletions
diff --git a/builtin/mainmenu/pkgmgr.lua b/builtin/mainmenu/pkgmgr.lua
index 787936e31..76d4a4123 100644
--- a/builtin/mainmenu/pkgmgr.lua
+++ b/builtin/mainmenu/pkgmgr.lua
@@ -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
diff --git a/doc/menu_lua_api.txt b/doc/menu_lua_api.txt
index f4dfff261..b4b6eaba2 100644
--- a/doc/menu_lua_api.txt
+++ b/doc/menu_lua_api.txt
@@ -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)
diff --git a/doc/minetest.6 b/doc/minetest.6
index bac70fe1a..42ed1a45f 100644
--- a/doc/minetest.6
+++ b/doc/minetest.6
@@ -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.
diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp
index e9dc609b0..30447c838 100644
--- a/src/content/subgames.cpp
+++ b/src/content/subgames.cpp
@@ -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;
+}
diff --git a/src/content/subgames.h b/src/content/subgames.h
index 60392639b..4a50803e8 100644
--- a/src/content/subgames.h
+++ b/src/content/subgames.h
@@ -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
diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
index 6e9a5c34f..57fddc0be 100644
--- a/src/script/lua_api/l_mainmenu.cpp
+++ b/src/script/lua_api/l_mainmenu.cpp
@@ -503,6 +503,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(
@@ -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);
diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
index ec2d20da2..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);
diff --git a/src/unittest/CMakeLists.txt b/src/unittest/CMakeLists.txt
index 5703b8906..52f870901 100644
--- a/src/unittest/CMakeLists.txt
+++ b/src/unittest/CMakeLists.txt
@@ -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"
diff --git a/src/unittest/test_config.h.in b/src/unittest/test_config.h.in
index 36850b00d..50d2398e4 100644
--- a/src/unittest/test_config.h.in
+++ b/src/unittest/test_config.h.in
@@ -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
index 000000000..724a863f5
--- /dev/null
+++ b/src/unittest/test_mod/test_mod/init.lua
@@ -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
index 000000000..56c64b2d8
--- /dev/null
+++ b/src/unittest/test_mod/test_mod/mod.conf
@@ -0,0 +1,2 @@
+name = test_mod
+description = A mod doing nothing, to test if MINETEST_MOD_PATH is recognised
diff --git a/src/unittest/test_servermodmanager.cpp b/src/unittest/test_servermodmanager.cpp
index e3edb0c32..4c473d8b5 100644
--- a/src/unittest/test_servermodmanager.cpp
+++ b/src/unittest/test_servermodmanager.cpp
@@ -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()