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