diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/content/mods.cpp | 76 | ||||
-rw-r--r-- | src/content/mods.h | 57 | ||||
-rw-r--r-- | src/content/subgames.cpp | 11 | ||||
-rw-r--r-- | src/content/subgames.h | 10 | ||||
-rw-r--r-- | src/script/lua_api/l_mainmenu.cpp | 12 | ||||
-rw-r--r-- | src/server/mods.cpp | 6 |
6 files changed, 122 insertions, 50 deletions
diff --git a/src/content/mods.cpp b/src/content/mods.cpp index 455506967..f75119bbb 100644 --- a/src/content/mods.cpp +++ b/src/content/mods.cpp @@ -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); diff --git a/src/content/mods.h b/src/content/mods.h index dd3b6e0e6..ab0a9300e 100644 --- a/src/content/mods.h +++ b/src/content/mods.h @@ -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(); diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp index 62e82e0e4..23355990e 100644 --- a/src/content/subgames.cpp +++ b/src/content/subgames.cpp @@ -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 diff --git a/src/content/subgames.h b/src/content/subgames.h index 4a50803e8..d36b4952f 100644 --- a/src/content/subgames.h +++ b/src/content/subgames.h @@ -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) : diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 736ad022f..db031dde5 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -323,9 +323,9 @@ int ModApiMainMenu::l_get_games(lua_State *L) lua_newtable(L); int table2 = lua_gettop(L); 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_pushstring(L, addon_mods_path.c_str()); + lua_pushstring(L, addon_mods_path.second.c_str()); lua_settable(L, table2); internal_index++; } @@ -533,14 +533,14 @@ 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); + lua_setfield(L, -2, "mods"); + for (const std::string &component : getEnvModPaths()) { - index++; lua_pushstring(L, component.c_str()); - lua_rawseti(L, -2, index); + lua_setfield(L, -2, fs::AbsolutePath(component).c_str()); } return 1; } diff --git a/src/server/mods.cpp b/src/server/mods.cpp index 609d8c346..ba76d4746 100644 --- a/src/server/mods.cpp +++ b/src/server/mods.cpp @@ -41,8 +41,10 @@ ServerModManager::ServerModManager(const std::string &worldpath) : SubgameSpec gamespec = findWorldSubgame(worldpath); // Add all game mods and all world mods - addModsInPath(gamespec.gamemods_path); - addModsInPath(worldpath + DIR_DELIM + "worldmods"); + std::string game_virtual_path; + 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 std::string worldmt = worldpath + DIR_DELIM + "world.mt"; |