diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index 8ef8647b02..1d6be0643e 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -31,7 +31,7 @@ // This string specifies which version of network stream current build uses. // It is used for making sure only compatible builds get connected, even within // single OpenRCT2 version. -#define NETWORK_STREAM_VERSION "8" +#define NETWORK_STREAM_VERSION "9" #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION static Peep* _pickup_peep = nullptr; @@ -125,6 +125,7 @@ public: void Flush(); void ProcessPending(); void ProcessPlayerList(); + void ProcessPlayerInfo(); void ProcessGameCommands(); void EnqueueGameAction(const GameAction* action); std::vector>::iterator GetPlayerIteratorByID(uint8_t id); @@ -173,6 +174,7 @@ public: void Client_Send_GAME_ACTION(const GameAction* action); void Server_Send_GAME_ACTION(const GameAction* action); void Server_Send_TICK(); + void Server_Send_PLAYERINFO(int32_t playerId); void Server_Send_PLAYERLIST(); void Client_Send_PING(); void Server_Send_PING(); @@ -291,7 +293,7 @@ private: }; std::map _serverTickData; - + std::multimap _pendingPlayerInfo; int32_t mode = NETWORK_MODE_NONE; int32_t status = NETWORK_STATUS_NONE; bool _closeLock = false; @@ -340,6 +342,7 @@ private: void Client_Handle_GAME_ACTION(NetworkConnection& connection, NetworkPacket& packet); void Server_Handle_GAME_ACTION(NetworkConnection& connection, NetworkPacket& packet); void Client_Handle_TICK(NetworkConnection& connection, NetworkPacket& packet); + void Client_Handle_PLAYERINFO(NetworkConnection& connection, NetworkPacket& packet); void Client_Handle_PLAYERLIST(NetworkConnection& connection, NetworkPacket& packet); void Client_Handle_PING(NetworkConnection& connection, NetworkPacket& packet); void Server_Handle_PING(NetworkConnection& connection, NetworkPacket& packet); @@ -379,6 +382,7 @@ Network::Network() client_command_handlers[NETWORK_COMMAND_GAME_ACTION] = &Network::Client_Handle_GAME_ACTION; client_command_handlers[NETWORK_COMMAND_TICK] = &Network::Client_Handle_TICK; client_command_handlers[NETWORK_COMMAND_PLAYERLIST] = &Network::Client_Handle_PLAYERLIST; + client_command_handlers[NETWORK_COMMAND_PLAYERINFO] = &Network::Client_Handle_PLAYERINFO; client_command_handlers[NETWORK_COMMAND_PING] = &Network::Client_Handle_PING; client_command_handlers[NETWORK_COMMAND_PINGLIST] = &Network::Client_Handle_PINGLIST; client_command_handlers[NETWORK_COMMAND_SETDISCONNECTMSG] = &Network::Client_Handle_SETDISCONNECTMSG; @@ -447,6 +451,7 @@ void Network::Close() player_list.clear(); group_list.clear(); _pendingPlayerList.reset(); + _pendingPlayerInfo.clear(); gfx_invalidate_screen(); @@ -1664,6 +1669,19 @@ void Network::Server_Send_TICK() SendPacketToClients(*packet); } +void Network::Server_Send_PLAYERINFO(int32_t playerId) +{ + std::unique_ptr packet(NetworkPacket::Allocate()); + *packet << (uint32_t)NETWORK_COMMAND_PLAYERINFO << gCurrentTicks; + + auto* player = GetPlayerByID(playerId); + if (player == nullptr) + return; + + player->Write(*packet); + SendPacketToClients(*packet); +} + void Network::Server_Send_PLAYERLIST() { std::unique_ptr packet(NetworkPacket::Allocate()); @@ -1853,6 +1871,7 @@ void Network::ProcessPending() { ProcessGameCommands(); ProcessPlayerList(); + ProcessPlayerInfo(); } void Network::ProcessPlayerList() @@ -1868,9 +1887,12 @@ void Network::ProcessPlayerList() for (auto&& pendingPlayer : _pendingPlayerList.players) { activePlayerIds.push_back(pendingPlayer.Id); - if (!GetPlayerByID(pendingPlayer.Id)) + + auto* player = GetPlayerByID(pendingPlayer.Id); + if (player == nullptr) { - NetworkPlayer* player = AddPlayer("", ""); + // Add new player. + player = AddPlayer("", ""); if (player) { *player = pendingPlayer; @@ -1880,6 +1902,11 @@ void Network::ProcessPlayerList() } } } + else + { + // Update. + *player = pendingPlayer; + } } // Remove any players that are not in newly received list @@ -1899,6 +1926,20 @@ void Network::ProcessPlayerList() _pendingPlayerList.reset(); } +void Network::ProcessPlayerInfo() +{ + auto range = _pendingPlayerInfo.equal_range(gCurrentTicks); + for (auto it = range.first; it != range.second; it++) + { + auto* player = GetPlayerByID(it->second.Id); + if (player != nullptr) + { + *player = it->second; + } + } + _pendingPlayerInfo.erase(gCurrentTicks); +} + void Network::ProcessGameCommands() { while (game_command_queue.begin() != game_command_queue.end()) @@ -1938,6 +1979,7 @@ void Network::ProcessGameCommands() if (result->Error == GA_ERROR::OK) { Server_Send_GAME_ACTION(action); + Server_Send_PLAYERINFO(action->GetPlayer()); } } else @@ -1979,6 +2021,7 @@ void Network::ProcessGameCommands() } Server_Send_GAMECMD(gc.eax, gc.ebx, gc.ecx, gc.edx, gc.esi, gc.edi, gc.ebp, gc.playerid, gc.callback); + Server_Send_PLAYERINFO(gc.playerid); } } } @@ -2913,6 +2956,17 @@ void Network::Client_Handle_TICK([[maybe_unused]] NetworkConnection& connection, _serverTickData.emplace(server_tick, tickData); } +void Network::Client_Handle_PLAYERINFO([[maybe_unused]] NetworkConnection& connection, NetworkPacket& packet) +{ + uint32_t tick; + packet >> tick; + + NetworkPlayer playerInfo; + playerInfo.Read(packet); + + _pendingPlayerInfo.emplace(tick, playerInfo); +} + void Network::Client_Handle_PLAYERLIST([[maybe_unused]] NetworkConnection& connection, NetworkPacket& packet) { uint32_t tick; diff --git a/src/openrct2/network/NetworkTypes.h b/src/openrct2/network/NetworkTypes.h index bdd96c5434..c6fb88ce81 100644 --- a/src/openrct2/network/NetworkTypes.h +++ b/src/openrct2/network/NetworkTypes.h @@ -55,6 +55,7 @@ enum NETWORK_COMMAND NETWORK_COMMAND_GAMECMD, NETWORK_COMMAND_TICK, NETWORK_COMMAND_PLAYERLIST, + NETWORK_COMMAND_PLAYERINFO, NETWORK_COMMAND_PING, NETWORK_COMMAND_PINGLIST, NETWORK_COMMAND_SETDISCONNECTMSG,