mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +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(); | ||||
| 	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) | ||||
|   | ||||
| @@ -111,7 +111,6 @@ class CServerHandler final : public IServerAPI, public LobbyInfo, public INetwor | ||||
| 	/// required to correctly deserialize gamestate using client-side game callback | ||||
| 	std::unique_ptr<CClient> nextClient; | ||||
|  | ||||
| 	void onServerFinished(); | ||||
| 	void sendLobbyPack(const CPackForLobby & pack) const 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<boost::thread> threadRunLocalServer; | ||||
| 	std::unique_ptr<boost::thread> threadNetwork; | ||||
| 	boost::thread threadRunLocalServer; | ||||
| 	boost::thread threadNetwork; | ||||
|  | ||||
| 	std::unique_ptr<CClient> client; | ||||
|  | ||||
| 	CondSh<bool> campaignServerRestartLock; | ||||
|  | ||||
| 	CServerHandler(); | ||||
| 	~CServerHandler(); | ||||
| 	 | ||||
| @@ -202,7 +199,8 @@ public: | ||||
| 	void debugStartTest(std::string filename, bool save = false); | ||||
|  | ||||
| 	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 showServerError(const std::string & txt) const; | ||||
|  | ||||
|   | ||||
| @@ -34,7 +34,7 @@ public: | ||||
|  | ||||
| 	virtual void visitLobbyClientConnected(LobbyClientConnected & 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 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) | ||||
| 	{ | ||||
| 		handler.endGameplay(pack.closeConnection, pack.restart); | ||||
| 		handler.restartGameplay(); | ||||
| 	} | ||||
| 	 | ||||
| 	if(pack.restart) | ||||
| 	{ | ||||
| 		if (handler.validateGameStart()) | ||||
| 			handler.sendStartGame(); | ||||
| 	} | ||||
| 	if (handler.validateGameStart()) | ||||
| 		handler.sendStartGame(); | ||||
| } | ||||
|  | ||||
| void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack) | ||||
|   | ||||
| @@ -13,7 +13,7 @@ | ||||
|  | ||||
| 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 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 visitLobbyGuiAction(LobbyGuiAction & pack) {} | ||||
| 	virtual void visitLobbyLoadProgress(LobbyLoadProgress & pack) {} | ||||
| 	virtual void visitLobbyEndGame(LobbyEndGame & pack) {} | ||||
| 	virtual void visitLobbyRestartGame(LobbyRestartGame & pack) {} | ||||
| 	virtual void visitLobbyStartGame(LobbyStartGame & pack) {} | ||||
| 	virtual void visitLobbyChangeHost(LobbyChangeHost & pack) {} | ||||
| 	virtual void visitLobbyUpdateState(LobbyUpdateState & pack) {} | ||||
|   | ||||
| @@ -708,9 +708,9 @@ void LobbyLoadProgress::visitTyped(ICPackVisitor & visitor) | ||||
| 	visitor.visitLobbyLoadProgress(*this); | ||||
| } | ||||
|  | ||||
| void LobbyEndGame::visitTyped(ICPackVisitor & visitor) | ||||
| void LobbyRestartGame::visitTyped(ICPackVisitor & visitor) | ||||
| { | ||||
| 	visitor.visitLobbyEndGame(*this); | ||||
| 	visitor.visitLobbyRestartGame(*this); | ||||
| } | ||||
|  | ||||
| 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; | ||||
| 	 | ||||
| 	template <typename Handler> void serialize(Handler &h) | ||||
| 	{ | ||||
| 		h & closeConnection; | ||||
| 		h & restart; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -37,7 +37,7 @@ void registerTypesLobbyPacks(Serializer &s) | ||||
| 	// Only host client send | ||||
| 	s.template registerType<CLobbyPackToPropagate, LobbyGuiAction>(); | ||||
| 	s.template registerType<CLobbyPackToPropagate, LobbyLoadProgress>(); | ||||
| 	s.template registerType<CLobbyPackToPropagate, LobbyEndGame>(); | ||||
| 	s.template registerType<CLobbyPackToPropagate, LobbyRestartGame>(); | ||||
| 	s.template registerType<CLobbyPackToPropagate, LobbyStartGame>(); | ||||
| 	s.template registerType<CLobbyPackToPropagate, LobbyChangeHost>(); | ||||
| 	// Only server send | ||||
|   | ||||
| @@ -140,6 +140,7 @@ void CConnection::enterGameplayConnectionMode(CGameState * gs) | ||||
|  | ||||
| 	setCallback(gs->callback); | ||||
| 	packWriter->addStdVecItems(gs); | ||||
| 	packReader->addStdVecItems(gs); | ||||
| } | ||||
|  | ||||
| void CConnection::disableSmartPointerSerialization() | ||||
|   | ||||
| @@ -445,7 +445,10 @@ void CGameHandler::changeSecSkill(const CGHeroInstance * hero, SecondarySkill wh | ||||
| void CGameHandler::handleClientDisconnection(std::shared_ptr<CConnection> c) | ||||
| { | ||||
| 	if(lobby->getState() == EServerState::SHUTDOWN || !gs || !gs->scenarioOps) | ||||
| 	{ | ||||
| 		assert(0); // game should have shut down before reaching this point! | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	for(auto & playerConnections : connections) | ||||
| 	{ | ||||
| @@ -3609,7 +3612,7 @@ void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player) | ||||
|  | ||||
| 			if(p->human) | ||||
| 			{ | ||||
| 				lobby->setState(EServerState::GAMEPLAY_ENDED); | ||||
| 				lobby->setState(EServerState::SHUTDOWN); | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
|   | ||||
| @@ -117,9 +117,7 @@ public: | ||||
| }; | ||||
|  | ||||
| CVCMIServer::CVCMIServer(boost::program_options::variables_map & opts) | ||||
| 	: restartGameplay(false) | ||||
| 	, state(EServerState::LOBBY) | ||||
| 	, currentClientId(1) | ||||
| 	: currentClientId(1) | ||||
| 	, currentPlayerId(1) | ||||
| 	, cmdLineOptions(opts) | ||||
| { | ||||
| @@ -153,13 +151,14 @@ void CVCMIServer::startAcceptingIncomingConnections() | ||||
|  | ||||
| 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.back()->enterLobbyConnectionMode(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		// TODO: reconnection support | ||||
| 		connection->close(); | ||||
| 	} | ||||
| } | ||||
| @@ -175,7 +174,11 @@ void CVCMIServer::onPacketReceived(const std::shared_ptr<INetworkConnection> & c | ||||
|  | ||||
| void CVCMIServer::setState(EServerState value) | ||||
| { | ||||
| 	assert(state != EServerState::SHUTDOWN); // do not attempt to restart dying server | ||||
| 	state = value; | ||||
|  | ||||
| 	if (state == EServerState::SHUTDOWN) | ||||
| 		networkHandler->stop(); | ||||
| } | ||||
|  | ||||
| EServerState CVCMIServer::getState() const | ||||
| @@ -208,7 +211,8 @@ void CVCMIServer::run() | ||||
|  | ||||
| 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; | ||||
|  | ||||
| 	static const auto serverUpdateInterval = std::chrono::milliseconds(100); | ||||
| @@ -230,18 +234,20 @@ void CVCMIServer::onTimer() | ||||
|  | ||||
| void CVCMIServer::prepareToRestart() | ||||
| { | ||||
| 	if(state == EServerState::GAMEPLAY) | ||||
| 	if(getState() != EServerState::GAMEPLAY) | ||||
| 	{ | ||||
| 		restartGameplay = true; | ||||
| 		* si = * gh->gs->initialOpts; | ||||
| 		si->seedToBeUsed = si->seedPostInit = 0; | ||||
| 		state = EServerState::LOBBY; | ||||
| 		if (si->campState) | ||||
| 		{ | ||||
| 			assert(si->campState->currentScenario().has_value()); | ||||
| 			campaignMap = si->campState->currentScenario().value_or(CampaignScenarioID(0)); | ||||
| 			campaignBonus = si->campState->getBonusID(campaignMap).value_or(-1); | ||||
| 		} | ||||
| 		assert(0); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	* si = * gh->gs->initialOpts; | ||||
| 	si->seedToBeUsed = si->seedPostInit = 0; | ||||
| 	setState(EServerState::LOBBY); | ||||
| 	if (si->campState) | ||||
| 	{ | ||||
| 		assert(si->campState->currentScenario().has_value()); | ||||
| 		campaignMap = si->campState->currentScenario().value_or(CampaignScenarioID(0)); | ||||
| 		campaignBonus = si->campState->getBonusID(campaignMap).value_or(-1); | ||||
| 	} | ||||
| 	 | ||||
| 	for(auto c : activeConnections) | ||||
| @@ -319,7 +325,7 @@ void CVCMIServer::startGameImmediately() | ||||
| 		c->enterGameplayConnectionMode(gh->gs); | ||||
|  | ||||
| 	gh->start(si->mode == EStartMode::LOAD_GAME); | ||||
| 	state = EServerState::GAMEPLAY; | ||||
| 	setState(EServerState::GAMEPLAY); | ||||
| 	lastTimerUpdateTime = gameplayStartTime = std::chrono::steady_clock::now(); | ||||
| 	onTimer(); | ||||
| } | ||||
| @@ -333,12 +339,11 @@ void CVCMIServer::onDisconnected(const std::shared_ptr<INetworkConnection> & con | ||||
|  | ||||
| 	if(activeConnections.empty() || hostClientId == c->connectionID) | ||||
| 	{ | ||||
| 		networkHandler->stop(); | ||||
| 		state = EServerState::SHUTDOWN; | ||||
| 		setState(EServerState::SHUTDOWN); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if(gh && state == EServerState::GAMEPLAY) | ||||
| 	if(gh && getState() == EServerState::GAMEPLAY) | ||||
| 	{ | ||||
| 		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) | ||||
| { | ||||
| 	assert(state == EServerState::LOBBY); | ||||
| 	assert(getState() == EServerState::LOBBY); | ||||
|  | ||||
| 	c->connectionID = currentClientId++; | ||||
|  | ||||
| @@ -446,13 +451,6 @@ void CVCMIServer::clientDisconnected(std::shared_ptr<CConnection> c) | ||||
| 	c->getConnection()->close(); | ||||
| 	vstd::erase(activeConnections, c); | ||||
|  | ||||
| 	if(activeConnections.empty() || hostClientId == c->connectionID) | ||||
| 	{ | ||||
| 		networkHandler->stop(); | ||||
| 		state = EServerState::SHUTDOWN; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| //	PlayerReinitInterface startAiPack; | ||||
| //	startAiPack.playerConnectionId = PlayerSettings::PLAYER_AI; | ||||
| // | ||||
| @@ -494,7 +492,7 @@ void CVCMIServer::reconnectPlayer(int connId) | ||||
| 	PlayerReinitInterface startAiPack; | ||||
| 	startAiPack.playerConnectionId = connId; | ||||
| 	 | ||||
| 	if(gh && si && state == EServerState::GAMEPLAY) | ||||
| 	if(gh && si && getState() == EServerState::GAMEPLAY) | ||||
| 	{ | ||||
| 		for(auto it = playerNames.begin(); it != playerNames.end(); ++it) | ||||
| 		{ | ||||
|   | ||||
| @@ -42,9 +42,7 @@ class GlobalLobbyProcessor; | ||||
| enum class EServerState : ui8 | ||||
| { | ||||
| 	LOBBY, | ||||
| 	GAMEPLAY_STARTING, | ||||
| 	GAMEPLAY, | ||||
| 	GAMEPLAY_ENDED, | ||||
| 	SHUTDOWN | ||||
| }; | ||||
|  | ||||
| @@ -59,10 +57,8 @@ class CVCMIServer : public LobbyInfo, public INetworkServerListener, public INet | ||||
|  | ||||
| 	std::unique_ptr<INetworkHandler> networkHandler; | ||||
|  | ||||
| 	bool restartGameplay; // FIXME: this is just a hack | ||||
|  | ||||
| 	std::shared_ptr<CApplier<CBaseForServerApply>> applier; | ||||
| 	EServerState state; | ||||
| 	EServerState state = EServerState::LOBBY; | ||||
|  | ||||
| 	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) | ||||
| 	{ | ||||
| 		throw std::runtime_error("Lost connection to a lobby server!"); | ||||
| 		owner.setState(EServerState::SHUTDOWN); | ||||
| 		return; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -68,7 +69,7 @@ void GlobalLobbyProcessor::receiveOperationFailed(const JsonNode & json) | ||||
| { | ||||
| 	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) | ||||
| @@ -91,7 +92,7 @@ void GlobalLobbyProcessor::receiveAccountJoinsRoom(const JsonNode & json) | ||||
|  | ||||
| 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) | ||||
|   | ||||
| @@ -31,7 +31,7 @@ public: | ||||
| 	virtual void visitForLobby(CPackForLobby & pack) override; | ||||
| 	virtual void visitLobbyClientConnected(LobbyClientConnected & 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 visitLobbyChangeHost(LobbyChangeHost & pack) override; | ||||
| 	virtual void visitLobbyChangePlayerOption(LobbyChangePlayerOption & pack) override; | ||||
| @@ -53,7 +53,7 @@ public: | ||||
| 	virtual void visitForLobby(CPackForLobby & pack) override; | ||||
| 	virtual void visitLobbyClientConnected(LobbyClientConnected & 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 visitLobbyChangeHost(LobbyChangeHost & pack) override; | ||||
| }; | ||||
| @@ -81,7 +81,7 @@ public: | ||||
| 	virtual void visitLobbySetCampaign(LobbySetCampaign & pack) override; | ||||
| 	virtual void visitLobbySetCampaignMap(LobbySetCampaignMap & 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 visitLobbyChangeHost(LobbyChangeHost & pack) override; | ||||
| 	virtual void visitLobbyChangePlayerOption(LobbyChangePlayerOption & pack) override; | ||||
|   | ||||
| @@ -36,14 +36,7 @@ void ApplyOnServerAfterAnnounceNetPackVisitor::visitForLobby(CPackForLobby & pac | ||||
|  | ||||
| void ClientPermissionsCheckerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack) | ||||
| { | ||||
| 	if(srv.getState() == EServerState::LOBBY) | ||||
| 	{ | ||||
| 		result = true; | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	result = false; | ||||
| 	return; | ||||
| 	result = srv.getState() == EServerState::LOBBY; | ||||
| } | ||||
|  | ||||
| void ApplyOnServerNetPackVisitor::visitLobbyClientConnected(LobbyClientConnected & pack) | ||||
| @@ -197,19 +190,19 @@ void ClientPermissionsCheckerNetPackVisitor::visitLobbyGuiAction(LobbyGuiAction | ||||
| 	result = srv.isClientHost(pack.c->connectionID); | ||||
| } | ||||
|  | ||||
| void ClientPermissionsCheckerNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack) | ||||
| void ClientPermissionsCheckerNetPackVisitor::visitLobbyRestartGame(LobbyRestartGame & pack) | ||||
| { | ||||
| 	result = srv.isClientHost(pack.c->connectionID); | ||||
| } | ||||
|  | ||||
| void ApplyOnServerNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack) | ||||
| void ApplyOnServerNetPackVisitor::visitLobbyRestartGame(LobbyRestartGame & pack) | ||||
| { | ||||
| 	srv.prepareToRestart(); | ||||
|  | ||||
| 	result = true; | ||||
| } | ||||
|  | ||||
| void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyEndGame(LobbyEndGame & pack) | ||||
| void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyRestartGame(LobbyRestartGame & pack) | ||||
| { | ||||
| 	for(auto & c : srv.activeConnections) | ||||
| 		c->enterLobbyConnectionMode(); | ||||
| @@ -241,8 +234,6 @@ void ApplyOnServerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack) | ||||
| 	 | ||||
| 	pack.initializedStartInfo = std::make_shared<StartInfo>(*srv.gh->getStartInfo(true)); | ||||
| 	pack.initializedGameState = srv.gh->gameState(); | ||||
|  | ||||
| 	srv.setState(EServerState::GAMEPLAY_STARTING); | ||||
| 	result = true; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -233,7 +233,7 @@ void TurnOrderProcessor::doStartNewDay() | ||||
|  | ||||
| 	if(!activePlayer) | ||||
| 	{ | ||||
| 		gameHandler->gameLobby()->setState(EServerState::GAMEPLAY_ENDED); | ||||
| 		gameHandler->gameLobby()->setState(EServerState::SHUTDOWN); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user