| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 | /* * CModInfo.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */#include "StdInc.h"#include "CModInfo.h"#include "../texts/CGeneralTextHandler.h"#include "../VCMI_Lib.h"#include "../filesystem/Filesystem.h"VCMI_LIB_NAMESPACE_BEGINstatic JsonNode addMeta(JsonNode config, const std::string & meta){	config.setModScope(meta);	return config;}std::set<TModID> CModInfo::readModList(const JsonNode & input){	std::set<TModID> result;	for (auto const & string : input.convertTo<std::set<std::string>>())		result.insert(boost::to_lower_copy(string));	return result;}CModInfo::CModInfo():	explicitlyEnabled(false),	implicitlyEnabled(true),	validation(PENDING){}CModInfo::CModInfo(const std::string & identifier, const JsonNode & local, const JsonNode & config):	identifier(identifier),	dependencies(readModList(config["depends"])),	conflicts(readModList(config["conflicts"])),	explicitlyEnabled(false),	implicitlyEnabled(true),	validation(PENDING),	config(addMeta(config, identifier)){	if (!config["name"].String().empty())		verificationInfo.name = config["name"].String();	else		verificationInfo.name = identifier;	verificationInfo.version = CModVersion::fromString(config["version"].String());	verificationInfo.parent = identifier.substr(0, identifier.find_last_of('.'));	if(verificationInfo.parent == identifier)		verificationInfo.parent.clear();	if(!config["compatibility"].isNull())	{		vcmiCompatibleMin = CModVersion::fromString(config["compatibility"]["min"].String());		vcmiCompatibleMax = CModVersion::fromString(config["compatibility"]["max"].String());	}	if (!config["language"].isNull())		baseLanguage = config["language"].String();	else		baseLanguage = "english";	loadLocalData(local);}JsonNode CModInfo::saveLocalData() const{	std::ostringstream stream;	stream << std::noshowbase << std::hex << std::setw(8) << std::setfill('0') << verificationInfo.checksum;	JsonNode conf;	conf["active"].Bool() = explicitlyEnabled;	conf["validated"].Bool() = validation != FAILED;	conf["checksum"].String() = stream.str();	return conf;}std::string CModInfo::getModDir(const std::string & name){	return "MODS/" + boost::algorithm::replace_all_copy(name, ".", "/MODS/");}JsonPath CModInfo::getModFile(const std::string & name){	return JsonPath::builtinTODO(getModDir(name) + "/mod.json");}void CModInfo::updateChecksum(ui32 newChecksum){	// comment-out next line to force validation of all mods ignoring checksum	if (newChecksum != verificationInfo.checksum)	{		verificationInfo.checksum = newChecksum;		validation = PENDING;	}}void CModInfo::loadLocalData(const JsonNode & data){	bool validated = false;	implicitlyEnabled = true;	explicitlyEnabled = !config["keepDisabled"].Bool();	verificationInfo.checksum = 0;	if (data.isStruct())	{		explicitlyEnabled = data["active"].Bool();		validated = data["validated"].Bool();		updateChecksum(strtol(data["checksum"].String().c_str(), nullptr, 16));	}	//check compatibility	implicitlyEnabled &= (vcmiCompatibleMin.isNull() || CModVersion::GameVersion().compatible(vcmiCompatibleMin, true, true));	implicitlyEnabled &= (vcmiCompatibleMax.isNull() || vcmiCompatibleMax.compatible(CModVersion::GameVersion(), true, true));	if(!implicitlyEnabled)		logGlobal->warn("Mod %s is incompatible with current version of VCMI and cannot be enabled", verificationInfo.name);	if (config["modType"].String() == "Translation")	{		if (baseLanguage != CGeneralTextHandler::getPreferredLanguage())		{			if (identifier.find_last_of('.') == std::string::npos)				logGlobal->warn("Translation mod %s was not loaded: language mismatch!", verificationInfo.name);			implicitlyEnabled = false;		}	}	if (config["modType"].String() == "Compatibility")	{		// compatibility mods are always explicitly enabled		// however they may be implicitly disabled - if one of their dependencies is missing		explicitlyEnabled = true;	}	if (isEnabled())		validation = validated ? PASSED : PENDING;	else		validation = validated ? PASSED : FAILED;	verificationInfo.impactsGameplay = checkModGameplayAffecting();}bool CModInfo::checkModGameplayAffecting() const{	if (modGameplayAffecting.has_value())		return *modGameplayAffecting;	static const std::vector<std::string> keysToTest = {		"heroClasses",		"artifacts",		"creatures",		"factions",		"objects",		"heroes",		"spells",		"skills",		"templates",		"scripts",		"battlefields",		"terrains",		"rivers",		"roads",		"obstacles"	};	JsonPath modFileResource(CModInfo::getModFile(identifier));	if(CResourceHandler::get("initial")->existsResource(modFileResource))	{		const JsonNode modConfig(modFileResource);		for(const auto & key : keysToTest)		{			if (!modConfig[key].isNull())			{				modGameplayAffecting = true;				return *modGameplayAffecting;			}		}	}	modGameplayAffecting = false;	return *modGameplayAffecting;}const ModVerificationInfo & CModInfo::getVerificationInfo() const{	assert(!verificationInfo.name.empty());	return verificationInfo;}bool CModInfo::isEnabled() const{	return implicitlyEnabled && explicitlyEnabled;}VCMI_LIB_NAMESPACE_END
 |