aboutsummaryrefslogtreecommitdiff
path: root/src/content
diff options
context:
space:
mode:
authorElias Fleckenstein <eliasfleckenstein@web.de>2022-05-17 22:12:00 +0200
committerElias Fleckenstein <eliasfleckenstein@web.de>2022-05-17 22:12:00 +0200
commit21df26984da91143c15587f5a03c98d68c3adc4e (patch)
treeaaa707a628ad331f67890023dffe1b4f60dd01d3 /src/content
parentb09fc5de5cdb021f43ad32b7e3f50dc75c0bc622 (diff)
parenteabf05758e3ba5f6f4bb1b8d1d1f02179b84e410 (diff)
downloaddragonfireclient-21df26984da91143c15587f5a03c98d68c3adc4e.tar.xz
Merge branch 'master' of https://github.com/minetest/minetest
Diffstat (limited to 'src/content')
-rw-r--r--src/content/mods.cpp159
-rw-r--r--src/content/mods.h67
-rw-r--r--src/content/subgames.cpp41
-rw-r--r--src/content/subgames.h12
4 files changed, 152 insertions, 127 deletions
diff --git a/src/content/mods.cpp b/src/content/mods.cpp
index 6f088a5b3..f75119bbb 100644
--- a/src/content/mods.cpp
+++ b/src/content/mods.cpp
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <json/json.h>
#include <algorithm>
#include "content/mods.h"
+#include "database/database.h"
#include "filesys.h"
#include "log.h"
#include "content/subgames.h"
@@ -88,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;
@@ -166,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)
@@ -184,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));
}
@@ -227,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)
@@ -293,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());
@@ -334,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;
+ }
+ }
+ }
}
}
@@ -412,93 +441,41 @@ 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);
}
#endif
-ModMetadata::ModMetadata(const std::string &mod_name) : m_mod_name(mod_name)
+ModMetadata::ModMetadata(const std::string &mod_name, ModMetadataDatabase *database):
+ m_mod_name(mod_name), m_database(database)
{
+ m_database->getModEntries(m_mod_name, &m_stringvars);
}
void ModMetadata::clear()
{
+ for (const auto &pair : m_stringvars) {
+ m_database->removeModEntry(m_mod_name, pair.first);
+ }
Metadata::clear();
- m_modified = true;
}
-bool ModMetadata::save(const std::string &root_path)
+bool ModMetadata::setString(const std::string &name, const std::string &var)
{
- 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;
+ if (Metadata::setString(name, var)) {
+ if (var.empty()) {
+ m_database->removeModEntry(m_mod_name, name);
+ } else {
+ m_database->setModEntry(m_mod_name, name, var);
}
- } 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, fastWriteJson(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::Value 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). Message: "
- << errs << std::endl;
- return false;
- }
-
- const Json::Value::Members attr_list = root.getMemberNames();
- for (const auto &it : attr_list) {
- Json::Value attr_value = root[it];
- m_stringvars[it] = attr_value.asString();
+ return true;
}
-
- return true;
-}
-
-bool ModMetadata::setString(const std::string &name, const std::string &var)
-{
- m_modified = Metadata::setString(name, var);
- return m_modified;
+ return false;
}
diff --git a/src/content/mods.h b/src/content/mods.h
index b56a97edb..ab0a9300e 100644
--- a/src/content/mods.h
+++ b/src/content/mods.h
@@ -31,6 +31,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "config.h"
#include "metadata.h"
+class ModMetadataDatabase;
+
#define MODNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_"
struct ModSpec
@@ -49,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)
{
}
@@ -69,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);
@@ -95,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();
@@ -149,20 +188,16 @@ class ModMetadata : public Metadata
{
public:
ModMetadata() = delete;
- ModMetadata(const std::string &mod_name);
+ ModMetadata(const std::string &mod_name, ModMetadataDatabase *database);
~ModMetadata() = default;
virtual void clear();
- bool save(const std::string &root_path);
- bool load(const std::string &root_path);
-
- bool isModified() const { return m_modified; }
const std::string &getModName() const { return m_mod_name; }
virtual bool setString(const std::string &name, const std::string &var);
private:
std::string m_mod_name;
- bool m_modified = false;
+ ModMetadataDatabase *m_database;
};
diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp
index e9dc609b0..23355990e 100644
--- a/src/content/subgames.cpp
+++ b/src/content/subgames.cpp
@@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "util/strfnd.h"
#include "defaultsettings.h" // for set_default_settings
-#include "mapgen/mapgen.h" // for MapgenParams
+#include "map_settings_manager.h"
#include "util/string.h"
#ifndef SERVER
@@ -107,11 +107,14 @@ 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[fs::AbsolutePath(mod_path)] = mod_path;
+ }
// Get meta
std::string conf_path = game_path + DIR_DELIM + "game.conf";
@@ -354,6 +357,7 @@ void loadGameConfAndInitWorld(const std::string &path, const std::string &name,
conf.set("backend", "sqlite3");
conf.set("player_backend", "sqlite3");
conf.set("auth_backend", "sqlite3");
+ conf.set("mod_storage_backend", "sqlite3");
conf.setBool("creative_mode", g_settings->getBool("creative_mode"));
conf.setBool("enable_damage", g_settings->getBool("enable_damage"));
@@ -365,22 +369,25 @@ void loadGameConfAndInitWorld(const std::string &path, const std::string &name,
// Create map_meta.txt if does not already exist
std::string map_meta_path = final_path + DIR_DELIM + "map_meta.txt";
if (!fs::PathExists(map_meta_path)) {
- verbosestream << "Creating map_meta.txt (" << map_meta_path << ")"
- << std::endl;
- std::ostringstream oss(std::ios_base::binary);
-
- Settings conf;
- MapgenParams params;
+ MapSettingsManager mgr(map_meta_path);
- params.readParams(g_settings);
- params.writeParams(&conf);
- conf.writeLines(oss);
- oss << "[end_of_params]\n";
+ mgr.setMapSetting("seed", g_settings->get("fixed_map_seed"));
- fs::safeWriteToFile(map_meta_path, oss.str());
+ mgr.makeMapgenParams();
+ mgr.saveMapMeta();
}
// The Settings object is no longer needed for created worlds
if (new_game_settings)
delete game_settings;
}
+
+std::vector<std::string> getEnvModPaths()
+{
+ const char *c_mod_path = getenv("MINETEST_MOD_PATH");
+ std::vector<std::string> paths;
+ Strfnd search_paths(c_mod_path ? c_mod_path : "");
+ while (!search_paths.at_end())
+ paths.push_back(search_paths.next(PATH_DELIM));
+ return paths;
+}
diff --git a/src/content/subgames.h b/src/content/subgames.h
index 60392639b..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) :
@@ -58,6 +62,8 @@ SubgameSpec findWorldSubgame(const std::string &world_path);
std::set<std::string> getAvailableGameIds();
std::vector<SubgameSpec> getAvailableGames();
+// Get the list of paths to mods in the environment variable $MINETEST_MOD_PATH
+std::vector<std::string> getEnvModPaths();
bool getWorldExists(const std::string &world_path);
//! Try to get the displayed name of a world