1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Add system message about mods incompatibility

This commit is contained in:
nordsoft 2022-09-23 15:02:19 +04:00
parent 2b0f02c832
commit e74890c4b1
11 changed files with 95 additions and 24 deletions

View File

@ -546,6 +546,11 @@ void CServerHandler::startCampaignScenario(std::shared_ptr<CCampaignState> cs)
SDL_PushEvent(&event);
}
void CServerHandler::showServerError(std::string txt)
{
CInfoWindow::showInfoDialog(txt, {});
}
int CServerHandler::howManyPlayerInterfaces()
{
int playerInts = 0;

View File

@ -137,6 +137,7 @@ public:
void startGameplay();
void endGameplay(bool closeConnection = true, bool restart = false);
void startCampaignScenario(std::shared_ptr<CCampaignState> cs = {});
void showServerError(std::string txt);
// TODO: LobbyState must be updated within game so we should always know how many player interfaces our client handle
int howManyPlayerInterfaces();

View File

@ -137,3 +137,9 @@ void LobbyUpdateState::applyOnLobbyScreen(CLobbyScreen * lobby, CServerHandler *
if(hostChanged)
lobby->toggleMode(handler->isHost());
}
void LobbyShowMessage::applyOnLobbyScreen(CLobbyScreen * lobby, CServerHandler * handler)
{
lobby->buttonStart->block(false);
handler->showServerError(message);
}

View File

@ -276,11 +276,34 @@ class DLL_LINKAGE CModHandler
void loadOneMod(std::string modName, std::string parent, const JsonNode & modSettings, bool enableMods);
public:
class Incompatibility: public std::logic_error
class DLL_LINKAGE Incompatibility: public std::logic_error
{
public:
Incompatibility(const std::string & w): std::logic_error(w)
{}
using StringPair = std::pair<const std::string, const std::string>;
using ModList = std::list<StringPair>;
Incompatibility(ModList && _missingMods):
std::logic_error("Mods are required to load game"),
missingMods(std::move(_missingMods))
{
std::ostringstream _ss;
_ss << std::logic_error::what() << std::endl;
for(auto & m : missingMods)
_ss << m.first << ' ' << m.second << std::endl;
message = _ss.str();
}
const char * what() const noexcept override
{
return message.c_str();
}
private:
//list of mods required to load the game
// first: mod name
// second: mod version
const ModList missingMods;
std::string message;
};
CIdentifierStorage identifiers;
@ -366,7 +389,6 @@ public:
{
h & activeMods;
for(const auto & m : activeMods)
h & allMods[m].version;
}
else
@ -374,22 +396,22 @@ public:
loadMods();
std::vector<TModID> newActiveMods;
h & newActiveMods;
Incompatibility::ModList missingMods;
for(auto & m : newActiveMods)
{
if(!allMods.count(m))
throw Incompatibility(m + " unkown mod");
CModInfo::Version mver;
h & mver;
if(!allMods[m].version.isNull() && !mver.isNull() && !allMods[m].version.compatible(mver))
{
std::string err = allMods[m].name +
": version needed " + mver.toString() +
"but you have installed " + allMods[m].version.toString();
throw Incompatibility(err);
}
allMods[m].enabled = true;
if(allMods.count(m) && (allMods[m].version.isNull() || mver.isNull() || allMods[m].version.compatible(mver)))
allMods[m].enabled = true;
else
missingMods.emplace_back(m, mver.toString());
}
if(!missingMods.empty())
throw Incompatibility(std::move(missingMods));
std::swap(activeMods, newActiveMods);
}

View File

@ -309,3 +309,15 @@ struct LobbyForceSetPlayer : public CLobbyPackToServer
h & targetPlayerColor;
}
};
struct LobbyShowMessage : public CLobbyPackToPropagate
{
std::string message;
void applyOnLobbyScreen(CLobbyScreen * lobby, CServerHandler * handler);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & message;
}
};

View File

@ -374,6 +374,7 @@ void registerTypesLobbyPacks(Serializer &s)
s.template registerType<CLobbyPackToPropagate, LobbyChangeHost>();
// Only server send
s.template registerType<CLobbyPackToPropagate, LobbyUpdateState>();
s.template registerType<CLobbyPackToPropagate, LobbyShowMessage>();
// For client with permissions
s.template registerType<CLobbyPackToServer, LobbyChangePlayerOption>();

View File

@ -2967,7 +2967,7 @@ void CGameHandler::save(const std::string & filename)
}
}
void CGameHandler::load(const std::string & filename)
bool CGameHandler::load(const std::string & filename)
{
logGlobal->info("Loading from %s", filename);
const auto stem = FileInfo::GetPathStem(filename);
@ -2984,12 +2984,20 @@ void CGameHandler::load(const std::string & filename)
}
logGlobal->info("Game has been successfully loaded!");
}
catch(std::exception &e)
catch(const CModHandler::Incompatibility & e)
{
logGlobal->error("Failed to load game: %s", e.what());
lobby->announceMessage(e.what());
return false;
}
catch(const std::exception & e)
{
logGlobal->error("Failed to load game: %s", e.what());
return false;
}
gs->preInit(VLC);
gs->updateOnLoad(lobby->si.get());
return true;
}
bool CGameHandler::bulkSplitStack(SlotID slotSrc, ObjectInstanceID srcOwner, si32 howMany)

View File

@ -257,7 +257,7 @@ public:
bool bulkMergeStacks(SlotID slotSrc, ObjectInstanceID srcOwner);
bool bulkSmartSplitStack(SlotID slotSrc, ObjectInstanceID srcOwner);
void save(const std::string &fname);
void load(const std::string &fname);
bool load(const std::string &fname);
void handleTimeEvents();
void handleTownEvents(CGTownInstance *town, NewTurn &n);

View File

@ -223,7 +223,7 @@ void CVCMIServer::threadAnnounceLobby()
}
}
void CVCMIServer::prepareToStartGame()
bool CVCMIServer::prepareToStartGame()
{
if(state == EServerState::GAMEPLAY)
{
@ -234,8 +234,9 @@ void CVCMIServer::prepareToStartGame()
// FIXME: dirry hack to make sure old CGameHandler::run is finished
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
}
state = EServerState::GAMEPLAY_STARTING;
gh = std::make_shared<CGameHandler>(this);
if(!gh)
gh = std::make_shared<CGameHandler>(this);
switch(si->mode)
{
case StartInfo::CAMPAIGN:
@ -252,13 +253,17 @@ void CVCMIServer::prepareToStartGame()
case StartInfo::LOAD_GAME:
logNetwork->info("Preparing to start loaded game");
gh->load(si->mapname);
if(!gh->load(si->mapname))
return false;
break;
default:
logNetwork->error("Wrong mode in StartInfo!");
assert(0);
break;
}
state = EServerState::GAMEPLAY_STARTING;
return true;
}
void CVCMIServer::startGameImmidiately()
@ -384,6 +389,14 @@ void CVCMIServer::announcePack(std::unique_ptr<CPackForLobby> pack)
applier->getApplier(typeList.getTypeID(pack.get()))->applyOnServerAfter(this, pack.get());
}
void CVCMIServer::announceMessage(const std::string & txt)
{
logNetwork->info("Show message: %s", txt);
auto cm = vstd::make_unique<LobbyShowMessage>();
cm->message = txt;
addToAnnounceQueue(std::move(cm));
}
void CVCMIServer::announceTxt(const std::string & txt, const std::string & playerName)
{
logNetwork->info("%s says: %s", playerName, txt);

View File

@ -63,7 +63,7 @@ public:
CVCMIServer(boost::program_options::variables_map & opts);
~CVCMIServer();
void run();
void prepareToStartGame();
bool prepareToStartGame();
void startGameImmidiately();
void startAsyncAccept();
@ -76,6 +76,7 @@ public:
bool passHost(int toConnectionId);
void announceTxt(const std::string & txt, const std::string & playerName = "system");
void announceMessage(const std::string & txt);
void addToAnnounceQueue(std::unique_ptr<CPackForLobby> pack);
void setPlayerConnectedId(PlayerSettings & pset, ui8 player) const;

View File

@ -177,7 +177,9 @@ bool LobbyStartGame::applyOnServer(CVCMIServer * srv)
return false;
}
// Server will prepare gamestate and we announce StartInfo to clients
srv->prepareToStartGame();
if(!srv->prepareToStartGame())
return false;
initializedStartInfo = std::make_shared<StartInfo>(*srv->gh->getStartInfo(true));
return true;
}