mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Restored all disabled mod functinality that was used by client
This commit is contained in:
		| @@ -362,17 +362,6 @@ void CMainMenu::update() | ||||
| 		menu->switchToTab(menu->getActiveTab()); | ||||
| 	} | ||||
|  | ||||
| 	static bool warnedAboutModDependencies = false; | ||||
|  | ||||
| 	if (!warnedAboutModDependencies) | ||||
| 	{ | ||||
| 		warnedAboutModDependencies = true; | ||||
| 		auto errorMessages = CGI->modh->getModLoadErrors(); | ||||
|  | ||||
| 		if (!errorMessages.empty()) | ||||
| 			CInfoWindow::showInfoDialog(errorMessages, std::vector<std::shared_ptr<CComponent>>(), PlayerColor(1)); | ||||
| 	} | ||||
|  | ||||
| 	// Handles mouse and key input | ||||
| 	GH.handleEvents(); | ||||
| 	GH.windows().simpleRedraw(); | ||||
|   | ||||
| @@ -809,7 +809,7 @@ void CModListView::installFiles(QStringList files) | ||||
| 					if(!modJsonUrl.isNull()) | ||||
| 						downloadFile(QString::fromStdString(modName + ".json"), QString::fromStdString(modJsonUrl.String()), tr("mods repository index")); | ||||
|  | ||||
| 					repository[modNameLower] = repoData; | ||||
| 					repository[modNameLower] = modJson; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
|   | ||||
| @@ -38,19 +38,14 @@ CModHandler::~CModHandler() = default; | ||||
|  | ||||
| std::vector<std::string> CModHandler::getAllMods() const | ||||
| { | ||||
| 	return modManager->getActiveMods();// TODO: currently identical to active | ||||
| 	return modManager->getAllMods(); | ||||
| } | ||||
|  | ||||
| std::vector<std::string> CModHandler::getActiveMods() const | ||||
| const std::vector<std::string> & CModHandler::getActiveMods() const | ||||
| { | ||||
| 	return modManager->getActiveMods(); | ||||
| } | ||||
|  | ||||
| std::string CModHandler::getModLoadErrors() const | ||||
| { | ||||
| 	return ""; // TODO: modLoadErrors->toString(); | ||||
| } | ||||
|  | ||||
| const ModDescription & CModHandler::getModInfo(const TModID & modId) const | ||||
| { | ||||
| 	return modManager->getModDescription(modId); | ||||
| @@ -86,35 +81,6 @@ static ISimpleResourceLoader * genModFilesystem(const std::string & modName, con | ||||
| 		return CResourceHandler::createFileSystem(getModDirectory(modName), defaultFS); | ||||
| } | ||||
|  | ||||
| //static ui32 calculateModChecksum(const std::string & modName, ISimpleResourceLoader * filesystem) | ||||
| //{ | ||||
| //	boost::crc_32_type modChecksum; | ||||
| //	// first - add current VCMI version into checksum to force re-validation on VCMI updates | ||||
| //	modChecksum.process_bytes(reinterpret_cast<const void*>(GameConstants::VCMI_VERSION.data()), GameConstants::VCMI_VERSION.size()); | ||||
| // | ||||
| //	// second - add mod.json into checksum because filesystem does not contains this file | ||||
| //	// FIXME: remove workaround for core mod | ||||
| //	if (modName != ModScope::scopeBuiltin()) | ||||
| //	{ | ||||
| //		auto modConfFile = CModInfo::getModFile(modName); | ||||
| //		ui32 configChecksum = CResourceHandler::get("initial")->load(modConfFile)->calculateCRC32(); | ||||
| //		modChecksum.process_bytes(reinterpret_cast<const void *>(&configChecksum), sizeof(configChecksum)); | ||||
| //	} | ||||
| //	// third - add all detected text files from this mod into checksum | ||||
| //	auto files = filesystem->getFilteredFiles([](const ResourcePath & resID) | ||||
| //	{ | ||||
| //		return (resID.getType() == EResType::TEXT || resID.getType() == EResType::JSON) && | ||||
| //			   ( boost::starts_with(resID.getName(), "DATA") || boost::starts_with(resID.getName(), "CONFIG")); | ||||
| //	}); | ||||
| // | ||||
| //	for (const ResourcePath & file : files) | ||||
| //	{ | ||||
| //		ui32 fileChecksum = filesystem->load(file)->calculateCRC32(); | ||||
| //		modChecksum.process_bytes(reinterpret_cast<const void *>(&fileChecksum), sizeof(fileChecksum)); | ||||
| //	} | ||||
| //	return modChecksum.checksum(); | ||||
| //} | ||||
|  | ||||
| void CModHandler::loadModFilesystems() | ||||
| { | ||||
| 	CGeneralTextHandler::detectInstallParameters(); | ||||
| @@ -250,7 +216,7 @@ std::set<TModID> CModHandler::getModEnabledSoftDependencies(const TModID & modId | ||||
| { | ||||
| 	std::set<TModID> softDependencies = getModSoftDependencies(modId); | ||||
|  | ||||
| 	vstd::erase_if(softDependencies, [&](const TModID & dependency){ return !modManager->isModActive(dependency);}); | ||||
| 	vstd::erase_if(softDependencies, [this](const TModID & dependency){ return !modManager->isModActive(dependency);}); | ||||
|  | ||||
| 	return softDependencies; | ||||
| } | ||||
| @@ -285,18 +251,41 @@ void CModHandler::load() | ||||
|  | ||||
| 	content->init(); | ||||
|  | ||||
| //	for(const TModID & modName : getActiveMods()) | ||||
| //	{ | ||||
| //		logMod->trace("Generating checksum for %s", modName); | ||||
| //		allMods[modName].updateChecksum(calculateModChecksum(modName, CResourceHandler::get(modName))); | ||||
| //	} | ||||
| 	const auto & activeMods = getActiveMods(); | ||||
|  | ||||
| 	for(const TModID & modName : getActiveMods()) | ||||
| 		content->preloadData(getModInfo(modName)); | ||||
| 	validationPassed.insert(activeMods.begin(), activeMods.end()); | ||||
|  | ||||
| 	for(const TModID & modName : activeMods) | ||||
| 	{ | ||||
| 		modChecksums[modName] = this->modManager->computeChecksum(modName); | ||||
| 	} | ||||
|  | ||||
| 	for(const TModID & modName : activeMods) | ||||
| 	{ | ||||
| 		const auto & modInfo = getModInfo(modName); | ||||
| 		bool isValid = content->preloadData(modInfo, isModValidationNeeded(modInfo)); | ||||
| 		if (isValid) | ||||
| 			logGlobal->info("\t\tParsing mod: OK (%s)", modInfo.getName()); | ||||
| 		else | ||||
| 			logGlobal->warn("\t\tParsing mod: Issues found! (%s)", modInfo.getName()); | ||||
|  | ||||
| 		if (!isValid) | ||||
| 			validationPassed.erase(modName); | ||||
| 	} | ||||
| 	logMod->info("\tParsing mod data"); | ||||
|  | ||||
| 	for(const TModID & modName : getActiveMods()) | ||||
| 		content->load(getModInfo(modName)); | ||||
| 	for(const TModID & modName : activeMods) | ||||
| 	{ | ||||
| 		const auto & modInfo = getModInfo(modName); | ||||
| 		bool isValid = content->load(getModInfo(modName), isModValidationNeeded(getModInfo(modName))); | ||||
| 		if (isValid) | ||||
| 			logGlobal->info("\t\tLoading mod: OK (%s)", modInfo.getName()); | ||||
| 		else | ||||
| 			logGlobal->warn("\t\tLoading mod: Issues found! (%s)", modInfo.getName()); | ||||
|  | ||||
| 		if (!isValid) | ||||
| 			validationPassed.erase(modName); | ||||
| 	} | ||||
|  | ||||
| #if SCRIPTING_ENABLED | ||||
| 	VLC->scriptHandler->performRegistration(VLC);//todo: this should be done before any other handlers load | ||||
| @@ -304,7 +293,7 @@ void CModHandler::load() | ||||
|  | ||||
| 	content->loadCustom(); | ||||
|  | ||||
| 	for(const TModID & modName : getActiveMods()) | ||||
| 	for(const TModID & modName : activeMods) | ||||
| 		loadTranslation(modName); | ||||
|  | ||||
| 	logMod->info("\tLoading mod data"); | ||||
| @@ -319,21 +308,30 @@ void CModHandler::load() | ||||
|  | ||||
| void CModHandler::afterLoad(bool onlyEssential) | ||||
| { | ||||
| 	//JsonNode modSettings; | ||||
| 	//for (auto & modEntry : getActiveMods()) | ||||
| 	//{ | ||||
| 	//	std::string pointer = "/" + boost::algorithm::replace_all_copy(modEntry.first, ".", "/mods/"); | ||||
| 	JsonNode modSettings; | ||||
| 	for (auto & modEntry : getActiveMods()) | ||||
| 	{ | ||||
| 		if (validationPassed.count(modEntry)) | ||||
| 			modManager->setValidatedChecksum(modEntry, modChecksums.at(modEntry)); | ||||
| 		else | ||||
| 			modManager->setValidatedChecksum(modEntry, std::nullopt); | ||||
| 	} | ||||
|  | ||||
| 	//	modSettings["activeMods"].resolvePointer(pointer) = modEntry.second.saveLocalData(); | ||||
| 	//} | ||||
| 	//modSettings[ModScope::scopeBuiltin()] = coreMod->saveLocalData(); | ||||
| 	//modSettings[ModScope::scopeBuiltin()]["name"].String() = "Original game files"; | ||||
| 	modManager->saveConfigurationState(); | ||||
| } | ||||
|  | ||||
| 	//if(!onlyEssential) | ||||
| 	//{ | ||||
| 	//	std::fstream file(CResourceHandler::get()->getResourceName(ResourcePath("config/modSettings.json"))->c_str(), std::ofstream::out | std::ofstream::trunc); | ||||
| 	//	file << modSettings.toString(); | ||||
| 	//} | ||||
| bool CModHandler::isModValidationNeeded(const ModDescription & mod) const | ||||
| { | ||||
| 	if (settings["mods"]["validation"].String() == "full") | ||||
| 		return true; | ||||
|  | ||||
| 	if (modManager->getValidatedChecksum(mod.getID()) == modChecksums.at(mod.getID())) | ||||
| 		return false; | ||||
|  | ||||
| 	if (settings["mods"]["validation"].String() == "off") | ||||
| 		return false; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
|   | ||||
| @@ -23,12 +23,16 @@ using TModID = std::string; | ||||
| class DLL_LINKAGE CModHandler final : boost::noncopyable | ||||
| { | ||||
| 	std::unique_ptr<ModManager> modManager; | ||||
| 	std::map<std::string, uint32_t> modChecksums; | ||||
| 	std::set<std::string> validationPassed; | ||||
|  | ||||
| 	void loadTranslation(const TModID & modName); | ||||
| 	void checkModFilesystemsConflicts(const std::map<TModID, ISimpleResourceLoader *> & modFilesystems); | ||||
|  | ||||
| 	bool isModValidationNeeded(const ModDescription & mod) const; | ||||
|  | ||||
| public: | ||||
| 	std::shared_ptr<CContentHandler> content; //FIXME: make private | ||||
| 	std::shared_ptr<CContentHandler> content; | ||||
|  | ||||
| 	/// receives list of available mods and trying to load mod.json from all of them | ||||
| 	void initializeConfig(); | ||||
| @@ -52,11 +56,8 @@ public: | ||||
|  | ||||
| 	/// returns list of all (active) mods | ||||
| 	std::vector<std::string> getAllMods() const; | ||||
| 	std::vector<std::string> getActiveMods() const; | ||||
| 	const std::vector<std::string> & getActiveMods() const; | ||||
|  | ||||
| 	/// Returns human-readable string that describes errors encounter during mod loading, such as missing dependencies | ||||
| 	std::string getModLoadErrors() const; | ||||
| 	 | ||||
| 	const ModDescription & getModInfo(const TModID & modId) const; | ||||
|  | ||||
| 	/// load content from all available mods | ||||
|   | ||||
| @@ -55,7 +55,7 @@ ContentTypeHandler::ContentTypeHandler(IHandlerBase * handler, const std::string | ||||
|  | ||||
| bool ContentTypeHandler::preloadModData(const std::string & modName, const JsonNode & fileList, bool validate) | ||||
| { | ||||
| 	bool result = false; | ||||
| 	bool result = true; | ||||
| 	JsonNode data = JsonUtils::assembleFromFiles(fileList, result); | ||||
| 	data.setModScope(modName); | ||||
|  | ||||
| @@ -259,22 +259,28 @@ void CContentHandler::init() | ||||
| 	handlers.insert(std::make_pair("biomes", ContentTypeHandler(VLC->biomeHandler.get(), "biome"))); | ||||
| } | ||||
|  | ||||
| bool CContentHandler::preloadModData(const std::string & modName, JsonNode modConfig, bool validate) | ||||
| bool CContentHandler::preloadData(const ModDescription & mod, bool validate) | ||||
| { | ||||
| 	bool result = true; | ||||
| 	if (validate && mod.getID() != ModScope::scopeBuiltin()) // TODO: remove workaround | ||||
| 	{ | ||||
| 		if (!JsonUtils::validate(mod.getLocalConfig(), "vcmi:mod", mod.getID())) | ||||
| 			result = false; | ||||
| 	} | ||||
|  | ||||
| 	for(auto & handler : handlers) | ||||
| 	{ | ||||
| 		result &= handler.second.preloadModData(modName, modConfig[handler.first], validate); | ||||
| 		result &= handler.second.preloadModData(mod.getID(), mod.getLocalValue(handler.first), validate); | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| bool CContentHandler::loadMod(const std::string & modName, bool validate) | ||||
| bool CContentHandler::load(const ModDescription & mod, bool validate) | ||||
| { | ||||
| 	bool result = true; | ||||
| 	for(auto & handler : handlers) | ||||
| 	{ | ||||
| 		result &= handler.second.loadMod(modName, validate); | ||||
| 		result &= handler.second.loadMod(mod.getID(), validate); | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
| @@ -295,62 +301,9 @@ void CContentHandler::afterLoadFinalization() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CContentHandler::preloadData(const ModDescription & mod) | ||||
| { | ||||
| 	preloadModData(mod.getID(), mod.getLocalConfig(), false); | ||||
|  | ||||
| //	bool validate = validateMod(mod); | ||||
| // | ||||
| //	// print message in format [<8-symbols checksum>] <modname> | ||||
| //	auto & info = mod.getVerificationInfo(); | ||||
| //	logMod->info("\t\t[%08x]%s", info.checksum, info.name); | ||||
| // | ||||
| //	if (validate && mod.identifier != ModScope::scopeBuiltin()) | ||||
| //	{ | ||||
| //		if (!JsonUtils::validate(mod.config, "vcmi:mod", mod.identifier)) | ||||
| //			mod.validation = CModInfo::FAILED; | ||||
| //	} | ||||
| //	if (!preloadModData(mod.identifier, mod.config, validate)) | ||||
| //		mod.validation = CModInfo::FAILED; | ||||
| } | ||||
|  | ||||
| void CContentHandler::load(const ModDescription & mod) | ||||
| { | ||||
| 	loadMod(mod.getID(), false); | ||||
|  | ||||
| //	bool validate = validateMod(mod); | ||||
| // | ||||
| //	if (!loadMod(mod.identifier, validate)) | ||||
| //		mod.validation = CModInfo::FAILED; | ||||
| // | ||||
| //	if (validate) | ||||
| //	{ | ||||
| //		if (mod.validation != CModInfo::FAILED) | ||||
| //			logMod->info("\t\t[DONE] %s", mod.getVerificationInfo().name); | ||||
| //		else | ||||
| //			logMod->error("\t\t[FAIL] %s", mod.getVerificationInfo().name); | ||||
| //	} | ||||
| //	else | ||||
| //		logMod->info("\t\t[SKIP] %s", mod.getVerificationInfo().name); | ||||
| } | ||||
|  | ||||
| const ContentTypeHandler & CContentHandler::operator[](const std::string & name) const | ||||
| { | ||||
| 	return handlers.at(name); | ||||
| } | ||||
|  | ||||
| bool CContentHandler::validateMod(const ModDescription & mod) const | ||||
| { | ||||
| 	if (settings["mods"]["validation"].String() == "full") | ||||
| 		return true; | ||||
|  | ||||
| //	if (mod.validation == CModInfo::PASSED) | ||||
| //		return false; | ||||
|  | ||||
| 	if (settings["mods"]["validation"].String() == "off") | ||||
| 		return false; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
|   | ||||
| @@ -50,23 +50,16 @@ public: | ||||
| /// class used to load all game data into handlers. Used only during loading | ||||
| class DLL_LINKAGE CContentHandler | ||||
| { | ||||
| 	/// preloads all data from fileList as data from modName. | ||||
| 	bool preloadModData(const std::string & modName, JsonNode modConfig, bool validate); | ||||
|  | ||||
| 	/// actually loads data in mod | ||||
| 	bool loadMod(const std::string & modName, bool validate); | ||||
|  | ||||
| 	std::map<std::string, ContentTypeHandler> handlers; | ||||
|  | ||||
| 	bool validateMod(const ModDescription & mod) const; | ||||
| public: | ||||
| 	void init(); | ||||
|  | ||||
| 	/// preloads all data from fileList as data from modName. | ||||
| 	void preloadData(const ModDescription & mod); | ||||
| 	bool preloadData(const ModDescription & mod, bool validateMod); | ||||
|  | ||||
| 	/// actually loads data in mod | ||||
| 	void load(const ModDescription & mod); | ||||
| 	bool load(const ModDescription & mod, bool validateMod); | ||||
|  | ||||
| 	void loadCustom(); | ||||
|  | ||||
|   | ||||
| @@ -26,7 +26,7 @@ ModDescription::ModDescription(const TModID & fullID, const JsonNode & localConf | ||||
| 	, conflicts(loadModList(getValue("conflicts"))) | ||||
| { | ||||
| 	if(getID() != "core") | ||||
| 		dependencies.insert("core"); | ||||
| 		dependencies.emplace("core"); | ||||
| } | ||||
|  | ||||
| ModDescription::~ModDescription() = default; | ||||
|   | ||||
| @@ -21,10 +21,11 @@ using TModSet = std::set<TModID>; | ||||
|  | ||||
| class DLL_LINKAGE ModDescription : boost::noncopyable | ||||
| { | ||||
| 	TModID identifier; | ||||
|  | ||||
| 	std::unique_ptr<JsonNode> localConfig; | ||||
| 	std::unique_ptr<JsonNode> repositoryConfig; | ||||
|  | ||||
| 	TModID identifier; | ||||
| 	TModSet dependencies; | ||||
| 	TModSet softDependencies; | ||||
| 	TModSet conflicts; | ||||
|   | ||||
| @@ -13,6 +13,7 @@ | ||||
| #include "ModDescription.h" | ||||
| #include "ModScope.h" | ||||
|  | ||||
| #include "../constants/StringConstants.h" | ||||
| #include "../filesystem/Filesystem.h" | ||||
| #include "../json/JsonNode.h" | ||||
| #include "../texts/CGeneralTextHandler.h" | ||||
| @@ -49,17 +50,45 @@ ModsState::ModsState() | ||||
|  | ||||
| 		for(const auto & submod : scanModsDirectory(getModSettingsDirectory(target))) | ||||
| 			testLocations.push_back(target + '.' + submod); | ||||
|  | ||||
| 		// TODO: check that this is vcmi mod and not era mod? | ||||
| 		// TODO: check that mod name is not reserved (ModScope::isScopeReserved(modFullName))) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| TModList ModsState::getAllMods() const | ||||
| TModList ModsState::getInstalledMods() const | ||||
| { | ||||
| 	return modList; | ||||
| } | ||||
|  | ||||
| uint32_t ModsState::computeChecksum(const TModID & modName) const | ||||
| { | ||||
| 	boost::crc_32_type modChecksum; | ||||
| 	// first - add current VCMI version into checksum to force re-validation on VCMI updates | ||||
| 	modChecksum.process_bytes(reinterpret_cast<const void*>(GameConstants::VCMI_VERSION.data()), GameConstants::VCMI_VERSION.size()); | ||||
|  | ||||
| 	// second - add mod.json into checksum because filesystem does not contains this file | ||||
| 	// FIXME: remove workaround for core mod | ||||
| 	if (modName != ModScope::scopeBuiltin()) | ||||
| 	{ | ||||
| 		auto modConfFile = getModDescriptionFile(modName); | ||||
| 		ui32 configChecksum = CResourceHandler::get("initial")->load(modConfFile)->calculateCRC32(); | ||||
| 		modChecksum.process_bytes(reinterpret_cast<const void *>(&configChecksum), sizeof(configChecksum)); | ||||
| 	} | ||||
|  | ||||
| 	// third - add all detected text files from this mod into checksum | ||||
| 	const auto & filesystem = CResourceHandler::get(modName); | ||||
|  | ||||
| 	auto files = filesystem->getFilteredFiles([](const ResourcePath & resID) | ||||
| 	{ | ||||
| 		return resID.getType() == EResType::JSON && boost::starts_with(resID.getName(), "CONFIG"); | ||||
| 	}); | ||||
|  | ||||
| 	for (const ResourcePath & file : files) | ||||
| 	{ | ||||
| 		ui32 fileChecksum = filesystem->load(file)->calculateCRC32(); | ||||
| 		modChecksum.process_bytes(reinterpret_cast<const void *>(&fileChecksum), sizeof(fileChecksum)); | ||||
| 	} | ||||
| 	return modChecksum.checksum(); | ||||
| } | ||||
|  | ||||
| std::vector<TModID> ModsState::scanModsDirectory(const std::string & modDir) const | ||||
| { | ||||
| 	size_t depth = boost::range::count(modDir, '/'); | ||||
| @@ -90,6 +119,9 @@ std::vector<TModID> ModsState::scanModsDirectory(const std::string & modDir) con | ||||
| 		if(name.find('.') != std::string::npos) | ||||
| 			continue; | ||||
|  | ||||
| 		if (ModScope::isScopeReserved(boost::to_lower_copy(name))) | ||||
| 			continue; | ||||
|  | ||||
| 		if(!CResourceHandler::get("initial")->existsResource(JsonPath::builtin(entry.getName() + "/MOD"))) | ||||
| 			continue; | ||||
|  | ||||
| @@ -123,20 +155,14 @@ ModsPresetState::ModsPresetState() | ||||
| 		else | ||||
| 			importInitialPreset(); // 1.5 format import | ||||
|  | ||||
| 		saveConfiguration(modConfig); | ||||
| 		saveConfigurationState(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void ModsPresetState::saveConfiguration(const JsonNode & modSettings) | ||||
| { | ||||
| 	std::fstream file(CResourceHandler::get()->getResourceName(ResourcePath("config/modSettings.json"))->c_str(), std::ofstream::out | std::ofstream::trunc); | ||||
| 	file << modSettings.toString(); | ||||
| } | ||||
|  | ||||
| void ModsPresetState::createInitialPreset() | ||||
| { | ||||
| 	// TODO: scan mods directory for all its content? Probably unnecessary since this looks like new install, but who knows? | ||||
| 	modConfig["presets"]["default"]["mods"].Vector().push_back(JsonNode("vcmi")); | ||||
| 	modConfig["presets"]["default"]["mods"].Vector().emplace_back("vcmi"); | ||||
| } | ||||
|  | ||||
| void ModsPresetState::importInitialPreset() | ||||
| @@ -146,7 +172,7 @@ void ModsPresetState::importInitialPreset() | ||||
| 	for(const auto & mod : modConfig["activeMods"].Struct()) | ||||
| 	{ | ||||
| 		if(mod.second["active"].Bool()) | ||||
| 			preset["mods"].Vector().push_back(JsonNode(mod.first)); | ||||
| 			preset["mods"].Vector().emplace_back(mod.first); | ||||
|  | ||||
| 		for(const auto & submod : mod.second["mods"].Struct()) | ||||
| 			preset["settings"][mod.first][submod.first] = submod.second["active"]; | ||||
| @@ -176,6 +202,15 @@ std::map<TModID, bool> ModsPresetState::getModSettings(const TModID & modID) con | ||||
| 	return modSettings; | ||||
| } | ||||
|  | ||||
| std::optional<uint32_t> ModsPresetState::getValidatedChecksum(const TModID & modName) const | ||||
| { | ||||
| 	const JsonNode & node = modConfig["validatedMods"][modName]; | ||||
| 	if (node.isNull()) | ||||
| 		return std::nullopt; | ||||
| 	else | ||||
| 		return node.Integer(); | ||||
| } | ||||
|  | ||||
| void ModsPresetState::setSettingActiveInPreset(const TModID & modName, const TModID & settingName, bool isActive) | ||||
| { | ||||
| 	const std::string & currentPresetName = modConfig["activePreset"].String(); | ||||
| @@ -212,6 +247,20 @@ std::vector<TModID> ModsPresetState::getActiveMods() const | ||||
| 	return allActiveMods; | ||||
| } | ||||
|  | ||||
| void ModsPresetState::setValidatedChecksum(const TModID & modName, std::optional<uint32_t> value) | ||||
| { | ||||
| 	if (value.has_value()) | ||||
| 		modConfig["validatedMods"][modName].Integer() = *value; | ||||
| 	else | ||||
| 		modConfig["validatedMods"].Struct().erase(modName); | ||||
| } | ||||
|  | ||||
| void ModsPresetState::saveConfigurationState() const | ||||
| { | ||||
| 	std::fstream file(CResourceHandler::get()->getResourceName(ResourcePath("config/modSettings.json"))->c_str(), std::ofstream::out | std::ofstream::trunc); | ||||
| 	file << modConfig.toCompactString(); | ||||
| } | ||||
|  | ||||
| ModsStorage::ModsStorage(const std::vector<TModID> & modsToLoad, const JsonNode & repositoryList) | ||||
| { | ||||
| 	JsonNode coreModConfig(JsonPath::builtin("config/gameConfig.json")); | ||||
| @@ -221,10 +270,7 @@ ModsStorage::ModsStorage(const std::vector<TModID> & modsToLoad, const JsonNode | ||||
| 	for(auto modID : modsToLoad) | ||||
| 	{ | ||||
| 		if(ModScope::isScopeReserved(modID)) | ||||
| 		{ | ||||
| 			logMod->error("Can not load mod %s - this name is reserved for internal use!", modID); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		JsonNode modConfig(getModDescriptionFile(modID)); | ||||
| 		modConfig.setModScope(modID); | ||||
| @@ -273,10 +319,10 @@ ModManager::ModManager(const JsonNode & repositoryList) | ||||
| 	: modsState(std::make_unique<ModsState>()) | ||||
| 	, modsPreset(std::make_unique<ModsPresetState>()) | ||||
| { | ||||
| 	//TODO: load only active mods & all their submods in game mode? | ||||
| 	modsStorage = std::make_unique<ModsStorage>(modsState->getInstalledMods(), repositoryList); | ||||
|  | ||||
| 	eraseMissingModsFromPreset(); | ||||
| 	//TODO: load only active mods & all their submods in game mode | ||||
| 	modsStorage = std::make_unique<ModsStorage>(modsState->getAllMods(), repositoryList); | ||||
| 	addNewModsToPreset(); | ||||
|  | ||||
| 	std::vector<TModID> desiredModList = modsPreset->getActiveMods(); | ||||
| @@ -301,6 +347,26 @@ const TModList & ModManager::getActiveMods() const | ||||
| 	return activeMods; | ||||
| } | ||||
|  | ||||
| uint32_t ModManager::computeChecksum(const TModID & modName) const | ||||
| { | ||||
| 	return modsState->computeChecksum(modName); | ||||
| } | ||||
|  | ||||
| std::optional<uint32_t> ModManager::getValidatedChecksum(const TModID & modName) const | ||||
| { | ||||
| 	return modsPreset->getValidatedChecksum(modName); | ||||
| } | ||||
|  | ||||
| void ModManager::setValidatedChecksum(const TModID & modName, std::optional<uint32_t> value) | ||||
| { | ||||
| 	modsPreset->setValidatedChecksum(modName, value); | ||||
| } | ||||
|  | ||||
| void ModManager::saveConfigurationState() const | ||||
| { | ||||
| 	modsPreset->saveConfigurationState(); | ||||
| } | ||||
|  | ||||
| TModList ModManager::getAllMods() const | ||||
| { | ||||
| 	return modsStorage->getAllMods(); | ||||
| @@ -308,7 +374,7 @@ TModList ModManager::getAllMods() const | ||||
|  | ||||
| void ModManager::eraseMissingModsFromPreset() | ||||
| { | ||||
| 	const TModList & installedMods = modsState->getAllMods(); | ||||
| 	const TModList & installedMods = modsState->getInstalledMods(); | ||||
| 	const TModList & rootMods = modsPreset->getActiveRootMods(); | ||||
|  | ||||
| 	for(const auto & rootMod : rootMods) | ||||
| @@ -335,7 +401,7 @@ void ModManager::eraseMissingModsFromPreset() | ||||
|  | ||||
| void ModManager::addNewModsToPreset() | ||||
| { | ||||
| 	const TModList & installedMods = modsState->getAllMods(); | ||||
| 	const TModList & installedMods = modsState->getInstalledMods(); | ||||
|  | ||||
| 	for(const auto & modID : installedMods) | ||||
| 	{ | ||||
| @@ -421,66 +487,4 @@ void ModManager::generateLoadOrder(std::vector<TModID> modsToResolve) | ||||
| 	brokenMods = modsToResolve; | ||||
| } | ||||
|  | ||||
| //	modLoadErrors = std::make_unique<MetaString>(); | ||||
| // | ||||
| //	auto addErrorMessage = [this](const std::string & textID, const std::string & brokenModID, const std::string & missingModID) | ||||
| //	{ | ||||
| //		modLoadErrors->appendTextID(textID); | ||||
| // | ||||
| //		if (allMods.count(brokenModID)) | ||||
| //			modLoadErrors->replaceRawString(allMods.at(brokenModID).getVerificationInfo().name); | ||||
| //		else | ||||
| //			modLoadErrors->replaceRawString(brokenModID); | ||||
| // | ||||
| //		if (allMods.count(missingModID)) | ||||
| //			modLoadErrors->replaceRawString(allMods.at(missingModID).getVerificationInfo().name); | ||||
| //		else | ||||
| //			modLoadErrors->replaceRawString(missingModID); | ||||
| // | ||||
| //	}; | ||||
| // | ||||
| //	// Left mods have unresolved dependencies, output all to log. | ||||
| //	for(const auto & brokenModID : modsToResolve) | ||||
| //	{ | ||||
| //		const CModInfo & brokenMod = allMods.at(brokenModID); | ||||
| //		bool showErrorMessage = false; | ||||
| //		for(const TModID & dependency : brokenMod.dependencies) | ||||
| //		{ | ||||
| //			if(!vstd::contains(resolvedModIDs, dependency) && brokenMod.config["modType"].String() != "Compatibility") | ||||
| //			{ | ||||
| //				addErrorMessage("vcmi.server.errors.modNoDependency", brokenModID, dependency); | ||||
| //				showErrorMessage = true; | ||||
| //			} | ||||
| //		} | ||||
| //		for(const TModID & conflict : brokenMod.conflicts) | ||||
| //		{ | ||||
| //			if(vstd::contains(resolvedModIDs, conflict)) | ||||
| //			{ | ||||
| //				addErrorMessage("vcmi.server.errors.modConflict", brokenModID, conflict); | ||||
| //				showErrorMessage = true; | ||||
| //			} | ||||
| //		} | ||||
| //		for(const TModID & reverseConflict : resolvedModIDs) | ||||
| //		{ | ||||
| //			if (vstd::contains(allMods.at(reverseConflict).conflicts, brokenModID)) | ||||
| //			{ | ||||
| //				addErrorMessage("vcmi.server.errors.modConflict", brokenModID, reverseConflict); | ||||
| //				showErrorMessage = true; | ||||
| //			} | ||||
| //		} | ||||
| // | ||||
| //		// some mods may in a (soft) dependency loop. | ||||
| //		if(!showErrorMessage && brokenMod.config["modType"].String() != "Compatibility") | ||||
| //		{ | ||||
| //			modLoadErrors->appendTextID("vcmi.server.errors.modDependencyLoop"); | ||||
| //			if (allMods.count(brokenModID)) | ||||
| //				modLoadErrors->replaceRawString(allMods.at(brokenModID).getVerificationInfo().name); | ||||
| //			else | ||||
| //				modLoadErrors->replaceRawString(brokenModID); | ||||
| //		} | ||||
| // | ||||
| //	} | ||||
| //	return sortedValidMods; | ||||
| //} | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
|   | ||||
| @@ -31,7 +31,9 @@ class ModsState : boost::noncopyable | ||||
| public: | ||||
| 	ModsState(); | ||||
|  | ||||
| 	TModList getAllMods() const; | ||||
| 	TModList getInstalledMods() const; | ||||
|  | ||||
| 	uint32_t computeChecksum(const TModID & modName) const; | ||||
| }; | ||||
|  | ||||
| /// Provides interface to access or change current mod preset | ||||
| @@ -39,8 +41,6 @@ class ModsPresetState : boost::noncopyable | ||||
| { | ||||
| 	JsonNode modConfig; | ||||
|  | ||||
| 	void saveConfiguration(const JsonNode & config); | ||||
|  | ||||
| 	void createInitialPreset(); | ||||
| 	void importInitialPreset(); | ||||
|  | ||||
| @@ -61,6 +61,10 @@ public: | ||||
|  | ||||
| 	/// Returns list of all known settings (submods) for a specified mod | ||||
| 	std::map<TModID, bool> getModSettings(const TModID & modID) const; | ||||
| 	std::optional<uint32_t> getValidatedChecksum(const TModID & modName) const; | ||||
| 	void setValidatedChecksum(const TModID & modName, std::optional<uint32_t> value); | ||||
|  | ||||
| 	void saveConfigurationState() const; | ||||
| }; | ||||
|  | ||||
| /// Provides access to mod properties | ||||
| @@ -101,7 +105,12 @@ public: | ||||
| 	const ModDescription & getModDescription(const TModID & modID) const; | ||||
| 	const TModList & getActiveMods() const; | ||||
| 	TModList getAllMods() const; | ||||
|  | ||||
| 	bool isModActive(const TModID & modID) const; | ||||
| 	uint32_t computeChecksum(const TModID & modName) const; | ||||
| 	std::optional<uint32_t> getValidatedChecksum(const TModID & modName) const; | ||||
| 	void setValidatedChecksum(const TModID & modName, std::optional<uint32_t> value); | ||||
| 	void saveConfigurationState() const; | ||||
| }; | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
|   | ||||
| @@ -116,7 +116,7 @@ JsonNode toJson(QVariant object) | ||||
| void jsonToFile(QString filename, const JsonNode & object) | ||||
| { | ||||
| 	std::fstream file(qstringToPath(filename).c_str(), std::ios::out | std::ios_base::binary); | ||||
| 	file << object.toString(); | ||||
| 	file << object.toCompactString(); | ||||
| } | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user