Browse Source

GameHandler now uses GameConnectionID instead of connection pointers

Ivan Savenko 3 tháng trước cách đây
mục cha
commit
52da332640

+ 28 - 36
client/AntilagServer.cpp

@@ -23,26 +23,6 @@ int ConnectionPackWriter::write(const std::byte * data, unsigned size)
 	return size;
 }
 
-void AntilagFakeConnection::sendPack(const CPack & pack)
-{
-	logGlobal->info("Prediction: pack '%s'", typeid(pack).name());
-
-	ConnectionPackWriter packWriter;
-	BinarySerializer serializer(&packWriter);
-	serializer & &pack;
-	writtenPacks.push_back(std::move(packWriter));
-}
-
-std::unique_ptr<CPack> AntilagFakeConnection::retrievePack(const std::vector<std::byte> & data)
-{
-	throw std::runtime_error("AntilagFakeConnection::retrievePack not implemented");
-}
-
-int AntilagFakeConnection::getConnectionID() const
-{
-	return 0;
-}
-
 void AntilagRollbackGeneratorVisitor::visitTryMoveHero(TryMoveHero & pack)
 {
 	auto rollbackMove = std::make_unique<TryMoveHero>();
@@ -119,12 +99,12 @@ void AntilagServer::onPacketReceived(const std::shared_ptr<INetworkConnection> &
 
 	logGlobal->info("Predicting effects of pack '%s'", typeid(*serverPack).name());
 
-	auto newConnection = std::make_shared<AntilagFakeConnection>();
-	newConnection->requestID = serverPack->requestID;
-	newConnection->senderID = serverPack->player;
-	predictedReplies.push_back(std::move(newConnection));
+	AntilagReplyPrediction newPrediction;
+	newPrediction.requestID = serverPack->requestID;
+	newPrediction.senderID = serverPack->player;
+	predictedReplies.push_back(std::move(newPrediction));
 
-	gameHandler->handleReceivedPack(predictedReplies.back(), *serverPack);
+	gameHandler->handleReceivedPack(GameConnectionID::FIRST_CONNECTION, *serverPack);
 }
 
 void AntilagServer::tryPredictReply(const CPackForServer & request)
@@ -145,8 +125,8 @@ bool AntilagServer::verifyReply(const CPackForClient & pack)
 		assert(currentPackageID == invalidPackageID);
 		assert(!predictedReplies.empty());
 		const auto & nextPrediction = predictedReplies.front();
-		assert(nextPrediction->senderID == packageReceived->player);
-		assert(nextPrediction->requestID == packageReceived->requestID);
+		assert(nextPrediction.senderID == packageReceived->player);
+		assert(nextPrediction.requestID == packageReceived->requestID);
 		currentPackageID = packageReceived->requestID;
 	}
 
@@ -161,8 +141,8 @@ bool AntilagServer::verifyReply(const CPackForClient & pack)
 	BinarySerializer serializer(&packWriter);
 	serializer & &pack;
 
-	if (packWriter.buffer == predictedReplies.front()->writtenPacks.front().buffer)
-		predictedReplies.front()->writtenPacks.erase(predictedReplies.front()->writtenPacks.begin());
+	if (packWriter.buffer == predictedReplies.front().writtenPacks.front().buffer)
+		predictedReplies.front().writtenPacks.erase(predictedReplies.front().writtenPacks.begin());
 	else
 		throw std::runtime_error("TODO: IMPLEMENT PACK ROLLBACK");
 
@@ -170,8 +150,8 @@ bool AntilagServer::verifyReply(const CPackForClient & pack)
 	{
 		assert(currentPackageID == packageApplied->requestID);
 		assert(!predictedReplies.empty());
-		assert(currentPackageID == predictedReplies.front()->requestID);
-		assert(predictedReplies.front()->writtenPacks.empty());
+		assert(currentPackageID == predictedReplies.front().requestID);
+		assert(predictedReplies.front().writtenPacks.empty());
 		predictedReplies.erase(predictedReplies.begin());
 		currentPackageID = invalidPackageID;
 	}
@@ -194,7 +174,7 @@ bool AntilagServer::isPlayerHost(const PlayerColor & color) const
 	return false; // TODO?
 }
 
-bool AntilagServer::hasPlayerAt(PlayerColor player, const std::shared_ptr<IGameConnection> & c) const
+bool AntilagServer::hasPlayerAt(PlayerColor player, GameConnectionID c) const
 {
 	return true; // TODO?
 }
@@ -204,10 +184,22 @@ bool AntilagServer::hasBothPlayersAtSameConnection(PlayerColor left, PlayerColor
 	return false; // TODO?
 }
 
-void AntilagServer::broadcastPack(CPackForClient & pack)
+void AntilagServer::applyPack(CPackForClient & pack)
 {
-	AntilagReplyPredictionVisitor visitor;
-	pack.visit(visitor);
-	predictedReplies.back()->sendPack(pack);
+//	AntilagReplyPredictionVisitor visitor;
+//	pack.visit(visitor);
+//	if (!visitor.canBeApplied())
+//		throw std::runtime_error("TODO: IMPLEMENT INTERRUPTION");
+
+	logGlobal->info("Prediction: pack '%s'", typeid(pack).name());
+
+	ConnectionPackWriter packWriter;
+	BinarySerializer serializer(&packWriter);
+	serializer & &pack;
+	predictedReplies.back().writtenPacks.push_back(std::move(packWriter));
 }
 
+void AntilagServer::sendPack(CPackForClient & pack, GameConnectionID connectionID)
+{
+	// TODO
+}

+ 8 - 12
client/AntilagServer.h

@@ -12,13 +12,12 @@
 #include "../lib/networkPacks/NetPackVisitor.h"
 #include "../server/IGameServer.h"
 #include "../lib/network/NetworkInterface.h"
-#include "../lib/serializer/IGameConnection.h"
 #include "../lib/serializer/CSerializer.h"
 #include "../lib/serializer/BinarySerializer.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 struct CPackForServer;
-class IGameConnection;
+class GameConnection;
 VCMI_LIB_NAMESPACE_END
 
 class CGameHandler;
@@ -31,13 +30,9 @@ public:
 	int write(const std::byte * data, unsigned size) final;
 };
 
-class AntilagFakeConnection final : public IGameConnection
+class AntilagReplyPrediction
 {
 public:
-	void sendPack(const CPack & pack) override;
-	std::unique_ptr<CPack> retrievePack(const std::vector<std::byte> & data) override;
-	int getConnectionID() const override;
-
 	PlayerColor senderID;
 	uint32_t requestID;
 	std::vector<ConnectionPackWriter> writtenPacks;
@@ -126,7 +121,6 @@ private:
 	//void visitChangeObjPos(ChangeObjPos & pack) override;
 	//void visitPlayerEndsTurn(PlayerEndsTurn & pack) override;
 	//void visitPlayerEndsGame(PlayerEndsGame & pack) override;
-	//void visitPlayerReinitInterface(PlayerReinitInterface & pack) override;
 	//void visitRemoveBonus(RemoveBonus & pack) override;
 	//void visitRemoveObject(RemoveObject & pack) override;
 	void visitTryMoveHero(TryMoveHero & pack) override;
@@ -186,9 +180,9 @@ public:
 // Fake server that is used by client to make a quick prediction on what real server would reply without waiting for network latency
 class AntilagServer final : public IGameServer, public INetworkConnectionListener, boost::noncopyable
 {
-	std::vector<std::shared_ptr<AntilagFakeConnection>> predictedReplies;
+	std::vector<AntilagReplyPrediction> predictedReplies;
 	std::shared_ptr<INetworkConnection> antilagNetConnection;
-	std::shared_ptr<IGameConnection> antilagGameConnection;
+	std::shared_ptr<GameConnection> antilagGameConnection;
 	std::unique_ptr<CGameHandler> gameHandler;
 
 	static constexpr uint32_t invalidPackageID = std::numeric_limits<uint32_t>::max();
@@ -198,9 +192,11 @@ class AntilagServer final : public IGameServer, public INetworkConnectionListene
 	void setState(EServerState value) override;
 	EServerState getState() const override;
 	bool isPlayerHost(const PlayerColor & color) const override;
-	bool hasPlayerAt(PlayerColor player, const std::shared_ptr<IGameConnection> & c) const override;
+	bool hasPlayerAt(PlayerColor player, GameConnectionID connection) const override;
 	bool hasBothPlayersAtSameConnection(PlayerColor left, PlayerColor right) const override;
-	void broadcastPack(CPackForClient & pack) override;
+	void applyPack(CPackForClient & pack) override;
+	void sendPack(CPackForClient & pack, GameConnectionID connectionID) override;
+
 	void onDisconnected(const std::shared_ptr<INetworkConnection> & connection, const std::string & errorMessage) override;
 	void onPacketReceived(const std::shared_ptr<INetworkConnection> & connection, const std::vector<std::byte> & message) override;
 

+ 4 - 4
client/CServerHandler.cpp

@@ -128,7 +128,7 @@ void CServerHandler::threadRunNetwork()
 
 void CServerHandler::resetStateForLobby(EStartMode mode, ESelectionScreen screen, EServerMode newServerMode, const std::vector<std::string> & playerNames)
 {
-	hostClientId = -1;
+	hostClientId = GameConnectionID::INVALID;
 	setState(EClientState::NONE);
 	serverMode = newServerMode;
 	mapToStart = nullptr;
@@ -297,7 +297,7 @@ bool CServerHandler::isMyColor(PlayerColor color) const
 	return isClientColor(logicConnection->connectionID, color);
 }
 
-ui8 CServerHandler::myFirstId() const
+PlayerConnectionID CServerHandler::myFirstId() const
 {
 	return clientFirstId(logicConnection->connectionID);
 }
@@ -508,7 +508,7 @@ void CServerHandler::sendMessage(const std::string & txt) const
 		if(id.length())
 		{
 			LobbyChangeHost lch;
-			lch.newHostConnectionId = boost::lexical_cast<int>(id);
+			lch.newHostConnectionId = static_cast<GameConnectionID>(boost::lexical_cast<int>(id));
 			sendLobbyPack(lch);
 		}
 	}
@@ -520,7 +520,7 @@ void CServerHandler::sendMessage(const std::string & txt) const
 		readed >> playerColorId;
 		if(connectedId.length() && playerColorId.length())
 		{
-			ui8 connected = boost::lexical_cast<int>(connectedId);
+			auto connected = static_cast<PlayerConnectionID>(boost::lexical_cast<int>(connectedId));
 			auto color = PlayerColor(boost::lexical_cast<int>(playerColorId));
 			if(color.isValidPlayer() && playerNames.find(connected) != playerNames.end())
 			{

+ 1 - 1
client/CServerHandler.h

@@ -159,7 +159,7 @@ public:
 	std::set<PlayerColor> getHumanColors();
 	PlayerColor myFirstColor() const;
 	bool isMyColor(PlayerColor color) const;
-	ui8 myFirstId() const; // Used by chat only!
+	PlayerConnectionID myFirstId() const; // Used by chat only!
 
 	EClientState getState() const;
 	void setState(EClientState newState);

+ 0 - 1
client/ClientNetPackVisitors.h

@@ -58,7 +58,6 @@ public:
 	void visitChangeObjPos(ChangeObjPos & pack) override;
 	void visitPlayerEndsTurn(PlayerEndsTurn & pack) override;
 	void visitPlayerEndsGame(PlayerEndsGame & pack) override;
-	void visitPlayerReinitInterface(PlayerReinitInterface & pack) override;
 	void visitRemoveBonus(RemoveBonus & pack) override;
 	void visitRemoveObject(RemoveObject & pack) override;
 	void visitTryMoveHero(TryMoveHero & pack) override;

+ 0 - 35
client/NetPacksClient.cpp

@@ -43,7 +43,6 @@
 #include "../lib/mapObjects/CGMarket.h"
 #include "../lib/mapObjects/CGTownInstance.h"
 #include "../lib/gameState/CGameState.h"
-#include "../lib/serializer/GameConnection.h"
 #include "../lib/CStack.h"
 #include "../lib/battle/BattleInfo.h"
 #include "../lib/GameConstants.h"
@@ -422,40 +421,6 @@ void ApplyClientNetPackVisitor::visitPlayerEndsGame(PlayerEndsGame & pack)
 	}
 }
 
-void ApplyClientNetPackVisitor::visitPlayerReinitInterface(PlayerReinitInterface & pack)
-{
-	auto initInterfaces = [this]()
-	{
-		cl.initPlayerInterfaces();
-
-		for(PlayerColor player(0); player < PlayerColor::PLAYER_LIMIT; ++player)
-		{
-			if(cl.gameState().isPlayerMakingTurn(player))
-			{
-				callAllInterfaces(cl, &IGameEventsReceiver::playerStartsTurn, player);
-				callOnlyThatInterface(cl, player, &CGameInterface::yourTurn, QueryID::NONE);
-			}
-		}
-	};
-	
-	for(auto player : pack.players)
-	{
-		auto & plSettings = GAME->server().si->getIthPlayersSettings(player);
-		if(pack.playerConnectionId == PlayerSettings::PLAYER_AI)
-		{
-			plSettings.connectedPlayerIDs.clear();
-			cl.initPlayerEnvironments();
-			initInterfaces();
-		}
-		else if(pack.playerConnectionId == GAME->server().logicConnection->connectionID)
-		{
-			plSettings.connectedPlayerIDs.insert(pack.playerConnectionId);
-			cl.playerint.clear();
-			initInterfaces();
-		}
-	}
-}
-
 void ApplyClientNetPackVisitor::visitRemoveBonus(RemoveBonus & pack)
 {
 	switch(pack.who)

+ 1 - 7
client/NetPacksLobbyClient.cpp

@@ -152,14 +152,8 @@ void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyPrepareStartGame(LobbyPrepareS
 
 void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
 {
-	if(pack.clientId != -1 && pack.clientId != handler.logicConnection->connectionID)
-	{
-		result = false;
-		return;
-	}
-	
 	handler.setState(EClientState::STARTING);
-	if(handler.si->mode != EStartMode::LOAD_GAME || pack.clientId == handler.logicConnection->connectionID)
+	if(handler.si->mode != EStartMode::LOAD_GAME)
 	{
 		auto modeBackup = handler.si->mode;
 		handler.si = pack.initializedStartInfo;

+ 2 - 1
lib/CMakeLists.txt

@@ -709,12 +709,13 @@ set(lib_MAIN_HEADERS
 	serializer/CSaveFile.h
 	serializer/CSerializer.h
 	serializer/CTypeList.h
-	serializer/IGameConnection.h
+	serializer/GameConnectionID.h
 	serializer/JsonDeserializer.h
 	serializer/JsonSerializeFormat.h
 	serializer/JsonSerializer.h
 	serializer/JsonUpdater.h
 	serializer/ESerializationVersion.h
+	serializer/PlayerConnectionID.h
 	serializer/RegisterTypes.h
 	serializer/Serializeable.h
 	serializer/SerializerReflection.h

+ 13 - 13
lib/StartInfo.cpp

@@ -71,7 +71,7 @@ const PlayerSettings & StartInfo::getIthPlayersSettings(const PlayerColor & no)
 	return const_cast<StartInfo &>(*this).getIthPlayersSettings(no);
 }
 
-PlayerSettings * StartInfo::getPlayersSettings(const ui8 connectedPlayerId)
+PlayerSettings * StartInfo::getPlayersSettings(PlayerConnectionID connectedPlayerId)
 {
 	for(auto & elem : playerInfos)
 	{
@@ -124,7 +124,7 @@ void LobbyInfo::verifyStateBeforeStart(bool ignoreNoHuman) const
 	}
 }
 
-bool LobbyInfo::isClientHost(int clientId) const
+bool LobbyInfo::isClientHost(GameConnectionID clientId) const
 {
 	return clientId == hostClientId;
 }
@@ -134,7 +134,7 @@ bool LobbyInfo::isPlayerHost(const PlayerColor & color) const
 	return vstd::contains(getAllClientPlayers(hostClientId), color);
 }
 
-std::set<PlayerColor> LobbyInfo::getAllClientPlayers(int clientId) const
+std::set<PlayerColor> LobbyInfo::getAllClientPlayers(GameConnectionID clientId) const
 {
 	std::set<PlayerColor> players;
 	for(auto & elem : si->playerInfos)
@@ -142,7 +142,7 @@ std::set<PlayerColor> LobbyInfo::getAllClientPlayers(int clientId) const
 		if(isClientHost(clientId) && elem.second.isControlledByAI())
 			players.insert(elem.first);
 
-		for(ui8 id : elem.second.connectedPlayerIDs)
+		for(PlayerConnectionID id : elem.second.connectedPlayerIDs)
 		{
 			if(vstd::contains(getConnectedPlayerIdsForClient(clientId), id))
 				players.insert(elem.first);
@@ -154,9 +154,9 @@ std::set<PlayerColor> LobbyInfo::getAllClientPlayers(int clientId) const
 	return players;
 }
 
-std::vector<ui8> LobbyInfo::getConnectedPlayerIdsForClient(int clientId) const
+std::vector<PlayerConnectionID> LobbyInfo::getConnectedPlayerIdsForClient(GameConnectionID clientId) const
 {
-	std::vector<ui8> ids;
+	std::vector<PlayerConnectionID> ids;
 
 	for(const auto & pair : playerNames)
 	{
@@ -172,12 +172,12 @@ std::vector<ui8> LobbyInfo::getConnectedPlayerIdsForClient(int clientId) const
 	return ids;
 }
 
-std::set<PlayerColor> LobbyInfo::clientHumanColors(int clientId)
+std::set<PlayerColor> LobbyInfo::clientHumanColors(GameConnectionID clientId)
 {
 	std::set<PlayerColor> players;
 	for(auto & elem : si->playerInfos)
 	{
-		for(ui8 id : elem.second.connectedPlayerIDs)
+		for(PlayerConnectionID id : elem.second.connectedPlayerIDs)
 		{
 			if(vstd::contains(getConnectedPlayerIdsForClient(clientId), id))
 			{
@@ -190,7 +190,7 @@ std::set<PlayerColor> LobbyInfo::clientHumanColors(int clientId)
 }
 
 
-PlayerColor LobbyInfo::clientFirstColor(int clientId) const
+PlayerColor LobbyInfo::clientFirstColor(GameConnectionID clientId) const
 {
 	for(auto & pair : si->playerInfos)
 	{
@@ -201,11 +201,11 @@ PlayerColor LobbyInfo::clientFirstColor(int clientId) const
 	return PlayerColor::CANNOT_DETERMINE;
 }
 
-bool LobbyInfo::isClientColor(int clientId, const PlayerColor & color) const
+bool LobbyInfo::isClientColor(GameConnectionID clientId, const PlayerColor & color) const
 {
 	if(si->playerInfos.find(color) != si->playerInfos.end())
 	{
-		for(ui8 id : si->playerInfos.find(color)->second.connectedPlayerIDs)
+		for(PlayerConnectionID id : si->playerInfos.find(color)->second.connectedPlayerIDs)
 		{
 			if(playerNames.find(id) != playerNames.end())
 			{
@@ -217,7 +217,7 @@ bool LobbyInfo::isClientColor(int clientId, const PlayerColor & color) const
 	return false;
 }
 
-ui8 LobbyInfo::clientFirstId(int clientId) const
+PlayerConnectionID LobbyInfo::clientFirstId(GameConnectionID clientId) const
 {
 	for(const auto & pair : playerNames)
 	{
@@ -225,7 +225,7 @@ ui8 LobbyInfo::clientFirstId(int clientId) const
 			return pair.first;
 	}
 
-	return 0;
+	return PlayerConnectionID::PLAYER_AI;
 }
 
 PlayerInfo & LobbyInfo::getPlayerInfo(PlayerColor color)

+ 15 - 15
lib/StartInfo.h

@@ -15,7 +15,9 @@
 #include "TurnTimerInfo.h"
 #include "ExtraOptionsInfo.h"
 #include "campaign/CampaignConstants.h"
+#include "serializer/GameConnectionID.h"
 #include "serializer/Serializeable.h"
+#include "serializer/PlayerConnectionID.h"
 #include "ResourceSet.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
@@ -80,8 +82,6 @@ struct DLL_LINKAGE Handicap {
 /// Struct which describes the name, the color, the starting bonus of a player
 struct DLL_LINKAGE PlayerSettings
 {
-	enum { PLAYER_AI = 0 }; // for use in playerID
-
 	PlayerStartingBonus bonus;
 	FactionID castle;
 	HeroTypeID hero;
@@ -93,7 +93,7 @@ struct DLL_LINKAGE PlayerSettings
 	Handicap handicap;
 
 	std::string name;
-	std::set<ui8> connectedPlayerIDs; //Empty - AI, or connectrd player ids
+	std::set<PlayerConnectionID> connectedPlayerIDs; //Empty - AI, or connectrd player ids
 	bool compOnly; //true if this player is a computer only player; required for RMG
 	template <typename Handler>
 	void serialize(Handler &h)
@@ -148,7 +148,7 @@ struct DLL_LINKAGE StartInfo : public Serializeable
 
 	PlayerSettings & getIthPlayersSettings(const PlayerColor & no);
 	const PlayerSettings & getIthPlayersSettings(const PlayerColor & no) const;
-	PlayerSettings * getPlayersSettings(const ui8 connectedPlayerId);
+	PlayerSettings * getPlayersSettings(PlayerConnectionID connectedPlayerId);
 
 	// TODO: Must be client-side
 	std::string getCampaignName() const;
@@ -183,7 +183,7 @@ struct DLL_LINKAGE StartInfo : public Serializeable
 
 struct ClientPlayer
 {
-	int connection;
+	GameConnectionID connection;
 	std::string name;
 
 	template <typename Handler> void serialize(Handler &h)
@@ -197,14 +197,14 @@ struct DLL_LINKAGE LobbyState
 {
 	std::shared_ptr<StartInfo> si;
 	std::shared_ptr<CMapInfo> mi;
-	std::map<ui8, ClientPlayer> playerNames; // id of player <-> player name; 0 is reserved as ID of AI "players"
-	int hostClientId;
+	std::map<PlayerConnectionID, ClientPlayer> playerNames; // id of player <-> player name;
+	GameConnectionID hostClientId = GameConnectionID::INVALID;
 	// TODO: Campaign-only and we don't really need either of them.
 	// Before start both go into CCampaignState that is part of StartInfo
 	CampaignScenarioID campaignMap;
 	int campaignBonus;
 
-	LobbyState() : si(new StartInfo()), hostClientId(-1), campaignMap(CampaignScenarioID::NONE), campaignBonus(-1) {}
+	LobbyState() : si(new StartInfo()), campaignMap(CampaignScenarioID::NONE), campaignBonus(-1) {}
 
 	template <typename Handler> void serialize(Handler &h)
 	{
@@ -225,16 +225,16 @@ struct DLL_LINKAGE LobbyInfo : public LobbyState
 
 	void verifyStateBeforeStart(bool ignoreNoHuman = false) const;
 
-	bool isClientHost(int clientId) const;
+	bool isClientHost(GameConnectionID clientId) const;
 	bool isPlayerHost(const PlayerColor & color) const;
-	std::set<PlayerColor> getAllClientPlayers(int clientId) const;
-	std::vector<ui8> getConnectedPlayerIdsForClient(int clientId) const;
+	std::set<PlayerColor> getAllClientPlayers(GameConnectionID clientId) const;
+	std::vector<PlayerConnectionID> getConnectedPlayerIdsForClient(GameConnectionID clientId) const;
 
 	// Helpers for lobby state access
-	std::set<PlayerColor> clientHumanColors(int clientId);
-	PlayerColor clientFirstColor(int clientId) const;
-	bool isClientColor(int clientId, const PlayerColor & color) const;
-	ui8 clientFirstId(int clientId) const; // Used by chat only!
+	std::set<PlayerColor> clientHumanColors(GameConnectionID clientId);
+	PlayerColor clientFirstColor(GameConnectionID clientId) const;
+	bool isClientColor(GameConnectionID clientId, const PlayerColor & color) const;
+	PlayerConnectionID clientFirstId(GameConnectionID clientId) const; // Used by chat only!
 	PlayerInfo & getPlayerInfo(PlayerColor color);
 	TeamID getPlayerTeamId(const PlayerColor & color);
 };

+ 0 - 13
lib/gameState/GameStatePackVisitor.cpp

@@ -321,19 +321,6 @@ void GameStatePackVisitor::visitPlayerEndsGame(PlayerEndsGame & pack)
 	gs.actingPlayers.erase(pack.player);
 }
 
-void GameStatePackVisitor::visitPlayerReinitInterface(PlayerReinitInterface & pack)
-{
-	if(!gs.getStartInfo())
-		return;
-
-	//TODO: what does mean if more that one player connected?
-	if(pack.playerConnectionId == PlayerSettings::PLAYER_AI)
-	{
-		for(const auto & player : pack.players)
-			gs.getStartInfo()->getIthPlayersSettings(player).connectedPlayerIDs.clear();
-	}
-}
-
 void GameStatePackVisitor::visitRemoveBonus(RemoveBonus & pack)
 {
 	CBonusSystemNode *node = nullptr;

+ 0 - 1
lib/gameState/GameStatePackVisitor.h

@@ -57,7 +57,6 @@ public:
 	void visitChangeObjPos(ChangeObjPos & pack) override;
 	void visitPlayerEndsTurn(PlayerEndsTurn & pack) override;
 	void visitPlayerEndsGame(PlayerEndsGame & pack) override;
-	void visitPlayerReinitInterface(PlayerReinitInterface & pack) override;
 	void visitRemoveBonus(RemoveBonus & pack) override;
 	void visitRemoveObject(RemoveObject & pack) override;
 	void visitTryMoveHero(TryMoveHero & pack) override;

+ 0 - 1
lib/networkPacks/NetPackVisitor.h

@@ -54,7 +54,6 @@ public:
 	virtual void visitChangeObjPos(ChangeObjPos & pack) {}
 	virtual void visitPlayerEndsTurn(PlayerEndsTurn & pack) {};
 	virtual void visitPlayerEndsGame(PlayerEndsGame & pack) {}
-	virtual void visitPlayerReinitInterface(PlayerReinitInterface & pack) {}
 	virtual void visitRemoveBonus(RemoveBonus & pack) {}
 	virtual void visitSetCommanderProperty(SetCommanderProperty & pack) {}
 	virtual void visitAddQuest(AddQuest & pack) {}

+ 0 - 5
lib/networkPacks/NetPacksLib.cpp

@@ -193,11 +193,6 @@ void PlayerEndsGame::visitTyped(ICPackVisitor & visitor)
 	visitor.visitPlayerEndsGame(*this);
 }
 
-void PlayerReinitInterface::visitTyped(ICPackVisitor & visitor)
-{
-	visitor.visitPlayerReinitInterface(*this);
-}
-
 void RemoveBonus::visitTyped(ICPackVisitor & visitor)
 {
 	visitor.visitRemoveBonus(*this);

+ 0 - 14
lib/networkPacks/PacksForClient.h

@@ -533,20 +533,6 @@ struct DLL_LINKAGE PlayerEndsGame : public CPackForClient
 	}
 };
 
-struct DLL_LINKAGE PlayerReinitInterface : public CPackForClient
-{
-	std::vector<PlayerColor> players;
-	ui8 playerConnectionId; //PLAYER_AI for AI player
-
-	void visitTyped(ICPackVisitor & visitor) override;
-
-	template <typename Handler> void serialize(Handler & h)
-	{
-		h & players;
-		h & playerConnectionId;
-	}
-};
-
 struct DLL_LINKAGE RemoveBonus : public CPackForClient
 {
 	explicit RemoveBonus(GiveBonus::ETarget Who = GiveBonus::ETarget::OBJECT)

+ 5 - 8
lib/networkPacks/PacksForLobby.h

@@ -41,8 +41,8 @@ struct DLL_LINKAGE LobbyClientConnected : public CLobbyPackToPropagate
 	std::vector<std::string> names;
 	EStartMode mode = EStartMode::INVALID;
 	// Changed by server before announcing pack
-	int clientId = -1;
-	int hostClientId = -1;
+	GameConnectionID clientId = GameConnectionID::INVALID;
+	GameConnectionID hostClientId = GameConnectionID::INVALID;
 	ESerializationVersion version = ESerializationVersion::CURRENT;
 
 	void visitTyped(ICPackVisitor & visitor) override;
@@ -61,10 +61,9 @@ struct DLL_LINKAGE LobbyClientConnected : public CLobbyPackToPropagate
 
 struct DLL_LINKAGE LobbyClientDisconnected : public CLobbyPackToPropagate
 {
-	int clientId;
+	GameConnectionID clientId = GameConnectionID::INVALID;
 	bool shutdownServer = false;
 
-
 	void visitTyped(ICPackVisitor & visitor) override;
 
 	template <typename Handler> void serialize(Handler &h)
@@ -138,7 +137,6 @@ struct DLL_LINKAGE LobbyStartGame : public CLobbyPackToPropagate
 	// Set by server
 	std::shared_ptr<StartInfo> initializedStartInfo;
 	std::shared_ptr<CGameState> initializedGameState;
-	int clientId = -1; //-1 means to all clients
 
 	void visitTyped(ICPackVisitor & visitor) override;
 
@@ -146,7 +144,6 @@ struct DLL_LINKAGE LobbyStartGame : public CLobbyPackToPropagate
 	{
 		if (!h.saving)
 			h.loadingGamestate = true;
-		h & clientId;
 		h & initializedStartInfo;
 		h & initializedGameState;
 		if (!h.saving)
@@ -156,7 +153,7 @@ struct DLL_LINKAGE LobbyStartGame : public CLobbyPackToPropagate
 
 struct DLL_LINKAGE LobbyChangeHost : public CLobbyPackToPropagate
 {
-	int newHostConnectionId = -1;
+	GameConnectionID newHostConnectionId = GameConnectionID::INVALID;
 
 	void visitTyped(ICPackVisitor & visitor) override;
 
@@ -340,7 +337,7 @@ struct DLL_LINKAGE LobbySetDifficulty : public CLobbyPackToServer
 
 struct DLL_LINKAGE LobbyForceSetPlayer : public CLobbyPackToServer
 {
-	ui8 targetConnectedPlayer = -1;
+	PlayerConnectionID targetConnectedPlayer = PlayerConnectionID::INVALID;
 	PlayerColor targetPlayerColor = PlayerColor::CANNOT_DETERMINE;
 
 	void visitTyped(ICPackVisitor & visitor) override;

+ 0 - 6
lib/serializer/GameConnection.cpp

@@ -58,7 +58,6 @@ GameConnection::GameConnection(std::weak_ptr<INetworkConnection> networkConnecti
 	, packWriter(std::make_unique<ConnectionPackWriter>())
 	, deserializer(std::make_unique<BinaryDeserializer>(packReader.get()))
 	, serializer(std::make_unique<BinarySerializer>(packWriter.get()))
-	, connectionID(-1)
 {
 	assert(networkConnection.lock() != nullptr);
 
@@ -68,11 +67,6 @@ GameConnection::GameConnection(std::weak_ptr<INetworkConnection> networkConnecti
 
 GameConnection::~GameConnection() = default;
 
-int GameConnection::getConnectionID() const
-{
-	return connectionID;
-}
-
 void GameConnection::sendPack(const CPack & pack)
 {
 	std::scoped_lock lock(writeMutex);

+ 5 - 6
lib/serializer/GameConnection.h

@@ -9,7 +9,7 @@
  */
 #pragma once
 
-#include "IGameConnection.h"
+#include "GameConnectionID.h"
 
 enum class ESerializationVersion : int32_t;
 
@@ -26,7 +26,7 @@ class IGameInfoCallback;
 
 /// Wrapper class for game connection
 /// Handles serialization and deserialization of data received from network
-class DLL_LINKAGE GameConnection final : public IGameConnection
+class DLL_LINKAGE GameConnection final
 {
 	/// Non-owning pointer to underlying connection
 	std::weak_ptr<INetworkConnection> networkConnection;
@@ -43,14 +43,13 @@ public:
 	std::shared_ptr<INetworkConnection> getConnection();
 
 	std::string uuid;
-	int connectionID;
+	GameConnectionID connectionID = GameConnectionID::INVALID;
 
 	explicit GameConnection(std::weak_ptr<INetworkConnection> networkConnection);
 	~GameConnection();
 
-	void sendPack(const CPack & pack) override;
-	int getConnectionID() const override;
-	std::unique_ptr<CPack> retrievePack(const std::vector<std::byte> & data) override;
+	void sendPack(const CPack & pack);
+	std::unique_ptr<CPack> retrievePack(const std::vector<std::byte> & data);
 
 	void enterLobbyConnectionMode();
 	void setCallback(IGameInfoCallback & cb);

+ 20 - 0
lib/serializer/GameConnectionID.h

@@ -0,0 +1,20 @@
+/*
+ * GameConnectionID.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+enum class GameConnectionID : int8_t
+{
+	INVALID = -1,
+	FIRST_CONNECTION = 1
+};
+
+VCMI_LIB_NAMESPACE_END

+ 0 - 24
lib/serializer/IGameConnection.h

@@ -1,24 +0,0 @@
-/*
- * IConnection.h, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-#pragma once
-
-VCMI_LIB_NAMESPACE_BEGIN
-
-struct CPack;
-
-class DLL_LINKAGE IGameConnection : boost::noncopyable
-{
-public:
-	virtual void sendPack(const CPack & pack) = 0;
-	virtual std::unique_ptr<CPack> retrievePack(const std::vector<std::byte> & data) = 0;
-	virtual int getConnectionID() const = 0;
-};
-
-VCMI_LIB_NAMESPACE_END

+ 21 - 0
lib/serializer/PlayerConnectionID.h

@@ -0,0 +1,21 @@
+/*
+ * PlayerConnectionID.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+enum class PlayerConnectionID : int8_t
+{
+	INVALID = -1,
+	PLAYER_AI = 0,
+	FIRST_HUMAN = 1
+};
+
+VCMI_LIB_NAMESPACE_END

+ 0 - 1
lib/serializer/RegisterTypes.h

@@ -148,7 +148,6 @@ void registerTypes(Serializer &s)
 	s.template registerType<ChangeObjPos>(101);
 	s.template registerType<PlayerEndsTurn>(102);
 	s.template registerType<PlayerEndsGame>(103);
-	s.template registerType<PlayerReinitInterface>(104);
 	s.template registerType<RemoveBonus>(105);
 	s.template registerType<ChangeFormation>(107);
 	s.template registerType<RemoveObject>(108);

+ 30 - 41
server/CGameHandler.cpp

@@ -75,7 +75,6 @@
 
 #include "../lib/serializer/CSaveFile.h"
 #include "../lib/serializer/CLoadFile.h"
-#include "../lib/serializer/IGameConnection.h"
 
 #include "../lib/spells/CSpellHandler.h"
 
@@ -437,7 +436,7 @@ void CGameHandler::changeSecSkill(const CGHeroInstance * hero, SecondarySkill wh
 
 }
 
-void CGameHandler::handleClientDisconnection(const std::shared_ptr<IGameConnection> & c)
+void CGameHandler::handleClientDisconnection(GameConnectionID connectionID)
 {
 	if(gameServer().getState() == EServerState::SHUTDOWN || !gameState().getStartInfo())
 	{
@@ -454,7 +453,7 @@ void CGameHandler::handleClientDisconnection(const std::shared_ptr<IGameConnecti
 		if (gameInfo().getPlayerState(player.first)->status != EPlayerStatus::INGAME)
 			continue;
 
-		if (gameServer().hasPlayerAt(player.first, c))
+		if (gameServer().hasPlayerAt(player.first, connectionID))
 			disconnectedPlayers.push_back(player.first);
 		else
 			remainingPlayers.push_back(player.first);
@@ -474,7 +473,7 @@ void CGameHandler::handleClientDisconnection(const std::shared_ptr<IGameConnecti
 	}
 }
 
-void CGameHandler::handleReceivedPack(std::shared_ptr<IGameConnection> connection, CPackForServer & pack)
+void CGameHandler::handleReceivedPack(GameConnectionID connection, CPackForServer & pack)
 {
 	//prepare struct informing that action was applied
 	auto sendPackageResponse = [&](bool successfullyApplied)
@@ -485,17 +484,15 @@ void CGameHandler::handleReceivedPack(std::shared_ptr<IGameConnection> connectio
 			CTypeList::getInstance().getTypeID(&pack),
 			successfullyApplied
 		);
-		connection->sendPack(applied);
+		gameServer().sendPack(applied, connection);
 	};
 
-	std::this_thread::sleep_for(std::chrono::milliseconds(100));
 	PackageReceived received(
 		pack.player,
 		pack.requestID,
 		CTypeList::getInstance().getTypeID(&pack)
 	);
-	connection->sendPack(received);
-
+	gameServer().sendPack(received, connection);
 
 	if(isBlockedByQueries(&pack, pack.player))
 	{
@@ -1133,7 +1130,7 @@ void CGameHandler::showBlockingDialog(const IObjectInterface * caller, BlockingD
 	auto dialogQuery = std::make_shared<CBlockingDialogQuery>(this, caller, *iw);
 	queries->addQuery(dialogQuery);
 	iw->queryID = dialogQuery->queryID;
-	sendToAllClients(*iw);
+	sendAndApply(*iw);
 }
 
 void CGameHandler::showTeleportDialog(TeleportDialog *iw)
@@ -1141,7 +1138,7 @@ void CGameHandler::showTeleportDialog(TeleportDialog *iw)
 	auto dialogQuery = std::make_shared<CTeleportDialogQuery>(this, *iw);
 	queries->addQuery(dialogQuery);
 	iw->queryID = dialogQuery->queryID;
-	sendToAllClients(*iw);
+	sendAndApply(*iw);
 }
 
 void CGameHandler::giveResource(PlayerColor player, GameResID which, int val)
@@ -1506,17 +1503,9 @@ void CGameHandler::heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)
 	}
 }
 
-void CGameHandler::sendToAllClients(CPackForClient & pack)
-{
-	logNetwork->trace("\tSending to all clients: %s", typeid(pack).name());
-	gameServer().broadcastPack(pack);
-}
-
 void CGameHandler::sendAndApply(CPackForClient & pack)
 {
-	sendToAllClients(pack);
-	gs->apply(pack);
-	logNetwork->trace("\tApplied on gameState(): %s", typeid(pack).name());
+	gameServer().applyPack(pack);
 }
 
 void CGameHandler::sendAndApply(CGarrisonOperationPack & pack)
@@ -1537,62 +1526,62 @@ void CGameHandler::sendAndApply(NewStructures & pack)
 	checkVictoryLossConditionsForPlayer(gameInfo().getTown(pack.tid)->tempOwner);
 }
 
-bool CGameHandler::isPlayerOwns(const std::shared_ptr<IGameConnection> & connection, const CPackForServer * pack, ObjectInstanceID id)
+bool CGameHandler::isPlayerOwns(GameConnectionID connectionID, const CPackForServer * pack, ObjectInstanceID id)
 {
-	return pack->player == gameState().getOwner(id) && hasPlayerAt(gameState().getOwner(id), connection);
+	return pack->player == gameState().getOwner(id) && hasPlayerAt(gameState().getOwner(id), connectionID);
 }
 
-void CGameHandler::throwNotAllowedAction(const std::shared_ptr<IGameConnection> & connection)
+void CGameHandler::throwNotAllowedAction(GameConnectionID connectionID)
 {
-	playerMessages->sendSystemMessage(connection, MetaString::createFromTextID("vcmi.server.errors.notAllowed"));
+	playerMessages->sendSystemMessage(connectionID, MetaString::createFromTextID("vcmi.server.errors.notAllowed"));
 
 	logNetwork->error("Player is not allowed to perform this action!");
 	throw ExceptionNotAllowedAction();
 }
 
-void CGameHandler::wrongPlayerMessage(const std::shared_ptr<IGameConnection> & connection, const CPackForServer * pack, PlayerColor expectedplayer)
+void CGameHandler::wrongPlayerMessage(GameConnectionID connectionID, const CPackForServer * pack, PlayerColor expectedplayer)
 {
 	auto str = MetaString::createFromTextID("vcmi.server.errors.wrongIdentified");
 	str.replaceName(pack->player);
 	str.replaceName(expectedplayer);
 	logNetwork->error(str.toString());
 
-	playerMessages->sendSystemMessage(connection, str);
+	playerMessages->sendSystemMessage(connectionID, str);
 }
 
-void CGameHandler::throwIfWrongOwner(const std::shared_ptr<IGameConnection> & connection, const CPackForServer * pack, ObjectInstanceID id)
+void CGameHandler::throwIfWrongOwner(GameConnectionID connectionID, const CPackForServer * pack, ObjectInstanceID id)
 {
-	if(!isPlayerOwns(connection, pack, id))
+	if(!isPlayerOwns(connectionID, pack, id))
 	{
-		wrongPlayerMessage(connection, pack, gameState().getOwner(id));
-		throwNotAllowedAction(connection);
+		wrongPlayerMessage(connectionID, pack, gameState().getOwner(id));
+		throwNotAllowedAction(connectionID);
 	}
 }
 
-void CGameHandler::throwIfPlayerNotActive(const std::shared_ptr<IGameConnection> & connection, const CPackForServer * pack)
+void CGameHandler::throwIfPlayerNotActive(GameConnectionID connectionID, const CPackForServer * pack)
 {
 	if (!turnOrder->isPlayerMakingTurn(pack->player))
-		throwNotAllowedAction(connection);
+		throwNotAllowedAction(connectionID);
 }
 
-void CGameHandler::throwIfWrongPlayer(const std::shared_ptr<IGameConnection> & connection, const CPackForServer * pack)
+void CGameHandler::throwIfWrongPlayer(GameConnectionID connectionID, const CPackForServer * pack)
 {
-	throwIfWrongPlayer(connection, pack, pack->player);
+	throwIfWrongPlayer(connectionID, pack, pack->player);
 }
 
-void CGameHandler::throwIfWrongPlayer(const std::shared_ptr<IGameConnection> & connection, const CPackForServer * pack, PlayerColor player)
+void CGameHandler::throwIfWrongPlayer(GameConnectionID connectionID, const CPackForServer * pack, PlayerColor player)
 {
-	if(!hasPlayerAt(player, connection) || pack->player != player)
+	if(!hasPlayerAt(player, connectionID) || pack->player != player)
 	{
-		wrongPlayerMessage(connection, pack, player);
-		throwNotAllowedAction(connection);
+		wrongPlayerMessage(connectionID, pack, player);
+		throwNotAllowedAction(connectionID);
 	}
 }
 
-void CGameHandler::throwAndComplain(const std::shared_ptr<IGameConnection> & connection, const std::string & txt)
+void CGameHandler::throwAndComplain(GameConnectionID connectionID, const std::string & txt)
 {
 	complain(txt);
-	throwNotAllowedAction(connection);
+	throwNotAllowedAction(connectionID);
 }
 
 void CGameHandler::save(const std::string & filename)
@@ -2046,9 +2035,9 @@ bool CGameHandler::arrangeStacks(ObjectInstanceID id1, ObjectInstanceID id2, ui8
 	return true;
 }
 
-bool CGameHandler::hasPlayerAt(PlayerColor player,  const std::shared_ptr<IGameConnection> & c) const
+bool CGameHandler::hasPlayerAt(PlayerColor player,  GameConnectionID connectionID) const
 {
-	return gameServer().hasPlayerAt(player, c);
+	return gameServer().hasPlayerAt(player, connectionID);
 }
 
 bool CGameHandler::hasBothPlayersAtSameConnection(PlayerColor left, PlayerColor right) const

+ 12 - 13
server/CGameHandler.h

@@ -16,13 +16,13 @@
 #include "../lib/ScriptHandler.h"
 #include "../lib/gameState/GameStatistics.h"
 #include "../lib/networkPacks/PacksForServer.h"
+#include "../lib/serializer/GameConnectionID.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
 struct SideInBattle;
 class IMarket;
 class SpellCastEnvironment;
-class IGameConnection;
 class CCommanderInstance;
 class EVictoryLossCheckResult;
 class CRandomGenerator;
@@ -204,9 +204,9 @@ public:
 	//////////////////////////////////////////////////////////////////////////
 
 	void init(StartInfo *si, Load::ProgressAccumulator & progressTracking);
-	void handleClientDisconnection(const std::shared_ptr<IGameConnection> & c);
-	void handleReceivedPack(std::shared_ptr<IGameConnection> c, CPackForServer & pack);
-	bool hasPlayerAt(PlayerColor player, const std::shared_ptr<IGameConnection> & c) const;
+	void handleClientDisconnection(GameConnectionID connectionI);
+	void handleReceivedPack(GameConnectionID connectionId, CPackForServer & pack);
+	bool hasPlayerAt(PlayerColor player, GameConnectionID connectionId) const;
 	bool hasBothPlayersAtSameConnection(PlayerColor left, PlayerColor right) const;
 
 	bool queryReply( QueryID qid, std::optional<int32_t> reply, PlayerColor player );
@@ -276,25 +276,24 @@ public:
 #endif
 	}
 
-	void sendToAllClients(CPackForClient & pack);
 	void sendAndApply(CPackForClient & pack) override;
 	void sendAndApply(CGarrisonOperationPack & pack);
 	void sendAndApply(SetResources & pack);
 	void sendAndApply(NewStructures & pack);
 
-	void wrongPlayerMessage(const std::shared_ptr<IGameConnection> & connection, const CPackForServer * pack, PlayerColor expectedplayer);
+	void wrongPlayerMessage(GameConnectionID connectionID, const CPackForServer * pack, PlayerColor expectedplayer);
 	/// Unconditionally throws with "Action not allowed" message
-	[[noreturn]] void throwNotAllowedAction(const std::shared_ptr<IGameConnection> & connection);
+	[[noreturn]] void throwNotAllowedAction(GameConnectionID connectionID);
 	/// Throws if player stated in pack is not making turn right now
-	void throwIfPlayerNotActive(const std::shared_ptr<IGameConnection> & connection, const CPackForServer * pack);
+	void throwIfPlayerNotActive(GameConnectionID connectionID, const CPackForServer * pack);
 	/// Throws if object is not owned by pack sender
-	void throwIfWrongOwner(const std::shared_ptr<IGameConnection> & connection, const CPackForServer * pack, ObjectInstanceID id);
+	void throwIfWrongOwner(GameConnectionID connectionID, const CPackForServer * pack, ObjectInstanceID id);
 	/// Throws if player is not present on connection of this pack
-	void throwIfWrongPlayer(const std::shared_ptr<IGameConnection> & connection, const CPackForServer * pack, PlayerColor player);
-	void throwIfWrongPlayer(const std::shared_ptr<IGameConnection> & connection, const CPackForServer * pack);
-	[[noreturn]] void throwAndComplain(const std::shared_ptr<IGameConnection> & connection, const std::string & txt);
+	void throwIfWrongPlayer(GameConnectionID connectionID, const CPackForServer * pack, PlayerColor player);
+	void throwIfWrongPlayer(GameConnectionID connectionID, const CPackForServer * pack);
+	[[noreturn]] void throwAndComplain(GameConnectionID connectionID, const std::string & txt);
 
-	bool isPlayerOwns(const std::shared_ptr<IGameConnection> & connection, const CPackForServer * pack, ObjectInstanceID id);
+	bool isPlayerOwns(GameConnectionID connectionID, const CPackForServer * pack, ObjectInstanceID id);
 
 	void start(bool resume);
 	void tick(int millisecondsPassed);

+ 47 - 67
server/CVCMIServer.cpp

@@ -60,7 +60,7 @@ public:
 	void visitForServer(CPackForServer & serverPack) override
 	{
 		if (gh)
-			gh->handleReceivedPack(connection, serverPack);
+			gh->handleReceivedPack(connection->connectionID, serverPack);
 		else
 			logNetwork->error("Received pack for game server while in lobby!");
 	}
@@ -71,8 +71,8 @@ public:
 };
 
 CVCMIServer::CVCMIServer(uint16_t port, bool runByClient)
-	: currentClientId(1)
-	, currentPlayerId(1)
+	: currentClientId(GameConnectionID::FIRST_CONNECTION)
+	, currentPlayerId(PlayerConnectionID::FIRST_HUMAN)
 	, port(port)
 	, runByClient(runByClient)
 {
@@ -300,7 +300,7 @@ void CVCMIServer::startGameImmediately()
 	{
 		auto players = getAllClientPlayers(activeConnection->connectionID);
 		std::stringstream sbuffer;
-		sbuffer << "Connection " << activeConnection->connectionID << " will handle " << players.size() << " player: ";
+		sbuffer << "Connection " << static_cast<int>(activeConnection->connectionID) << " will handle " << players.size() << " player: ";
 		for (PlayerColor color : players)
 			sbuffer << color << " ";
 
@@ -390,7 +390,7 @@ void CVCMIServer::announceTxt(const std::string & txt, const std::string & playe
 	announceTxt(str, playerName);
 }
 
-bool CVCMIServer::passHost(int toConnectionId)
+bool CVCMIServer::passHost(GameConnectionID toConnectionId)
 {
 	for(auto activeConnection : activeConnections)
 	{
@@ -400,7 +400,7 @@ bool CVCMIServer::passHost(int toConnectionId)
 			continue;
 
 		hostClientId = activeConnection->connectionID;
-		announceTxt(boost::str(boost::format("Pass host to connection %d") % toConnectionId));
+		announceTxt(boost::str(boost::format("Pass host to connection %d") % static_cast<int>(toConnectionId)));
 		return true;
 	}
 	return false;
@@ -410,27 +410,27 @@ void CVCMIServer::clientConnected(std::shared_ptr<GameConnection> c, std::vector
 {
 	assert(getState() == EServerState::LOBBY);
 
-	c->connectionID = currentClientId++;
+	c->connectionID = vstd::next(currentClientId, 1);
 	c->uuid = uuid;
 
-	if(hostClientId == -1)
+	if(hostClientId == GameConnectionID::INVALID)
 	{
 		hostClientId = c->connectionID;
 		si->mode = mode;
 	}
 
-	logNetwork->info("Connection with client %d established. UUID: %s", c->connectionID, c->uuid);
+	logNetwork->info("Connection with client %d established. UUID: %s", static_cast<int>(c->connectionID), c->uuid);
 
 	for(auto & name : names)
 	{
-		logNetwork->info("Client %d player: %s", c->connectionID, name);
-		ui8 id = currentPlayerId++;
+		logNetwork->info("Client %d player: %s", static_cast<int>(c->connectionID), name);
+		PlayerConnectionID id = vstd::next(currentPlayerId, 1);
 
 		ClientPlayer cp;
 		cp.connection = c->connectionID;
 		cp.name = name;
 		playerNames.try_emplace(id, cp);
-		announceTxt(boost::str(boost::format("%s (pid %d cid %d) joins the game") % name % id % c->connectionID));
+		announceTxt(boost::str(boost::format("%s (pid %d cid %d) joins the game") % name % static_cast<int>(id) % static_cast<int>(c->connectionID)));
 
 		//put new player in first slot with AI
 		for(auto & elem : si->playerInfos)
@@ -458,39 +458,11 @@ void CVCMIServer::clientDisconnected(std::shared_ptr<GameConnection> connection)
 
 	if(gh && getState() == EServerState::GAMEPLAY)
 	{
-		gh->handleClientDisconnection(connection);
+		gh->handleClientDisconnection(connection->connectionID);
 	}
 }
 
-void CVCMIServer::reconnectPlayer(int connId)
-{
-	PlayerReinitInterface startAiPack;
-	startAiPack.playerConnectionId = connId;
-
-	if(gh && si && getState() == 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;
-
-			std::string messageText = boost::str(boost::format("%s (cid %d) is connected") % playerSettings->name % connId);
-			gh->playerMessages->broadcastMessage(playerSettings->color, messageText);
-
-			startAiPack.players.push_back(playerSettings->color);
-		}
-
-		if(!startAiPack.players.empty())
-			gh->sendAndApply(startAiPack);
-	}
-}
-
-void CVCMIServer::setPlayerConnectedId(PlayerSettings & pset, ui8 player) const
+void CVCMIServer::setPlayerConnectedId(PlayerSettings & pset, PlayerConnectionID player) const
 {
 	if(vstd::contains(playerNames, player))
 		pset.name = playerNames.find(player)->second.name;
@@ -498,7 +470,7 @@ void CVCMIServer::setPlayerConnectedId(PlayerSettings & pset, ui8 player) const
 		pset.name = LIBRARY->generaltexth->allTexts[468]; //Computer
 
 	pset.connectedPlayerIDs.clear();
-	if(player != PlayerSettings::PLAYER_AI)
+	if(player != PlayerConnectionID::PLAYER_AI)
 		pset.connectedPlayerIDs.insert(player);
 }
 
@@ -525,7 +497,7 @@ void CVCMIServer::updateStartInfoOnMapChange(std::shared_ptr<CMapInfo> mapInfo,
 			}
 			else
 			{
-				setPlayerConnectedId(ps.second, PlayerSettings::PLAYER_AI);
+				setPlayerConnectedId(ps.second, PlayerConnectionID::PLAYER_AI);
 			}
 		}
 	}
@@ -550,7 +522,7 @@ void CVCMIServer::updateStartInfoOnMapChange(std::shared_ptr<CMapInfo> mapInfo,
 			}
 			else
 			{
-				setPlayerConnectedId(pset, PlayerSettings::PLAYER_AI);
+				setPlayerConnectedId(pset, PlayerConnectionID::PLAYER_AI);
 				if(!pinfo.canHumanPlay)
 				{
 					pset.compOnly = true;
@@ -626,8 +598,8 @@ void CVCMIServer::setPlayer(PlayerColor clickedColor)
 	struct PlayerToRestore
 	{
 		PlayerColor color;
-		int id;
-		void reset() { id = -1; color = PlayerColor::CANNOT_DETERMINE; }
+		PlayerConnectionID id;
+		void reset() { id = PlayerConnectionID::PLAYER_AI; color = PlayerColor::CANNOT_DETERMINE; }
 		PlayerToRestore(){ reset(); }
 	};
 
@@ -635,24 +607,24 @@ void CVCMIServer::setPlayer(PlayerColor clickedColor)
 	PlayerSettings & clicked = si->playerInfos[clickedColor];
 
 	//identify clicked player
-	int clickedNameID = 0; //number of player - zero means AI, assume it initially
+	PlayerConnectionID clickedNameID = PlayerConnectionID::PLAYER_AI;
 	if(clicked.isControlledByHuman())
 		clickedNameID = *(clicked.connectedPlayerIDs.begin()); //if not AI - set appropriate ID
 
-	if(clickedNameID > 0 && playerToRestore.id == clickedNameID) //player to restore is about to being replaced -> put him back to the old place
+	if(clickedNameID > PlayerConnectionID::PLAYER_AI && playerToRestore.id == clickedNameID) //player to restore is about to being replaced -> put him back to the old place
 	{
 		PlayerSettings & restPos = si->playerInfos[playerToRestore.color];
 		setPlayerConnectedId(restPos, playerToRestore.id);
 		playerToRestore.reset();
 	}
 
-	int newPlayer; //which player will take clicked position
+	PlayerConnectionID newPlayer; //which player will take clicked position
 
 	//who will be put here?
-	if(!clickedNameID) //AI player clicked -> if possible replace computer with unallocated player
+	if(clickedNameID == PlayerConnectionID::PLAYER_AI) //AI player clicked -> if possible replace computer with unallocated player
 	{
 		newPlayer = getIdOfFirstUnallocatedPlayer();
-		if(!newPlayer) //no "free" player -> get just first one
+		if(newPlayer == PlayerConnectionID::PLAYER_AI) //no "free" player -> get just first one
 			newPlayer = playerNames.begin()->first;
 	}
 	else //human clicked -> take next
@@ -663,23 +635,23 @@ void CVCMIServer::setPlayer(PlayerColor clickedColor)
 		if(i != playerNames.end())
 			newPlayer = i->first;
 		else
-			newPlayer = 0; //AI if we scrolled through all players
+			newPlayer = PlayerConnectionID::PLAYER_AI; //AI if we scrolled through all players
 	}
 
 	setPlayerConnectedId(clicked, newPlayer); //put player
 
 	//if that player was somewhere else, we need to replace him with computer
-	if(newPlayer) //not AI
+	if(newPlayer != PlayerConnectionID::PLAYER_AI) //not AI
 	{
 		for(auto i = si->playerInfos.begin(); i != si->playerInfos.end(); i++)
 		{
-			int curNameID = *(i->second.connectedPlayerIDs.begin());
+			PlayerConnectionID curNameID = *(i->second.connectedPlayerIDs.begin());
 			if(i->first != clickedColor && curNameID == newPlayer)
 			{
 				assert(i->second.connectedPlayerIDs.size());
 				playerToRestore.color = i->first;
 				playerToRestore.id = newPlayer;
-				setPlayerConnectedId(i->second, PlayerSettings::PLAYER_AI); //set computer
+				setPlayerConnectedId(i->second, PlayerConnectionID::PLAYER_AI); //set computer
 				break;
 			}
 		}
@@ -699,7 +671,7 @@ void CVCMIServer::setPlayerName(PlayerColor color, const std::string & name)
 	if(player.connectedPlayerIDs.empty())
 		return;
 
-	int nameID = *(player.connectedPlayerIDs.begin()); //if not AI - set appropriate ID
+	PlayerConnectionID nameID = *(player.connectedPlayerIDs.begin()); //if not AI - set appropriate ID
 
 	playerNames[nameID].name = name;
 	setPlayerConnectedId(player, nameID);
@@ -855,9 +827,9 @@ void CVCMIServer::setCampaignBonus(int bonusId)
 		for(auto & elem : si->playerInfos)
 		{
 			if(elem.first == startingPlayer)
-				setPlayerConnectedId(elem.second, 1);
+				setPlayerConnectedId(elem.second, PlayerConnectionID::FIRST_HUMAN);
 			else
-				setPlayerConnectedId(elem.second, PlayerSettings::PLAYER_AI);
+				setPlayerConnectedId(elem.second, PlayerConnectionID::PLAYER_AI);
 		}
 	}
 }
@@ -1003,14 +975,14 @@ std::vector<HeroTypeID> CVCMIServer::getUsedHeroes()
 	return heroIds;
 }
 
-ui8 CVCMIServer::getIdOfFirstUnallocatedPlayer() const
+PlayerConnectionID CVCMIServer::getIdOfFirstUnallocatedPlayer() const
 {
 	for(auto i = playerNames.cbegin(); i != playerNames.cend(); i++)
 	{
 		if(!si->getPlayersSettings(i->first))
 			return i->first;
 	}
-	return 0;
+	return PlayerConnectionID::PLAYER_AI;
 }
 
 void CVCMIServer::multiplayerWelcomeMessage()
@@ -1142,25 +1114,33 @@ bool CVCMIServer::isPlayerHost(const PlayerColor & color) const
 	return LobbyInfo::isPlayerHost(color);
 }
 
-bool CVCMIServer::hasPlayerAt(PlayerColor player, const std::shared_ptr<IGameConnection> & c) const
+bool CVCMIServer::hasPlayerAt(PlayerColor player, GameConnectionID connectionID) const
 {
-	return vstd::contains(getAllClientPlayers(c->getConnectionID()), player);
+	return vstd::contains(getAllClientPlayers(connectionID), player);
 }
 
 bool CVCMIServer::hasBothPlayersAtSameConnection(PlayerColor left, PlayerColor right) const
 {
 	for (const auto & c : activeConnections)
-	{
-		if (hasPlayerAt(left, c) && hasPlayerAt(right, c))
+		if (hasPlayerAt(left, c->connectionID) && hasPlayerAt(right, c->connectionID))
 			return true;
-	}
 
 	return false;
 }
 
-void CVCMIServer::broadcastPack(CPackForClient & pack)
+void CVCMIServer::applyPack(CPackForClient & pack)
 {
+	logNetwork->trace("\tSending to all clients: %s", typeid(pack).name());
 	for (const auto & c : activeConnections)
 		c->sendPack(pack);
+	gh->gs->apply(pack);
+	logNetwork->trace("\tApplied on gameState(): %s", typeid(pack).name());
+}
+
+void CVCMIServer::sendPack(CPackForClient & pack, GameConnectionID connectionID)
+{
+	for (const auto & c : activeConnections)
+		if (c->connectionID == connectionID)
+			c->sendPack(pack);
 }
 

+ 8 - 8
server/CVCMIServer.h

@@ -49,8 +49,8 @@ class CVCMIServer : public LobbyInfo, public INetworkServerListener, public INet
 
 	std::shared_ptr<GameConnection> findConnection(const std::shared_ptr<INetworkConnection> &);
 
-	int currentClientId;
-	ui8 currentPlayerId;
+	GameConnectionID currentClientId;
+	PlayerConnectionID currentPlayerId;
 	uint16_t port;
 	bool runByClient;
 
@@ -62,9 +62,10 @@ public:
 	void setState(EServerState value) override;
 	EServerState getState() const override;
 	bool isPlayerHost(const PlayerColor & color) const override;
-	bool hasPlayerAt(PlayerColor player, const std::shared_ptr<IGameConnection> & c) const override;
+	bool hasPlayerAt(PlayerColor player, GameConnectionID connectionID) const override;
 	bool hasBothPlayersAtSameConnection(PlayerColor left, PlayerColor right) const override;
-	void broadcastPack(CPackForClient & pack) override;
+	void applyPack(CPackForClient & pack) override;
+	void sendPack(CPackForClient & pack, GameConnectionID connectionID) override;
 
 	/// List of all active connections
 	std::vector<std::shared_ptr<GameConnection>> activeConnections;
@@ -93,17 +94,16 @@ public:
 	void threadHandleClient(std::shared_ptr<GameConnection> c);
 
 	void announcePack(CPackForLobby & pack);
-	bool passHost(int toConnectionId);
+	bool passHost(GameConnectionID toConnectionId);
 
 	void announceTxt(const MetaString & txt, const std::string & playerName = "system");
 	void announceTxt(const std::string & txt, const std::string & playerName = "system");
 
-	void setPlayerConnectedId(PlayerSettings & pset, ui8 player) const;
+	void setPlayerConnectedId(PlayerSettings & pset, PlayerConnectionID player) const;
 	void updateStartInfoOnMapChange(std::shared_ptr<CMapInfo> mapInfo, std::shared_ptr<CMapGenOptions> mapGenOpt = {});
 
 	void clientConnected(std::shared_ptr<GameConnection> c, std::vector<std::string> & names, const std::string & uuid, EStartMode mode);
 	void clientDisconnected(std::shared_ptr<GameConnection> c);
-	void reconnectPlayer(int connId);
 
 	void announceMessage(const MetaString & txt);
 	void announceMessage(const std::string & txt);
@@ -133,7 +133,7 @@ public:
 	void setCampaignMap(CampaignScenarioID mapId);
 	void setCampaignBonus(int bonusId);
 
-	ui8 getIdOfFirstUnallocatedPlayer() const;
+	PlayerConnectionID getIdOfFirstUnallocatedPlayer() const;
 
 	void multiplayerWelcomeMessage();
 };

+ 6 - 3
server/IGameServer.h

@@ -9,10 +9,12 @@
  */
 #pragma once
 
+#include "../lib/serializer/GameConnectionID.h"
+
 VCMI_LIB_NAMESPACE_BEGIN
 class PlayerColor;
-class IGameConnection;
 struct CPackForClient;
+
 VCMI_LIB_NAMESPACE_END
 
 enum class EServerState : ui8
@@ -31,7 +33,8 @@ public:
 	virtual void setState(EServerState value) = 0;
 	virtual EServerState getState() const = 0;
 	virtual bool isPlayerHost(const PlayerColor & color) const = 0;
-	virtual bool hasPlayerAt(PlayerColor player, const std::shared_ptr<IGameConnection> & c) const = 0;
+	virtual bool hasPlayerAt(PlayerColor player, GameConnectionID connectionID) const = 0;
 	virtual bool hasBothPlayersAtSameConnection(PlayerColor left, PlayerColor right) const = 0;
-	virtual void broadcastPack(CPackForClient & pack) = 0;
+	virtual void applyPack(CPackForClient & pack) = 0;
+	virtual void sendPack(CPackForClient & pack, GameConnectionID connectionID) = 0;
 };

+ 1 - 13
server/NetPacksLobbyServer.cpp

@@ -220,19 +220,7 @@ void ApplyOnServerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
 
 void ApplyOnServerAfterAnnounceNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
 {
-	if(pack.clientId == -1) //do not restart game for single client only
-		srv.startGameImmediately();
-	else
-	{
-		for(const auto & connection : srv.activeConnections)
-		{
-			if(connection->connectionID == pack.clientId)
-			{
-				connection->setCallback(srv.gh->gameInfo());
-				srv.reconnectPlayer(pack.clientId);
-			}
-		}
-	}
+	srv.startGameImmediately();
 }
 
 void ClientPermissionsCheckerNetPackVisitor::visitLobbyChangeHost(LobbyChangeHost & pack)

+ 2 - 4
server/ServerNetPackVisitors.h

@@ -11,17 +11,15 @@
 
 #include "../lib/networkPacks/NetPackVisitor.h"
 
-class IGameConnection;
-
 class ApplyGhNetPackVisitor : public VCMI_LIB_WRAP_NAMESPACE(ICPackVisitor)
 {
 private:
-	std::shared_ptr<IGameConnection> connection;
+	GameConnectionID connection;
 	CGameHandler & gh;
 	bool result;
 
 public:
-	ApplyGhNetPackVisitor(CGameHandler & gh, const std::shared_ptr<IGameConnection> & connection)
+	ApplyGhNetPackVisitor(CGameHandler & gh, GameConnectionID connection)
 		: connection(connection)
 		, gh(gh)
 		, result(false)

+ 5 - 6
server/processors/PlayerMessageProcessor.cpp

@@ -32,7 +32,6 @@
 #include "../../lib/mapping/CMap.h"
 #include "../../lib/networkPacks/PacksForClient.h"
 #include "../../lib/networkPacks/StackLocation.h"
-#include "../../lib/serializer/IGameConnection.h"
 #include "../../lib/spells/CSpellHandler.h"
 #include "../lib/VCMIDirs.h"
 
@@ -964,25 +963,25 @@ void PlayerMessageProcessor::executeCheatCode(const std::string & cheatName, Pla
 		callbacks.at(cheatName)();
 }
 
-void PlayerMessageProcessor::sendSystemMessage(std::shared_ptr<IGameConnection> connection, const MetaString & message)
+void PlayerMessageProcessor::sendSystemMessage(GameConnectionID connectionID, const MetaString & message)
 {
 	SystemMessage sm;
 	sm.text = message;
-	connection->sendPack(sm);
+	gameHandler->gameServer().sendPack(sm, connectionID);
 }
 
-void PlayerMessageProcessor::sendSystemMessage(std::shared_ptr<IGameConnection> connection, const std::string & message)
+void PlayerMessageProcessor::sendSystemMessage(GameConnectionID connectionID, const std::string & message)
 {
 	MetaString str;
 	str.appendRawString(message);
-	sendSystemMessage(connection, str);
+	sendSystemMessage(connectionID, str);
 }
 
 void PlayerMessageProcessor::broadcastSystemMessage(MetaString message)
 {
 	SystemMessage sm;
 	sm.text = message;
-	gameHandler->sendToAllClients(sm);
+	gameHandler->gameServer().applyPack(sm);
 }
 
 void PlayerMessageProcessor::broadcastSystemMessage(const std::string & message)

+ 3 - 3
server/processors/PlayerMessageProcessor.h

@@ -10,11 +10,11 @@
 #pragma once
 
 #include "../../lib/GameConstants.h"
+#include "../../lib/serializer/GameConnectionID.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 class CGHeroInstance;
 class CGTownInstance;
-class IGameConnection;
 class MetaString;
 VCMI_LIB_NAMESPACE_END
 
@@ -80,8 +80,8 @@ public:
 	void playerMessage(PlayerColor player, const std::string & message, ObjectInstanceID currObj);
 
 	/// Send message to specific client with "System" as sender
-	void sendSystemMessage(std::shared_ptr<IGameConnection> connection, const MetaString & message);
-	void sendSystemMessage(std::shared_ptr<IGameConnection> connection, const std::string & message);
+	void sendSystemMessage(GameConnectionID connectionID, const MetaString & message);
+	void sendSystemMessage(GameConnectionID connectionID, const std::string & message);
 
 	/// Send message to all players with "System" as sender
 	void broadcastSystemMessage(MetaString message);

+ 1 - 1
test/game/CGameStateTest.cpp

@@ -165,7 +165,7 @@ public:
 
 			PlayerSettings & pset = si.playerInfos[PlayerColor(i)];
 			pset.color = PlayerColor(i);
-			pset.connectedPlayerIDs.insert(i);
+			pset.connectedPlayerIDs.insert(static_cast<PlayerConnectionID>(i));
 			pset.name = "Player";
 
 			pset.castle = pinfo.defaultCastle();