From ef6feca501fcf0d5a1fd2021f1d4df96a4533f65 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Wed, 8 Feb 2017 00:15:55 +0100 Subject: Add ModMetadata API (#5131) * mod can create a ModMetadata object where store its values and retrieve it. * Modmetadata object can only be fetched at mod loading * Save when modified using same time as map interval or at server stop * add helper function to get mod storage path * ModMetadata has exactly same calls than all every other Metadata --- src/mods.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 3 deletions(-) (limited to 'src/mods.cpp') diff --git a/src/mods.cpp b/src/mods.cpp index 1b1bdb07b..bae9a42d3 100644 --- a/src/mods.cpp +++ b/src/mods.cpp @@ -21,13 +21,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "mods.h" #include "filesys.h" -#include "util/strfnd.h" #include "log.h" #include "subgame.h" #include "settings.h" -#include "util/strfnd.h" #include "convert_json.h" -#include "exceptions.h" static bool parseDependsLine(std::istream &is, std::string &dep, std::set &symbols) @@ -356,3 +353,80 @@ Json::Value getModstoreUrl(std::string url) } #endif + +ModMetadata::ModMetadata(const std::string &mod_name): + m_mod_name(mod_name), + m_modified(false) +{ + m_stringvars.clear(); +} + +void ModMetadata::clear() +{ + Metadata::clear(); + m_modified = true; +} + +bool ModMetadata::save(const std::string &root_path) +{ + Json::Value json; + for (StringMap::const_iterator it = m_stringvars.begin(); + it != m_stringvars.end(); ++it) { + json[it->first] = it->second; + } + + if (!fs::PathExists(root_path)) { + if (!fs::CreateAllDirs(root_path)) { + errorstream << "ModMetadata[" << m_mod_name << "]: Unable to save. '" + << root_path << "' tree cannot be created." << std::endl; + return false; + } + } else if (!fs::IsDir(root_path)) { + errorstream << "ModMetadata[" << m_mod_name << "]: Unable to save. '" + << root_path << "' is not a directory." << std::endl; + return false; + } + + bool w_ok = fs::safeWriteToFile(root_path + DIR_DELIM + m_mod_name, + Json::FastWriter().write(json)); + + if (w_ok) { + m_modified = false; + } else { + errorstream << "ModMetadata[" << m_mod_name << "]: failed write file." << std::endl; + } + return w_ok; +} + +bool ModMetadata::load(const std::string &root_path) +{ + m_stringvars.clear(); + + std::ifstream is((root_path + DIR_DELIM + m_mod_name).c_str(), std::ios_base::binary); + if (!is.good()) { + return false; + } + + Json::Reader reader; + Json::Value root; + if (!reader.parse(is, root)) { + errorstream << "ModMetadata[" << m_mod_name << "]: failed read data " + "(Json decoding failure)." << 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(); + } + + return true; +} + +bool ModMetadata::setString(const std::string &name, const std::string &var) +{ + m_modified = Metadata::setString(name, var); + return m_modified; +} -- cgit v1.2.3 From 92b45b2a189b703fc7cfc8ddbc09a7ad563a13bc Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Fri, 27 Jan 2017 07:41:10 +0100 Subject: [CSM] implement client side mod loading (#5123) * client side mods are located in clientmods/ * move builtin/preview.lua to clientmods/preview/init.lua as a preview mod * refactor ModConfiguration class to work properly with client and server using child objects * move some Server constructor mod load code to ModConfiguration to reduce code duplication between client and server * remove mods.{cpp,h} unused functions * use UNORDERED_SET instead of std::set in some modspec storages --- CMakeLists.txt | 1 + builtin/client/chatcommands.lua | 14 +-- builtin/client/init.lua | 1 - builtin/client/preview.lua | 42 --------- clientmods/preview/init.lua | 42 +++++++++ src/client.cpp | 44 ++++++++- src/client.h | 3 +- src/mods.cpp | 197 +++++++++++++++++++++------------------- src/mods.h | 57 +++++++----- src/server.cpp | 25 ++--- 10 files changed, 236 insertions(+), 190 deletions(-) delete mode 100644 builtin/client/preview.lua create mode 100644 clientmods/preview/init.lua (limited to 'src/mods.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index d2568a9ae..7fe950c81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,6 +152,7 @@ endif() install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/builtin" DESTINATION "${SHAREDIR}") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/client" DESTINATION "${SHAREDIR}") +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/clientmods" DESTINATION "${SHAREDIR}") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games" DESTINATION "${SHAREDIR}" PATTERN ".git*" EXCLUDE) if(BUILD_CLIENT) diff --git a/builtin/client/chatcommands.lua b/builtin/client/chatcommands.lua index b49c222ef..43b4d9a72 100644 --- a/builtin/client/chatcommands.lua +++ b/builtin/client/chatcommands.lua @@ -5,24 +5,24 @@ core.register_on_sending_chat_messages(function(message) if not (message:sub(1,1) == "/") then return false end - + core.display_chat_message("issued command: " .. message) - + local cmd, param = string.match(message, "^/([^ ]+) *(.*)") if not param then param = "" end - + local cmd_def = core.registered_chatcommands[cmd] - + if cmd_def then core.set_last_run_mod(cmd_def.mod_origin) - local success, message = cmd_def.func(param) + local _, message = cmd_def.func(param) if message then core.display_chat_message(message) end return true end - + return false -end) \ No newline at end of file +end) diff --git a/builtin/client/init.lua b/builtin/client/init.lua index b204ee5e6..592274540 100644 --- a/builtin/client/init.lua +++ b/builtin/client/init.lua @@ -7,7 +7,6 @@ dofile(clientpath .. "register.lua") dofile(commonpath .. "after.lua") dofile(commonpath .. "chatcommands.lua") dofile(clientpath .. "chatcommands.lua") -dofile(clientpath .. "preview.lua") core.register_on_death(function() core.display_chat_message("You died.") diff --git a/builtin/client/preview.lua b/builtin/client/preview.lua deleted file mode 100644 index 4c01d665f..000000000 --- a/builtin/client/preview.lua +++ /dev/null @@ -1,42 +0,0 @@ --- This is an example function to ensure it's working properly, should be removed before merge -core.register_on_shutdown(function() - print("[PREVIEW] shutdown client") -end) - --- This is an example function to ensure it's working properly, should be removed before merge -core.register_on_receiving_chat_messages(function(message) - print("[PREVIEW] Received message " .. message) - return false -end) - --- This is an example function to ensure it's working properly, should be removed before merge -core.register_on_sending_chat_messages(function(message) - print("[PREVIEW] Sending message " .. message) - return false -end) - --- This is an example function to ensure it's working properly, should be removed before merge -core.register_on_hp_modification(function(hp) - print("[PREVIEW] HP modified " .. hp) -end) - --- This is an example function to ensure it's working properly, should be removed before merge -core.register_on_damage_taken(function(hp) - print("[PREVIEW] Damage taken " .. hp) -end) - --- This is an example function to ensure it's working properly, should be removed before merge -core.register_globalstep(function(dtime) - -- print("[PREVIEW] globalstep " .. dtime) -end) - --- This is an example function to ensure it's working properly, should be removed before merge -core.register_chatcommand("dump", { - func = function(param) - return true, dump(_G) - end, -}) - -core.after(2, function() - print("After 2") -end) diff --git a/clientmods/preview/init.lua b/clientmods/preview/init.lua new file mode 100644 index 000000000..4c01d665f --- /dev/null +++ b/clientmods/preview/init.lua @@ -0,0 +1,42 @@ +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_on_shutdown(function() + print("[PREVIEW] shutdown client") +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_on_receiving_chat_messages(function(message) + print("[PREVIEW] Received message " .. message) + return false +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_on_sending_chat_messages(function(message) + print("[PREVIEW] Sending message " .. message) + return false +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_on_hp_modification(function(hp) + print("[PREVIEW] HP modified " .. hp) +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_on_damage_taken(function(hp) + print("[PREVIEW] Damage taken " .. hp) +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_globalstep(function(dtime) + -- print("[PREVIEW] globalstep " .. dtime) +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_chatcommand("dump", { + func = function(param) + return true, dump(_G) + end, +}) + +core.after(2, function() + print("After 2") +end) diff --git a/src/client.cpp b/src/client.cpp index 3b8074252..4bb63fef1 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -268,14 +268,50 @@ Client::Client( void Client::initMods() { - std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua"; + m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME); + + ClientModConfiguration modconf(getClientModsLuaPath()); + std::vector mods = modconf.getMods(); + std::vector unsatisfied_mods = modconf.getUnsatisfiedMods(); + // complain about mods with unsatisfied dependencies + if (!modconf.isConsistent()) { + modconf.printUnsatisfiedModsError(); + } + + // Print mods + infostream << "Client Loading mods: "; + for (std::vector::const_iterator i = mods.begin(); + i != mods.end(); ++i) { + infostream << (*i).name << " "; + } + + infostream << std::endl; + // Load and run "mod" scripts + for (std::vector::const_iterator it = mods.begin(); + it != mods.end(); ++it) { + const ModSpec &mod = *it; + if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) { + throw ModError("Error loading mod \"" + mod.name + + "\": Mod name does not follow naming conventions: " + "Only chararacters [a-z0-9_] are allowed."); + } + std::string script_path = mod.path + DIR_DELIM + "init.lua"; + infostream << " [" << padStringRight(mod.name, 12) << "] [\"" + << script_path << "\"]" << std::endl; + m_script->loadMod(script_path, mod.name); + } +} - m_script->loadMod(script_path, BUILTIN_MOD_NAME); +const std::string &Client::getBuiltinLuaPath() +{ + static const std::string builtin_dir = porting::path_share + DIR_DELIM + "builtin"; + return builtin_dir; } -const std::string Client::getBuiltinLuaPath() +const std::string &Client::getClientModsLuaPath() { - return porting::path_share + DIR_DELIM + "builtin"; + static const std::string clientmods_dir = porting::path_share + DIR_DELIM + "clientmods"; + return clientmods_dir; } const std::vector& Client::getMods() const diff --git a/src/client.h b/src/client.h index d170f9a07..9b7130268 100644 --- a/src/client.h +++ b/src/client.h @@ -433,7 +433,8 @@ public: ClientEnvironment& getEnv() { return m_env; } ITextureSource *tsrc() { return getTextureSource(); } ISoundManager *sound() { return getSoundManager(); } - static const std::string getBuiltinLuaPath(); + static const std::string &getBuiltinLuaPath(); + static const std::string &getClientModsLuaPath(); virtual const std::vector &getMods() const; virtual const ModSpec* getModSpec(const std::string &modname) const; diff --git a/src/mods.cpp b/src/mods.cpp index bae9a42d3..5a7dc6dca 100644 --- a/src/mods.cpp +++ b/src/mods.cpp @@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "subgame.h" #include "settings.h" #include "convert_json.h" +#include "exceptions.h" +#include "porting.h" static bool parseDependsLine(std::istream &is, std::string &dep, std::set &symbols) @@ -107,28 +109,6 @@ std::map getModsInPath(std::string path, bool part_of_modp return result; } -std::map flattenModTree(std::map mods) -{ - std::map result; - for(std::map::iterator it = mods.begin(); - it != mods.end(); ++it) - { - ModSpec mod = (*it).second; - if(mod.is_modpack) - { - std::map content = - flattenModTree(mod.modpack_content); - result.insert(content.begin(),content.end()); - result.insert(std::make_pair(mod.name,mod)); - } - else //not a modpack - { - result.insert(std::make_pair(mod.name,mod)); - } - } - return result; -} - std::vector flattenMods(std::map mods) { std::vector result; @@ -151,78 +131,32 @@ std::vector flattenMods(std::map mods) return result; } -ModConfiguration::ModConfiguration(std::string worldpath) +ModConfiguration::ModConfiguration(const std::string &worldpath): + m_unsatisfied_mods(), + m_sorted_mods(), + m_name_conflicts() { - SubgameSpec gamespec = findWorldSubgame(worldpath); - - // Add all game mods and all world mods - 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::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::iterator it = addon_mods_in_path.begin(); - it != addon_mods_in_path.end(); ++it) - { - 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); +} - // report on name conflicts - if(!m_name_conflicts.empty()){ - std::string s = "Unresolved name conflicts for mods "; - for(std::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) + "\""; - } - s += "."; - throw ModError(s); +void ModConfiguration::printUnsatisfiedModsError() const +{ + for (std::vector::const_iterator it = m_unsatisfied_mods.begin(); + it != m_unsatisfied_mods.end(); ++it) { + ModSpec mod = *it; + 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 << "\""; + errorstream << std::endl; } - - // get the mods in order - resolveDependencies(); } -void ModConfiguration::addModsInPath(std::string path) +void ModConfiguration::addModsInPath(const std::string &path) { addMods(flattenMods(getModsInPath(path))); } -void ModConfiguration::addMods(std::vector new_mods) +void ModConfiguration::addMods(const std::vector &new_mods) { // Maintain a map of all existing m_unsatisfied_mods. // Keys are mod names and values are indices into m_unsatisfied_mods. @@ -240,8 +174,8 @@ void ModConfiguration::addMods(std::vector new_mods) std::set seen_this_iteration; - for(std::vector::const_iterator it = new_mods.begin(); - it != new_mods.end(); ++it){ + 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) continue; @@ -280,6 +214,24 @@ void ModConfiguration::addMods(std::vector new_mods) } } +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) { + if (it != m_name_conflicts.begin()) s += ", "; + s += std::string("\"") + (*it) + "\""; + } + s += "."; + throw ModError(s); + } + + // get the mods in order + resolveDependencies(); +} + void ModConfiguration::resolveDependencies() { // Step 1: Compile a list of the mod names we're working with @@ -293,19 +245,19 @@ void ModConfiguration::resolveDependencies() // 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){ + for (std::vector::iterator it = m_unsatisfied_mods.begin(); + it != m_unsatisfied_mods.end(); ++it) { ModSpec mod = *it; mod.unsatisfied_depends = mod.depends; // check which optional dependencies actually exist - for(std::set::iterator it_optdep = mod.optdepends.begin(); - it_optdep != mod.optdepends.end(); ++it_optdep){ + for (UNORDERED_SET::iterator it_optdep = mod.optdepends.begin(); + it_optdep != mod.optdepends.end(); ++it_optdep) { std::string optdep = *it_optdep; - if(modnames.count(optdep) != 0) + if (modnames.count(optdep) != 0) mod.unsatisfied_depends.insert(optdep); } // if a mod has no depends it is initially satisfied - if(mod.unsatisfied_depends.empty()) + if (mod.unsatisfied_depends.empty()) satisfied.push_back(mod); else unsatisfied.push_back(mod); @@ -335,6 +287,65 @@ void ModConfiguration::resolveDependencies() m_unsatisfied_mods.assign(unsatisfied.begin(), unsatisfied.end()); } +ServerModConfiguration::ServerModConfiguration(const std::string &worldpath): + ModConfiguration(worldpath) +{ + SubgameSpec gamespec = findWorldSubgame(worldpath); + + // Add all game mods and all world mods + 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(); +} + +#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(std::string url) { diff --git a/src/mods.h b/src/mods.h index 61af5e5d1..c9bd51d99 100644 --- a/src/mods.h +++ b/src/mods.h @@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include "util/cpp11_container.h" #include "config.h" #include "metadata.h" @@ -37,9 +38,9 @@ struct ModSpec std::string name; std::string path; //if normal mod: - std::set depends; - std::set optdepends; - std::set unsatisfied_depends; + UNORDERED_SET depends; + UNORDERED_SET optdepends; + UNORDERED_SET unsatisfied_depends; bool part_of_modpack; bool is_modpack; @@ -62,12 +63,6 @@ void parseModContents(ModSpec &mod); std::map getModsInPath(std::string path, bool part_of_modpack = false); -// If failed, returned modspec has name=="" -ModSpec findCommonMod(const std::string &modname); - -// expands modpack contents, but does not replace them. -std::map flattenModTree(std::map mods); - // replaces modpack Modspecs with their content std::vector flattenMods(std::map mods); @@ -77,17 +72,8 @@ std::vector flattenMods(std::map mods); class ModConfiguration { public: - ModConfiguration(): - m_unsatisfied_mods(), - m_sorted_mods(), - m_name_conflicts() - {} - - - ModConfiguration(std::string worldpath); - // checks if all dependencies are fullfilled. - bool isConsistent() + bool isConsistent() const { return m_unsatisfied_mods.empty(); } @@ -97,19 +83,24 @@ public: return m_sorted_mods; } - std::vector getUnsatisfiedMods() + const std::vector &getUnsatisfiedMods() const { return m_unsatisfied_mods; } -private: + void printUnsatisfiedModsError() const; + +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(std::string path); + void addModsInPath(const std::string &path); // adds all mods in the set. - void addMods(std::vector new_mods); + void addMods(const std::vector &new_mods); + void checkConflictsAndDeps(); +private: // move mods from m_unsatisfied_mods to m_sorted_mods // in an order that satisfies dependencies void resolveDependencies(); @@ -132,10 +123,28 @@ private: // 1. game mod in modpack; 2. game mod; // 3. world mod in modpack; 4. world mod; // 5. addon mod in modpack; 6. addon mod. - std::set m_name_conflicts; + UNORDERED_SET m_name_conflicts; + + // Deleted default constructor + ModConfiguration() {} }; +class ServerModConfiguration: public ModConfiguration +{ +public: + ServerModConfiguration(const std::string &worldpath); + +}; + +#ifndef SERVER +class ClientModConfiguration: public ModConfiguration +{ +public: + ClientModConfiguration(const std::string &path); +}; +#endif + #if USE_CURL Json::Value getModstoreUrl(std::string url); #else diff --git a/src/server.cpp b/src/server.cpp index 3adbf40cc..dd6c9a418 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -218,20 +218,12 @@ Server::Server( std::string ban_path = m_path_world + DIR_DELIM "ipban.txt"; m_banmanager = new BanManager(ban_path); - ModConfiguration modconf(m_path_world); + ServerModConfiguration modconf(m_path_world); m_mods = modconf.getMods(); std::vector unsatisfied_mods = modconf.getUnsatisfiedMods(); // complain about mods with unsatisfied dependencies - if(!modconf.isConsistent()) { - for(std::vector::iterator it = unsatisfied_mods.begin(); - it != unsatisfied_mods.end(); ++it) { - ModSpec mod = *it; - errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: "; - for(std::set::iterator dep_it = mod.unsatisfied_depends.begin(); - dep_it != mod.unsatisfied_depends.end(); ++dep_it) - errorstream << " \"" << *dep_it << "\""; - errorstream << std::endl; - } + if (!modconf.isConsistent()) { + modconf.printUnsatisfiedModsError(); } Settings worldmt_settings; @@ -271,20 +263,17 @@ Server::Server( m_script = new ServerScripting(this); - std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua"; - - m_script->loadMod(script_path, BUILTIN_MOD_NAME); + m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME); // Print mods infostream << "Server: Loading mods: "; - for(std::vector::iterator i = m_mods.begin(); + for (std::vector::const_iterator i = m_mods.begin(); i != m_mods.end(); ++i) { - const ModSpec &mod = *i; - infostream << mod.name << " "; + infostream << (*i).name << " "; } infostream << std::endl; // Load and run "mod" scripts - for (std::vector::iterator it = m_mods.begin(); + for (std::vector::const_iterator it = m_mods.begin(); it != m_mods.end(); ++it) { const ModSpec &mod = *it; if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) { -- cgit v1.2.3 From cf37a5569002e83cc4d6916b39118ceba134da1b Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Wed, 19 Apr 2017 00:36:30 +0200 Subject: Fix various variables passed by copy instead of const ref (#5610) Pointed by cppcheck --- src/activeobject.h | 2 +- src/client.cpp | 2 +- src/client.h | 2 +- src/content_cao.cpp | 2 +- src/content_cao.h | 2 +- src/filecache.h | 2 +- src/game.cpp | 18 ++++++++++-------- src/map.cpp | 7 ++++--- src/map.h | 8 +++----- src/mods.cpp | 2 +- src/mods.h | 5 +++-- src/shader.cpp | 4 ++-- src/treegen.cpp | 2 +- src/treegen.h | 2 +- 14 files changed, 31 insertions(+), 29 deletions(-) (limited to 'src/mods.cpp') diff --git a/src/activeobject.h b/src/activeobject.h index fe6c08514..71b9df514 100644 --- a/src/activeobject.h +++ b/src/activeobject.h @@ -43,7 +43,7 @@ enum ActiveObjectType { struct ActiveObjectMessage { - ActiveObjectMessage(u16 id_, bool reliable_=true, std::string data_=""): + ActiveObjectMessage(u16 id_, bool reliable_=true, const std::string &data_ = "") : id(id_), reliable(reliable_), datastring(data_) diff --git a/src/client.cpp b/src/client.cpp index 7b962cd94..3cea4fbf4 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -57,7 +57,7 @@ extern gui::IGUIEnvironment* guienv; Client::Client( IrrlichtDevice *device, const char *playername, - std::string password, + const std::string &password, MapDrawControl &control, IWritableTextureSource *tsrc, IWritableShaderSource *shsrc, diff --git a/src/client.h b/src/client.h index e7fcb597d..c55d7bcd5 100644 --- a/src/client.h +++ b/src/client.h @@ -245,7 +245,7 @@ public: Client( IrrlichtDevice *device, const char *playername, - std::string password, + const std::string &password, MapDrawControl &control, IWritableTextureSource *tsrc, IWritableShaderSource *shsrc, diff --git a/src/content_cao.cpp b/src/content_cao.cpp index ac283da88..3aa3bad97 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -1313,7 +1313,7 @@ void GenericCAO::updateTexturePos() } } -void GenericCAO::updateTextures(const std::string mod) +void GenericCAO::updateTextures(const std::string &mod) { ITextureSource *tsrc = m_client->tsrc(); diff --git a/src/content_cao.h b/src/content_cao.h index f30e90e21..a0601d692 100644 --- a/src/content_cao.h +++ b/src/content_cao.h @@ -200,7 +200,7 @@ public: void updateTexturePos(); - void updateTextures(const std::string mod); + void updateTextures(const std::string &mod); void updateAnimation(); diff --git a/src/filecache.h b/src/filecache.h index f390f71b7..627ab45ed 100644 --- a/src/filecache.h +++ b/src/filecache.h @@ -30,7 +30,7 @@ public: /* 'dir' is the file cache directory to use. */ - FileCache(std::string dir) : m_dir(dir) {} + FileCache(const std::string &dir) : m_dir(dir) {} bool update(const std::string &name, const std::string &data); bool load(const std::string &name, std::ostream &os); diff --git a/src/game.cpp b/src/game.cpp index f584a58ef..198baeca3 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -79,14 +79,15 @@ extern Profiler *g_profiler; Text input system */ -struct TextDestNodeMetadata : public TextDest { +struct TextDestNodeMetadata : public TextDest +{ TextDestNodeMetadata(v3s16 p, Client *client) { m_p = p; m_client = client; } // This is deprecated I guess? -celeron55 - void gotText(std::wstring text) + void gotText(const std::wstring &text) { std::string ntext = wide_to_utf8(text); infostream << "Submitting 'text' field of node at (" << m_p.X << "," @@ -104,13 +105,14 @@ struct TextDestNodeMetadata : public TextDest { Client *m_client; }; -struct TextDestPlayerInventory : public TextDest { +struct TextDestPlayerInventory : public TextDest +{ TextDestPlayerInventory(Client *client) { m_client = client; m_formname = ""; } - TextDestPlayerInventory(Client *client, std::string formname) + TextDestPlayerInventory(Client *client, const std::string &formname) { m_client = client; m_formname = formname; @@ -131,13 +133,13 @@ struct LocalFormspecHandler : public TextDest m_formname = formname; } - LocalFormspecHandler(std::string formname, Client *client): + LocalFormspecHandler(const std::string &formname, Client *client): m_client(client) { m_formname = formname; } - void gotText(std::wstring message) + void gotText(const std::wstring &message) { errorstream << "LocalFormspecHandler::gotText old style message received" << std::endl; } @@ -1190,7 +1192,7 @@ protected: u16 port, const SubgameSpec &gamespec); bool initSound(); - bool createSingleplayerServer(const std::string map_dir, + bool createSingleplayerServer(const std::string &map_dir, const SubgameSpec &gamespec, u16 port, std::string *address); // Client creation @@ -1780,7 +1782,7 @@ bool Game::initSound() return true; } -bool Game::createSingleplayerServer(const std::string map_dir, +bool Game::createSingleplayerServer(const std::string &map_dir, const SubgameSpec &gamespec, u16 port, std::string *address) { showOverlayMessage(wgettext("Creating server..."), 0, 5); diff --git a/src/map.cpp b/src/map.cpp index b690ea3b3..3da96e77b 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1226,7 +1226,8 @@ bool Map::isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes) { /* ServerMap */ -ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge): +ServerMap::ServerMap(const std::string &savedir, IGameDef *gamedef, + EmergeManager *emerge): Map(dout_server, gamedef), settings_mgr(g_settings, savedir + DIR_DELIM + "map_meta.txt"), m_emerge(emerge), @@ -1936,7 +1937,7 @@ std::string ServerMap::getSectorDir(v2s16 pos, int layout) } } -v2s16 ServerMap::getSectorPos(std::string dirname) +v2s16 ServerMap::getSectorPos(const std::string &dirname) { unsigned int x = 0, y = 0; int r; @@ -1966,7 +1967,7 @@ v2s16 ServerMap::getSectorPos(std::string dirname) return pos; } -v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile) +v3s16 ServerMap::getBlockPos(const std::string §ordir, const std::string &blockfile) { v2s16 p2d = getSectorPos(sectordir); diff --git a/src/map.h b/src/map.h index ea8dc76d1..90f97db8b 100644 --- a/src/map.h +++ b/src/map.h @@ -360,7 +360,7 @@ public: /* savedir: directory to which map data should be saved */ - ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge); + ServerMap(const std::string &savedir, IGameDef *gamedef, EmergeManager *emerge); ~ServerMap(); s32 mapType() const @@ -422,16 +422,14 @@ public: // returns something like "map/sectors/xxxxxxxx" std::string getSectorDir(v2s16 pos, int layout = 2); // dirname: final directory name - v2s16 getSectorPos(std::string dirname); - v3s16 getBlockPos(std::string sectordir, std::string blockfile); + v2s16 getSectorPos(const std::string &dirname); + v3s16 getBlockPos(const std::string §ordir, const std::string &blockfile); static std::string getBlockFilename(v3s16 p); /* Database functions */ static Database *createDatabase(const std::string &name, const std::string &savedir, Settings &conf); - // Verify we can read/write to the database - void verifyDatabase(); // Returns true if the database file does not exist bool loadFromFolders(); diff --git a/src/mods.cpp b/src/mods.cpp index 5a7dc6dca..6fce8e93d 100644 --- a/src/mods.cpp +++ b/src/mods.cpp @@ -347,7 +347,7 @@ ClientModConfiguration::ClientModConfiguration(const std::string &path): #endif #if USE_CURL -Json::Value getModstoreUrl(std::string url) +Json::Value getModstoreUrl(const std::string &url) { std::vector extra_headers; diff --git a/src/mods.h b/src/mods.h index c9bd51d99..1e62db54d 100644 --- a/src/mods.h +++ b/src/mods.h @@ -146,9 +146,10 @@ public: #endif #if USE_CURL -Json::Value getModstoreUrl(std::string url); +Json::Value getModstoreUrl(const std::string &url); #else -inline Json::Value getModstoreUrl(std::string url) { +inline Json::Value getModstoreUrl(const std::string &url) +{ return Json::Value(); } #endif diff --git a/src/shader.cpp b/src/shader.cpp index 79485025b..66f32c9a1 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -340,7 +340,7 @@ IWritableShaderSource* createShaderSource(IrrlichtDevice *device) /* Generate shader given the shader name. */ -ShaderInfo generate_shader(std::string name, +ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype, IrrlichtDevice *device, std::vector &callbacks, const std::vector &setter_factories, @@ -525,7 +525,7 @@ void ShaderSource::rebuildShaders() } -ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype, +ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype, IrrlichtDevice *device, std::vector &callbacks, const std::vector &setter_factories, SourceShaderCache *sourcecache) diff --git a/src/treegen.cpp b/src/treegen.cpp index 505954e8e..8bf9619a0 100644 --- a/src/treegen.cpp +++ b/src/treegen.cpp @@ -113,7 +113,7 @@ void make_tree(MMVManip &vmanip, v3s16 p0, // L-System tree LUA spawner treegen::error spawn_ltree(ServerEnvironment *env, v3s16 p0, - INodeDefManager *ndef, TreeDef tree_definition) + INodeDefManager *ndef, const TreeDef &tree_definition) { ServerMap *map = &env->getServerMap(); std::map modified_blocks; diff --git a/src/treegen.h b/src/treegen.h index 4e6f95e67..8777c369c 100644 --- a/src/treegen.h +++ b/src/treegen.h @@ -73,7 +73,7 @@ namespace treegen { TreeDef tree_definition); // Spawn L-systems tree from LUA treegen::error spawn_ltree (ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, - TreeDef tree_definition); + const TreeDef &tree_definition); // L-System tree gen helper functions void tree_node_placement(MMVManip &vmanip, v3f p0, -- cgit v1.2.3 From 90808a4f34dca379e872074bdfd472faf1c48cf3 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Sat, 20 May 2017 22:29:15 +0200 Subject: Real control fix (#5787) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Allow enabling and disabling mods. * Re-fix 605599b6f150b89ba6539c4d088231b326adcb48 This breaks some chars like € in chat. Instead verify is char is a non control char -> iswcntrl --- src/guiChatConsole.cpp | 2 +- src/mods.cpp | 100 +++++++++++++++++++++++++++++-------------------- src/mods.h | 2 + src/server.cpp | 26 ------------- 4 files changed, 62 insertions(+), 68 deletions(-) (limited to 'src/mods.cpp') diff --git a/src/guiChatConsole.cpp b/src/guiChatConsole.cpp index 8281da861..5bb80bbbe 100644 --- a/src/guiChatConsole.cpp +++ b/src/guiChatConsole.cpp @@ -627,7 +627,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event) bool backwards = event.KeyInput.Shift; prompt.nickCompletion(names, backwards); return true; - } else if (iswprint(event.KeyInput.Char) && !event.KeyInput.Control) { + } else if (!iswcntrl(event.KeyInput.Char) && !event.KeyInput.Control) { #if defined(__linux__) && (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9) wchar_t wc = L'_'; mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) ); diff --git a/src/mods.cpp b/src/mods.cpp index 6fce8e93d..0e583b2db 100644 --- a/src/mods.cpp +++ b/src/mods.cpp @@ -214,6 +214,55 @@ void ModConfiguration::addMods(const std::vector &new_mods) } } +void ModConfiguration::addModsFormConfig(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 (std::vector::iterator it = names.begin(); + it != names.end(); ++it) { + std::string name = *it; + if (name.compare(0,9,"load_mod_")==0 && conf.getBool(name)) + load_mod_names.insert(name.substr(9)); + } + + std::vector addon_mods; + for (std::set::const_iterator i = mods.begin(); + i != mods.end(); ++i) { + 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 (std::vector::iterator it = addon_mods.begin(); + it != addon_mods.end(); ++it) + load_mod_names.erase((*it).name); + std::vector UnsatisfiedMods = getUnsatisfiedMods(); + for (std::vector::iterator it = UnsatisfiedMods.begin(); + it != UnsatisfiedMods.end(); ++it) + load_mod_names.erase((*it).name); + if (!load_mod_names.empty()) { + errorstream << "The following mods could not be found:"; + for (std::set::iterator it = load_mod_names.begin(); + it != load_mod_names.end(); ++it) + errorstream << " \"" << (*it) << "\""; + errorstream << std::endl; + } +} + void ModConfiguration::checkConflictsAndDeps() { // report on name conflicts @@ -296,53 +345,22 @@ 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"; + addModsFormConfig(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(); + std::set paths; + std::string path_user = porting::path_user + DIR_DELIM + "clientmods"; + paths.insert(path); + paths.insert(path_user); + + std::string settings_path = path_user + DIR_DELIM + "mods.conf"; + addModsFormConfig(settings_path, paths); } #endif diff --git a/src/mods.h b/src/mods.h index 1e62db54d..7455a51ea 100644 --- a/src/mods.h +++ b/src/mods.h @@ -99,6 +99,8 @@ protected: // adds all mods in the set. void addMods(const std::vector &new_mods); + void addModsFormConfig(const std::string &settings_path, const std::set &mods); + void checkConflictsAndDeps(); private: // move mods from m_unsatisfied_mods to m_sorted_mods diff --git a/src/server.cpp b/src/server.cpp index 6889451d9..1e8e6a5d2 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -230,32 +230,6 @@ Server::Server( modconf.printUnsatisfiedModsError(); } - Settings worldmt_settings; - std::string worldmt = m_path_world + DIR_DELIM + "world.mt"; - worldmt_settings.readConfigFile(worldmt.c_str()); - std::vector names = worldmt_settings.getNames(); - std::set load_mod_names; - for(std::vector::iterator it = names.begin(); - it != names.end(); ++it) { - std::string name = *it; - if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name)) - load_mod_names.insert(name.substr(9)); - } - // complain about mods declared to be loaded, but not found - for(std::vector::iterator it = m_mods.begin(); - it != m_mods.end(); ++it) - load_mod_names.erase((*it).name); - for(std::vector::iterator it = unsatisfied_mods.begin(); - it != unsatisfied_mods.end(); ++it) - load_mod_names.erase((*it).name); - if(!load_mod_names.empty()) { - errorstream << "The following mods could not be found:"; - for(std::set::iterator it = load_mod_names.begin(); - it != load_mod_names.end(); ++it) - errorstream << " \"" << (*it) << "\""; - errorstream << std::endl; - } - //lock environment MutexAutoLock envlock(m_env_mutex); -- cgit v1.2.3