X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmods.cpp;h=dae49233978c29fa01fef5378486a92af6b6f59e;hb=2153965cf92ab61b0d7e095cf3c2755924fdc221;hp=6fce8e93d1d45140a0cad4379ff9089be74d814c;hpb=cf37a5569002e83cc4d6916b39118ceba134da1b;p=minetest.git diff --git a/src/mods.cpp b/src/mods.cpp index 6fce8e93d..dae492339 100644 --- a/src/mods.cpp +++ b/src/mods.cpp @@ -19,14 +19,14 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include +#include #include "mods.h" #include "filesys.h" #include "log.h" #include "subgame.h" #include "settings.h" -#include "convert_json.h" -#include "exceptions.h" #include "porting.h" +#include "convert_json.h" static bool parseDependsLine(std::istream &is, std::string &dep, std::set &symbols) @@ -41,7 +41,7 @@ static bool parseDependsLine(std::istream &is, --pos; } dep = trim(dep.substr(0, pos)); - return dep != ""; + return !dep.empty(); } void parseModContents(ModSpec &spec) @@ -91,13 +91,13 @@ std::map getModsInPath(std::string path, bool part_of_modp std::map result; std::vector dirlist = fs::GetDirListing(path); - for(u32 j=0; j getModsInPath(std::string path, bool part_of_modp std::vector flattenMods(std::map mods) { std::vector result; - for(std::map::iterator it = mods.begin(); - it != mods.end(); ++it) - { - ModSpec mod = (*it).second; - if(mod.is_modpack) - { + for (const auto &it : mods) { + const ModSpec &mod = it.second; + if (mod.is_modpack) { std::vector content = flattenMods(mod.modpack_content); result.reserve(result.size() + content.size()); result.insert(result.end(),content.begin(),content.end()); @@ -131,22 +128,16 @@ std::vector flattenMods(std::map mods) return result; } -ModConfiguration::ModConfiguration(const std::string &worldpath): - m_unsatisfied_mods(), - m_sorted_mods(), - m_name_conflicts() +ModConfiguration::ModConfiguration(const std::string &worldpath) { } void ModConfiguration::printUnsatisfiedModsError() const { - for (std::vector::const_iterator it = m_unsatisfied_mods.begin(); - it != m_unsatisfied_mods.end(); ++it) { - ModSpec mod = *it; + for (const ModSpec &mod : m_unsatisfied_mods) { errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: "; - for (UNORDERED_SET::iterator dep_it = mod.unsatisfied_depends.begin(); - dep_it != mod.unsatisfied_depends.end(); ++dep_it) - errorstream << " \"" << *dep_it << "\""; + for (const std::string &unsatisfied_depend : mod.unsatisfied_depends) + errorstream << " \"" << unsatisfied_depend << "\""; errorstream << std::endl; } } @@ -174,17 +165,15 @@ void ModConfiguration::addMods(const std::vector &new_mods) std::set seen_this_iteration; - for (std::vector::const_iterator it = new_mods.begin(); - it != new_mods.end(); ++it) { - const ModSpec &mod = *it; - if(mod.part_of_modpack != (bool)want_from_modpack) + for (const ModSpec &mod : new_mods) { + if (mod.part_of_modpack != (bool)want_from_modpack) continue; - if(existing_mods.count(mod.name) == 0){ + + if (existing_mods.count(mod.name) == 0) { // GOOD CASE: completely new mod. m_unsatisfied_mods.push_back(mod); existing_mods[mod.name] = m_unsatisfied_mods.size() - 1; - } - else if(seen_this_iteration.count(mod.name) == 0){ + } else if(seen_this_iteration.count(mod.name) == 0) { // BAD CASE: name conflict in different levels. u32 oldindex = existing_mods[mod.name]; const ModSpec &oldmod = m_unsatisfied_mods[oldindex]; @@ -197,8 +186,7 @@ void ModConfiguration::addMods(const std::vector &new_mods) // If there was a "VERY BAD CASE" name conflict // in an earlier level, ignore it. m_name_conflicts.erase(mod.name); - } - else{ + } else { // VERY BAD CASE: name conflict in the same level. u32 oldindex = existing_mods[mod.name]; const ModSpec &oldmod = m_unsatisfied_mods[oldindex]; @@ -209,18 +197,65 @@ void ModConfiguration::addMods(const std::vector &new_mods) m_unsatisfied_mods[oldindex] = mod; m_name_conflicts.insert(mod.name); } + seen_this_iteration.insert(mod.name); } } } +void ModConfiguration::addModsFromConfig(const std::string &settings_path, const std::set &mods) +{ + Settings conf; + std::set load_mod_names; + + conf.readConfigFile(settings_path.c_str()); + std::vector names = conf.getNames(); + for (const std::string &name : names) { + if (name.compare(0,9,"load_mod_")==0 && conf.getBool(name)) + load_mod_names.insert(name.substr(9)); + } + + std::vector addon_mods; + for (const std::string &i : mods) { + std::vector addon_mods_in_path = flattenMods(getModsInPath(i)); + for (std::vector::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 + conf.setBool("load_mod_" + mod.name, false); + } + } + conf.updateConfigFile(settings_path.c_str()); + + addMods(addon_mods); + checkConflictsAndDeps(); + + // complain about mods declared to be loaded, but not found + for (const ModSpec &addon_mod : addon_mods) + load_mod_names.erase(addon_mod.name); + + std::vector unsatisfiedMods = getUnsatisfiedMods(); + + for (const ModSpec &unsatisfiedMod : unsatisfiedMods) + load_mod_names.erase(unsatisfiedMod.name); + + if (!load_mod_names.empty()) { + errorstream << "The following mods could not be found:"; + for (const std::string &mod : load_mod_names) + errorstream << " \"" << mod << "\""; + errorstream << std::endl; + } +} + void ModConfiguration::checkConflictsAndDeps() { // report on name conflicts if (!m_name_conflicts.empty()) { std::string s = "Unresolved name conflicts for mods "; - for (UNORDERED_SET::const_iterator it = m_name_conflicts.begin(); - it != m_name_conflicts.end(); ++it) { + for (std::unordered_set::const_iterator it = + m_name_conflicts.begin(); it != m_name_conflicts.end(); ++it) { if (it != m_name_conflicts.begin()) s += ", "; s += std::string("\"") + (*it) + "\""; } @@ -236,23 +271,18 @@ void ModConfiguration::resolveDependencies() { // Step 1: Compile a list of the mod names we're working with std::set modnames; - for(std::vector::iterator it = m_unsatisfied_mods.begin(); - it != m_unsatisfied_mods.end(); ++it){ - modnames.insert((*it).name); + for (const ModSpec &mod : m_unsatisfied_mods) { + modnames.insert(mod.name); } // Step 2: get dependencies (including optional dependencies) // of each mod, split mods into satisfied and unsatisfied std::list satisfied; std::list unsatisfied; - for (std::vector::iterator it = m_unsatisfied_mods.begin(); - it != m_unsatisfied_mods.end(); ++it) { - ModSpec mod = *it; + for (ModSpec mod : m_unsatisfied_mods) { mod.unsatisfied_depends = mod.depends; // check which optional dependencies actually exist - for (UNORDERED_SET::iterator it_optdep = mod.optdepends.begin(); - it_optdep != mod.optdepends.end(); ++it_optdep) { - std::string optdep = *it_optdep; + for (const std::string &optdep : mod.optdepends) { if (modnames.count(optdep) != 0) mod.unsatisfied_depends.insert(optdep); } @@ -269,15 +299,13 @@ void ModConfiguration::resolveDependencies() ModSpec mod = satisfied.back(); m_sorted_mods.push_back(mod); satisfied.pop_back(); - for(std::list::iterator it = unsatisfied.begin(); - it != unsatisfied.end(); ){ + for (auto it = unsatisfied.begin(); it != unsatisfied.end(); ) { ModSpec& mod2 = *it; mod2.unsatisfied_depends.erase(mod.name); - if(mod2.unsatisfied_depends.empty()){ + if (mod2.unsatisfied_depends.empty()) { satisfied.push_back(mod2); it = unsatisfied.erase(it); - } - else{ + } else { ++it; } } @@ -296,80 +324,28 @@ ServerModConfiguration::ServerModConfiguration(const std::string &worldpath): addModsInPath(gamespec.gamemods_path); addModsInPath(worldpath + DIR_DELIM + "worldmods"); - // check world.mt file for mods explicitely declared to be - // loaded or not by a load_mod_ = ... line. - std::string worldmt = worldpath+DIR_DELIM+"world.mt"; - Settings worldmt_settings; - worldmt_settings.readConfigFile(worldmt.c_str()); - std::vector names = worldmt_settings.getNames(); - std::set include_mod_names; - for (std::vector::const_iterator it = names.begin(); - it != names.end(); ++it) { - std::string name = *it; - // for backwards compatibility: exclude only mods which are - // explicitely excluded. if mod is not mentioned at all, it is - // enabled. So by default, all installed mods are enabled. - if (name.compare(0,9,"load_mod_") == 0 && - worldmt_settings.getBool(name)) { - include_mod_names.insert(name.substr(9)); - } - } - - // Collect all mods that are also in include_mod_names - std::vector addon_mods; - for (std::set::const_iterator it_path = gamespec.addon_mods_paths.begin(); - it_path != gamespec.addon_mods_paths.end(); ++it_path) { - std::vector addon_mods_in_path = flattenMods(getModsInPath(*it_path)); - for (std::vector::const_iterator it = addon_mods_in_path.begin(); - it != addon_mods_in_path.end(); ++it) { - const ModSpec& mod = *it; - if (include_mod_names.count(mod.name) != 0) - addon_mods.push_back(mod); - else - worldmt_settings.setBool("load_mod_" + mod.name, false); - } - } - worldmt_settings.updateConfigFile(worldmt.c_str()); - - addMods(addon_mods); - - checkConflictsAndDeps(); + // Load normal mods + std::string worldmt = worldpath + DIR_DELIM + "world.mt"; + addModsFromConfig(worldmt, gamespec.addon_mods_paths); } #ifndef SERVER ClientModConfiguration::ClientModConfiguration(const std::string &path): ModConfiguration(path) { - addModsInPath(path); - addModsInPath(porting::path_user + DIR_DELIM + "clientmods"); - checkConflictsAndDeps(); -} -#endif - -#if USE_CURL -Json::Value getModstoreUrl(const std::string &url) -{ - std::vector extra_headers; + std::set paths; + std::string path_user = porting::path_user + DIR_DELIM + "clientmods"; + paths.insert(path); + paths.insert(path_user); - bool special_http_header = true; - - try { - special_http_header = g_settings->getBool("modstore_disable_special_http_header"); - } catch (SettingNotFoundException) {} - - if (special_http_header) { - extra_headers.push_back("Accept: application/vnd.minetest.mmdb-v1+json"); - } - return fetchJsonValue(url, special_http_header ? &extra_headers : NULL); + std::string settings_path = path_user + DIR_DELIM + "mods.conf"; + addModsFromConfig(settings_path, paths); } - #endif ModMetadata::ModMetadata(const std::string &mod_name): - m_mod_name(mod_name), - m_modified(false) + m_mod_name(mod_name) { - m_stringvars.clear(); } void ModMetadata::clear() @@ -399,7 +375,7 @@ bool ModMetadata::save(const std::string &root_path) } bool w_ok = fs::safeWriteToFile(root_path + DIR_DELIM + m_mod_name, - Json::FastWriter().write(json)); + fastWriteJson(json)); if (w_ok) { m_modified = false; @@ -418,19 +394,21 @@ bool ModMetadata::load(const std::string &root_path) return false; } - Json::Reader reader; Json::Value root; - if (!reader.parse(is, root)) { + Json::CharReaderBuilder builder; + builder.settings_["collectComments"] = false; + std::string errs; + + if (!Json::parseFromStream(builder, is, &root, &errs)) { errorstream << "ModMetadata[" << m_mod_name << "]: failed read data " - "(Json decoding failure)." << std::endl; + "(Json decoding failure). Message: " << errs << std::endl; return false; } const Json::Value::Members attr_list = root.getMemberNames(); - for (Json::Value::Members::const_iterator it = attr_list.begin(); - it != attr_list.end(); ++it) { - Json::Value attr_value = root[*it]; - m_stringvars[*it] = attr_value.asString(); + for (const auto &it : attr_list) { + Json::Value attr_value = root[it]; + m_stringvars[it] = attr_value.asString(); } return true;