mirror of
https://github.com/minetest/minetest.git
synced 2024-11-04 23:03:46 +01:00
Use virtual paths to specify exact mod to enable (#11784)
This commit is contained in:
parent
8c0331d244
commit
128f6359e9
@ -205,14 +205,19 @@ local function handle_buttons(this, fields)
|
|||||||
local mods = worldfile:to_table()
|
local mods = worldfile:to_table()
|
||||||
|
|
||||||
local rawlist = this.data.list:get_raw_list()
|
local rawlist = this.data.list:get_raw_list()
|
||||||
|
local was_set = {}
|
||||||
|
|
||||||
for i = 1, #rawlist do
|
for i = 1, #rawlist do
|
||||||
local mod = rawlist[i]
|
local mod = rawlist[i]
|
||||||
if not mod.is_modpack and
|
if not mod.is_modpack and
|
||||||
not mod.is_game_content then
|
not mod.is_game_content then
|
||||||
if modname_valid(mod.name) then
|
if modname_valid(mod.name) then
|
||||||
worldfile:set("load_mod_" .. mod.name,
|
if mod.enabled then
|
||||||
mod.enabled and "true" or "false")
|
worldfile:set("load_mod_" .. mod.name, mod.virtual_path)
|
||||||
|
was_set[mod.name] = true
|
||||||
|
elseif not was_set[mod.name] then
|
||||||
|
worldfile:set("load_mod_" .. mod.name, "false")
|
||||||
|
end
|
||||||
elseif mod.enabled then
|
elseif mod.enabled then
|
||||||
gamedata.errormessage = fgettext_ne("Failed to enable mo" ..
|
gamedata.errormessage = fgettext_ne("Failed to enable mo" ..
|
||||||
"d \"$1\" as it contains disallowed characters. " ..
|
"d \"$1\" as it contains disallowed characters. " ..
|
||||||
@ -256,12 +261,26 @@ local function handle_buttons(this, fields)
|
|||||||
if fields.btn_enable_all_mods then
|
if fields.btn_enable_all_mods then
|
||||||
local list = this.data.list:get_raw_list()
|
local list = this.data.list:get_raw_list()
|
||||||
|
|
||||||
|
-- When multiple copies of a mod are installed, we need to avoid enabling multiple of them
|
||||||
|
-- at a time. So lets first collect all the enabled mods, and then use this to exclude
|
||||||
|
-- multiple enables.
|
||||||
|
|
||||||
|
local was_enabled = {}
|
||||||
for i = 1, #list do
|
for i = 1, #list do
|
||||||
if not list[i].is_game_content
|
if not list[i].is_game_content
|
||||||
and not list[i].is_modpack then
|
and not list[i].is_modpack and list[i].enabled then
|
||||||
|
was_enabled[list[i].name] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, #list do
|
||||||
|
if not list[i].is_game_content and not list[i].is_modpack and
|
||||||
|
not was_enabled[list[i].name] then
|
||||||
list[i].enabled = true
|
list[i].enabled = true
|
||||||
|
was_enabled[list[i].name] = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
enabled_all = true
|
enabled_all = true
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -378,7 +378,7 @@ local function parse_config_file(read_all, parse_mods)
|
|||||||
-- Parse mods
|
-- Parse mods
|
||||||
local mods_category_initialized = false
|
local mods_category_initialized = false
|
||||||
local mods = {}
|
local mods = {}
|
||||||
get_mods(core.get_modpath(), mods)
|
get_mods(core.get_modpath(), "mods", mods)
|
||||||
for _, mod in ipairs(mods) do
|
for _, mod in ipairs(mods) do
|
||||||
local path = mod.path .. DIR_DELIM .. FILENAME
|
local path = mod.path .. DIR_DELIM .. FILENAME
|
||||||
local file = io.open(path, "r")
|
local file = io.open(path, "r")
|
||||||
|
@ -100,12 +100,13 @@ local function load_texture_packs(txtpath, retval)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function get_mods(path,retval,modpack)
|
function get_mods(path, virtual_path, retval, modpack)
|
||||||
local mods = core.get_dir_list(path, true)
|
local mods = core.get_dir_list(path, true)
|
||||||
|
|
||||||
for _, name in ipairs(mods) do
|
for _, name in ipairs(mods) do
|
||||||
if name:sub(1, 1) ~= "." then
|
if name:sub(1, 1) ~= "." then
|
||||||
local prefix = path .. DIR_DELIM .. name
|
local mod_path = path .. DIR_DELIM .. name
|
||||||
|
local mod_virtual_path = virtual_path .. "/" .. name
|
||||||
local toadd = {
|
local toadd = {
|
||||||
dir_name = name,
|
dir_name = name,
|
||||||
parent_dir = path,
|
parent_dir = path,
|
||||||
@ -114,18 +115,18 @@ function get_mods(path,retval,modpack)
|
|||||||
|
|
||||||
-- Get config file
|
-- Get config file
|
||||||
local mod_conf
|
local mod_conf
|
||||||
local modpack_conf = io.open(prefix .. DIR_DELIM .. "modpack.conf")
|
local modpack_conf = io.open(mod_path .. DIR_DELIM .. "modpack.conf")
|
||||||
if modpack_conf then
|
if modpack_conf then
|
||||||
toadd.is_modpack = true
|
toadd.is_modpack = true
|
||||||
modpack_conf:close()
|
modpack_conf:close()
|
||||||
|
|
||||||
mod_conf = Settings(prefix .. DIR_DELIM .. "modpack.conf"):to_table()
|
mod_conf = Settings(mod_path .. DIR_DELIM .. "modpack.conf"):to_table()
|
||||||
if mod_conf.name then
|
if mod_conf.name then
|
||||||
name = mod_conf.name
|
name = mod_conf.name
|
||||||
toadd.is_name_explicit = true
|
toadd.is_name_explicit = true
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
mod_conf = Settings(prefix .. DIR_DELIM .. "mod.conf"):to_table()
|
mod_conf = Settings(mod_path .. DIR_DELIM .. "mod.conf"):to_table()
|
||||||
if mod_conf.name then
|
if mod_conf.name then
|
||||||
name = mod_conf.name
|
name = mod_conf.name
|
||||||
toadd.is_name_explicit = true
|
toadd.is_name_explicit = true
|
||||||
@ -136,12 +137,13 @@ function get_mods(path,retval,modpack)
|
|||||||
toadd.name = name
|
toadd.name = name
|
||||||
toadd.author = mod_conf.author
|
toadd.author = mod_conf.author
|
||||||
toadd.release = tonumber(mod_conf.release) or 0
|
toadd.release = tonumber(mod_conf.release) or 0
|
||||||
toadd.path = prefix
|
toadd.path = mod_path
|
||||||
|
toadd.virtual_path = mod_virtual_path
|
||||||
toadd.type = "mod"
|
toadd.type = "mod"
|
||||||
|
|
||||||
-- Check modpack.txt
|
-- Check modpack.txt
|
||||||
-- Note: modpack.conf is already checked above
|
-- Note: modpack.conf is already checked above
|
||||||
local modpackfile = io.open(prefix .. DIR_DELIM .. "modpack.txt")
|
local modpackfile = io.open(mod_path .. DIR_DELIM .. "modpack.txt")
|
||||||
if modpackfile then
|
if modpackfile then
|
||||||
modpackfile:close()
|
modpackfile:close()
|
||||||
toadd.is_modpack = true
|
toadd.is_modpack = true
|
||||||
@ -153,7 +155,7 @@ function get_mods(path,retval,modpack)
|
|||||||
elseif toadd.is_modpack then
|
elseif toadd.is_modpack then
|
||||||
toadd.type = "modpack"
|
toadd.type = "modpack"
|
||||||
toadd.is_modpack = true
|
toadd.is_modpack = true
|
||||||
get_mods(prefix, retval, name)
|
get_mods(mod_path, mod_virtual_path, retval, name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -397,6 +399,14 @@ function pkgmgr.is_modpack_entirely_enabled(data, name)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function disable_all_by_name(list, name, except)
|
||||||
|
for i=1, #list do
|
||||||
|
if list[i].name == name and list[i] ~= except then
|
||||||
|
list[i].enabled = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
---------- toggles or en/disables a mod or modpack and its dependencies --------
|
---------- toggles or en/disables a mod or modpack and its dependencies --------
|
||||||
local function toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mod)
|
local function toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mod)
|
||||||
if not mod.is_modpack then
|
if not mod.is_modpack then
|
||||||
@ -404,6 +414,9 @@ local function toggle_mod_or_modpack(list, toggled_mods, enabled_mods, toset, mo
|
|||||||
if toset == nil then
|
if toset == nil then
|
||||||
toset = not mod.enabled
|
toset = not mod.enabled
|
||||||
end
|
end
|
||||||
|
if toset then
|
||||||
|
disable_all_by_name(list, mod.name, mod)
|
||||||
|
end
|
||||||
if mod.enabled ~= toset then
|
if mod.enabled ~= toset then
|
||||||
mod.enabled = toset
|
mod.enabled = toset
|
||||||
toggled_mods[#toggled_mods+1] = mod.name
|
toggled_mods[#toggled_mods+1] = mod.name
|
||||||
@ -648,8 +661,8 @@ function pkgmgr.preparemodlist(data)
|
|||||||
|
|
||||||
--read global mods
|
--read global mods
|
||||||
local modpaths = core.get_modpaths()
|
local modpaths = core.get_modpaths()
|
||||||
for _, modpath in ipairs(modpaths) do
|
for key, modpath in pairs(modpaths) do
|
||||||
get_mods(modpath, global_mods)
|
get_mods(modpath, key, global_mods)
|
||||||
end
|
end
|
||||||
|
|
||||||
for i=1,#global_mods,1 do
|
for i=1,#global_mods,1 do
|
||||||
@ -688,25 +701,40 @@ function pkgmgr.preparemodlist(data)
|
|||||||
DIR_DELIM .. "world.mt"
|
DIR_DELIM .. "world.mt"
|
||||||
|
|
||||||
local worldfile = Settings(filename)
|
local worldfile = Settings(filename)
|
||||||
|
|
||||||
for key, value in pairs(worldfile:to_table()) do
|
for key, value in pairs(worldfile:to_table()) do
|
||||||
if key:sub(1, 9) == "load_mod_" then
|
if key:sub(1, 9) == "load_mod_" then
|
||||||
key = key:sub(10)
|
key = key:sub(10)
|
||||||
local element = nil
|
local mod_found = false
|
||||||
for i=1,#retval,1 do
|
|
||||||
|
local fallback_found = false
|
||||||
|
local fallback_mod = nil
|
||||||
|
|
||||||
|
for i=1, #retval do
|
||||||
if retval[i].name == key and
|
if retval[i].name == key and
|
||||||
not retval[i].is_modpack then
|
not retval[i].is_modpack then
|
||||||
element = retval[i]
|
if core.is_yes(value) or retval[i].virtual_path == value then
|
||||||
|
retval[i].enabled = true
|
||||||
|
mod_found = true
|
||||||
break
|
break
|
||||||
|
elseif fallback_found then
|
||||||
|
-- Only allow fallback if only one mod matches
|
||||||
|
fallback_mod = nil
|
||||||
|
else
|
||||||
|
fallback_found = true
|
||||||
|
fallback_mod = retval[i]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if element ~= nil then
|
end
|
||||||
element.enabled = value ~= "false" and value ~= "nil" and value
|
|
||||||
|
if not mod_found then
|
||||||
|
if fallback_mod and value:find("/") then
|
||||||
|
fallback_mod.enabled = true
|
||||||
else
|
else
|
||||||
core.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found")
|
core.log("info", "Mod: " .. key .. " " .. dump(value) .. " but not found")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return retval
|
return retval
|
||||||
end
|
end
|
||||||
@ -797,7 +825,7 @@ function pkgmgr.get_game_mods(gamespec, retval)
|
|||||||
if gamespec ~= nil and
|
if gamespec ~= nil and
|
||||||
gamespec.gamemods_path ~= nil and
|
gamespec.gamemods_path ~= nil and
|
||||||
gamespec.gamemods_path ~= "" then
|
gamespec.gamemods_path ~= "" then
|
||||||
get_mods(gamespec.gamemods_path, retval)
|
get_mods(gamespec.gamemods_path, ("games/%s/mods"):format(gamespec.id), retval)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -221,13 +221,24 @@ Package - content which is downloadable from the content db, may or may not be i
|
|||||||
* returns path to global user data,
|
* returns path to global user data,
|
||||||
the directory that contains user-provided mods, worlds, games, and texture packs.
|
the directory that contains user-provided mods, worlds, games, and texture packs.
|
||||||
* core.get_modpath() (possible in async calls)
|
* core.get_modpath() (possible in async calls)
|
||||||
* returns path to global modpath, where mods can be installed
|
* returns path to global modpath in the user path, where mods can be installed
|
||||||
* core.get_modpaths() (possible in async calls)
|
* core.get_modpaths() (possible in async calls)
|
||||||
* returns list of paths to global modpaths, where mods have been installed
|
* returns table of virtual path to global modpaths, where mods have been installed
|
||||||
|
|
||||||
The difference with "core.get_modpath" is that no mods should be installed in these
|
The difference with "core.get_modpath" is that no mods should be installed in these
|
||||||
directories by Minetest -- they might be read-only.
|
directories by Minetest -- they might be read-only.
|
||||||
|
|
||||||
|
Ex:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
mods = "/home/user/.minetest/mods",
|
||||||
|
share = "/usr/share/minetest/mods",
|
||||||
|
|
||||||
|
-- Custom dirs can be specified by the MINETEST_MOD_DIR env variable
|
||||||
|
["/path/to/custom/dir"] = "/path/to/custom/dir",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
* core.get_clientmodpath() (possible in async calls)
|
* core.get_clientmodpath() (possible in async calls)
|
||||||
* returns path to global client-side modpath
|
* returns path to global client-side modpath
|
||||||
* core.get_gamepath() (possible in async calls)
|
* core.get_gamepath() (possible in async calls)
|
||||||
|
@ -133,6 +133,19 @@ Example content (added indentation and - explanations):
|
|||||||
load_mod_<mod> = false - whether <mod> is to be loaded in this world
|
load_mod_<mod> = false - whether <mod> is to be loaded in this world
|
||||||
auth_backend = files - which DB backend to use for authentication data
|
auth_backend = files - which DB backend to use for authentication data
|
||||||
|
|
||||||
|
For load_mod_<mod>, the possible values are:
|
||||||
|
|
||||||
|
* `false` - Do not load the mod.
|
||||||
|
* `true` - Load the mod from wherever it is found (may cause conflicts if the same mod appears also in some other place).
|
||||||
|
* `mods/modpack/moddir` - Relative path to the mod
|
||||||
|
* Must be one of the following:
|
||||||
|
* `mods/`: mods in the user path's mods folder (ex `/home/user/.minetest/mods`)
|
||||||
|
* `share/`: mods in the share's mods folder (ex: `/usr/share/minetest/mods`)
|
||||||
|
* `/path/to/env`: you can use absolute paths to mods inside folders specified with the `MINETEST_MOD_PATH` env variable.
|
||||||
|
* Other locations and absolute paths are not supported
|
||||||
|
* Note that `moddir` is the directory name, not the mod name specified in mod.conf.
|
||||||
|
|
||||||
|
|
||||||
Player File Format
|
Player File Format
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ void parseModContents(ModSpec &spec)
|
|||||||
modpack2_is.close();
|
modpack2_is.close();
|
||||||
|
|
||||||
spec.is_modpack = true;
|
spec.is_modpack = true;
|
||||||
spec.modpack_content = getModsInPath(spec.path, true);
|
spec.modpack_content = getModsInPath(spec.path, spec.virtual_path, true);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Settings info;
|
Settings info;
|
||||||
@ -167,13 +167,14 @@ void parseModContents(ModSpec &spec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, ModSpec> getModsInPath(
|
std::map<std::string, ModSpec> getModsInPath(
|
||||||
const std::string &path, bool part_of_modpack)
|
const std::string &path, const std::string &virtual_path, bool part_of_modpack)
|
||||||
{
|
{
|
||||||
// NOTE: this function works in mutual recursion with parseModContents
|
// NOTE: this function works in mutual recursion with parseModContents
|
||||||
|
|
||||||
std::map<std::string, ModSpec> result;
|
std::map<std::string, ModSpec> result;
|
||||||
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(path);
|
std::vector<fs::DirListNode> dirlist = fs::GetDirListing(path);
|
||||||
std::string modpath;
|
std::string mod_path;
|
||||||
|
std::string mod_virtual_path;
|
||||||
|
|
||||||
for (const fs::DirListNode &dln : dirlist) {
|
for (const fs::DirListNode &dln : dirlist) {
|
||||||
if (!dln.dir)
|
if (!dln.dir)
|
||||||
@ -185,10 +186,14 @@ std::map<std::string, ModSpec> getModsInPath(
|
|||||||
if (modname[0] == '.')
|
if (modname[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
modpath.clear();
|
mod_path.clear();
|
||||||
modpath.append(path).append(DIR_DELIM).append(modname);
|
mod_path.append(path).append(DIR_DELIM).append(modname);
|
||||||
|
|
||||||
ModSpec spec(modname, modpath, part_of_modpack);
|
mod_virtual_path.clear();
|
||||||
|
// Intentionally uses / to keep paths same on different platforms
|
||||||
|
mod_virtual_path.append(virtual_path).append("/").append(modname);
|
||||||
|
|
||||||
|
ModSpec spec(modname, mod_path, part_of_modpack, mod_virtual_path);
|
||||||
parseModContents(spec);
|
parseModContents(spec);
|
||||||
result.insert(std::make_pair(modname, spec));
|
result.insert(std::make_pair(modname, spec));
|
||||||
}
|
}
|
||||||
@ -228,9 +233,9 @@ void ModConfiguration::printUnsatisfiedModsError() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModConfiguration::addModsInPath(const std::string &path)
|
void ModConfiguration::addModsInPath(const std::string &path, const std::string &virtual_path)
|
||||||
{
|
{
|
||||||
addMods(flattenMods(getModsInPath(path)));
|
addMods(flattenMods(getModsInPath(path, virtual_path)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModConfiguration::addMods(const std::vector<ModSpec> &new_mods)
|
void ModConfiguration::addMods(const std::vector<ModSpec> &new_mods)
|
||||||
@ -294,31 +299,41 @@ void ModConfiguration::addMods(const std::vector<ModSpec> &new_mods)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ModConfiguration::addModsFromConfig(
|
void ModConfiguration::addModsFromConfig(
|
||||||
const std::string &settings_path, const std::set<std::string> &mods)
|
const std::string &settings_path,
|
||||||
|
const std::unordered_map<std::string, std::string> &modPaths)
|
||||||
{
|
{
|
||||||
Settings conf;
|
Settings conf;
|
||||||
std::set<std::string> load_mod_names;
|
std::unordered_map<std::string, std::string> load_mod_names;
|
||||||
|
|
||||||
conf.readConfigFile(settings_path.c_str());
|
conf.readConfigFile(settings_path.c_str());
|
||||||
std::vector<std::string> names = conf.getNames();
|
std::vector<std::string> names = conf.getNames();
|
||||||
for (const std::string &name : names) {
|
for (const std::string &name : names) {
|
||||||
if (name.compare(0, 9, "load_mod_") == 0 && conf.get(name) != "false" &&
|
const auto &value = conf.get(name);
|
||||||
conf.get(name) != "nil")
|
if (name.compare(0, 9, "load_mod_") == 0 && value != "false" &&
|
||||||
load_mod_names.insert(name.substr(9));
|
value != "nil")
|
||||||
|
load_mod_names[name.substr(9)] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ModSpec> addon_mods;
|
std::vector<ModSpec> addon_mods;
|
||||||
for (const std::string &i : mods) {
|
std::unordered_map<std::string, std::vector<std::string>> candidates;
|
||||||
std::vector<ModSpec> addon_mods_in_path = flattenMods(getModsInPath(i));
|
|
||||||
|
for (const auto &modPath : modPaths) {
|
||||||
|
std::vector<ModSpec> addon_mods_in_path = flattenMods(getModsInPath(modPath.second, modPath.first));
|
||||||
for (std::vector<ModSpec>::const_iterator it = addon_mods_in_path.begin();
|
for (std::vector<ModSpec>::const_iterator it = addon_mods_in_path.begin();
|
||||||
it != addon_mods_in_path.end(); ++it) {
|
it != addon_mods_in_path.end(); ++it) {
|
||||||
const ModSpec &mod = *it;
|
const ModSpec &mod = *it;
|
||||||
if (load_mod_names.count(mod.name) != 0)
|
const auto &pair = load_mod_names.find(mod.name);
|
||||||
|
if (pair != load_mod_names.end()) {
|
||||||
|
if (is_yes(pair->second) || pair->second == mod.virtual_path) {
|
||||||
addon_mods.push_back(mod);
|
addon_mods.push_back(mod);
|
||||||
else
|
} else {
|
||||||
|
candidates[pair->first].emplace_back(mod.virtual_path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
conf.setBool("load_mod_" + mod.name, false);
|
conf.setBool("load_mod_" + mod.name, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
conf.updateConfigFile(settings_path.c_str());
|
conf.updateConfigFile(settings_path.c_str());
|
||||||
|
|
||||||
addMods(addon_mods);
|
addMods(addon_mods);
|
||||||
@ -335,9 +350,22 @@ void ModConfiguration::addModsFromConfig(
|
|||||||
|
|
||||||
if (!load_mod_names.empty()) {
|
if (!load_mod_names.empty()) {
|
||||||
errorstream << "The following mods could not be found:";
|
errorstream << "The following mods could not be found:";
|
||||||
for (const std::string &mod : load_mod_names)
|
for (const auto &pair : load_mod_names)
|
||||||
errorstream << " \"" << mod << "\"";
|
errorstream << " \"" << pair.first << "\"";
|
||||||
errorstream << std::endl;
|
errorstream << std::endl;
|
||||||
|
|
||||||
|
for (const auto &pair : load_mod_names) {
|
||||||
|
const auto &candidate = candidates.find(pair.first);
|
||||||
|
if (candidate != candidates.end()) {
|
||||||
|
errorstream << "Unable to load " << pair.first << " as the specified path "
|
||||||
|
<< pair.second << " could not be found. "
|
||||||
|
<< "However, it is available in the following locations:"
|
||||||
|
<< std::endl;
|
||||||
|
for (const auto &path : candidate->second) {
|
||||||
|
errorstream << " - " << path << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,10 +441,12 @@ void ModConfiguration::resolveDependencies()
|
|||||||
ClientModConfiguration::ClientModConfiguration(const std::string &path) :
|
ClientModConfiguration::ClientModConfiguration(const std::string &path) :
|
||||||
ModConfiguration(path)
|
ModConfiguration(path)
|
||||||
{
|
{
|
||||||
std::set<std::string> paths;
|
std::unordered_map<std::string, std::string> paths;
|
||||||
std::string path_user = porting::path_user + DIR_DELIM + "clientmods";
|
std::string path_user = porting::path_user + DIR_DELIM + "clientmods";
|
||||||
paths.insert(path);
|
if (path != path_user) {
|
||||||
paths.insert(path_user);
|
paths["share"] = path;
|
||||||
|
}
|
||||||
|
paths["mods"] = path_user;
|
||||||
|
|
||||||
std::string settings_path = path_user + DIR_DELIM + "mods.conf";
|
std::string settings_path = path_user + DIR_DELIM + "mods.conf";
|
||||||
addModsFromConfig(settings_path, paths);
|
addModsFromConfig(settings_path, paths);
|
||||||
|
@ -51,17 +51,36 @@ struct ModSpec
|
|||||||
bool part_of_modpack = false;
|
bool part_of_modpack = false;
|
||||||
bool is_modpack = false;
|
bool is_modpack = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A constructed canonical path to represent this mod's location.
|
||||||
|
* This intended to be used as an identifier for a modpath that tolerates file movement,
|
||||||
|
* and cannot be used to read the mod files.
|
||||||
|
*
|
||||||
|
* Note that `mymod` is the directory name, not the mod name specified in mod.conf.
|
||||||
|
*
|
||||||
|
* Ex:
|
||||||
|
*
|
||||||
|
* - mods/mymod
|
||||||
|
* - mods/mymod (1)
|
||||||
|
* (^ this would have name=mymod in mod.conf)
|
||||||
|
* - mods/modpack1/mymod
|
||||||
|
* - games/mygame/mods/mymod
|
||||||
|
* - worldmods/mymod
|
||||||
|
*/
|
||||||
|
std::string virtual_path;
|
||||||
|
|
||||||
// For logging purposes
|
// For logging purposes
|
||||||
std::vector<const char *> deprecation_msgs;
|
std::vector<const char *> deprecation_msgs;
|
||||||
|
|
||||||
// if modpack:
|
// if modpack:
|
||||||
std::map<std::string, ModSpec> modpack_content;
|
std::map<std::string, ModSpec> modpack_content;
|
||||||
ModSpec(const std::string &name = "", const std::string &path = "") :
|
|
||||||
name(name), path(path)
|
ModSpec()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
ModSpec(const std::string &name, const std::string &path, bool part_of_modpack) :
|
|
||||||
name(name), path(path), part_of_modpack(part_of_modpack)
|
ModSpec(const std::string &name, const std::string &path, bool part_of_modpack, const std::string &virtual_path) :
|
||||||
|
name(name), path(path), part_of_modpack(part_of_modpack), virtual_path(virtual_path)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,8 +90,16 @@ struct ModSpec
|
|||||||
// Retrieves depends, optdepends, is_modpack and modpack_content
|
// Retrieves depends, optdepends, is_modpack and modpack_content
|
||||||
void parseModContents(ModSpec &mod);
|
void parseModContents(ModSpec &mod);
|
||||||
|
|
||||||
std::map<std::string, ModSpec> getModsInPath(
|
/**
|
||||||
const std::string &path, bool part_of_modpack = false);
|
* Gets a list of all mods and modpacks in path
|
||||||
|
*
|
||||||
|
* @param Path to search, should be absolute
|
||||||
|
* @param part_of_modpack Is this searching within a modpack?
|
||||||
|
* @param virtual_path Virtual path for this directory, see comment in ModSpec
|
||||||
|
* @returns map of mods
|
||||||
|
*/
|
||||||
|
std::map<std::string, ModSpec> getModsInPath(const std::string &path,
|
||||||
|
const std::string &virtual_path, bool part_of_modpack = false);
|
||||||
|
|
||||||
// replaces modpack Modspecs with their content
|
// replaces modpack Modspecs with their content
|
||||||
std::vector<ModSpec> flattenMods(const std::map<std::string, ModSpec> &mods);
|
std::vector<ModSpec> flattenMods(const std::map<std::string, ModSpec> &mods);
|
||||||
@ -97,15 +124,25 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
ModConfiguration(const std::string &worldpath);
|
ModConfiguration(const std::string &worldpath);
|
||||||
// adds all mods in the given path. used for games, modpacks
|
|
||||||
// and world-specific mods (worldmods-folders)
|
/**
|
||||||
void addModsInPath(const std::string &path);
|
* adds all mods in the given path. used for games, modpacks
|
||||||
|
* and world-specific mods (worldmods-folders)
|
||||||
|
*
|
||||||
|
* @param path To search, should be absolute
|
||||||
|
* @param virtual_path Virtual path for this directory, see comment in ModSpec
|
||||||
|
*/
|
||||||
|
void addModsInPath(const std::string &path, const std::string &virtual_path);
|
||||||
|
|
||||||
// adds all mods in the set.
|
// adds all mods in the set.
|
||||||
void addMods(const std::vector<ModSpec> &new_mods);
|
void addMods(const std::vector<ModSpec> &new_mods);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param settings_path Path to world.mt
|
||||||
|
* @param modPaths Map from virtual name to mod path
|
||||||
|
*/
|
||||||
void addModsFromConfig(const std::string &settings_path,
|
void addModsFromConfig(const std::string &settings_path,
|
||||||
const std::set<std::string> &mods);
|
const std::unordered_map<std::string, std::string> &modPaths);
|
||||||
|
|
||||||
void checkConflictsAndDeps();
|
void checkConflictsAndDeps();
|
||||||
|
|
||||||
|
@ -107,14 +107,13 @@ SubgameSpec findSubgame(const std::string &id)
|
|||||||
std::string gamemod_path = game_path + DIR_DELIM + "mods";
|
std::string gamemod_path = game_path + DIR_DELIM + "mods";
|
||||||
|
|
||||||
// Find mod directories
|
// Find mod directories
|
||||||
std::set<std::string> mods_paths;
|
std::unordered_map<std::string, std::string> mods_paths;
|
||||||
if (!user_game)
|
mods_paths["mods"] = user + DIR_DELIM + "mods";
|
||||||
mods_paths.insert(share + DIR_DELIM + "mods");
|
if (!user_game && user != share)
|
||||||
if (user != share || user_game)
|
mods_paths["share"] = share + DIR_DELIM + "mods";
|
||||||
mods_paths.insert(user + DIR_DELIM + "mods");
|
|
||||||
|
|
||||||
for (const std::string &mod_path : getEnvModPaths()) {
|
for (const std::string &mod_path : getEnvModPaths()) {
|
||||||
mods_paths.insert(mod_path);
|
mods_paths[fs::AbsolutePath(mod_path)] = mod_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get meta
|
// Get meta
|
||||||
|
@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class Settings;
|
class Settings;
|
||||||
@ -33,13 +34,16 @@ struct SubgameSpec
|
|||||||
int release;
|
int release;
|
||||||
std::string path;
|
std::string path;
|
||||||
std::string gamemods_path;
|
std::string gamemods_path;
|
||||||
std::set<std::string> addon_mods_paths;
|
|
||||||
|
/**
|
||||||
|
* Map from virtual path to mods path
|
||||||
|
*/
|
||||||
|
std::unordered_map<std::string, std::string> addon_mods_paths;
|
||||||
std::string menuicon_path;
|
std::string menuicon_path;
|
||||||
|
|
||||||
SubgameSpec(const std::string &id = "", const std::string &path = "",
|
SubgameSpec(const std::string &id = "", const std::string &path = "",
|
||||||
const std::string &gamemods_path = "",
|
const std::string &gamemods_path = "",
|
||||||
const std::set<std::string> &addon_mods_paths =
|
const std::unordered_map<std::string, std::string> &addon_mods_paths = {},
|
||||||
std::set<std::string>(),
|
|
||||||
const std::string &name = "",
|
const std::string &name = "",
|
||||||
const std::string &menuicon_path = "",
|
const std::string &menuicon_path = "",
|
||||||
const std::string &author = "", int release = 0) :
|
const std::string &author = "", int release = 0) :
|
||||||
|
@ -323,9 +323,9 @@ int ModApiMainMenu::l_get_games(lua_State *L)
|
|||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
int table2 = lua_gettop(L);
|
int table2 = lua_gettop(L);
|
||||||
int internal_index = 1;
|
int internal_index = 1;
|
||||||
for (const std::string &addon_mods_path : game.addon_mods_paths) {
|
for (const auto &addon_mods_path : game.addon_mods_paths) {
|
||||||
lua_pushnumber(L, internal_index);
|
lua_pushnumber(L, internal_index);
|
||||||
lua_pushstring(L, addon_mods_path.c_str());
|
lua_pushstring(L, addon_mods_path.second.c_str());
|
||||||
lua_settable(L, table2);
|
lua_settable(L, table2);
|
||||||
internal_index++;
|
internal_index++;
|
||||||
}
|
}
|
||||||
@ -533,14 +533,14 @@ int ModApiMainMenu::l_get_modpath(lua_State *L)
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
int ModApiMainMenu::l_get_modpaths(lua_State *L)
|
int ModApiMainMenu::l_get_modpaths(lua_State *L)
|
||||||
{
|
{
|
||||||
int index = 1;
|
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
|
|
||||||
ModApiMainMenu::l_get_modpath(L);
|
ModApiMainMenu::l_get_modpath(L);
|
||||||
lua_rawseti(L, -2, index);
|
lua_setfield(L, -2, "mods");
|
||||||
|
|
||||||
for (const std::string &component : getEnvModPaths()) {
|
for (const std::string &component : getEnvModPaths()) {
|
||||||
index++;
|
|
||||||
lua_pushstring(L, component.c_str());
|
lua_pushstring(L, component.c_str());
|
||||||
lua_rawseti(L, -2, index);
|
lua_setfield(L, -2, fs::AbsolutePath(component).c_str());
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,10 @@ ServerModManager::ServerModManager(const std::string &worldpath) :
|
|||||||
SubgameSpec gamespec = findWorldSubgame(worldpath);
|
SubgameSpec gamespec = findWorldSubgame(worldpath);
|
||||||
|
|
||||||
// Add all game mods and all world mods
|
// Add all game mods and all world mods
|
||||||
addModsInPath(gamespec.gamemods_path);
|
std::string game_virtual_path;
|
||||||
addModsInPath(worldpath + DIR_DELIM + "worldmods");
|
game_virtual_path.append("games/").append(gamespec.id).append("/mods");
|
||||||
|
addModsInPath(gamespec.gamemods_path, game_virtual_path);
|
||||||
|
addModsInPath(worldpath + DIR_DELIM + "worldmods", "worldmods");
|
||||||
|
|
||||||
// Load normal mods
|
// Load normal mods
|
||||||
std::string worldmt = worldpath + DIR_DELIM + "world.mt";
|
std::string worldmt = worldpath + DIR_DELIM + "world.mt";
|
||||||
|
Loading…
Reference in New Issue
Block a user