mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Verifying mods before starting map
This commit is contained in:
		| @@ -131,6 +131,15 @@ void CLobbyScreen::startScenario(bool allowOnlyAI) | ||||
| 		CSH->sendStartGame(allowOnlyAI); | ||||
| 		buttonStart->block(true); | ||||
| 	} | ||||
| 	catch(CModHandler::Incompatibility & e) | ||||
| 	{ | ||||
| 		logGlobal->warn("Incompatibility exception during start scenario: %s", e.what()); | ||||
| 		 | ||||
| 		auto errorMsg = VLC->generaltexth->translate("vcmi.server.errors.modsIncompatibility") + '\n'; | ||||
| 		errorMsg += e.what(); | ||||
| 		 | ||||
| 		CInfoWindow::showInfoDialog(errorMsg, CInfoWindow::TCompsInfo(), PlayerColor(1)); | ||||
| 	} | ||||
| 	catch(std::exception & e) | ||||
| 	{ | ||||
| 		logGlobal->error("Exception during startScenario: %s", e.what()); | ||||
|   | ||||
| @@ -967,6 +967,11 @@ std::vector<std::string> CModHandler::getActiveMods() | ||||
| 	return activeMods; | ||||
| } | ||||
|  | ||||
| const CModInfo & CModHandler::getModInfo(const TModID & modId) const | ||||
| { | ||||
| 	return allMods.at(modId); | ||||
| } | ||||
|  | ||||
| static JsonNode genDefaultFS() | ||||
| { | ||||
| 	// default FS config for mods: directory "Content" that acts as H3 root directory | ||||
|   | ||||
| @@ -174,7 +174,7 @@ public: | ||||
| 	const ContentTypeHandler & operator[] (const std::string & name) const; | ||||
| }; | ||||
|  | ||||
| typedef std::string TModID; | ||||
| using TModID = std::string; | ||||
|  | ||||
| class DLL_LINKAGE CModInfo | ||||
| { | ||||
| @@ -347,6 +347,8 @@ public: | ||||
| 	/// returns list of all (active) mods | ||||
| 	std::vector<std::string> getAllMods(); | ||||
| 	std::vector<std::string> getActiveMods(); | ||||
| 	 | ||||
| 	const CModInfo & getModInfo(const TModID & modId) const; | ||||
|  | ||||
| 	/// load content from all available mods | ||||
| 	void load(); | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
| #include "mapping/CMapInfo.h" | ||||
| #include "mapping/CCampaignHandler.h" | ||||
| #include "mapping/CMap.h" | ||||
| #include "mapping/CMapService.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| @@ -67,8 +68,16 @@ std::string StartInfo::getCampaignName() const | ||||
|  | ||||
| void LobbyInfo::verifyStateBeforeStart(bool ignoreNoHuman) const | ||||
| { | ||||
| 	if(!mi) | ||||
| 	if(!mi || !mi->mapHeader) | ||||
| 		throw std::domain_error("ExceptionMapMissing"); | ||||
| 	 | ||||
| 	auto missingMods = CMapService::verifyMapHeaderMods(*mi->mapHeader); | ||||
| 	CModHandler::Incompatibility::ModList modList; | ||||
| 	for(const auto & m : missingMods) | ||||
| 		modList.push_back({m.first, m.second.toString()}); | ||||
| 	 | ||||
| 	if(!modList.empty()) | ||||
| 		throw CModHandler::Incompatibility(std::move(modList)); | ||||
|  | ||||
| 	//there must be at least one human player before game can be started | ||||
| 	std::map<PlayerColor, PlayerSettings>::const_iterator i; | ||||
|   | ||||
| @@ -275,6 +275,10 @@ enum EMapFormat: ui8 | ||||
| }; | ||||
| } | ||||
|  | ||||
| // Inherit from container to enable forward declaration | ||||
| class ModCompatibilityInfo: public std::map<TModID, CModInfo::Version> | ||||
| {}; | ||||
|  | ||||
| /// The map header holds information about loss/victory condition,map format, version, players, height, width,... | ||||
| class DLL_LINKAGE CMapHeader | ||||
| { | ||||
| @@ -295,7 +299,7 @@ public: | ||||
| 	ui8 levels() const; | ||||
|  | ||||
| 	EMapFormat::EMapFormat version; /// The default value is EMapFormat::SOD. | ||||
| 	std::map<TModID, CModInfo::Version> mods; /// set of mods required to play a map | ||||
| 	ModCompatibilityInfo mods; /// set of mods required to play a map | ||||
| 	 | ||||
| 	si32 height; /// The default value is 72. | ||||
| 	si32 width; /// The default value is 72. | ||||
|   | ||||
| @@ -86,6 +86,24 @@ void CMapService::saveMap(const std::unique_ptr<CMap> & map, boost::filesystem:: | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ModCompatibilityInfo CMapService::verifyMapHeaderMods(const CMapHeader & map) | ||||
| { | ||||
| 	ModCompatibilityInfo modCompatibilityInfo; | ||||
| 	const auto & activeMods = VLC->modh->getActiveMods(); | ||||
| 	for(const auto & mapMod : map.mods) | ||||
| 	{ | ||||
| 		if(vstd::contains(activeMods, mapMod.first)) | ||||
| 		{ | ||||
| 			const auto & modInfo = VLC->modh->getModInfo(mapMod.first); | ||||
| 			if(modInfo.version.compatible(mapMod.second)) | ||||
| 				continue; | ||||
| 		} | ||||
| 		 | ||||
| 		modCompatibilityInfo[mapMod.first] = mapMod.second; | ||||
| 	}	 | ||||
| 	return modCompatibilityInfo; | ||||
| } | ||||
|  | ||||
| std::unique_ptr<CInputStream> CMapService::getStreamFromFS(const ResourceID & name) | ||||
| { | ||||
| 	return CResourceHandler::get()->load(name); | ||||
|   | ||||
| @@ -21,6 +21,8 @@ class CInputStream; | ||||
| class IMapLoader; | ||||
| class IMapPatcher; | ||||
|  | ||||
| class ModCompatibilityInfo; | ||||
|  | ||||
| /** | ||||
|  * The map service provides loading and saving of VCMI/H3 map files. | ||||
|  */ | ||||
| @@ -74,7 +76,15 @@ public: | ||||
| 	 */ | ||||
| 	std::unique_ptr<CMapHeader> loadMapHeader(const ui8 * buffer, int size, const std::string & name, const std::string & modName, const std::string & encoding) const; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Tests if mods used in the map are currently loaded | ||||
| 	 * @param map const reference to map header | ||||
| 	 * @return data structure representing missing or incompatible mods (those which are needed from map but not loaded) | ||||
| 	 */ | ||||
| 	static ModCompatibilityInfo verifyMapHeaderMods(const CMapHeader & map); | ||||
| 	 | ||||
| 	void saveMap(const std::unique_ptr<CMap> & map, boost::filesystem::path fullPath) const; | ||||
| 	 | ||||
| private: | ||||
| 	/** | ||||
| 	 * Gets a map input stream object specified by a map name. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user