1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00

Verifying mods before starting map

This commit is contained in:
nordsoft 2023-04-16 15:38:13 +04:00
parent 67e1b48d47
commit 954a2abb71
7 changed files with 60 additions and 3 deletions

View File

@ -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());

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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.