1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-23 00:28:08 +02:00

Fixes and cleanup of game client network shutdown and restart

This commit is contained in:
Ivan Savenko
2024-02-03 19:08:45 +02:00
parent 6eef197cea
commit 2c2bec791c
17 changed files with 102 additions and 146 deletions

View File

@ -131,12 +131,12 @@ CServerHandler::~CServerHandler()
networkHandler->stop(); networkHandler->stop();
try try
{ {
threadNetwork->join(); threadNetwork.join();
} }
catch (const std::runtime_error & e) catch (const std::runtime_error & e)
{ {
logGlobal->error("Failed to shut down network thread! Reason: %s", e.what()); logGlobal->error("Failed to shut down network thread! Reason: %s", e.what());
assert(false); assert(0);
} }
} }
@ -144,17 +144,16 @@ CServerHandler::CServerHandler()
: applier(std::make_unique<CApplier<CBaseForLobbyApply>>()) : applier(std::make_unique<CApplier<CBaseForLobbyApply>>())
, lobbyClient(std::make_unique<GlobalLobbyClient>()) , lobbyClient(std::make_unique<GlobalLobbyClient>())
, networkHandler(INetworkHandler::createHandler()) , networkHandler(INetworkHandler::createHandler())
, threadNetwork(&CServerHandler::threadRunNetwork, this)
, state(EClientState::NONE) , state(EClientState::NONE)
, campaignStateToSend(nullptr) , campaignStateToSend(nullptr)
, screenType(ESelectionScreen::unknown) , screenType(ESelectionScreen::unknown)
, serverMode(EServerMode::NONE) , serverMode(EServerMode::NONE)
, loadMode(ELoadMode::NONE) , loadMode(ELoadMode::NONE)
, client(nullptr) , client(nullptr)
, campaignServerRestartLock(false)
{ {
uuid = boost::uuids::to_string(boost::uuids::random_generator()()); uuid = boost::uuids::to_string(boost::uuids::random_generator()());
registerTypesLobbyPacks(*applier); registerTypesLobbyPacks(*applier);
threadNetwork = std::make_unique<boost::thread>(&CServerHandler::threadRunNetwork, this);
} }
void CServerHandler::threadRunNetwork() void CServerHandler::threadRunNetwork()
@ -192,8 +191,8 @@ GlobalLobbyClient & CServerHandler::getGlobalLobby()
void CServerHandler::startLocalServerAndConnect(bool connectToLobby) void CServerHandler::startLocalServerAndConnect(bool connectToLobby)
{ {
if(threadRunLocalServer) if(threadRunLocalServer.joinable())
threadRunLocalServer->join(); threadRunLocalServer.join();
th->update(); th->update();
@ -203,19 +202,17 @@ void CServerHandler::startLocalServerAndConnect(bool connectToLobby)
if(connectToLobby) if(connectToLobby)
args.push_back("--lobby"); args.push_back("--lobby");
threadRunLocalServer = std::make_unique<boost::thread>([&cond, args, this] { threadRunLocalServer = boost::thread([&cond, args] {
setThreadName("CVCMIServer"); setThreadName("CVCMIServer");
CVCMIServer::create(&cond, args); CVCMIServer::create(&cond, args);
onServerFinished();
}); });
threadRunLocalServer->detach();
#elif defined(VCMI_ANDROID) #elif defined(VCMI_ANDROID)
{ {
CAndroidVMHelper envHelper; CAndroidVMHelper envHelper;
envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "startServer", true); envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "startServer", true);
} }
#else #else
threadRunLocalServer = std::make_unique<boost::thread>(&CServerHandler::threadRunServer, this, connectToLobby); //runs server executable; threadRunLocalServer = boost::thread(&CServerHandler::threadRunServer, this, connectToLobby); //runs server executable;
#endif #endif
logNetwork->trace("Setting up thread calling server: %d ms", th->getDiff()); logNetwork->trace("Setting up thread calling server: %d ms", th->getDiff());
@ -357,10 +354,7 @@ ui8 CServerHandler::myFirstId() const
bool CServerHandler::isServerLocal() const bool CServerHandler::isServerLocal() const
{ {
if(threadRunLocalServer) return threadRunLocalServer.joinable();
return true;
return false;
} }
bool CServerHandler::isHost() const bool CServerHandler::isHost() const
@ -416,7 +410,10 @@ void CServerHandler::sendClientDisconnecting()
{ {
// FIXME: This is workaround needed to make sure client not trying to sent anything to non existed server // FIXME: This is workaround needed to make sure client not trying to sent anything to non existed server
if(state == EClientState::DISCONNECTING) if(state == EClientState::DISCONNECTING)
{
assert(0);
return; return;
}
state = EClientState::DISCONNECTING; state = EClientState::DISCONNECTING;
mapToStart = nullptr; mapToStart = nullptr;
@ -433,12 +430,8 @@ void CServerHandler::sendClientDisconnecting()
logNetwork->info("Sent leaving signal to the server"); logNetwork->info("Sent leaving signal to the server");
} }
sendLobbyPack(lcd); sendLobbyPack(lcd);
c->getConnection()->close();
{
// Network thread might be applying network pack at this moment
auto unlockInterface = vstd::makeUnlockGuard(GH.interfaceMutex);
c.reset(); c.reset();
}
} }
void CServerHandler::setCampaignState(std::shared_ptr<CampaignState> newCampaign) void CServerHandler::setCampaignState(std::shared_ptr<CampaignState> newCampaign)
@ -585,9 +578,7 @@ void CServerHandler::sendRestartGame() const
{ {
GH.windows().createAndPushWindow<CLoadingScreen>(); GH.windows().createAndPushWindow<CLoadingScreen>();
LobbyEndGame endGame; LobbyRestartGame endGame;
endGame.closeConnection = false;
endGame.restart = true;
sendLobbyPack(endGame); sendLobbyPack(endGame);
} }
@ -676,21 +667,16 @@ void CServerHandler::startGameplay(VCMI_LIB_WRAP_NAMESPACE(CGameState) * gameSta
state = EClientState::GAMEPLAY; state = EClientState::GAMEPLAY;
} }
void CServerHandler::endGameplay(bool closeConnection, bool restart) void CServerHandler::endGameplay()
{ {
if(closeConnection)
{
// Game is ending // Game is ending
// Tell the network thread to reach a stable state // Tell the network thread to reach a stable state
CSH->sendClientDisconnecting(); CSH->sendClientDisconnecting();
logNetwork->info("Closed connection."); logNetwork->info("Closed connection.");
}
client->endGame(); client->endGame();
client.reset(); client.reset();
if(!restart)
{
if(CMM) if(CMM)
{ {
GH.curInt = CMM.get(); GH.curInt = CMM.get();
@ -700,14 +686,16 @@ void CServerHandler::endGameplay(bool closeConnection, bool restart)
{ {
GH.curInt = CMainMenu::create().get(); GH.curInt = CMainMenu::create().get();
} }
} }
void CServerHandler::restartGameplay()
{
client->endGame();
client.reset();
if(c)
{
nextClient = std::make_unique<CClient>(); nextClient = std::make_unique<CClient>();
c->setCallback(nextClient.get()); c->setCallback(nextClient.get());
c->enterLobbyConnectionMode(); c->enterLobbyConnectionMode();
}
} }
void CServerHandler::startCampaignScenario(HighScoreParameter param, std::shared_ptr<CampaignState> cs) void CServerHandler::startCampaignScenario(HighScoreParameter param, std::shared_ptr<CampaignState> cs)
@ -728,7 +716,6 @@ void CServerHandler::startCampaignScenario(HighScoreParameter param, std::shared
GH.dispatchMainThread([ourCampaign, this]() GH.dispatchMainThread([ourCampaign, this]()
{ {
CSH->campaignServerRestartLock.set(true);
CSH->endGameplay(); CSH->endGameplay();
auto & epilogue = ourCampaign->scenario(*ourCampaign->lastScenario()).epilog; auto & epilogue = ourCampaign->scenario(*ourCampaign->lastScenario()).epilog;
@ -751,13 +738,14 @@ void CServerHandler::startCampaignScenario(HighScoreParameter param, std::shared
GH.windows().createAndPushWindow<CHighScoreInputScreen>(true, *highScoreCalc); GH.windows().createAndPushWindow<CHighScoreInputScreen>(true, *highScoreCalc);
} }
}; };
threadRunLocalServer.join();
if(epilogue.hasPrologEpilog) if(epilogue.hasPrologEpilog)
{ {
GH.windows().createAndPushWindow<CPrologEpilogVideo>(epilogue, finisher); GH.windows().createAndPushWindow<CPrologEpilogVideo>(epilogue, finisher);
} }
else else
{ {
CSH->campaignServerRestartLock.waitUntil(false);
finisher(); finisher();
} }
}); });
@ -877,23 +865,19 @@ public:
void CServerHandler::onPacketReceived(const std::shared_ptr<INetworkConnection> &, const std::vector<std::byte> & message) void CServerHandler::onPacketReceived(const std::shared_ptr<INetworkConnection> &, const std::vector<std::byte> & message)
{ {
CPack * pack = c->retrievePack(message);
if(state == EClientState::DISCONNECTING) if(state == EClientState::DISCONNECTING)
{ {
// FIXME: server shouldn't really send netpacks after it's tells client to disconnect assert(0); //Should not be possible - socket must be closed at this point
// Though currently they'll be delivered and might cause crash. return;
vstd::clear_pointer(pack);
} }
else
{ CPack * pack = c->retrievePack(message);
ServerHandlerCPackVisitor visitor(*this); ServerHandlerCPackVisitor visitor(*this);
pack->visit(visitor); pack->visit(visitor);
}
} }
void CServerHandler::onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage) void CServerHandler::onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage)
{ {
assert(networkConnection == connection);
networkConnection.reset(); networkConnection.reset();
if(state == EClientState::DISCONNECTING) if(state == EClientState::DISCONNECTING)
@ -987,17 +971,9 @@ void CServerHandler::threadRunServer(bool connectToLobby)
logNetwork->error("Error: server failed to close correctly or crashed!"); logNetwork->error("Error: server failed to close correctly or crashed!");
logNetwork->error("Check %s for more info", logName); logNetwork->error("Check %s for more info", logName);
} }
onServerFinished();
#endif #endif
} }
void CServerHandler::onServerFinished()
{
threadRunLocalServer.reset();
if (CSH)
CSH->campaignServerRestartLock.setn(false);
}
void CServerHandler::sendLobbyPack(const CPackForLobby & pack) const void CServerHandler::sendLobbyPack(const CPackForLobby & pack) const
{ {
if(state != EClientState::STARTING) if(state != EClientState::STARTING)

View File

@ -111,7 +111,6 @@ class CServerHandler final : public IServerAPI, public LobbyInfo, public INetwor
/// required to correctly deserialize gamestate using client-side game callback /// required to correctly deserialize gamestate using client-side game callback
std::unique_ptr<CClient> nextClient; std::unique_ptr<CClient> nextClient;
void onServerFinished();
void sendLobbyPack(const CPackForLobby & pack) const override; void sendLobbyPack(const CPackForLobby & pack) const override;
void onPacketReceived(const NetworkConnectionPtr &, const std::vector<std::byte> & message) override; void onPacketReceived(const NetworkConnectionPtr &, const std::vector<std::byte> & message) override;
@ -145,13 +144,11 @@ public:
//////////////////// ////////////////////
std::unique_ptr<CStopWatch> th; std::unique_ptr<CStopWatch> th;
std::unique_ptr<boost::thread> threadRunLocalServer; boost::thread threadRunLocalServer;
std::unique_ptr<boost::thread> threadNetwork; boost::thread threadNetwork;
std::unique_ptr<CClient> client; std::unique_ptr<CClient> client;
CondSh<bool> campaignServerRestartLock;
CServerHandler(); CServerHandler();
~CServerHandler(); ~CServerHandler();
@ -202,7 +199,8 @@ public:
void debugStartTest(std::string filename, bool save = false); void debugStartTest(std::string filename, bool save = false);
void startGameplay(VCMI_LIB_WRAP_NAMESPACE(CGameState) * gameState = nullptr); void startGameplay(VCMI_LIB_WRAP_NAMESPACE(CGameState) * gameState = nullptr);
void endGameplay(bool closeConnection = true, bool restart = false); void endGameplay();
void restartGameplay();
void startCampaignScenario(HighScoreParameter param, std::shared_ptr<CampaignState> cs = {}); void startCampaignScenario(HighScoreParameter param, std::shared_ptr<CampaignState> cs = {});
void showServerError(const std::string & txt) const; void showServerError(const std::string & txt) const;

View File

@ -34,7 +34,7 @@ public:
virtual void visitLobbyClientConnected(LobbyClientConnected & pack) override; virtual void visitLobbyClientConnected(LobbyClientConnected & pack) override;
virtual void visitLobbyClientDisconnected(LobbyClientDisconnected & pack) override; virtual void visitLobbyClientDisconnected(LobbyClientDisconnected & pack) override;
virtual void visitLobbyEndGame(LobbyEndGame & pack) override; virtual void visitLobbyRestartGame(LobbyRestartGame & pack) override;
virtual void visitLobbyStartGame(LobbyStartGame & pack) override; virtual void visitLobbyStartGame(LobbyStartGame & pack) override;
virtual void visitLobbyUpdateState(LobbyUpdateState & pack) override; virtual void visitLobbyUpdateState(LobbyUpdateState & pack) override;
}; };

View File

@ -133,18 +133,15 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyGuiAction(LobbyGuiAction & pack
} }
} }
void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack) void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyRestartGame(LobbyRestartGame & pack)
{ {
if(handler.state == EClientState::GAMEPLAY) if(handler.state == EClientState::GAMEPLAY)
{ {
handler.endGameplay(pack.closeConnection, pack.restart); handler.restartGameplay();
} }
if(pack.restart)
{
if (handler.validateGameStart()) if (handler.validateGameStart())
handler.sendStartGame(); handler.sendStartGame();
}
} }
void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack) void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)

View File

@ -13,7 +13,7 @@
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
class NetworkConnection : public INetworkConnection, std::enable_shared_from_this<NetworkConnection> class NetworkConnection : public INetworkConnection, public std::enable_shared_from_this<NetworkConnection>
{ {
static const int messageHeaderSize = sizeof(uint32_t); static const int messageHeaderSize = sizeof(uint32_t);
static const int messageMaxSize = 64 * 1024 * 1024; // arbitrary size to prevent potential massive allocation if we receive garbage input static const int messageMaxSize = 64 * 1024 * 1024; // arbitrary size to prevent potential massive allocation if we receive garbage input

View File

@ -151,7 +151,7 @@ public:
virtual void visitLobbyChatMessage(LobbyChatMessage & pack) {} virtual void visitLobbyChatMessage(LobbyChatMessage & pack) {}
virtual void visitLobbyGuiAction(LobbyGuiAction & pack) {} virtual void visitLobbyGuiAction(LobbyGuiAction & pack) {}
virtual void visitLobbyLoadProgress(LobbyLoadProgress & pack) {} virtual void visitLobbyLoadProgress(LobbyLoadProgress & pack) {}
virtual void visitLobbyEndGame(LobbyEndGame & pack) {} virtual void visitLobbyRestartGame(LobbyRestartGame & pack) {}
virtual void visitLobbyStartGame(LobbyStartGame & pack) {} virtual void visitLobbyStartGame(LobbyStartGame & pack) {}
virtual void visitLobbyChangeHost(LobbyChangeHost & pack) {} virtual void visitLobbyChangeHost(LobbyChangeHost & pack) {}
virtual void visitLobbyUpdateState(LobbyUpdateState & pack) {} virtual void visitLobbyUpdateState(LobbyUpdateState & pack) {}

View File

@ -708,9 +708,9 @@ void LobbyLoadProgress::visitTyped(ICPackVisitor & visitor)
visitor.visitLobbyLoadProgress(*this); visitor.visitLobbyLoadProgress(*this);
} }
void LobbyEndGame::visitTyped(ICPackVisitor & visitor) void LobbyRestartGame::visitTyped(ICPackVisitor & visitor)
{ {
visitor.visitLobbyEndGame(*this); visitor.visitLobbyRestartGame(*this);
} }
void LobbyStartGame::visitTyped(ICPackVisitor & visitor) void LobbyStartGame::visitTyped(ICPackVisitor & visitor)

View File

@ -111,17 +111,12 @@ struct DLL_LINKAGE LobbyLoadProgress : public CLobbyPackToPropagate
} }
}; };
struct DLL_LINKAGE LobbyEndGame : public CLobbyPackToPropagate struct DLL_LINKAGE LobbyRestartGame : public CLobbyPackToPropagate
{ {
bool closeConnection = false;
bool restart = false;
void visitTyped(ICPackVisitor & visitor) override; void visitTyped(ICPackVisitor & visitor) override;
template <typename Handler> void serialize(Handler &h) template <typename Handler> void serialize(Handler &h)
{ {
h & closeConnection;
h & restart;
} }
}; };

View File

@ -37,7 +37,7 @@ void registerTypesLobbyPacks(Serializer &s)
// Only host client send // Only host client send
s.template registerType<CLobbyPackToPropagate, LobbyGuiAction>(); s.template registerType<CLobbyPackToPropagate, LobbyGuiAction>();
s.template registerType<CLobbyPackToPropagate, LobbyLoadProgress>(); s.template registerType<CLobbyPackToPropagate, LobbyLoadProgress>();
s.template registerType<CLobbyPackToPropagate, LobbyEndGame>(); s.template registerType<CLobbyPackToPropagate, LobbyRestartGame>();
s.template registerType<CLobbyPackToPropagate, LobbyStartGame>(); s.template registerType<CLobbyPackToPropagate, LobbyStartGame>();
s.template registerType<CLobbyPackToPropagate, LobbyChangeHost>(); s.template registerType<CLobbyPackToPropagate, LobbyChangeHost>();
// Only server send // Only server send

View File

@ -140,6 +140,7 @@ void CConnection::enterGameplayConnectionMode(CGameState * gs)
setCallback(gs->callback); setCallback(gs->callback);
packWriter->addStdVecItems(gs); packWriter->addStdVecItems(gs);
packReader->addStdVecItems(gs);
} }
void CConnection::disableSmartPointerSerialization() void CConnection::disableSmartPointerSerialization()

View File

@ -445,7 +445,10 @@ void CGameHandler::changeSecSkill(const CGHeroInstance * hero, SecondarySkill wh
void CGameHandler::handleClientDisconnection(std::shared_ptr<CConnection> c) void CGameHandler::handleClientDisconnection(std::shared_ptr<CConnection> c)
{ {
if(lobby->getState() == EServerState::SHUTDOWN || !gs || !gs->scenarioOps) if(lobby->getState() == EServerState::SHUTDOWN || !gs || !gs->scenarioOps)
{
assert(0); // game should have shut down before reaching this point!
return; return;
}
for(auto & playerConnections : connections) for(auto & playerConnections : connections)
{ {
@ -3609,7 +3612,7 @@ void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player)
if(p->human) if(p->human)
{ {
lobby->setState(EServerState::GAMEPLAY_ENDED); lobby->setState(EServerState::SHUTDOWN);
} }
} }
else else

View File

@ -117,9 +117,7 @@ public:
}; };
CVCMIServer::CVCMIServer(boost::program_options::variables_map & opts) CVCMIServer::CVCMIServer(boost::program_options::variables_map & opts)
: restartGameplay(false) : currentClientId(1)
, state(EServerState::LOBBY)
, currentClientId(1)
, currentPlayerId(1) , currentPlayerId(1)
, cmdLineOptions(opts) , cmdLineOptions(opts)
{ {
@ -153,13 +151,14 @@ void CVCMIServer::startAcceptingIncomingConnections()
void CVCMIServer::onNewConnection(const std::shared_ptr<INetworkConnection> & connection) void CVCMIServer::onNewConnection(const std::shared_ptr<INetworkConnection> & connection)
{ {
if(state == EServerState::LOBBY) if(getState() == EServerState::LOBBY)
{ {
activeConnections.push_back(std::make_shared<CConnection>(connection)); activeConnections.push_back(std::make_shared<CConnection>(connection));
activeConnections.back()->enterLobbyConnectionMode(); activeConnections.back()->enterLobbyConnectionMode();
} }
else else
{ {
// TODO: reconnection support
connection->close(); connection->close();
} }
} }
@ -175,7 +174,11 @@ void CVCMIServer::onPacketReceived(const std::shared_ptr<INetworkConnection> & c
void CVCMIServer::setState(EServerState value) void CVCMIServer::setState(EServerState value)
{ {
assert(state != EServerState::SHUTDOWN); // do not attempt to restart dying server
state = value; state = value;
if (state == EServerState::SHUTDOWN)
networkHandler->stop();
} }
EServerState CVCMIServer::getState() const EServerState CVCMIServer::getState() const
@ -208,7 +211,8 @@ void CVCMIServer::run()
void CVCMIServer::onTimer() void CVCMIServer::onTimer()
{ {
if (state != EServerState::GAMEPLAY) // we might receive onTimer call after transitioning from GAMEPLAY to LOBBY state, e.g. on game restart
if (getState() != EServerState::GAMEPLAY)
return; return;
static const auto serverUpdateInterval = std::chrono::milliseconds(100); static const auto serverUpdateInterval = std::chrono::milliseconds(100);
@ -230,19 +234,21 @@ void CVCMIServer::onTimer()
void CVCMIServer::prepareToRestart() void CVCMIServer::prepareToRestart()
{ {
if(state == EServerState::GAMEPLAY) if(getState() != EServerState::GAMEPLAY)
{ {
restartGameplay = true; assert(0);
return;
}
* si = * gh->gs->initialOpts; * si = * gh->gs->initialOpts;
si->seedToBeUsed = si->seedPostInit = 0; si->seedToBeUsed = si->seedPostInit = 0;
state = EServerState::LOBBY; setState(EServerState::LOBBY);
if (si->campState) if (si->campState)
{ {
assert(si->campState->currentScenario().has_value()); assert(si->campState->currentScenario().has_value());
campaignMap = si->campState->currentScenario().value_or(CampaignScenarioID(0)); campaignMap = si->campState->currentScenario().value_or(CampaignScenarioID(0));
campaignBonus = si->campState->getBonusID(campaignMap).value_or(-1); campaignBonus = si->campState->getBonusID(campaignMap).value_or(-1);
} }
}
for(auto c : activeConnections) for(auto c : activeConnections)
c->enterLobbyConnectionMode(); c->enterLobbyConnectionMode();
@ -319,7 +325,7 @@ void CVCMIServer::startGameImmediately()
c->enterGameplayConnectionMode(gh->gs); c->enterGameplayConnectionMode(gh->gs);
gh->start(si->mode == EStartMode::LOAD_GAME); gh->start(si->mode == EStartMode::LOAD_GAME);
state = EServerState::GAMEPLAY; setState(EServerState::GAMEPLAY);
lastTimerUpdateTime = gameplayStartTime = std::chrono::steady_clock::now(); lastTimerUpdateTime = gameplayStartTime = std::chrono::steady_clock::now();
onTimer(); onTimer();
} }
@ -333,12 +339,11 @@ void CVCMIServer::onDisconnected(const std::shared_ptr<INetworkConnection> & con
if(activeConnections.empty() || hostClientId == c->connectionID) if(activeConnections.empty() || hostClientId == c->connectionID)
{ {
networkHandler->stop(); setState(EServerState::SHUTDOWN);
state = EServerState::SHUTDOWN;
return; return;
} }
if(gh && state == EServerState::GAMEPLAY) if(gh && getState() == EServerState::GAMEPLAY)
{ {
gh->handleClientDisconnection(c); gh->handleClientDisconnection(c);
@ -406,7 +411,7 @@ bool CVCMIServer::passHost(int toConnectionId)
void CVCMIServer::clientConnected(std::shared_ptr<CConnection> c, std::vector<std::string> & names, const std::string & uuid, EStartMode mode) void CVCMIServer::clientConnected(std::shared_ptr<CConnection> c, std::vector<std::string> & names, const std::string & uuid, EStartMode mode)
{ {
assert(state == EServerState::LOBBY); assert(getState() == EServerState::LOBBY);
c->connectionID = currentClientId++; c->connectionID = currentClientId++;
@ -446,13 +451,6 @@ void CVCMIServer::clientDisconnected(std::shared_ptr<CConnection> c)
c->getConnection()->close(); c->getConnection()->close();
vstd::erase(activeConnections, c); vstd::erase(activeConnections, c);
if(activeConnections.empty() || hostClientId == c->connectionID)
{
networkHandler->stop();
state = EServerState::SHUTDOWN;
return;
}
// PlayerReinitInterface startAiPack; // PlayerReinitInterface startAiPack;
// startAiPack.playerConnectionId = PlayerSettings::PLAYER_AI; // startAiPack.playerConnectionId = PlayerSettings::PLAYER_AI;
// //
@ -494,7 +492,7 @@ void CVCMIServer::reconnectPlayer(int connId)
PlayerReinitInterface startAiPack; PlayerReinitInterface startAiPack;
startAiPack.playerConnectionId = connId; startAiPack.playerConnectionId = connId;
if(gh && si && state == EServerState::GAMEPLAY) if(gh && si && getState() == EServerState::GAMEPLAY)
{ {
for(auto it = playerNames.begin(); it != playerNames.end(); ++it) for(auto it = playerNames.begin(); it != playerNames.end(); ++it)
{ {

View File

@ -42,9 +42,7 @@ class GlobalLobbyProcessor;
enum class EServerState : ui8 enum class EServerState : ui8
{ {
LOBBY, LOBBY,
GAMEPLAY_STARTING,
GAMEPLAY, GAMEPLAY,
GAMEPLAY_ENDED,
SHUTDOWN SHUTDOWN
}; };
@ -59,10 +57,8 @@ class CVCMIServer : public LobbyInfo, public INetworkServerListener, public INet
std::unique_ptr<INetworkHandler> networkHandler; std::unique_ptr<INetworkHandler> networkHandler;
bool restartGameplay; // FIXME: this is just a hack
std::shared_ptr<CApplier<CBaseForServerApply>> applier; std::shared_ptr<CApplier<CBaseForServerApply>> applier;
EServerState state; EServerState state = EServerState::LOBBY;
std::shared_ptr<CConnection> findConnection(const std::shared_ptr<INetworkConnection> &); std::shared_ptr<CConnection> findConnection(const std::shared_ptr<INetworkConnection> &);

View File

@ -31,7 +31,8 @@ void GlobalLobbyProcessor::onDisconnected(const std::shared_ptr<INetworkConnecti
{ {
if (connection == controlConnection) if (connection == controlConnection)
{ {
throw std::runtime_error("Lost connection to a lobby server!"); owner.setState(EServerState::SHUTDOWN);
return;
} }
else else
{ {
@ -68,7 +69,7 @@ void GlobalLobbyProcessor::receiveOperationFailed(const JsonNode & json)
{ {
logGlobal->info("Lobby: Failed to login into a lobby server!"); logGlobal->info("Lobby: Failed to login into a lobby server!");
throw std::runtime_error("Failed to login into a lobby server!"); owner.setState(EServerState::SHUTDOWN);
} }
void GlobalLobbyProcessor::receiveLoginSuccess(const JsonNode & json) void GlobalLobbyProcessor::receiveLoginSuccess(const JsonNode & json)
@ -91,7 +92,7 @@ void GlobalLobbyProcessor::receiveAccountJoinsRoom(const JsonNode & json)
void GlobalLobbyProcessor::onConnectionFailed(const std::string & errorMessage) void GlobalLobbyProcessor::onConnectionFailed(const std::string & errorMessage)
{ {
throw std::runtime_error("Failed to connect to a lobby server!"); owner.setState(EServerState::SHUTDOWN);
} }
void GlobalLobbyProcessor::onConnectionEstablished(const std::shared_ptr<INetworkConnection> & connection) void GlobalLobbyProcessor::onConnectionEstablished(const std::shared_ptr<INetworkConnection> & connection)

View File

@ -31,7 +31,7 @@ public:
virtual void visitForLobby(CPackForLobby & pack) override; virtual void visitForLobby(CPackForLobby & pack) override;
virtual void visitLobbyClientConnected(LobbyClientConnected & pack) override; virtual void visitLobbyClientConnected(LobbyClientConnected & pack) override;
virtual void visitLobbyClientDisconnected(LobbyClientDisconnected & pack) override; virtual void visitLobbyClientDisconnected(LobbyClientDisconnected & pack) override;
virtual void visitLobbyEndGame(LobbyEndGame & pack) override; virtual void visitLobbyRestartGame(LobbyRestartGame & pack) override;
virtual void visitLobbyStartGame(LobbyStartGame & pack) override; virtual void visitLobbyStartGame(LobbyStartGame & pack) override;
virtual void visitLobbyChangeHost(LobbyChangeHost & pack) override; virtual void visitLobbyChangeHost(LobbyChangeHost & pack) override;
virtual void visitLobbyChangePlayerOption(LobbyChangePlayerOption & pack) override; virtual void visitLobbyChangePlayerOption(LobbyChangePlayerOption & pack) override;
@ -53,7 +53,7 @@ public:
virtual void visitForLobby(CPackForLobby & pack) override; virtual void visitForLobby(CPackForLobby & pack) override;
virtual void visitLobbyClientConnected(LobbyClientConnected & pack) override; virtual void visitLobbyClientConnected(LobbyClientConnected & pack) override;
virtual void visitLobbyClientDisconnected(LobbyClientDisconnected & pack) override; virtual void visitLobbyClientDisconnected(LobbyClientDisconnected & pack) override;
virtual void visitLobbyEndGame(LobbyEndGame & pack) override; virtual void visitLobbyRestartGame(LobbyRestartGame & pack) override;
virtual void visitLobbyStartGame(LobbyStartGame & pack) override; virtual void visitLobbyStartGame(LobbyStartGame & pack) override;
virtual void visitLobbyChangeHost(LobbyChangeHost & pack) override; virtual void visitLobbyChangeHost(LobbyChangeHost & pack) override;
}; };
@ -81,7 +81,7 @@ public:
virtual void visitLobbySetCampaign(LobbySetCampaign & pack) override; virtual void visitLobbySetCampaign(LobbySetCampaign & pack) override;
virtual void visitLobbySetCampaignMap(LobbySetCampaignMap & pack) override; virtual void visitLobbySetCampaignMap(LobbySetCampaignMap & pack) override;
virtual void visitLobbySetCampaignBonus(LobbySetCampaignBonus & pack) override; virtual void visitLobbySetCampaignBonus(LobbySetCampaignBonus & pack) override;
virtual void visitLobbyEndGame(LobbyEndGame & pack) override; virtual void visitLobbyRestartGame(LobbyRestartGame & pack) override;
virtual void visitLobbyStartGame(LobbyStartGame & pack) override; virtual void visitLobbyStartGame(LobbyStartGame & pack) override;
virtual void visitLobbyChangeHost(LobbyChangeHost & pack) override; virtual void visitLobbyChangeHost(LobbyChangeHost & pack) override;
virtual void visitLobbyChangePlayerOption(LobbyChangePlayerOption & pack) override; virtual void visitLobbyChangePlayerOption(LobbyChangePlayerOption & pack) override;

View File

@ -36,14 +36,7 @@ void ApplyOnServerAfterAnnounceNetPackVisitor::visitForLobby(CPackForLobby & pac
void ClientPermissionsCheckerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack) void ClientPermissionsCheckerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack)
{ {
if(srv.getState() == EServerState::LOBBY) result = srv.getState() == EServerState::LOBBY;
{
result = true;
return;
}
result = false;
return;
} }
void ApplyOnServerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack) void ApplyOnServerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack)
@ -197,19 +190,19 @@ void ClientPermissionsCheckerNetPackVisitor::visitLobbyGuiAction(LobbyGuiAction
result = srv.isClientHost(pack.c->connectionID); result = srv.isClientHost(pack.c->connectionID);
} }
void ClientPermissionsCheckerNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack) void ClientPermissionsCheckerNetPackVisitor::visitLobbyRestartGame(LobbyRestartGame & pack)
{ {
result = srv.isClientHost(pack.c->connectionID); result = srv.isClientHost(pack.c->connectionID);
} }
void ApplyOnServerNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack) void ApplyOnServerNetPackVisitor::visitLobbyRestartGame(LobbyRestartGame & pack)
{ {
srv.prepareToRestart(); srv.prepareToRestart();
result = true; result = true;
} }
void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack) void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyRestartGame(LobbyRestartGame & pack)
{ {
for(auto & c : srv.activeConnections) for(auto & c : srv.activeConnections)
c->enterLobbyConnectionMode(); c->enterLobbyConnectionMode();
@ -241,8 +234,6 @@ void ApplyOnServerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
pack.initializedStartInfo = std::make_shared<StartInfo>(*srv.gh->getStartInfo(true)); pack.initializedStartInfo = std::make_shared<StartInfo>(*srv.gh->getStartInfo(true));
pack.initializedGameState = srv.gh->gameState(); pack.initializedGameState = srv.gh->gameState();
srv.setState(EServerState::GAMEPLAY_STARTING);
result = true; result = true;
} }

View File

@ -233,7 +233,7 @@ void TurnOrderProcessor::doStartNewDay()
if(!activePlayer) if(!activePlayer)
{ {
gameHandler->gameLobby()->setState(EServerState::GAMEPLAY_ENDED); gameHandler->gameLobby()->setState(EServerState::SHUTDOWN);
return; return;
} }