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:
@ -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)
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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) {}
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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> &);
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ void TurnOrderProcessor::doStartNewDay()
|
|||||||
|
|
||||||
if(!activePlayer)
|
if(!activePlayer)
|
||||||
{
|
{
|
||||||
gameHandler->gameLobby()->setState(EServerState::GAMEPLAY_ENDED);
|
gameHandler->gameLobby()->setState(EServerState::SHUTDOWN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user