Skip to content

Commit

Permalink
Add "MINETEST_MOD_PATH" environment variable (#11515)
Browse files Browse the repository at this point in the history
This adds an environment variable MINETEST_MOD_PATH.
When it exists, Minetest will look there for mods in addition to ~/.minetest/mods/.
  • Loading branch information
emixa-d committed Oct 6, 2021
1 parent 53e126a commit 9fab5d5
Show file tree
Hide file tree
Showing 12 changed files with 74 additions and 6 deletions.
8 changes: 3 additions & 5 deletions builtin/mainmenu/pkgmgr.lua
Expand Up @@ -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
Expand Down
8 changes: 7 additions & 1 deletion doc/menu_lua_api.txt
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions doc/minetest.6
Expand Up @@ -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.
Expand Down
14 changes: 14 additions & 0 deletions src/content/subgames.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
2 changes: 2 additions & 0 deletions src/content/subgames.h
Expand Up @@ -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
Expand Down
17 changes: 17 additions & 0 deletions src/script/lua_api/l_mainmenu.cpp
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/script/lua_api/l_mainmenu.h
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/unittest/CMakeLists.txt
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions src/unittest/test_config.h.in
Expand Up @@ -4,3 +4,4 @@

#define TEST_WORLDDIR "@TEST_WORLDDIR@"
#define TEST_SUBGAME_PATH "@TEST_SUBGAME_PATH@"
#define TEST_MOD_PATH "@TEST_MOD_PATH@"
1 change: 1 addition & 0 deletions src/unittest/test_mod/test_mod/init.lua
@@ -0,0 +1 @@
-- deliberately empty
2 changes: 2 additions & 0 deletions 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
21 changes: 21 additions & 0 deletions src/unittest/test_servermodmanager.cpp
Expand Up @@ -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);
Expand All @@ -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
}

Expand All @@ -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);
}
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit 9fab5d5

Please sign in to comment.