mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
Merge pull request #975 from Nordsoft91/incomatibility-response
Incompatibility response
This commit is contained in:
commit
27dbee6069
@ -580,6 +580,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;
|
||||
|
@ -145,6 +145,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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -31,7 +31,8 @@
|
||||
{
|
||||
"errors" :
|
||||
{
|
||||
"existingProcess" : "Another vcmiserver process is running, please terminate it first"
|
||||
"existingProcess" : "Another vcmiserver process is running, please terminate it first",
|
||||
"modsIncompatibility" : "Required mods to load game:"
|
||||
}
|
||||
},
|
||||
"systemOptions" :
|
||||
|
@ -278,11 +278,32 @@ 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::exception
|
||||
{
|
||||
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):
|
||||
missingMods(std::move(_missingMods))
|
||||
{
|
||||
std::ostringstream _ss;
|
||||
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;
|
||||
@ -368,7 +389,6 @@ public:
|
||||
{
|
||||
h & activeMods;
|
||||
for(const auto & m : activeMods)
|
||||
|
||||
h & allMods[m].version;
|
||||
}
|
||||
else
|
||||
@ -376,22 +396,23 @@ public:
|
||||
loadMods();
|
||||
std::vector<TModID> newActiveMods;
|
||||
h & newActiveMods;
|
||||
for(auto & m : newActiveMods)
|
||||
|
||||
Incompatibility::ModList missingMods;
|
||||
for(const 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);
|
||||
}
|
||||
|
||||
|
@ -313,4 +313,16 @@ struct LobbyForceSetPlayer : public CLobbyPackToServer
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -376,6 +376,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>();
|
||||
|
@ -2969,7 +2969,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);
|
||||
@ -2986,12 +2986,22 @@ 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());
|
||||
auto errorMsg = VLC->generaltexth->localizedTexts["server"]["errors"]["modsIncompatibility"].String() + '\n';
|
||||
errorMsg += e.what();
|
||||
lobby->announceMessage(errorMsg);
|
||||
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)
|
||||
|
@ -262,7 +262,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);
|
||||
|
@ -220,7 +220,7 @@ void CVCMIServer::threadAnnounceLobby()
|
||||
}
|
||||
}
|
||||
|
||||
void CVCMIServer::prepareToStartGame()
|
||||
bool CVCMIServer::prepareToStartGame()
|
||||
{
|
||||
if(state == EServerState::GAMEPLAY)
|
||||
{
|
||||
@ -231,8 +231,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:
|
||||
@ -249,13 +250,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()
|
||||
@ -381,6 +386,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);
|
||||
|
@ -68,7 +68,7 @@ public:
|
||||
CVCMIServer(boost::program_options::variables_map & opts);
|
||||
~CVCMIServer();
|
||||
void run();
|
||||
void prepareToStartGame();
|
||||
bool prepareToStartGame();
|
||||
void startGameImmidiately();
|
||||
|
||||
void startAsyncAccept();
|
||||
@ -81,6 +81,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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user