1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-07-02 16:38:41 +00:00

Use virtual paths to specify exact mod to enable (#11784)

This commit is contained in:
rubenwardy 2022-01-30 22:40:53 +00:00 committed by GitHub
parent 8c0331d244
commit 128f6359e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 223 additions and 80 deletions

View file

@ -89,7 +89,7 @@ void parseModContents(ModSpec &spec)
modpack2_is.close();
spec.is_modpack = true;
spec.modpack_content = getModsInPath(spec.path, true);
spec.modpack_content = getModsInPath(spec.path, spec.virtual_path, true);
} else {
Settings info;
@ -167,13 +167,14 @@ void parseModContents(ModSpec &spec)
}
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
std::map<std::string, ModSpec> result;
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) {
if (!dln.dir)
@ -185,10 +186,14 @@ std::map<std::string, ModSpec> getModsInPath(
if (modname[0] == '.')
continue;
modpath.clear();
modpath.append(path).append(DIR_DELIM).append(modname);
mod_path.clear();
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);
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)
@ -294,29 +299,39 @@ void ModConfiguration::addMods(const std::vector<ModSpec> &new_mods)
}
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;
std::set<std::string> load_mod_names;
std::unordered_map<std::string, std::string> load_mod_names;
conf.readConfigFile(settings_path.c_str());
std::vector<std::string> names = conf.getNames();
for (const std::string &name : names) {
if (name.compare(0, 9, "load_mod_") == 0 && conf.get(name) != "false" &&
conf.get(name) != "nil")
load_mod_names.insert(name.substr(9));
const auto &value = conf.get(name);
if (name.compare(0, 9, "load_mod_") == 0 && value != "false" &&
value != "nil")
load_mod_names[name.substr(9)] = value;
}
std::vector<ModSpec> addon_mods;
for (const std::string &i : mods) {
std::vector<ModSpec> addon_mods_in_path = flattenMods(getModsInPath(i));
std::unordered_map<std::string, std::vector<std::string>> candidates;
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();
it != addon_mods_in_path.end(); ++it) {
const ModSpec &mod = *it;
if (load_mod_names.count(mod.name) != 0)
addon_mods.push_back(mod);
else
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);
} else {
candidates[pair->first].emplace_back(mod.virtual_path);
}
} else {
conf.setBool("load_mod_" + mod.name, false);
}
}
}
conf.updateConfigFile(settings_path.c_str());
@ -335,9 +350,22 @@ void ModConfiguration::addModsFromConfig(
if (!load_mod_names.empty()) {
errorstream << "The following mods could not be found:";
for (const std::string &mod : load_mod_names)
errorstream << " \"" << mod << "\"";
for (const auto &pair : load_mod_names)
errorstream << " \"" << pair.first << "\"";
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) :
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";
paths.insert(path);
paths.insert(path_user);
if (path != path_user) {
paths["share"] = path;
}
paths["mods"] = path_user;
std::string settings_path = path_user + DIR_DELIM + "mods.conf";
addModsFromConfig(settings_path, paths);

View file

@ -51,17 +51,36 @@ struct ModSpec
bool part_of_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
std::vector<const char *> deprecation_msgs;
// if modpack:
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
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
std::vector<ModSpec> flattenMods(const std::map<std::string, ModSpec> &mods);
@ -97,15 +124,25 @@ public:
protected:
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.
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,
const std::set<std::string> &mods);
const std::unordered_map<std::string, std::string> &modPaths);
void checkConflictsAndDeps();

View file

@ -107,14 +107,13 @@ SubgameSpec findSubgame(const std::string &id)
std::string gamemod_path = game_path + DIR_DELIM + "mods";
// Find mod directories
std::set<std::string> mods_paths;
if (!user_game)
mods_paths.insert(share + DIR_DELIM + "mods");
if (user != share || user_game)
mods_paths.insert(user + DIR_DELIM + "mods");
std::unordered_map<std::string, std::string> mods_paths;
mods_paths["mods"] = user + DIR_DELIM + "mods";
if (!user_game && user != share)
mods_paths["share"] = share + DIR_DELIM + "mods";
for (const std::string &mod_path : getEnvModPaths()) {
mods_paths.insert(mod_path);
mods_paths[fs::AbsolutePath(mod_path)] = mod_path;
}
// Get meta

View file

@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include <set>
#include <unordered_map>
#include <vector>
class Settings;
@ -33,13 +34,16 @@ struct SubgameSpec
int release;
std::string 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;
SubgameSpec(const std::string &id = "", const std::string &path = "",
const std::string &gamemods_path = "",
const std::set<std::string> &addon_mods_paths =
std::set<std::string>(),
const std::unordered_map<std::string, std::string> &addon_mods_paths = {},
const std::string &name = "",
const std::string &menuicon_path = "",
const std::string &author = "", int release = 0) :