Переглянути джерело

Transfer player ownership to AI

nordsoft 3 роки тому
батько
коміт
f4b7cf8196

+ 9 - 0
client/NetPacksClient.cpp

@@ -345,6 +345,15 @@ void PlayerEndsGame::applyCl(CClient *cl)
 		handleQuit(settings["session"]["spectate"].Bool()); // if spectator is active ask to close client or not
 }
 
+void PlayerReinitInterface::applyCl(CClient * cl)
+{
+	CSH->si->getIthPlayersSettings(player).connectedPlayerIDs.clear();
+	cl->initPlayerEnvironments();
+	cl->initPlayerInterfaces();
+	if(cl->gameState()->currentPlayer == player)
+		callOnlyThatInterface(cl, player, &CGameInterface::yourTurn);
+}
+
 void RemoveBonus::applyCl(CClient *cl)
 {
 	cl->invalidatePaths();

+ 15 - 0
lib/NetPacks.h

@@ -421,6 +421,21 @@ struct PlayerEndsGame : public CPackForClient
 	}
 };
 
+struct PlayerReinitInterface : public CPackForClient
+{
+	void applyCl(CClient * cl);
+	DLL_LINKAGE void applyGs(CGameState *gs);
+	
+	PlayerColor player;
+	ui8 playerConnectionId; //PLAYER_AI fro AI player
+	
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & player;
+		h & playerConnectionId;
+	}
+};
+
 struct RemoveBonus :  public CPackForClient
 {
 	RemoveBonus(ui8 Who = 0)

+ 9 - 0
lib/NetPacksLib.cpp

@@ -365,6 +365,15 @@ DLL_LINKAGE void PlayerEndsGame::applyGs(CGameState *gs)
 	}
 }
 
+DLL_LINKAGE void PlayerReinitInterface::applyGs(CGameState *gs)
+{
+	if(!gs || !gs->scenarioOps)
+		return;
+	
+	//TODO: what does mean if more that one player connected?
+	gs->scenarioOps->getIthPlayersSettings(player).connectedPlayerIDs.clear();
+}
+
 DLL_LINKAGE void RemoveBonus::applyGs(CGameState *gs)
 {
 	CBonusSystemNode *node;

+ 1 - 0
lib/registerTypes/RegisterTypes.h

@@ -240,6 +240,7 @@ void registerTypesClientPacks1(Serializer &s)
 	s.template registerType<CPackForClient, GiveBonus>();
 	s.template registerType<CPackForClient, ChangeObjPos>();
 	s.template registerType<CPackForClient, PlayerEndsGame>();
+	s.template registerType<CPackForClient, PlayerReinitInterface>();
 	s.template registerType<CPackForClient, RemoveBonus>();
 	s.template registerType<CPackForClient, UpdateArtHandlerLists>();
 	s.template registerType<CPackForClient, UpdateMapEvents>();

+ 14 - 5
server/CGameHandler.cpp

@@ -1324,7 +1324,7 @@ void CGameHandler::addGenericKilledLog(BattleLogMessage & blm, const CStack * de
 
 void CGameHandler::handleClientDisconnection(std::shared_ptr<CConnection> c)
 {
-	for(auto playerConns : connections)
+	/*for(auto playerConns : connections)
 	{
 		for(auto i = playerConns.second.begin(); i != playerConns.second.end(); )
 		{
@@ -1342,7 +1342,7 @@ void CGameHandler::handleClientDisconnection(std::shared_ptr<CConnection> c)
 			else
 				++i;
 		}
-	}
+	}*/
 }
 
 void CGameHandler::handleReceivedPack(CPackForServer * pack)
@@ -5003,7 +5003,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
 
 void CGameHandler::playerMessage(PlayerColor player, const std::string &message, ObjectInstanceID currObj)
 {
-	bool cheated = true;
+	bool cheated = false;
 	PlayerMessageClient temp_message(player, message);
 	sendAndApply(&temp_message);
 
@@ -6924,6 +6924,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
 {
 	if (cheat == "vcmiistari")
 	{
+		cheated = true;
 		if (!hero) return;
 		///Give hero spellbook
 		if (!hero->hasSpellbook())
@@ -6949,6 +6950,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
 	}
 	else if (cheat == "vcmiarmenelos")
 	{
+		cheated = true;
 		if (!town) return;
 		///Build all buildings in selected town
 		for (auto & build : town->town->buildings)
@@ -6963,6 +6965,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
 	}
 	else if (cheat == "vcmiainur" || cheat == "vcmiangband" || cheat == "vcmiglaurung")
 	{
+		cheated = true;
 		if (!hero) return;
 		///Gives N creatures into each slot
 		std::map<std::string, std::pair<int, int>> creatures;
@@ -6977,6 +6980,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
 	}
 	else if (cheat == "vcminoldor")
 	{
+		cheated = true;
 		if (!hero) return;
 		///Give all war machines to hero
 		if (!hero->getArt(ArtifactPosition::MACH1))
@@ -6988,6 +6992,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
 	}
 	else if (cheat == "vcmiforgeofnoldorking")
 	{
+		cheated = true;
 		if (!hero) return;
 		///Give hero all artifacts except war machines, spell scrolls and spell book
 		for (int g = 7; g < VLC->arth->objects.size(); ++g) //including artifacts from mods
@@ -6995,12 +7000,14 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
 	}
 	else if (cheat == "vcmiglorfindel")
 	{
+		cheated = true;
 		if (!hero) return;
 		///selected hero gains a new level
 		changePrimSkill(hero, PrimarySkill::EXPERIENCE, VLC->heroh->reqExp(hero->level + 1) - VLC->heroh->reqExp(hero->level));
 	}
 	else if (cheat == "vcminahar")
 	{
+		cheated = true;
 		if (!hero) return;
 		///Give 1000000 movement points to hero
 		SetMovePoints smp;
@@ -7017,6 +7024,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
 	}
 	else if (cheat == "vcmiformenos")
 	{
+		cheated = true;
 		///Give resources to player
 		TResources resources;
 		resources[Res::GOLD] = 100000;
@@ -7027,6 +7035,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
 	}
 	else if (cheat == "vcmisilmaril")
 	{
+		cheated = true;
 		///Player wins
 		PlayerCheated pc;
 		pc.player = player;
@@ -7035,6 +7044,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
 	}
 	else if (cheat == "vcmimelkor")
 	{
+		cheated = true;
 		///Player looses
 		PlayerCheated pc;
 		pc.player = player;
@@ -7043,6 +7053,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
 	}
 	else if (cheat == "vcmieagles" || cheat == "vcmiungoliant")
 	{
+		cheated = true;
 		///Reveal or conceal FoW
 		FoWChange fc;
 		fc.mode = (cheat == "vcmieagles" ? 1 : 0);
@@ -7061,8 +7072,6 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons
 		delete [] hlp_tab;
 		sendAndApply(&fc);
 	}
-	else
-		cheated = false;
 }
 
 void CGameHandler::removeObstacle(const CObstacleInstance & obstacle)

+ 30 - 7
server/CVCMIServer.cpp

@@ -474,22 +474,45 @@ void CVCMIServer::clientConnected(std::shared_ptr<CConnection> c, std::vector<st
 void CVCMIServer::clientDisconnected(std::shared_ptr<CConnection> c)
 {
 	connections -= c;
+	if(connections.empty())
+		throw std::runtime_error("No more connections. Closing server.");
+	
+	if(hostClient == c)
+	{
+		//TODO: support host transfer role
+		state = EServerState::SHUTDOWN;
+		return;
+	}
+	
 	for(auto it = playerNames.begin(); it != playerNames.end();)
 	{
 		if(it->second.connection != c->connectionID)
 		{
-			it++;
+			++it;
 			continue;
 		}
 
 		int id = it->first;
-		announceTxt(boost::str(boost::format("%s (pid %d cid %d) left the game") % id % playerNames[id].name % c->connectionID));
-		playerNames.erase(it++);
-
-		// Reset in-game players client used back to AI
-		if(PlayerSettings * s = si->getPlayersSettings(id))
+		std::string playerLeftMsgText = boost::str(boost::format("%s (pid %d cid %d) left the game") % id % playerNames[id].name % c->connectionID);
+		announceTxt(playerLeftMsgText); //send lobby text, it will be ignored for non-lobby clients
+		auto * playerSettings = si->getPlayersSettings(id);
+		if(!playerSettings)
+		{
+			++it;
+			continue;
+		}
+		
+		it = playerNames.erase(it);
+		setPlayerConnectedId(*playerSettings, PlayerSettings::PLAYER_AI);
+		
+		if(gh && si && state == EServerState::GAMEPLAY)
 		{
-			setPlayerConnectedId(*s, PlayerSettings::PLAYER_AI);
+			gh->playerMessage(playerSettings->color, playerLeftMsgText, ObjectInstanceID{});
+			gh->connections[playerSettings->color].insert(hostClient);
+			PlayerReinitInterface startAiPack;
+			startAiPack.player = playerSettings->color;
+			startAiPack.playerConnectionId = PlayerSettings::PLAYER_AI;
+			gh->sendAndApply(&startAiPack);
 		}
 	}
 }