From 52da332640ed1ce0c70353739cf42d973038ec3b Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sun, 29 Jun 2025 16:13:56 +0300 Subject: [PATCH] GameHandler now uses GameConnectionID instead of connection pointers --- client/AntilagServer.cpp | 64 +++++------ client/AntilagServer.h | 20 ++-- client/CServerHandler.cpp | 8 +- client/CServerHandler.h | 2 +- client/ClientNetPackVisitors.h | 1 - client/NetPacksClient.cpp | 35 ------ client/NetPacksLobbyClient.cpp | 8 +- lib/CMakeLists.txt | 3 +- lib/StartInfo.cpp | 26 ++--- lib/StartInfo.h | 30 ++--- lib/gameState/GameStatePackVisitor.cpp | 13 --- lib/gameState/GameStatePackVisitor.h | 1 - lib/networkPacks/NetPackVisitor.h | 1 - lib/networkPacks/NetPacksLib.cpp | 5 - lib/networkPacks/PacksForClient.h | 14 --- lib/networkPacks/PacksForLobby.h | 13 +-- lib/serializer/GameConnection.cpp | 6 - lib/serializer/GameConnection.h | 11 +- lib/serializer/GameConnectionID.h | 20 ++++ lib/serializer/IGameConnection.h | 24 ---- lib/serializer/PlayerConnectionID.h | 21 ++++ lib/serializer/RegisterTypes.h | 1 - server/CGameHandler.cpp | 71 +++++------- server/CGameHandler.h | 25 ++-- server/CVCMIServer.cpp | 114 ++++++++----------- server/CVCMIServer.h | 16 +-- server/IGameServer.h | 9 +- server/NetPacksLobbyServer.cpp | 14 +-- server/ServerNetPackVisitors.h | 6 +- server/processors/PlayerMessageProcessor.cpp | 11 +- server/processors/PlayerMessageProcessor.h | 6 +- test/game/CGameStateTest.cpp | 2 +- 32 files changed, 238 insertions(+), 363 deletions(-) create mode 100644 lib/serializer/GameConnectionID.h delete mode 100644 lib/serializer/IGameConnection.h create mode 100644 lib/serializer/PlayerConnectionID.h diff --git a/client/AntilagServer.cpp b/client/AntilagServer.cpp index 26c40da31..bcccddf01 100644 --- a/client/AntilagServer.cpp +++ b/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 AntilagFakeConnection::retrievePack(const std::vector & 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(); @@ -119,12 +99,12 @@ void AntilagServer::onPacketReceived(const std::shared_ptr & logGlobal->info("Predicting effects of pack '%s'", typeid(*serverPack).name()); - auto newConnection = std::make_shared(); - 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 & 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 +} diff --git a/client/AntilagServer.h b/client/AntilagServer.h index e5a7b1122..f4b1f5a0e 100644 --- a/client/AntilagServer.h +++ b/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 retrievePack(const std::vector & data) override; - int getConnectionID() const override; - PlayerColor senderID; uint32_t requestID; std::vector 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> predictedReplies; + std::vector predictedReplies; std::shared_ptr antilagNetConnection; - std::shared_ptr antilagGameConnection; + std::shared_ptr antilagGameConnection; std::unique_ptr gameHandler; static constexpr uint32_t invalidPackageID = std::numeric_limits::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 & 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 & connection, const std::string & errorMessage) override; void onPacketReceived(const std::shared_ptr & connection, const std::vector & message) override; diff --git a/client/CServerHandler.cpp b/client/CServerHandler.cpp index d772f4c85..366f84da6 100644 --- a/client/CServerHandler.cpp +++ b/client/CServerHandler.cpp @@ -128,7 +128,7 @@ void CServerHandler::threadRunNetwork() void CServerHandler::resetStateForLobby(EStartMode mode, ESelectionScreen screen, EServerMode newServerMode, const std::vector & 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(id); + lch.newHostConnectionId = static_cast(boost::lexical_cast(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(connectedId); + auto connected = static_cast(boost::lexical_cast(connectedId)); auto color = PlayerColor(boost::lexical_cast(playerColorId)); if(color.isValidPlayer() && playerNames.find(connected) != playerNames.end()) { diff --git a/client/CServerHandler.h b/client/CServerHandler.h index 9ebddbe52..0f765ee0e 100644 --- a/client/CServerHandler.h +++ b/client/CServerHandler.h @@ -159,7 +159,7 @@ public: std::set 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); diff --git a/client/ClientNetPackVisitors.h b/client/ClientNetPackVisitors.h index 412294c90..7f23ee33a 100644 --- a/client/ClientNetPackVisitors.h +++ b/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; diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 40820a4bd..14908abe8 100644 --- a/client/NetPacksClient.cpp +++ b/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) diff --git a/client/NetPacksLobbyClient.cpp b/client/NetPacksLobbyClient.cpp index 34f8171f1..a419d60ca 100644 --- a/client/NetPacksLobbyClient.cpp +++ b/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; diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 1d8d2b0f4..c297e1bac 100644 --- a/lib/CMakeLists.txt +++ b/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 diff --git a/lib/StartInfo.cpp b/lib/StartInfo.cpp index 637e71bbb..bf18a9fbb 100644 --- a/lib/StartInfo.cpp +++ b/lib/StartInfo.cpp @@ -71,7 +71,7 @@ const PlayerSettings & StartInfo::getIthPlayersSettings(const PlayerColor & no) return const_cast(*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 LobbyInfo::getAllClientPlayers(int clientId) const +std::set LobbyInfo::getAllClientPlayers(GameConnectionID clientId) const { std::set players; for(auto & elem : si->playerInfos) @@ -142,7 +142,7 @@ std::set 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 LobbyInfo::getAllClientPlayers(int clientId) const return players; } -std::vector LobbyInfo::getConnectedPlayerIdsForClient(int clientId) const +std::vector LobbyInfo::getConnectedPlayerIdsForClient(GameConnectionID clientId) const { - std::vector ids; + std::vector ids; for(const auto & pair : playerNames) { @@ -172,12 +172,12 @@ std::vector LobbyInfo::getConnectedPlayerIdsForClient(int clientId) const return ids; } -std::set LobbyInfo::clientHumanColors(int clientId) +std::set LobbyInfo::clientHumanColors(GameConnectionID clientId) { std::set 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 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) diff --git a/lib/StartInfo.h b/lib/StartInfo.h index 4f161bf48..964172b23 100644 --- a/lib/StartInfo.h +++ b/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 connectedPlayerIDs; //Empty - AI, or connectrd player ids + std::set connectedPlayerIDs; //Empty - AI, or connectrd player ids bool compOnly; //true if this player is a computer only player; required for RMG template 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 void serialize(Handler &h) @@ -197,14 +197,14 @@ struct DLL_LINKAGE LobbyState { std::shared_ptr si; std::shared_ptr mi; - std::map playerNames; // id of player <-> player name; 0 is reserved as ID of AI "players" - int hostClientId; + std::map 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 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 getAllClientPlayers(int clientId) const; - std::vector getConnectedPlayerIdsForClient(int clientId) const; + std::set getAllClientPlayers(GameConnectionID clientId) const; + std::vector getConnectedPlayerIdsForClient(GameConnectionID clientId) const; // Helpers for lobby state access - std::set 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 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); }; diff --git a/lib/gameState/GameStatePackVisitor.cpp b/lib/gameState/GameStatePackVisitor.cpp index cb2a6fa95..9bcf4bc21 100644 --- a/lib/gameState/GameStatePackVisitor.cpp +++ b/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; diff --git a/lib/gameState/GameStatePackVisitor.h b/lib/gameState/GameStatePackVisitor.h index da6707d2b..fa4421e4e 100644 --- a/lib/gameState/GameStatePackVisitor.h +++ b/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; diff --git a/lib/networkPacks/NetPackVisitor.h b/lib/networkPacks/NetPackVisitor.h index 6ed5cd32f..eef61f439 100644 --- a/lib/networkPacks/NetPackVisitor.h +++ b/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) {} diff --git a/lib/networkPacks/NetPacksLib.cpp b/lib/networkPacks/NetPacksLib.cpp index 4adbf7fa9..5d7c08477 100644 --- a/lib/networkPacks/NetPacksLib.cpp +++ b/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); diff --git a/lib/networkPacks/PacksForClient.h b/lib/networkPacks/PacksForClient.h index 35df19ab1..7123da36b 100644 --- a/lib/networkPacks/PacksForClient.h +++ b/lib/networkPacks/PacksForClient.h @@ -533,20 +533,6 @@ struct DLL_LINKAGE PlayerEndsGame : public CPackForClient } }; -struct DLL_LINKAGE PlayerReinitInterface : public CPackForClient -{ - std::vector players; - ui8 playerConnectionId; //PLAYER_AI for AI player - - void visitTyped(ICPackVisitor & visitor) override; - - template void serialize(Handler & h) - { - h & players; - h & playerConnectionId; - } -}; - struct DLL_LINKAGE RemoveBonus : public CPackForClient { explicit RemoveBonus(GiveBonus::ETarget Who = GiveBonus::ETarget::OBJECT) diff --git a/lib/networkPacks/PacksForLobby.h b/lib/networkPacks/PacksForLobby.h index 2f314d872..549499fdc 100644 --- a/lib/networkPacks/PacksForLobby.h +++ b/lib/networkPacks/PacksForLobby.h @@ -41,8 +41,8 @@ struct DLL_LINKAGE LobbyClientConnected : public CLobbyPackToPropagate std::vector 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 void serialize(Handler &h) @@ -138,7 +137,6 @@ struct DLL_LINKAGE LobbyStartGame : public CLobbyPackToPropagate // Set by server std::shared_ptr initializedStartInfo; std::shared_ptr 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; diff --git a/lib/serializer/GameConnection.cpp b/lib/serializer/GameConnection.cpp index b05eea82d..75cb974e4 100644 --- a/lib/serializer/GameConnection.cpp +++ b/lib/serializer/GameConnection.cpp @@ -58,7 +58,6 @@ GameConnection::GameConnection(std::weak_ptr networkConnecti , packWriter(std::make_unique()) , deserializer(std::make_unique(packReader.get())) , serializer(std::make_unique(packWriter.get())) - , connectionID(-1) { assert(networkConnection.lock() != nullptr); @@ -68,11 +67,6 @@ GameConnection::GameConnection(std::weak_ptr networkConnecti GameConnection::~GameConnection() = default; -int GameConnection::getConnectionID() const -{ - return connectionID; -} - void GameConnection::sendPack(const CPack & pack) { std::scoped_lock lock(writeMutex); diff --git a/lib/serializer/GameConnection.h b/lib/serializer/GameConnection.h index ed0085c4e..926b7984d 100644 --- a/lib/serializer/GameConnection.h +++ b/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 networkConnection; @@ -43,14 +43,13 @@ public: std::shared_ptr getConnection(); std::string uuid; - int connectionID; + GameConnectionID connectionID = GameConnectionID::INVALID; explicit GameConnection(std::weak_ptr networkConnection); ~GameConnection(); - void sendPack(const CPack & pack) override; - int getConnectionID() const override; - std::unique_ptr retrievePack(const std::vector & data) override; + void sendPack(const CPack & pack); + std::unique_ptr retrievePack(const std::vector & data); void enterLobbyConnectionMode(); void setCallback(IGameInfoCallback & cb); diff --git a/lib/serializer/GameConnectionID.h b/lib/serializer/GameConnectionID.h new file mode 100644 index 000000000..9aea69bd4 --- /dev/null +++ b/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 diff --git a/lib/serializer/IGameConnection.h b/lib/serializer/IGameConnection.h deleted file mode 100644 index 3441f38d0..000000000 --- a/lib/serializer/IGameConnection.h +++ /dev/null @@ -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 retrievePack(const std::vector & data) = 0; - virtual int getConnectionID() const = 0; -}; - -VCMI_LIB_NAMESPACE_END diff --git a/lib/serializer/PlayerConnectionID.h b/lib/serializer/PlayerConnectionID.h new file mode 100644 index 000000000..bd27ae4c0 --- /dev/null +++ b/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 diff --git a/lib/serializer/RegisterTypes.h b/lib/serializer/RegisterTypes.h index 8a94c0152..22a4c7508 100644 --- a/lib/serializer/RegisterTypes.h +++ b/lib/serializer/RegisterTypes.h @@ -148,7 +148,6 @@ void registerTypes(Serializer &s) s.template registerType(101); s.template registerType(102); s.template registerType(103); - s.template registerType(104); s.template registerType(105); s.template registerType(107); s.template registerType(108); diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index b3e96220f..e5f04a325 100644 --- a/server/CGameHandler.cpp +++ b/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 & c) +void CGameHandler::handleClientDisconnection(GameConnectionID connectionID) { if(gameServer().getState() == EServerState::SHUTDOWN || !gameState().getStartInfo()) { @@ -454,7 +453,7 @@ void CGameHandler::handleClientDisconnection(const std::shared_ptrstatus != 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 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 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(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(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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 diff --git a/server/CGameHandler.h b/server/CGameHandler.h index 25126e761..eaf8b6564 100644 --- a/server/CGameHandler.h +++ b/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 & c); - void handleReceivedPack(std::shared_ptr c, CPackForServer & pack); - bool hasPlayerAt(PlayerColor player, const std::shared_ptr & 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 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 & 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 & connection); + [[noreturn]] void throwNotAllowedAction(GameConnectionID connectionID); /// Throws if player stated in pack is not making turn right now - void throwIfPlayerNotActive(const std::shared_ptr & 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 & 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 & connection, const CPackForServer * pack, PlayerColor player); - void throwIfWrongPlayer(const std::shared_ptr & connection, const CPackForServer * pack); - [[noreturn]] void throwAndComplain(const std::shared_ptr & 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 & connection, const CPackForServer * pack, ObjectInstanceID id); + bool isPlayerOwns(GameConnectionID connectionID, const CPackForServer * pack, ObjectInstanceID id); void start(bool resume); void tick(int millisecondsPassed); diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index 2d0b31d0f..eaa2ef2de 100644 --- a/server/CVCMIServer.cpp +++ b/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(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(toConnectionId))); return true; } return false; @@ -410,27 +410,27 @@ void CVCMIServer::clientConnected(std::shared_ptr 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(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(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(id) % static_cast(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 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 mapInfo, } else { - setPlayerConnectedId(ps.second, PlayerSettings::PLAYER_AI); + setPlayerConnectedId(ps.second, PlayerConnectionID::PLAYER_AI); } } } @@ -550,7 +522,7 @@ void CVCMIServer::updateStartInfoOnMapChange(std::shared_ptr 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 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 & 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); } diff --git a/server/CVCMIServer.h b/server/CVCMIServer.h index de3b6fd97..41b392e90 100644 --- a/server/CVCMIServer.h +++ b/server/CVCMIServer.h @@ -49,8 +49,8 @@ class CVCMIServer : public LobbyInfo, public INetworkServerListener, public INet std::shared_ptr findConnection(const std::shared_ptr &); - 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 & 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> activeConnections; @@ -93,17 +94,16 @@ public: void threadHandleClient(std::shared_ptr 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 mapInfo, std::shared_ptr mapGenOpt = {}); void clientConnected(std::shared_ptr c, std::vector & names, const std::string & uuid, EStartMode mode); void clientDisconnected(std::shared_ptr 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(); }; diff --git a/server/IGameServer.h b/server/IGameServer.h index 9e082f2b2..935419bac 100644 --- a/server/IGameServer.h +++ b/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 & 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; }; diff --git a/server/NetPacksLobbyServer.cpp b/server/NetPacksLobbyServer.cpp index 6e70c9a45..15b0cd352 100644 --- a/server/NetPacksLobbyServer.cpp +++ b/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) diff --git a/server/ServerNetPackVisitors.h b/server/ServerNetPackVisitors.h index 65f8221e6..a6ffffb63 100644 --- a/server/ServerNetPackVisitors.h +++ b/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 connection; + GameConnectionID connection; CGameHandler & gh; bool result; public: - ApplyGhNetPackVisitor(CGameHandler & gh, const std::shared_ptr & connection) + ApplyGhNetPackVisitor(CGameHandler & gh, GameConnectionID connection) : connection(connection) , gh(gh) , result(false) diff --git a/server/processors/PlayerMessageProcessor.cpp b/server/processors/PlayerMessageProcessor.cpp index 30054a582..68dc10276 100644 --- a/server/processors/PlayerMessageProcessor.cpp +++ b/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 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 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) diff --git a/server/processors/PlayerMessageProcessor.h b/server/processors/PlayerMessageProcessor.h index b083c65b8..426cc948e 100644 --- a/server/processors/PlayerMessageProcessor.h +++ b/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 connection, const MetaString & message); - void sendSystemMessage(std::shared_ptr 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); diff --git a/test/game/CGameStateTest.cpp b/test/game/CGameStateTest.cpp index f0791a4f8..66f29aa47 100644 --- a/test/game/CGameStateTest.cpp +++ b/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(i)); pset.name = "Player"; pset.castle = pinfo.defaultCastle();