Bladeren bron

Freeze current state

nordsoft 3 jaren geleden
bovenliggende
commit
512cf014aa

+ 7 - 0
client/CMT.cpp

@@ -395,6 +395,7 @@ int main(int argc, char * argv[])
 	CCS = new CClientState();
 	CGI = new CGameInfo(); //contains all global informations about game (texts, lodHandlers, map handler etc.)
 	CSH = new CServerHandler();
+	
 	// Initialize video
 #ifdef DISABLE_VIDEO
 	CCS->videoh = new CEmptyVideoPlayer();
@@ -495,6 +496,12 @@ int main(int argc, char * argv[])
 	{
 		GH.curInt = CMainMenu::create().get();
 	}
+	
+	// Restore remote session - start game immediately
+	if(settings["server"]["reconnect"].Bool())
+	{
+		CSH->restoreLastSession();
+	}
 
 	if(!settings["session"]["headless"].Bool())
 	{

+ 29 - 0
client/CServerHandler.cpp

@@ -118,6 +118,11 @@ CServerHandler::CServerHandler()
 	uuid = boost::uuids::to_string(boost::uuids::random_generator()());
 	applier = std::make_shared<CApplier<CBaseForLobbyApply>>();
 	registerTypesLobbyPacks(*applier);
+	
+	if(settings["remoteSession"].Bool())
+	{
+		uuid = settings["uuid"].String();
+	}
 }
 
 void CServerHandler::resetStateForLobby(const StartInfo::EMode mode, const std::vector<std::string> * names)
@@ -549,6 +554,15 @@ void CServerHandler::startGameplay(CGameState * gameState)
 	// After everything initialized we can accept CPackToClient netpacks
 	c->enterGameplayConnectionMode(client->gameState());
 	state = EClientState::GAMEPLAY;
+	
+	//store settings to continue game
+	if(!isServerLocal() && isGuest())
+	{
+		Settings saveSession = settings.write["server"]["reconnect"];
+		saveSession->Bool() = true;
+		Settings saveUuid = settings.write["server"]["uuid"];
+		saveUuid->String() = uuid;
+	}
 }
 
 void CServerHandler::endGameplay(bool closeConnection, bool restart)
@@ -579,6 +593,10 @@ void CServerHandler::endGameplay(bool closeConnection, bool restart)
 	
 	c->enterLobbyConnectionMode();
 	c->disableStackSendingByID();
+	
+	//reset settings
+	Settings saveSession = settings.write["server"]["reconnect"];
+	saveSession->Bool() = false;
 }
 
 void CServerHandler::startCampaignScenario(std::shared_ptr<CCampaignState> cs)
@@ -629,6 +647,17 @@ ui8 CServerHandler::getLoadMode()
 	return loadMode;
 }
 
+void CServerHandler::restoreLastSession()
+{
+	std::vector<std::string> nm{"stub"};
+	resetStateForLobby(StartInfo::LOAD_GAME, &nm);
+	screenType = ESelectionScreen::loadGame;
+	justConnectToServer("127.0.0.1", 3030);
+	//c->disableSmartVectorMemberSerialization();
+	//c->disableSmartPointerSerialization();
+	//c->disableStackSendingByID();
+}
+
 void CServerHandler::debugStartTest(std::string filename, bool save)
 {
 	logGlobal->info("Starting debug test with file: %s", filename);

+ 1 - 0
client/CServerHandler.h

@@ -155,6 +155,7 @@ public:
 	ui8 getLoadMode();
 
 	void debugStartTest(std::string filename, bool save = false);
+	void restoreLastSession();
 };
 
 extern CServerHandler * CSH;

+ 14 - 4
client/NetPacksClient.cpp

@@ -347,11 +347,21 @@ void PlayerEndsGame::applyCl(CClient *cl)
 
 void PlayerReinitInterface::applyCl(CClient * cl)
 {
-	CSH->si->getIthPlayersSettings(player).connectedPlayerIDs.clear();
-	cl->initPlayerEnvironments();
-	cl->initPlayerInterfaces();
-	if(cl->gameState()->currentPlayer == player)
+	auto & plSettings = CSH->si->getIthPlayersSettings(player);
+	if(!playerConnectionId)
+	{
+		plSettings.connectedPlayerIDs.clear();
+		cl->initPlayerEnvironments();
+		cl->initPlayerInterfaces();
+		if(cl->gameState()->currentPlayer == player)
+			callOnlyThatInterface(cl, player, &CGameInterface::yourTurn);
+	}
+	else
+	{
+		plSettings.connectedPlayerIDs.insert(playerConnectionId);
+		callAllInterfaces(cl, &IGameEventsReceiver::playerStartsTurn, player);
 		callOnlyThatInterface(cl, player, &CGameInterface::yourTurn);
+	}
 }
 
 void RemoveBonus::applyCl(CClient *cl)

+ 6 - 0
client/NetPacksLobbyClient.cpp

@@ -109,6 +109,9 @@ bool LobbyEndGame::applyOnLobbyHandler(CServerHandler * handler)
 
 bool LobbyStartGame::applyOnLobbyHandler(CServerHandler * handler)
 {
+	if(clientId != -1 && clientId != handler->c->connectionID)
+		return false;
+	
 	handler->state = EClientState::STARTING;
 	if(handler->si->mode != StartInfo::LOAD_GAME)
 	{
@@ -121,6 +124,9 @@ bool LobbyStartGame::applyOnLobbyHandler(CServerHandler * handler)
 
 void LobbyStartGame::applyOnLobbyScreen(CLobbyScreen * lobby, CServerHandler * handler)
 {
+	if(clientId != -1 && clientId != handler->c->connectionID)
+		return;
+	
 	GH.pushIntT<CLoadingScreen>(std::bind(&CServerHandler::startGameplay, handler, initializedGameState));
 }
 

+ 9 - 1
config/schemas/settings.json

@@ -253,7 +253,7 @@
 			"type" : "object",
 			"additionalProperties" : false,
 			"default": {},
-			"required" : [ "server", "port", "localInformation", "playerAI", "friendlyAI","neutralAI", "enemyAI" ],
+			"required" : [ "server", "port", "localInformation", "playerAI", "friendlyAI","neutralAI", "enemyAI", "reconnect", "uuid" ],
 			"properties" : {
 				"server" : {
 					"type":"string",
@@ -282,6 +282,14 @@
 				"enemyAI" : {
 					"type" : "string",
 					"default" : "BattleAI"
+				},
+				"reconnect" : {
+					"type" : "boolean",
+					"default" : false
+				},
+				"uuid" : {
+					"type" : "string",
+					"default" : ""
 				}
 			}
 		},

+ 1 - 1
lib/NetPacksLib.cpp

@@ -371,7 +371,7 @@ DLL_LINKAGE void PlayerReinitInterface::applyGs(CGameState *gs)
 		return;
 	
 	//TODO: what does mean if more that one player connected?
-	gs->scenarioOps->getIthPlayersSettings(player).connectedPlayerIDs.clear();
+	//gs->scenarioOps->getIthPlayersSettings(player).connectedPlayerIDs.clear();
 }
 
 DLL_LINKAGE void RemoveBonus::applyGs(CGameState *gs)

+ 3 - 1
lib/NetPacksLobby.h

@@ -159,8 +159,9 @@ struct LobbyStartGame : public CLobbyPackToPropagate
 	// Set by server
 	std::shared_ptr<StartInfo> initializedStartInfo;
 	CGameState * initializedGameState;
+	int clientId; //-1 means to all clients
 
-	LobbyStartGame() : initializedStartInfo(nullptr), initializedGameState(nullptr) {}
+	LobbyStartGame() : initializedStartInfo(nullptr), initializedGameState(nullptr), clientId(-1) {}
 	bool checkClientPermissions(CVCMIServer * srv) const;
 	bool applyOnServer(CVCMIServer * srv);
 	void applyOnServerAfterAnnounce(CVCMIServer * srv);
@@ -169,6 +170,7 @@ struct LobbyStartGame : public CLobbyPackToPropagate
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
+		h & clientId;
 		h & initializedStartInfo;
 		bool sps = h.smartPointerSerialization;
 		h.smartPointerSerialization = true;

+ 61 - 8
server/CVCMIServer.cpp

@@ -205,8 +205,8 @@ void CVCMIServer::threadAnnounceLobby()
 			}
 			if(state != EServerState::LOBBY)
 			{
-				if(acceptor)
-					acceptor->close();
+				//if(acceptor)
+					//acceptor->close();
 			}
 
 			if(acceptor)
@@ -305,11 +305,35 @@ void CVCMIServer::connectionAccepted(const boost::system::error_code & ec)
 
 	try
 	{
-		logNetwork->info("We got a new connection! :)");
-		auto c = std::make_shared<CConnection>(upcomingConnection, SERVER_NAME, uuid);
-		upcomingConnection.reset();
-		connections.insert(c);
-		c->handler = std::make_shared<boost::thread>(&CVCMIServer::threadHandleClient, this, c);
+		/*if(state == EServerState::GAMEPLAY && !hangingConnections.empty())
+		{
+			logNetwork->info("Reconnection player");
+			(*hangingConnections.begin())->socket = upcomingConnection;
+			upcomingConnection.reset();
+			//immediately start game
+			//std::unique_ptr<LobbyStartGame> startGameForReconnectedPlayer(new LobbyStartGame);
+			//startGameForReconnectedPlayer->initializedStartInfo = si;
+			//startGameForReconnectedPlayer->initializedGameState = gh->gs;
+			//startGameForReconnectedPlayer->clientId = (*hangingConnections.begin())->connectionID;
+			//announcePack(std::move(startGameForReconnectedPlayer));
+			
+			(*hangingConnections.begin())->handler = std::make_shared<boost::thread>(&CVCMIServer::threadHandleClient, this, *hangingConnections.begin());
+		}*/
+		if(state == EServerState::LOBBY || !hangingConnections.empty())
+		{
+			logNetwork->info("We got a new connection! :)");
+			auto c = std::make_shared<CConnection>(upcomingConnection, SERVER_NAME, uuid);
+			upcomingConnection.reset();
+			connections.insert(c);
+			c->handler = std::make_shared<boost::thread>(&CVCMIServer::threadHandleClient, this, c);
+			
+			if(!hangingConnections.empty())
+			{
+				logNetwork->info("Reconnection player");
+				c->connectionID = (*hangingConnections.begin())->connectionID;
+				//hangingConnections.clear();
+			}
+		}
 	}
 	catch(std::exception & e)
 	{
@@ -344,7 +368,11 @@ void CVCMIServer::threadHandleClient(std::shared_ptr<CConnection> c)
 	{
         (void)e;
 		if(state != EServerState::LOBBY)
-			gh->handleClientDisconnection(c);
+		{
+			hangingConnections.insert(c);
+			connections.erase(c);
+			//gh->handleClientDisconnection(c);
+		}
 	}
 	/*
 	catch(const std::exception & e)
@@ -517,6 +545,31 @@ void CVCMIServer::clientDisconnected(std::shared_ptr<CConnection> c)
 	}
 }
 
+void CVCMIServer::reconnectPlayer(int connId)
+{
+	if(gh && si && state == EServerState::GAMEPLAY)
+	{
+		for(auto it = playerNames.begin(); it != playerNames.end(); ++it)
+		{
+			if(it->second.connection != connId)
+				continue;
+			
+			int id = it->first;
+			auto * playerSettings = si->getPlayersSettings(id);
+			if(!playerSettings)
+				continue;
+			
+			PlayerReinitInterface startAiPack;
+			startAiPack.player = playerSettings->color;
+			startAiPack.playerConnectionId = connId;
+			gh->sendAndApply(&startAiPack);
+		}
+		//gh->playerMessage(playerSettings->color, playerLeftMsgText, ObjectInstanceID{});
+		//gh->connections[playerSettings->color].insert(hostClient);
+		
+	}
+}
+
 void CVCMIServer::setPlayerConnectedId(PlayerSettings & pset, ui8 player) const
 {
 	if(vstd::contains(playerNames, player))

+ 3 - 0
server/CVCMIServer.h

@@ -61,6 +61,8 @@ public:
 
 	boost::program_options::variables_map cmdLineOptions;
 	std::set<std::shared_ptr<CConnection>> connections;
+	std::set<std::shared_ptr<CConnection>> hangingConnections; //keep connections of players disconnected during the game
+	
 	std::atomic<int> currentClientId;
 	std::atomic<ui8> currentPlayerId;
 	std::shared_ptr<CConnection> hostClient;
@@ -90,6 +92,7 @@ public:
 
 	void clientConnected(std::shared_ptr<CConnection> c, std::vector<std::string> & names, std::string uuid, StartInfo::EMode mode);
 	void clientDisconnected(std::shared_ptr<CConnection> c);
+	void reconnectPlayer(int connId);
 
 	void updateAndPropagateLobbyState();
 

+ 26 - 2
server/NetPacksLobbyServer.cpp

@@ -52,7 +52,19 @@ void LobbyClientConnected::applyOnServerAfterAnnounce(CVCMIServer * srv)
 	// FIXME: we need to avoid senting something to client that not yet get answer for LobbyClientConnected
 	// Until UUID set we only pass LobbyClientConnected to this client
 	c->uuid = uuid;
-	srv->updateAndPropagateLobbyState();
+	if(srv->state == EServerState::GAMEPLAY)
+	{
+		//immediately start game
+		std::unique_ptr<LobbyStartGame> startGameForReconnectedPlayer(new LobbyStartGame);
+		startGameForReconnectedPlayer->initializedStartInfo = srv->si;
+		startGameForReconnectedPlayer->initializedGameState = srv->gh->gameState();
+		startGameForReconnectedPlayer->clientId = c->connectionID;
+		srv->addToAnnounceQueue(std::move(startGameForReconnectedPlayer));
+	}
+	else
+	{
+		srv->updateAndPropagateLobbyState();
+	}
 }
 
 bool LobbyClientDisconnected::checkClientPermissions(CVCMIServer * srv) const
@@ -209,7 +221,19 @@ bool LobbyStartGame::applyOnServer(CVCMIServer * srv)
 
 void LobbyStartGame::applyOnServerAfterAnnounce(CVCMIServer * srv)
 {
-	srv->startGameImmidiately();
+	if(clientId == -1) //do not restart game for single client only
+		srv->startGameImmidiately();
+	else
+	{
+		for(auto & c : srv->connections)
+		{
+			if(c->connectionID == clientId)
+			{
+				c->enterGameplayConnectionMode(srv->gh->gameState());
+				srv->reconnectPlayer(clientId);
+			}
+		}
+	}
 }
 
 bool LobbyChangeHost::checkClientPermissions(CVCMIServer * srv) const