From 8ef5d0e838a763cba52933bab6dd1952086f2114 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 24 Jul 2020 20:59:22 +0200 Subject: [PATCH 01/10] Rename some things to clarify purpose, add constant for map requests --- src/openrct2/network/Network.cpp | 26 +++++++++++++------------- src/openrct2/network/NetworkPacket.cpp | 2 +- src/openrct2/network/NetworkTypes.h | 3 ++- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index b0638969ae..ff6383baf4 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -193,7 +193,7 @@ public: void Server_Send_EVENT_PLAYER_JOINED(const char* playerName); void Server_Send_EVENT_PLAYER_DISCONNECTED(const char* playerName, const char* reason); void Client_Send_GAMEINFO(); - void Client_Send_OBJECTS(const std::vector& objects); + void Client_Send_RequestMap(const std::vector& objects); void Server_Send_OBJECTS(NetworkConnection& connection, const std::vector& objects) const; void Server_Send_SCRIPTS(NetworkConnection& connection) const; @@ -310,10 +310,10 @@ private: void Client_Handle_EVENT(NetworkConnection& connection, NetworkPacket& packet); void Client_Handle_TOKEN(NetworkConnection& connection, NetworkPacket& packet); void Server_Handle_TOKEN(NetworkConnection& connection, NetworkPacket& packet); - void Client_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet); + void Client_Handle_OBJECTS_LIST(NetworkConnection& connection, NetworkPacket& packet); void Client_Handle_SCRIPTS(NetworkConnection& connection, NetworkPacket& packet); void Client_Handle_GAMESTATE(NetworkConnection& connection, NetworkPacket& packet); - void Server_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet); + void Server_Handle_MAPREQUEST(NetworkConnection& connection, NetworkPacket& packet); uint8_t* save_for_network(size_t& out_size, const std::vector& objects) const; @@ -346,7 +346,7 @@ Network::Network() client_command_handlers[NETWORK_COMMAND_EVENT] = &Network::Client_Handle_EVENT; client_command_handlers[NETWORK_COMMAND_GAMEINFO] = &Network::Client_Handle_GAMEINFO; client_command_handlers[NETWORK_COMMAND_TOKEN] = &Network::Client_Handle_TOKEN; - client_command_handlers[NETWORK_COMMAND_OBJECTS] = &Network::Client_Handle_OBJECTS; + client_command_handlers[NETWORK_COMMAND_OBJECTS_LIST] = &Network::Client_Handle_OBJECTS_LIST; client_command_handlers[NETWORK_COMMAND_SCRIPTS] = &Network::Client_Handle_SCRIPTS; client_command_handlers[NETWORK_COMMAND_GAMESTATE] = &Network::Client_Handle_GAMESTATE; server_command_handlers.resize(NETWORK_COMMAND_MAX, nullptr); @@ -356,7 +356,7 @@ Network::Network() server_command_handlers[NETWORK_COMMAND_PING] = &Network::Server_Handle_PING; server_command_handlers[NETWORK_COMMAND_GAMEINFO] = &Network::Server_Handle_GAMEINFO; server_command_handlers[NETWORK_COMMAND_TOKEN] = &Network::Server_Handle_TOKEN; - server_command_handlers[NETWORK_COMMAND_OBJECTS] = &Network::Server_Handle_OBJECTS; + server_command_handlers[NETWORK_COMMAND_MAP_REQUEST] = &Network::Server_Handle_MAPREQUEST; server_command_handlers[NETWORK_COMMAND_REQUEST_GAMESTATE] = &Network::Server_Handle_REQUEST_GAMESTATE; _chat_log_fs << std::unitbuf; @@ -1449,11 +1449,11 @@ void Network::Client_Send_AUTH( _serverConnection->QueuePacket(std::move(packet)); } -void Network::Client_Send_OBJECTS(const std::vector& objects) +void Network::Client_Send_RequestMap(const std::vector& objects) { log_verbose("client requests %u objects", uint32_t(objects.size())); std::unique_ptr packet(NetworkPacket::Allocate()); - *packet << static_cast(NETWORK_COMMAND_OBJECTS) << static_cast(objects.size()); + *packet << static_cast(NETWORK_COMMAND_MAP_REQUEST) << static_cast(objects.size()); for (const auto& object : objects) { log_verbose("client requests object %s", object.c_str()); @@ -1474,7 +1474,7 @@ void Network::Server_Send_OBJECTS(NetworkConnection& connection, const std::vect { log_verbose("Server sends objects list with %u items", objects.size()); std::unique_ptr packet(NetworkPacket::Allocate()); - *packet << static_cast(NETWORK_COMMAND_OBJECTS) << static_cast(objects.size()); + *packet << static_cast(NETWORK_COMMAND_OBJECTS_LIST) << static_cast(objects.size()); for (auto object : objects) { log_verbose("Object %.8s (checksum %x)", object->ObjectEntry.name, object->ObjectEntry.checksum); @@ -2529,7 +2529,7 @@ void Network::Server_Handle_TOKEN(NetworkConnection& connection, [[maybe_unused] Server_Send_TOKEN(connection); } -void Network::Client_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet) +void Network::Client_Handle_OBJECTS_LIST(NetworkConnection& connection, NetworkPacket& packet) { auto& repo = GetContext()->GetObjectRepository(); uint32_t size; @@ -2542,7 +2542,7 @@ void Network::Client_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket log_warning("Server sent invalid amount of objects"); return; } - std::vector requested_objects; + std::vector missingObjects; for (uint32_t i = 0; i < size; i++) { const char* name = reinterpret_cast(packet.Read(8)); @@ -2556,7 +2556,7 @@ void Network::Client_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket if (ori == nullptr) { log_verbose("Requesting object %s with checksum %x from server", s.c_str(), checksum); - requested_objects.push_back(s); + missingObjects.push_back(s); } else if (ori->ObjectEntry.checksum != checksum || ori->ObjectEntry.flags != flags) { @@ -2565,7 +2565,7 @@ void Network::Client_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket ori->ObjectEntry.flags, checksum, flags); } } - Client_Send_OBJECTS(requested_objects); + Client_Send_RequestMap(missingObjects); } void Network::Client_Handle_SCRIPTS(NetworkConnection& connection, NetworkPacket& packet) @@ -2660,7 +2660,7 @@ void Network::Client_Handle_GAMESTATE(NetworkConnection& connection, NetworkPack } } -void Network::Server_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet) +void Network::Server_Handle_MAPREQUEST(NetworkConnection& connection, NetworkPacket& packet) { uint32_t size; packet >> size; diff --git a/src/openrct2/network/NetworkPacket.cpp b/src/openrct2/network/NetworkPacket.cpp index 7369b8614b..f39bcf11eb 100644 --- a/src/openrct2/network/NetworkPacket.cpp +++ b/src/openrct2/network/NetworkPacket.cpp @@ -57,7 +57,7 @@ bool NetworkPacket::CommandRequiresAuth() case NETWORK_COMMAND_AUTH: case NETWORK_COMMAND_TOKEN: case NETWORK_COMMAND_GAMEINFO: - case NETWORK_COMMAND_OBJECTS: + case NETWORK_COMMAND_OBJECTS_LIST: return false; default: return true; diff --git a/src/openrct2/network/NetworkTypes.h b/src/openrct2/network/NetworkTypes.h index 9ccc96cd3f..9f5a36a6e2 100644 --- a/src/openrct2/network/NetworkTypes.h +++ b/src/openrct2/network/NetworkTypes.h @@ -63,7 +63,8 @@ enum NETWORK_COMMAND NETWORK_COMMAND_GROUPLIST, NETWORK_COMMAND_EVENT, NETWORK_COMMAND_TOKEN, - NETWORK_COMMAND_OBJECTS, + NETWORK_COMMAND_OBJECTS_LIST, + NETWORK_COMMAND_MAP_REQUEST, NETWORK_COMMAND_GAME_ACTION, NETWORK_COMMAND_PLAYERINFO, NETWORK_COMMAND_REQUEST_GAMESTATE, From 0f31b82af00c5e09c39e0b70e3cdddaab331f23e Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 24 Jul 2020 22:35:32 +0200 Subject: [PATCH 02/10] Add missing network command --- src/openrct2/network/NetworkPacket.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/openrct2/network/NetworkPacket.cpp b/src/openrct2/network/NetworkPacket.cpp index f39bcf11eb..dfc29e213d 100644 --- a/src/openrct2/network/NetworkPacket.cpp +++ b/src/openrct2/network/NetworkPacket.cpp @@ -58,6 +58,7 @@ bool NetworkPacket::CommandRequiresAuth() case NETWORK_COMMAND_TOKEN: case NETWORK_COMMAND_GAMEINFO: case NETWORK_COMMAND_OBJECTS_LIST: + case NETWORK_COMMAND_MAP_REQUEST: return false; default: return true; From 1eedaf32ddf9d0e2c5760bbd0060ed0ce4b2a182 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 24 Jul 2020 22:36:45 +0200 Subject: [PATCH 03/10] Refactor sending the object list including status reporting --- data/language/en-GB.txt | 1 + src/openrct2/localisation/StringIds.h | 1 + src/openrct2/network/Network.cpp | 99 ++++++++++++++++++--------- 3 files changed, 67 insertions(+), 34 deletions(-) diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index f74793e030..99c653c904 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3664,6 +3664,7 @@ STR_6374 :C STR_6375 :Unknown Ride STR_6376 :{WINDOW_COLOUR_2}Ride vehicle:{NEWLINE}{BLACK}{STRINGID} for {STRINGID} STR_6377 :{WINDOW_COLOUR_2}Type: {BLACK}{STRINGID} for {STRINGID} +STR_6378 :Receiving objects list {INT32} / {INT32} ############# # Scenarios # diff --git a/src/openrct2/localisation/StringIds.h b/src/openrct2/localisation/StringIds.h index 6cc0e32b72..e9904014cd 100644 --- a/src/openrct2/localisation/StringIds.h +++ b/src/openrct2/localisation/StringIds.h @@ -3906,6 +3906,7 @@ enum STR_RESEARCH_VEHICLE_LABEL = 6376, STR_RESEARCH_TYPE_LABEL_VEHICLE = 6377, + STR_MULTIPLAYER_RECEIVING_OBJECTS_LIST = 6378, // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working /* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings }; diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index ff6383baf4..55a893b3cf 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -194,7 +194,7 @@ public: void Server_Send_EVENT_PLAYER_DISCONNECTED(const char* playerName, const char* reason); void Client_Send_GAMEINFO(); void Client_Send_RequestMap(const std::vector& objects); - void Server_Send_OBJECTS(NetworkConnection& connection, const std::vector& objects) const; + void Server_Send_OBJECTS_LIST(NetworkConnection& connection, const std::vector& objects) const; void Server_Send_SCRIPTS(NetworkConnection& connection) const; NetworkStats_t GetStats() const; @@ -280,6 +280,7 @@ private: std::string _serverLogPath; std::string _serverLogFilenameFormat = "%Y%m%d-%H%M%S.txt"; std::shared_ptr _env; + std::vector _missingObjects; void UpdateServer(); void UpdateClient(); @@ -1470,18 +1471,24 @@ void Network::Server_Send_TOKEN(NetworkConnection& connection) connection.QueuePacket(std::move(packet)); } -void Network::Server_Send_OBJECTS(NetworkConnection& connection, const std::vector& objects) const +void Network::Server_Send_OBJECTS_LIST(NetworkConnection& connection, const std::vector& objects) const { log_verbose("Server sends objects list with %u items", objects.size()); - std::unique_ptr packet(NetworkPacket::Allocate()); - *packet << static_cast(NETWORK_COMMAND_OBJECTS_LIST) << static_cast(objects.size()); - for (auto object : objects) + + for (size_t i = 0; i < objects.size(); ++i) { + const auto* object = objects[i]; + + std::unique_ptr packet(NetworkPacket::Allocate()); + *packet << static_cast(NETWORK_COMMAND_OBJECTS_LIST) << static_cast(i) + << static_cast(objects.size()); + log_verbose("Object %.8s (checksum %x)", object->ObjectEntry.name, object->ObjectEntry.checksum); packet->Write(reinterpret_cast(object->ObjectEntry.name), 8); *packet << object->ObjectEntry.checksum << object->ObjectEntry.flags; + + connection.QueuePacket(std::move(packet)); } - connection.QueuePacket(std::move(packet)); } void Network::Server_Send_SCRIPTS(NetworkConnection& connection) const @@ -1588,7 +1595,7 @@ void Network::Server_Send_MAP(NetworkConnection* connection) } return; } - size_t chunksize = CHUNK_SIZE; + size_t chunksize = 128; //CHUNK_SIZE; for (size_t i = 0; i < out_size; i += chunksize) { size_t datasize = std::min(chunksize, out_size - i); @@ -2505,7 +2512,7 @@ void Network::Server_Client_Joined(const char* name, const std::string& keyhash, auto context = GetContext(); auto& objManager = context->GetObjectManager(); auto objects = objManager.GetPackableObjects(); - Server_Send_OBJECTS(connection, objects); + Server_Send_OBJECTS_LIST(connection, objects); Server_Send_SCRIPTS(connection); // Log player joining event @@ -2532,40 +2539,64 @@ void Network::Server_Handle_TOKEN(NetworkConnection& connection, [[maybe_unused] void Network::Client_Handle_OBJECTS_LIST(NetworkConnection& connection, NetworkPacket& packet) { auto& repo = GetContext()->GetObjectRepository(); - uint32_t size; - packet >> size; - log_verbose("client received object list, it has %u entries", size); - if (size > OBJECT_ENTRY_COUNT) + + uint32_t index = 0; + uint32_t totalObjects = 0; + packet >> index >> totalObjects; + + if (index == 0) + { + // Start of objects list. + _missingObjects.clear(); + } + + if (totalObjects > OBJECT_ENTRY_COUNT) { connection.SetLastDisconnectReason(STR_MULTIPLAYER_SERVER_INVALID_REQUEST); connection.Socket->Disconnect(); log_warning("Server sent invalid amount of objects"); return; } - std::vector missingObjects; - for (uint32_t i = 0; i < size; i++) + + char objectListMsg[256]; + uint32_t args[] = { + index + 1, + totalObjects, + }; + format_string(objectListMsg, 256, STR_MULTIPLAYER_RECEIVING_OBJECTS_LIST, &args); + + auto intent = Intent(WC_NETWORK_STATUS); + intent.putExtra(INTENT_EXTRA_MESSAGE, std::string{ objectListMsg }); + intent.putExtra(INTENT_EXTRA_CALLBACK, []() -> void { gNetwork.Close(); }); + context_open_intent(&intent); + + const char* name = reinterpret_cast(packet.Read(8)); + // Required, as packet has no null terminators. + std::string s(name, name + 8); + uint32_t checksum, flags; + packet >> checksum >> flags; + + const ObjectRepositoryItem* ori = repo.FindObject(s.c_str()); + // This could potentially request the object if checksums don't match, but since client + // won't replace its version with server-provided one, we don't do that. + if (ori == nullptr) { - const char* name = reinterpret_cast(packet.Read(8)); - // Required, as packet has no null terminators. - std::string s(name, name + 8); - uint32_t checksum, flags; - packet >> checksum >> flags; - const ObjectRepositoryItem* ori = repo.FindObject(s.c_str()); - // This could potentially request the object if checksums don't match, but since client - // won't replace its version with server-provided one, we don't do that. - if (ori == nullptr) - { - log_verbose("Requesting object %s with checksum %x from server", s.c_str(), checksum); - missingObjects.push_back(s); - } - else if (ori->ObjectEntry.checksum != checksum || ori->ObjectEntry.flags != flags) - { - log_warning( - "Object %s has different checksum/flags (%x/%x) than server (%x/%x).", s.c_str(), ori->ObjectEntry.checksum, - ori->ObjectEntry.flags, checksum, flags); - } + log_verbose("Requesting object %s with checksum %x from server", s.c_str(), checksum); + _missingObjects.push_back(s); + } + else if (ori->ObjectEntry.checksum != checksum || ori->ObjectEntry.flags != flags) + { + log_warning( + "Object %s has different checksum/flags (%x/%x) than server (%x/%x).", s.c_str(), ori->ObjectEntry.checksum, + ori->ObjectEntry.flags, checksum, flags); + } + + if (_missingObjects.size() == totalObjects) + { + log_verbose("client received object list, it has %u entries", totalObjects); + Client_Send_RequestMap(_missingObjects); + _missingObjects.clear(); } - Client_Send_RequestMap(missingObjects); } void Network::Client_Handle_SCRIPTS(NetworkConnection& connection, NetworkPacket& packet) From 908090104a1957fea693a08ae0a232235e1e97ec Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 24 Jul 2020 22:49:05 +0200 Subject: [PATCH 04/10] Send client heartbeats to keep connection alive --- src/openrct2/network/Network.cpp | 32 +++++++++++++++++++++++++- src/openrct2/network/NetworkPacket.cpp | 1 + src/openrct2/network/NetworkTypes.h | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index 55a893b3cf..a50ae2a601 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -196,6 +196,7 @@ public: void Client_Send_RequestMap(const std::vector& objects); void Server_Send_OBJECTS_LIST(NetworkConnection& connection, const std::vector& objects) const; void Server_Send_SCRIPTS(NetworkConnection& connection) const; + void Client_Send_HEARTBEAT(NetworkConnection& connection) const; NetworkStats_t GetStats() const; json_t* GetServerInfoAsJson() const; @@ -275,6 +276,7 @@ private: uint32_t _actionId; uint32_t _lastUpdateTime = 0; uint32_t _currentDeltaTime = 0; + uint32_t _lastSentHeartbeat = 0; std::string _chatLogPath; std::string _chatLogFilenameFormat = "%Y%m%d-%H%M%S.txt"; std::string _serverLogPath; @@ -289,6 +291,7 @@ private: std::vector client_command_handlers; std::vector server_command_handlers; void Server_Handle_REQUEST_GAMESTATE(NetworkConnection& connection, NetworkPacket& packet); + void Server_Handle_HEARTBEAT(NetworkConnection& connection, NetworkPacket& packet); void Client_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet); void Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet); void Server_Client_Joined(const char* name, const std::string& keyhash, NetworkConnection& connection); @@ -359,6 +362,7 @@ Network::Network() server_command_handlers[NETWORK_COMMAND_TOKEN] = &Network::Server_Handle_TOKEN; server_command_handlers[NETWORK_COMMAND_MAP_REQUEST] = &Network::Server_Handle_MAPREQUEST; server_command_handlers[NETWORK_COMMAND_REQUEST_GAMESTATE] = &Network::Server_Handle_REQUEST_GAMESTATE; + server_command_handlers[NETWORK_COMMAND_HEARTBEAT] = &Network::Server_Handle_HEARTBEAT; _chat_log_fs << std::unitbuf; _server_log_fs << std::unitbuf; @@ -865,6 +869,16 @@ void Network::UpdateClient() window_close_by_class(WC_MULTIPLAYER); Close(); } + else + { + uint32_t ticks = platform_get_ticks(); + if (ticks - _lastSentHeartbeat >= 3000) + { + Client_Send_HEARTBEAT(*_serverConnection); + _lastSentHeartbeat = ticks; + } + } + break; } } @@ -1527,6 +1541,16 @@ void Network::Server_Send_SCRIPTS(NetworkConnection& connection) const connection.QueuePacket(std::move(packet)); } +void Network::Client_Send_HEARTBEAT(NetworkConnection& connection) const +{ + log_verbose("Sending heartbeat"); + + std::unique_ptr packet(NetworkPacket::Allocate()); + *packet << static_cast(NETWORK_COMMAND_HEARTBEAT); + + connection.QueuePacket(std::move(packet)); +} + NetworkStats_t Network::GetStats() const { NetworkStats_t stats = {}; @@ -1595,7 +1619,7 @@ void Network::Server_Send_MAP(NetworkConnection* connection) } return; } - size_t chunksize = 128; //CHUNK_SIZE; + size_t chunksize = CHUNK_SIZE; for (size_t i = 0; i < out_size; i += chunksize) { size_t datasize = std::min(chunksize, out_size - i); @@ -2451,6 +2475,12 @@ void Network::Server_Handle_REQUEST_GAMESTATE(NetworkConnection& connection, Net } } +void Network::Server_Handle_HEARTBEAT(NetworkConnection& connection, NetworkPacket& packet) +{ + log_verbose("Client %s heartbeat", connection.Socket->GetHostName()); + connection.ResetLastPacketTime(); +} + void Network::Client_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet) { uint32_t auth_status; diff --git a/src/openrct2/network/NetworkPacket.cpp b/src/openrct2/network/NetworkPacket.cpp index dfc29e213d..c82a711a53 100644 --- a/src/openrct2/network/NetworkPacket.cpp +++ b/src/openrct2/network/NetworkPacket.cpp @@ -59,6 +59,7 @@ bool NetworkPacket::CommandRequiresAuth() case NETWORK_COMMAND_GAMEINFO: case NETWORK_COMMAND_OBJECTS_LIST: case NETWORK_COMMAND_MAP_REQUEST: + case NETWORK_COMMAND_HEARTBEAT: return false; default: return true; diff --git a/src/openrct2/network/NetworkTypes.h b/src/openrct2/network/NetworkTypes.h index 9f5a36a6e2..ad42b45992 100644 --- a/src/openrct2/network/NetworkTypes.h +++ b/src/openrct2/network/NetworkTypes.h @@ -70,6 +70,7 @@ enum NETWORK_COMMAND NETWORK_COMMAND_REQUEST_GAMESTATE, NETWORK_COMMAND_GAMESTATE, NETWORK_COMMAND_SCRIPTS, + NETWORK_COMMAND_HEARTBEAT, NETWORK_COMMAND_MAX, NETWORK_COMMAND_INVALID = -1 }; From d230bc8914fd0099c43e43320ddb8bd02b4d4e9d Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 24 Jul 2020 22:50:40 +0200 Subject: [PATCH 05/10] Bump up network version --- src/openrct2/network/Network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index a50ae2a601..d545c939e3 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -32,7 +32,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 "22" +#define NETWORK_STREAM_VERSION "23" #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION static Peep* _pickup_peep = nullptr; From e31317e025bdde04b1fd38ddb78d7970fe4d1da3 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 24 Jul 2020 23:00:07 +0200 Subject: [PATCH 06/10] Rename function to be consistent --- src/openrct2/network/Network.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index d545c939e3..8374479a13 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -193,7 +193,7 @@ public: void Server_Send_EVENT_PLAYER_JOINED(const char* playerName); void Server_Send_EVENT_PLAYER_DISCONNECTED(const char* playerName, const char* reason); void Client_Send_GAMEINFO(); - void Client_Send_RequestMap(const std::vector& objects); + void Client_Send_REQUESTMAP(const std::vector& objects); void Server_Send_OBJECTS_LIST(NetworkConnection& connection, const std::vector& objects) const; void Server_Send_SCRIPTS(NetworkConnection& connection) const; void Client_Send_HEARTBEAT(NetworkConnection& connection) const; @@ -1464,7 +1464,7 @@ void Network::Client_Send_AUTH( _serverConnection->QueuePacket(std::move(packet)); } -void Network::Client_Send_RequestMap(const std::vector& objects) +void Network::Client_Send_REQUESTMAP(const std::vector& objects) { log_verbose("client requests %u objects", uint32_t(objects.size())); std::unique_ptr packet(NetworkPacket::Allocate()); @@ -2624,7 +2624,7 @@ void Network::Client_Handle_OBJECTS_LIST(NetworkConnection& connection, NetworkP if (_missingObjects.size() == totalObjects) { log_verbose("client received object list, it has %u entries", totalObjects); - Client_Send_RequestMap(_missingObjects); + Client_Send_REQUESTMAP(_missingObjects); _missingObjects.clear(); } } From 6c40d9f3d589134aab952b957ca98b3325ebd375 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 24 Jul 2020 23:10:11 +0200 Subject: [PATCH 07/10] Fix formatting --- src/openrct2/network/Network.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index 8374479a13..f0010d0652 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -1485,7 +1485,8 @@ void Network::Server_Send_TOKEN(NetworkConnection& connection) connection.QueuePacket(std::move(packet)); } -void Network::Server_Send_OBJECTS_LIST(NetworkConnection& connection, const std::vector& objects) const +void Network::Server_Send_OBJECTS_LIST( + NetworkConnection& connection, const std::vector& objects) const { log_verbose("Server sends objects list with %u items", objects.size()); From 241ff111dd1fa01bb16eee754140abec5c615410 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 25 Jul 2020 10:45:04 +0200 Subject: [PATCH 08/10] Address reviews --- data/language/en-GB.txt | 2 +- src/openrct2/localisation/StringIds.h | 1 + src/openrct2/network/Network.cpp | 50 +++++++++++++------------- src/openrct2/network/NetworkPacket.cpp | 2 +- src/openrct2/network/NetworkTypes.h | 2 +- 5 files changed, 29 insertions(+), 28 deletions(-) diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 99c653c904..c3e6366c05 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3664,7 +3664,7 @@ STR_6374 :C STR_6375 :Unknown Ride STR_6376 :{WINDOW_COLOUR_2}Ride vehicle:{NEWLINE}{BLACK}{STRINGID} for {STRINGID} STR_6377 :{WINDOW_COLOUR_2}Type: {BLACK}{STRINGID} for {STRINGID} -STR_6378 :Receiving objects list {INT32} / {INT32} +STR_6378 :Receiving objects list: {INT32} / {INT32} ############# # Scenarios # diff --git a/src/openrct2/localisation/StringIds.h b/src/openrct2/localisation/StringIds.h index e9904014cd..bc79126dfd 100644 --- a/src/openrct2/localisation/StringIds.h +++ b/src/openrct2/localisation/StringIds.h @@ -3907,6 +3907,7 @@ enum STR_RESEARCH_TYPE_LABEL_VEHICLE = 6377, STR_MULTIPLAYER_RECEIVING_OBJECTS_LIST = 6378, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working /* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings }; diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index f0010d0652..29f6cdc76a 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -360,7 +360,7 @@ Network::Network() server_command_handlers[NETWORK_COMMAND_PING] = &Network::Server_Handle_PING; server_command_handlers[NETWORK_COMMAND_GAMEINFO] = &Network::Server_Handle_GAMEINFO; server_command_handlers[NETWORK_COMMAND_TOKEN] = &Network::Server_Handle_TOKEN; - server_command_handlers[NETWORK_COMMAND_MAP_REQUEST] = &Network::Server_Handle_MAPREQUEST; + server_command_handlers[NETWORK_COMMAND_MAPREQUEST] = &Network::Server_Handle_MAPREQUEST; server_command_handlers[NETWORK_COMMAND_REQUEST_GAMESTATE] = &Network::Server_Handle_REQUEST_GAMESTATE; server_command_handlers[NETWORK_COMMAND_HEARTBEAT] = &Network::Server_Handle_HEARTBEAT; @@ -1468,7 +1468,7 @@ void Network::Client_Send_REQUESTMAP(const std::vector& objects) { log_verbose("client requests %u objects", uint32_t(objects.size())); std::unique_ptr packet(NetworkPacket::Allocate()); - *packet << static_cast(NETWORK_COMMAND_MAP_REQUEST) << static_cast(objects.size()); + *packet << static_cast(NETWORK_COMMAND_MAPREQUEST) << static_cast(objects.size()); for (const auto& object : objects) { log_verbose("client requests object %s", object.c_str()); @@ -1490,12 +1490,11 @@ void Network::Server_Send_OBJECTS_LIST( { log_verbose("Server sends objects list with %u items", objects.size()); - for (size_t i = 0; i < objects.size(); ++i) + bool startOfObjectList = true; + for (auto* object : objects) { - const auto* object = objects[i]; - std::unique_ptr packet(NetworkPacket::Allocate()); - *packet << static_cast(NETWORK_COMMAND_OBJECTS_LIST) << static_cast(i) + *packet << static_cast(NETWORK_COMMAND_OBJECTS_LIST) << startOfObjectList << static_cast(objects.size()); log_verbose("Object %.8s (checksum %x)", object->ObjectEntry.name, object->ObjectEntry.checksum); @@ -1503,6 +1502,7 @@ void Network::Server_Send_OBJECTS_LIST( *packet << object->ObjectEntry.checksum << object->ObjectEntry.flags; connection.QueuePacket(std::move(packet)); + startOfObjectList = false; } } @@ -2571,13 +2571,12 @@ void Network::Client_Handle_OBJECTS_LIST(NetworkConnection& connection, NetworkP { auto& repo = GetContext()->GetObjectRepository(); - uint32_t index = 0; + bool startOfObjectList = false; uint32_t totalObjects = 0; - packet >> index >> totalObjects; + packet >> startOfObjectList >> totalObjects; - if (index == 0) + if (startOfObjectList) { - // Start of objects list. _missingObjects.clear(); } @@ -2589,25 +2588,14 @@ void Network::Client_Handle_OBJECTS_LIST(NetworkConnection& connection, NetworkP return; } - char objectListMsg[256]; - uint32_t args[] = { - index + 1, - totalObjects, - }; - format_string(objectListMsg, 256, STR_MULTIPLAYER_RECEIVING_OBJECTS_LIST, &args); - - auto intent = Intent(WC_NETWORK_STATUS); - intent.putExtra(INTENT_EXTRA_MESSAGE, std::string{ objectListMsg }); - intent.putExtra(INTENT_EXTRA_CALLBACK, []() -> void { gNetwork.Close(); }); - context_open_intent(&intent); - - const char* name = reinterpret_cast(packet.Read(8)); + auto name = reinterpret_cast(packet.Read(8)); // Required, as packet has no null terminators. std::string s(name, name + 8); - uint32_t checksum, flags; + uint32_t checksum = 0; + uint32_t flags = 0; packet >> checksum >> flags; - const ObjectRepositoryItem* ori = repo.FindObject(s.c_str()); + const auto* ori = repo.FindObject(s.c_str()); // This could potentially request the object if checksums don't match, but since client // won't replace its version with server-provided one, we don't do that. if (ori == nullptr) @@ -2622,6 +2610,18 @@ void Network::Client_Handle_OBJECTS_LIST(NetworkConnection& connection, NetworkP ori->ObjectEntry.flags, checksum, flags); } + char objectListMsg[256]; + uint32_t args[] = { + static_cast(_missingObjects.size()), + totalObjects, + }; + format_string(objectListMsg, 256, STR_MULTIPLAYER_RECEIVING_OBJECTS_LIST, &args); + + auto intent = Intent(WC_NETWORK_STATUS); + intent.putExtra(INTENT_EXTRA_MESSAGE, std::string{ objectListMsg }); + intent.putExtra(INTENT_EXTRA_CALLBACK, []() -> void { gNetwork.Close(); }); + context_open_intent(&intent); + if (_missingObjects.size() == totalObjects) { log_verbose("client received object list, it has %u entries", totalObjects); diff --git a/src/openrct2/network/NetworkPacket.cpp b/src/openrct2/network/NetworkPacket.cpp index c82a711a53..ef4a7cd310 100644 --- a/src/openrct2/network/NetworkPacket.cpp +++ b/src/openrct2/network/NetworkPacket.cpp @@ -58,7 +58,7 @@ bool NetworkPacket::CommandRequiresAuth() case NETWORK_COMMAND_TOKEN: case NETWORK_COMMAND_GAMEINFO: case NETWORK_COMMAND_OBJECTS_LIST: - case NETWORK_COMMAND_MAP_REQUEST: + case NETWORK_COMMAND_MAPREQUEST: case NETWORK_COMMAND_HEARTBEAT: return false; default: diff --git a/src/openrct2/network/NetworkTypes.h b/src/openrct2/network/NetworkTypes.h index ad42b45992..68c1b96fa1 100644 --- a/src/openrct2/network/NetworkTypes.h +++ b/src/openrct2/network/NetworkTypes.h @@ -64,7 +64,7 @@ enum NETWORK_COMMAND NETWORK_COMMAND_EVENT, NETWORK_COMMAND_TOKEN, NETWORK_COMMAND_OBJECTS_LIST, - NETWORK_COMMAND_MAP_REQUEST, + NETWORK_COMMAND_MAPREQUEST, NETWORK_COMMAND_GAME_ACTION, NETWORK_COMMAND_PLAYERINFO, NETWORK_COMMAND_REQUEST_GAMESTATE, From ab48c00a896662d5dbf4c68521edd7db044e8e84 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 25 Jul 2020 15:23:26 +0200 Subject: [PATCH 09/10] Fix client being stuck on empty object list --- src/openrct2/network/Network.cpp | 101 ++++++++++++++++++------------- 1 file changed, 58 insertions(+), 43 deletions(-) diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index 29f6cdc76a..7c2f295b38 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -1490,19 +1490,30 @@ void Network::Server_Send_OBJECTS_LIST( { log_verbose("Server sends objects list with %u items", objects.size()); - bool startOfObjectList = true; - for (auto* object : objects) + if (objects.empty()) { std::unique_ptr packet(NetworkPacket::Allocate()); - *packet << static_cast(NETWORK_COMMAND_OBJECTS_LIST) << startOfObjectList + *packet << static_cast(NETWORK_COMMAND_OBJECTS_LIST) << static_cast(0) << static_cast(objects.size()); - log_verbose("Object %.8s (checksum %x)", object->ObjectEntry.name, object->ObjectEntry.checksum); - packet->Write(reinterpret_cast(object->ObjectEntry.name), 8); - *packet << object->ObjectEntry.checksum << object->ObjectEntry.flags; - connection.QueuePacket(std::move(packet)); - startOfObjectList = false; + } + else + { + for (size_t i = 0; i < objects.size(); ++i) + { + const auto* object = objects[i]; + + std::unique_ptr packet(NetworkPacket::Allocate()); + *packet << static_cast(NETWORK_COMMAND_OBJECTS_LIST) << static_cast(i) + << static_cast(objects.size()); + + log_verbose("Object %.8s (checksum %x)", object->ObjectEntry.name, object->ObjectEntry.checksum); + packet->Write(reinterpret_cast(object->ObjectEntry.name), 8); + *packet << object->ObjectEntry.checksum << object->ObjectEntry.flags; + + connection.QueuePacket(std::move(packet)); + } } } @@ -2571,12 +2582,13 @@ void Network::Client_Handle_OBJECTS_LIST(NetworkConnection& connection, NetworkP { auto& repo = GetContext()->GetObjectRepository(); - bool startOfObjectList = false; + uint32_t index = 0; uint32_t totalObjects = 0; - packet >> startOfObjectList >> totalObjects; + packet >> index >> totalObjects; - if (startOfObjectList) + if (index == 0) { + // Start of objects list. _missingObjects.clear(); } @@ -2588,41 +2600,44 @@ void Network::Client_Handle_OBJECTS_LIST(NetworkConnection& connection, NetworkP return; } - auto name = reinterpret_cast(packet.Read(8)); - // Required, as packet has no null terminators. - std::string s(name, name + 8); - uint32_t checksum = 0; - uint32_t flags = 0; - packet >> checksum >> flags; + if (totalObjects > 0) + { + char objectListMsg[256]; + const uint32_t args[] = { + index + 1, + totalObjects, + }; + format_string(objectListMsg, 256, STR_MULTIPLAYER_RECEIVING_OBJECTS_LIST, &args); - const auto* ori = repo.FindObject(s.c_str()); - // This could potentially request the object if checksums don't match, but since client - // won't replace its version with server-provided one, we don't do that. - if (ori == nullptr) - { - log_verbose("Requesting object %s with checksum %x from server", s.c_str(), checksum); - _missingObjects.push_back(s); - } - else if (ori->ObjectEntry.checksum != checksum || ori->ObjectEntry.flags != flags) - { - log_warning( - "Object %s has different checksum/flags (%x/%x) than server (%x/%x).", s.c_str(), ori->ObjectEntry.checksum, - ori->ObjectEntry.flags, checksum, flags); + auto intent = Intent(WC_NETWORK_STATUS); + intent.putExtra(INTENT_EXTRA_MESSAGE, std::string{ objectListMsg }); + intent.putExtra(INTENT_EXTRA_CALLBACK, []() -> void { gNetwork.Close(); }); + context_open_intent(&intent); + + auto name = reinterpret_cast(packet.Read(8)); + // Required, as packet has no null terminators. + std::string s(name, name + 8); + uint32_t checksum = 0; + uint32_t flags = 0; + packet >> checksum >> flags; + + const ObjectRepositoryItem* ori = repo.FindObject(s.c_str()); + // This could potentially request the object if checksums don't match, but since client + // won't replace its version with server-provided one, we don't do that. + if (ori == nullptr) + { + log_verbose("Requesting object %s with checksum %x from server", s.c_str(), checksum); + _missingObjects.push_back(s); + } + else if (ori->ObjectEntry.checksum != checksum || ori->ObjectEntry.flags != flags) + { + log_warning( + "Object %s has different checksum/flags (%x/%x) than server (%x/%x).", s.c_str(), ori->ObjectEntry.checksum, + ori->ObjectEntry.flags, checksum, flags); + } } - char objectListMsg[256]; - uint32_t args[] = { - static_cast(_missingObjects.size()), - totalObjects, - }; - format_string(objectListMsg, 256, STR_MULTIPLAYER_RECEIVING_OBJECTS_LIST, &args); - - auto intent = Intent(WC_NETWORK_STATUS); - intent.putExtra(INTENT_EXTRA_MESSAGE, std::string{ objectListMsg }); - intent.putExtra(INTENT_EXTRA_CALLBACK, []() -> void { gNetwork.Close(); }); - context_open_intent(&intent); - - if (_missingObjects.size() == totalObjects) + if (index + 1 >= totalObjects) { log_verbose("client received object list, it has %u entries", totalObjects); Client_Send_REQUESTMAP(_missingObjects); From 4b587e39895bc302a1e779870fb185866e7ce98c Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 25 Jul 2020 15:27:19 +0200 Subject: [PATCH 10/10] Minor cleanup --- src/openrct2/network/Network.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index 7c2f295b38..92ac640809 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -193,7 +193,7 @@ public: void Server_Send_EVENT_PLAYER_JOINED(const char* playerName); void Server_Send_EVENT_PLAYER_DISCONNECTED(const char* playerName, const char* reason); void Client_Send_GAMEINFO(); - void Client_Send_REQUESTMAP(const std::vector& objects); + void Client_Send_MAPREQUEST(const std::vector& objects); void Server_Send_OBJECTS_LIST(NetworkConnection& connection, const std::vector& objects) const; void Server_Send_SCRIPTS(NetworkConnection& connection) const; void Client_Send_HEARTBEAT(NetworkConnection& connection) const; @@ -1464,7 +1464,7 @@ void Network::Client_Send_AUTH( _serverConnection->QueuePacket(std::move(packet)); } -void Network::Client_Send_REQUESTMAP(const std::vector& objects) +void Network::Client_Send_MAPREQUEST(const std::vector& objects) { log_verbose("client requests %u objects", uint32_t(objects.size())); std::unique_ptr packet(NetworkPacket::Allocate()); @@ -2586,9 +2586,9 @@ void Network::Client_Handle_OBJECTS_LIST(NetworkConnection& connection, NetworkP uint32_t totalObjects = 0; packet >> index >> totalObjects; - if (index == 0) + static constexpr uint32_t OBJECT_START_INDEX = 0; + if (index == OBJECT_START_INDEX) { - // Start of objects list. _missingObjects.clear(); } @@ -2614,33 +2614,33 @@ void Network::Client_Handle_OBJECTS_LIST(NetworkConnection& connection, NetworkP intent.putExtra(INTENT_EXTRA_CALLBACK, []() -> void { gNetwork.Close(); }); context_open_intent(&intent); - auto name = reinterpret_cast(packet.Read(8)); - // Required, as packet has no null terminators. - std::string s(name, name + 8); + char objectName[12]{}; + std::memcpy(objectName, packet.Read(8), 8); + uint32_t checksum = 0; uint32_t flags = 0; packet >> checksum >> flags; - const ObjectRepositoryItem* ori = repo.FindObject(s.c_str()); + const auto* object = repo.FindObject(objectName); // This could potentially request the object if checksums don't match, but since client // won't replace its version with server-provided one, we don't do that. - if (ori == nullptr) + if (object == nullptr) { - log_verbose("Requesting object %s with checksum %x from server", s.c_str(), checksum); - _missingObjects.push_back(s); + log_verbose("Requesting object %s with checksum %x from server", objectName, checksum); + _missingObjects.push_back(objectName); } - else if (ori->ObjectEntry.checksum != checksum || ori->ObjectEntry.flags != flags) + else if (object->ObjectEntry.checksum != checksum || object->ObjectEntry.flags != flags) { log_warning( - "Object %s has different checksum/flags (%x/%x) than server (%x/%x).", s.c_str(), ori->ObjectEntry.checksum, - ori->ObjectEntry.flags, checksum, flags); + "Object %s has different checksum/flags (%x/%x) than server (%x/%x).", objectName, object->ObjectEntry.checksum, + object->ObjectEntry.flags, checksum, flags); } } if (index + 1 >= totalObjects) { log_verbose("client received object list, it has %u entries", totalObjects); - Client_Send_REQUESTMAP(_missingObjects); + Client_Send_MAPREQUEST(_missingObjects); _missingObjects.clear(); } }