1 /* 2 Minetest 3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU Lesser General Public License as published by 7 the Free Software Foundation; either version 2.1 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public License along 16 with this program; if not, write to the Free Software Foundation, Inc., 17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 #pragma once 21 22 #include "irrlichttypes.h" 23 #include <list> 24 #include <set> 25 #include <vector> 26 #include <string> 27 #include <map> 28 #include <json/json.h> 29 #include <unordered_set> 30 #include "util/basic_macros.h" 31 #include "config.h" 32 #include "metadata.h" 33 34 #define MODNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_" 35 36 struct ModSpec 37 { 38 std::string name; 39 std::string author; 40 std::string path; 41 std::string desc; 42 int release = 0; 43 44 // if normal mod: 45 std::unordered_set<std::string> depends; 46 std::unordered_set<std::string> optdepends; 47 std::unordered_set<std::string> unsatisfied_depends; 48 49 bool part_of_modpack = false; 50 bool is_modpack = false; 51 52 // if modpack: 53 std::map<std::string, ModSpec> modpack_content; 54 ModSpec(const std::string &name = "", const std::string &path = "") : nameModSpec55 name(name), path(path) 56 { 57 } ModSpecModSpec58 ModSpec(const std::string &name, const std::string &path, bool part_of_modpack) : 59 name(name), path(path), part_of_modpack(part_of_modpack) 60 { 61 } 62 }; 63 64 // Retrieves depends, optdepends, is_modpack and modpack_content 65 void parseModContents(ModSpec &mod); 66 67 std::map<std::string, ModSpec> getModsInPath( 68 const std::string &path, bool part_of_modpack = false); 69 70 // replaces modpack Modspecs with their content 71 std::vector<ModSpec> flattenMods(const std::map<std::string, ModSpec> &mods); 72 73 // a ModConfiguration is a subset of installed mods, expected to have 74 // all dependencies fullfilled, so it can be used as a list of mods to 75 // load when the game starts. 76 class ModConfiguration 77 { 78 public: 79 // checks if all dependencies are fullfilled. isConsistent()80 bool isConsistent() const { return m_unsatisfied_mods.empty(); } 81 getMods()82 const std::vector<ModSpec> &getMods() const { return m_sorted_mods; } 83 getUnsatisfiedMods()84 const std::vector<ModSpec> &getUnsatisfiedMods() const 85 { 86 return m_unsatisfied_mods; 87 } 88 89 void printUnsatisfiedModsError() const; 90 91 protected: 92 ModConfiguration(const std::string &worldpath); 93 // adds all mods in the given path. used for games, modpacks 94 // and world-specific mods (worldmods-folders) 95 void addModsInPath(const std::string &path); 96 97 // adds all mods in the set. 98 void addMods(const std::vector<ModSpec> &new_mods); 99 100 void addModsFromConfig(const std::string &settings_path, 101 const std::set<std::string> &mods); 102 103 void checkConflictsAndDeps(); 104 105 protected: 106 // list of mods sorted such that they can be loaded in the 107 // given order with all dependencies being fullfilled. I.e., 108 // every mod in this list has only dependencies on mods which 109 // appear earlier in the vector. 110 std::vector<ModSpec> m_sorted_mods; 111 112 private: 113 // move mods from m_unsatisfied_mods to m_sorted_mods 114 // in an order that satisfies dependencies 115 void resolveDependencies(); 116 117 // mods with unmet dependencies. Before dependencies are resolved, 118 // this is where all mods are stored. Afterwards this contains 119 // only the ones with really unsatisfied dependencies. 120 std::vector<ModSpec> m_unsatisfied_mods; 121 122 // set of mod names for which an unresolved name conflict 123 // exists. A name conflict happens when two or more mods 124 // at the same level have the same name but different paths. 125 // Levels (mods in higher levels override mods in lower levels): 126 // 1. game mod in modpack; 2. game mod; 127 // 3. world mod in modpack; 4. world mod; 128 // 5. addon mod in modpack; 6. addon mod. 129 std::unordered_set<std::string> m_name_conflicts; 130 131 // Deleted default constructor 132 ModConfiguration() = default; 133 }; 134 135 #ifndef SERVER 136 class ClientModConfiguration : public ModConfiguration 137 { 138 public: 139 ClientModConfiguration(const std::string &path); 140 }; 141 #endif 142 143 class ModMetadata : public Metadata 144 { 145 public: 146 ModMetadata() = delete; 147 ModMetadata(const std::string &mod_name); 148 ~ModMetadata() = default; 149 150 virtual void clear(); 151 152 bool save(const std::string &root_path); 153 bool load(const std::string &root_path); 154 isModified()155 bool isModified() const { return m_modified; } getModName()156 const std::string &getModName() const { return m_mod_name; } 157 158 virtual bool setString(const std::string &name, const std::string &var); 159 160 private: 161 std::string m_mod_name; 162 bool m_modified = false; 163 }; 164