From 5ebc95e0b24ddfaaf6ba23d46e22aee77fa5cc33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Fri, 14 Oct 2016 07:29:45 +0200 Subject: [PATCH] Mediate objects to send over from server --- src/network/NetworkConnection.h | 1 + src/network/NetworkPacket.cpp | 1 + src/network/NetworkTypes.h | 1 + src/network/network.cpp | 77 +++++++++++++++- src/network/network.h | 6 +- src/rct2/S6Exporter.cpp | 150 ++++++++++++++++++++------------ src/rct2/S6Exporter.h | 8 ++ src/scenario.c | 21 +---- src/scenario.h | 2 - 9 files changed, 188 insertions(+), 79 deletions(-) diff --git a/src/network/NetworkConnection.h b/src/network/NetworkConnection.h index 0c49b1c0bb..982e8dd38e 100644 --- a/src/network/NetworkConnection.h +++ b/src/network/NetworkConnection.h @@ -39,6 +39,7 @@ public: uint32 PingTime = 0; NetworkKey Key; std::vector Challenge; + std::vector RequestedObjects; NetworkConnection(); ~NetworkConnection(); diff --git a/src/network/NetworkPacket.cpp b/src/network/NetworkPacket.cpp index f1eaeffa9e..21afdf1993 100644 --- a/src/network/NetworkPacket.cpp +++ b/src/network/NetworkPacket.cpp @@ -68,6 +68,7 @@ bool NetworkPacket::CommandRequiresAuth() case NETWORK_COMMAND_AUTH: case NETWORK_COMMAND_TOKEN: case NETWORK_COMMAND_GAMEINFO: + case NETWORK_COMMAND_OBJECTS: return false; default: return true; diff --git a/src/network/NetworkTypes.h b/src/network/NetworkTypes.h index 0c933fba2b..2dc75b13d6 100644 --- a/src/network/NetworkTypes.h +++ b/src/network/NetworkTypes.h @@ -56,6 +56,7 @@ enum NETWORK_COMMAND NETWORK_COMMAND_GROUPLIST, NETWORK_COMMAND_EVENT, NETWORK_COMMAND_TOKEN, + NETWORK_COMMAND_OBJECTS, NETWORK_COMMAND_MAX, NETWORK_COMMAND_INVALID = -1 }; diff --git a/src/network/network.cpp b/src/network/network.cpp index 456d157733..71853a38e6 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -50,6 +50,8 @@ int _pickup_peep_old_x = SPRITE_LOCATION_NULL; #include "../core/Path.hpp" #include "../core/String.hpp" #include "../core/Util.hpp" +#include "../object/ObjectRepository.h" +#include "../rct2/S6Exporter.h" extern "C" { #include "../config.h" @@ -116,6 +118,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; server_command_handlers.resize(NETWORK_COMMAND_MAX, 0); server_command_handlers[NETWORK_COMMAND_AUTH] = &Network::Server_Handle_AUTH; server_command_handlers[NETWORK_COMMAND_CHAT] = &Network::Server_Handle_CHAT; @@ -123,6 +126,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; OpenSSL_add_all_algorithms(); } @@ -858,6 +862,19 @@ void Network::Client_Send_AUTH(const char* name, const char* password, const cha server_connection.QueuePacket(std::move(packet)); } +void Network::Client_Send_OBJECTS(const std::vector &objects) +{ + log_verbose("client requests %u objects", uint32(objects.size())); + std::unique_ptr packet(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_OBJECTS << (uint32)objects.size(); + for (uint32 i = 0; i < objects.size(); i++) + { + log_verbose("client requests object %s", objects[i].c_str()); + packet->Write((const uint8 *)objects[i].c_str(), 8); + } + server_connection.QueuePacket(std::move(packet)); +} + void Network::Server_Send_TOKEN(NetworkConnection& connection) { std::unique_ptr packet(NetworkPacket::Allocate()); @@ -866,6 +883,20 @@ void Network::Server_Send_TOKEN(NetworkConnection& connection) connection.QueuePacket(std::move(packet)); } +void Network::Server_Send_OBJECTS(NetworkConnection& connection, rct_object_entry * object_list, uint32 size) +{ + log_verbose("Server sends objects list with %u items", size); + std::unique_ptr packet(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_OBJECTS << size; + for (uint32 i = 0; i < size; i++) + { + log_verbose("Object %.8s (checksum %x)", object_list[i].name, object_list[i].checksum); + packet->Write((const uint8 *)object_list[i].name, 8); + *packet << object_list[i].checksum; + } + connection.QueuePacket(std::move(packet)); +} + void Network::Server_Send_AUTH(NetworkConnection& connection) { uint8 new_playerid = 0; @@ -894,7 +925,7 @@ void Network::Server_Send_MAP(NetworkConnection* connection) SDL_RWops* rw = SDL_RWFromFP(temp, SDL_TRUE); size_t out_size; unsigned char *header; - header = save_for_network(rw, out_size); + header = save_for_network(rw, out_size, connection->RequestedObjects); SDL_RWclose(rw); if (header == nullptr) { connection->SetLastDisconnectReason(STR_MULTIPLAYER_CONNECTION_CLOSED); @@ -916,13 +947,13 @@ void Network::Server_Send_MAP(NetworkConnection* connection) free(header); } -unsigned char * Network::save_for_network(SDL_RWops *rw_buffer, size_t &out_size) const +unsigned char * Network::save_for_network(SDL_RWops *rw_buffer, size_t &out_size, const std::vector &objects) const { unsigned char * header = nullptr; out_size = 0; bool RLEState = gUseRLE; gUseRLE = false; - scenario_save_network(rw_buffer); + scenario_save_network(rw_buffer, objects); gUseRLE = RLEState; int size = (int)SDL_RWtell(rw_buffer); std::vector buffer(size); @@ -1439,9 +1470,49 @@ void Network::Server_Handle_TOKEN(NetworkConnection& connection, NetworkPacket& for (int i = 0; i < token_size; i++) { connection.Challenge[i] = (uint8)(rand() & 0xff); } + rct_object_entry object_entries[OBJECT_ENTRY_COUNT]; + int count = scenario_get_num_packed_objects_to_write(object_entries); + Server_Send_OBJECTS(connection, object_entries, count); Server_Send_TOKEN(connection); } +void Network::Client_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet) +{ + IObjectRepository * repo = GetObjectRepository(); + uint32 size; + packet >> size; + log_verbose("client received object list, it has %u entries", size); + std::vector requested_objects; + for (uint32 i = 0; i < size; i++) + { + const char * name = (const char *)packet.Read(8); + uint32 checksum; + packet >> checksum; + std::string s(name, name + 8); + const ObjectRepositoryItem * ori = repo->FindObject(s.c_str()); + if (ori == nullptr || ori->ObjectEntry.checksum != checksum) { + log_verbose("Requesting object %s with checksum %x from server", + s.c_str(), checksum); + requested_objects.push_back(s); + } + } + Client_Send_OBJECTS(requested_objects); +} + +void Network::Server_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet) +{ + uint32 size; + packet >> size; + log_verbose("Client requested %u objects", size); + for (uint32 i = 0; i < size; i++) + { + const char * name = (const char *)packet.Read(8); + std::string s(name, name + 8); + log_verbose("Client requested object %s", s.c_str()); + connection.RequestedObjects.push_back(s); + } +} + void Network::Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet) { if (connection.AuthStatus != NETWORK_AUTH_OK) { diff --git a/src/network/network.h b/src/network/network.h index 0db5f98a0f..b9e932a5f0 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -142,6 +142,8 @@ 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 Server_Send_OBJECTS(NetworkConnection& connection, rct_object_entry * object_list, uint32 size); std::vector> player_list; std::vector> group_list; @@ -236,8 +238,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 Server_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet); - unsigned char * save_for_network(SDL_RWops *buffer, size_t &out_size) const; + unsigned char * save_for_network(SDL_RWops *buffer, size_t &out_size, const std::vector &objects) const; }; namespace Convert diff --git a/src/rct2/S6Exporter.cpp b/src/rct2/S6Exporter.cpp index 5a572a1314..250afd39cf 100644 --- a/src/rct2/S6Exporter.cpp +++ b/src/rct2/S6Exporter.cpp @@ -17,6 +17,8 @@ #include "../core/Exception.hpp" #include "../core/IStream.hpp" #include "../core/String.hpp" +#include "../object/ObjectRepository.h" +#include "../object/Object.h" #include "S6Exporter.h" extern "C" @@ -90,7 +92,7 @@ void S6Exporter::SaveScenario(SDL_RWops *rw) void S6Exporter::Save(SDL_RWops * rw, bool isScenario) { _s6.header.type = isScenario ? S6_TYPE_SCENARIO : S6_TYPE_SAVEDGAME; - _s6.header.num_packed_objects = ExportObjects ? scenario_get_num_packed_objects_to_write() : 0; + _s6.header.num_packed_objects = !ExportObjects ? uint16(ExportObjectsList.size()) : scenario_get_num_packed_objects_to_write(nullptr); _s6.header.version = S6_RCT2_VERSION; _s6.header.magic_number = S6_MAGIC_NUMBER; @@ -124,7 +126,7 @@ void S6Exporter::Save(SDL_RWops * rw, bool isScenario) // 2: Write packed objects if (_s6.header.num_packed_objects > 0) { - if (!scenario_write_packed_objects(rw)) + if (!scenario_write_packed_objects(rw, ExportObjectsList, ExportObjects)) { free(buffer); throw Exception("Unable to pack objects."); @@ -226,6 +228,11 @@ void S6Exporter::Save(SDL_RWops * rw, bool isScenario) } void S6Exporter::Export() +{ + Export(std::vector(), true); +} + +void S6Exporter::Export(const std::vector &objects, bool export_all) { _s6.info = gS6Info; @@ -451,6 +458,92 @@ uint32 S6Exporter::GetLoanHash(money32 initialCash, money32 bankLoan, uint32 max return value; } + +// Save game state without modifying any of the state for multiplayer +int scenario_save_network(SDL_RWops * rw, const std::vector &objects) +{ + viewport_set_saved_view(); + + bool result = false; + auto s6exporter = new S6Exporter(); + try + { + s6exporter->ExportObjects = false; + s6exporter->ExportObjectsList = objects; + s6exporter->Export(); + s6exporter->SaveGame(rw); + result = true; + } + catch (Exception) + { + } + delete s6exporter; + + if (!result) + { + return 0; + } + + // Write other data not in normal save files + SDL_RWwrite(rw, gSpriteSpatialIndex, 0x10001 * sizeof(uint16), 1); + SDL_WriteLE32(rw, gGamePaused); + SDL_WriteLE32(rw, _guestGenerationProbability); + SDL_WriteLE32(rw, _suggestedGuestMaximum); + SDL_WriteU8(rw, gCheatsSandboxMode); + SDL_WriteU8(rw, gCheatsDisableClearanceChecks); + SDL_WriteU8(rw, gCheatsDisableSupportLimits); + SDL_WriteU8(rw, gCheatsDisableTrainLengthLimit); + SDL_WriteU8(rw, gCheatsEnableChainLiftOnAllTrack); + SDL_WriteU8(rw, gCheatsShowAllOperatingModes); + SDL_WriteU8(rw, gCheatsShowVehiclesFromOtherTrackTypes); + SDL_WriteU8(rw, gCheatsFastLiftHill); + SDL_WriteU8(rw, gCheatsDisableBrakesFailure); + SDL_WriteU8(rw, gCheatsDisableAllBreakdowns); + SDL_WriteU8(rw, gCheatsUnlockAllPrices); + SDL_WriteU8(rw, gCheatsBuildInPauseMode); + SDL_WriteU8(rw, gCheatsIgnoreRideIntensity); + SDL_WriteU8(rw, gCheatsDisableVandalism); + SDL_WriteU8(rw, gCheatsDisableLittering); + SDL_WriteU8(rw, gCheatsNeverendingMarketing); + SDL_WriteU8(rw, gCheatsFreezeClimate); + SDL_WriteU8(rw, gCheatsDisablePlantAging); + SDL_WriteU8(rw, gCheatsAllowArbitraryRideTypeChanges); + + gfx_invalidate_screen(); + return 1; +} + +int scenario_write_packed_objects(SDL_RWops* rw, std::vector &objects, bool export_all) +{ + log_verbose("exporting packed objects"); + if (export_all) + { + log_verbose("exporting all"); + for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) { + const rct_object_entry *entry = get_loaded_object_entry(i); + void *entryData = get_loaded_object_chunk(i); + if (entryData != (void*)-1 && !(entry->flags & 0xF0)) { + if (!object_saved_packed(rw, entry)) { + return 0; + } + } + } + } else { + IObjectRepository * repo = GetObjectRepository(); + for (const auto &name : objects) + { + log_verbose("exporting object %s", name.c_str()); + const ObjectRepositoryItem *item = repo->FindObject(name.c_str()); + if (intptr_t(item->LoadedObject->GetLegacyData()) != -1 && !(item->ObjectEntry.flags & 0xF0)) { + if (!object_saved_packed(rw, &item->ObjectEntry)) { + return 0; + } + } + } + } + return 1; +} + extern "C" { enum { @@ -515,57 +608,4 @@ extern "C" } return result; } - - // Save game state without modifying any of the state for multiplayer - int scenario_save_network(SDL_RWops * rw) - { - viewport_set_saved_view(); - - bool result = false; - auto s6exporter = new S6Exporter(); - try - { - s6exporter->ExportObjects = true; - s6exporter->Export(); - s6exporter->SaveGame(rw); - result = true; - } - catch (Exception) - { - } - delete s6exporter; - - if (!result) - { - return 0; - } - - // Write other data not in normal save files - SDL_RWwrite(rw, gSpriteSpatialIndex, 0x10001 * sizeof(uint16), 1); - SDL_WriteLE32(rw, gGamePaused); - SDL_WriteLE32(rw, _guestGenerationProbability); - SDL_WriteLE32(rw, _suggestedGuestMaximum); - SDL_WriteU8(rw, gCheatsSandboxMode); - SDL_WriteU8(rw, gCheatsDisableClearanceChecks); - SDL_WriteU8(rw, gCheatsDisableSupportLimits); - SDL_WriteU8(rw, gCheatsDisableTrainLengthLimit); - SDL_WriteU8(rw, gCheatsEnableChainLiftOnAllTrack); - SDL_WriteU8(rw, gCheatsShowAllOperatingModes); - SDL_WriteU8(rw, gCheatsShowVehiclesFromOtherTrackTypes); - SDL_WriteU8(rw, gCheatsFastLiftHill); - SDL_WriteU8(rw, gCheatsDisableBrakesFailure); - SDL_WriteU8(rw, gCheatsDisableAllBreakdowns); - SDL_WriteU8(rw, gCheatsUnlockAllPrices); - SDL_WriteU8(rw, gCheatsBuildInPauseMode); - SDL_WriteU8(rw, gCheatsIgnoreRideIntensity); - SDL_WriteU8(rw, gCheatsDisableVandalism); - SDL_WriteU8(rw, gCheatsDisableLittering); - SDL_WriteU8(rw, gCheatsNeverendingMarketing); - SDL_WriteU8(rw, gCheatsFreezeClimate); - SDL_WriteU8(rw, gCheatsDisablePlantAging); - SDL_WriteU8(rw, gCheatsAllowArbitraryRideTypeChanges); - - gfx_invalidate_screen(); - return 1; - } } diff --git a/src/rct2/S6Exporter.h b/src/rct2/S6Exporter.h index 9cba306ddf..b28d94d5cd 100644 --- a/src/rct2/S6Exporter.h +++ b/src/rct2/S6Exporter.h @@ -16,6 +16,9 @@ #pragma once +#include +#include + #include "../common.h" extern "C" @@ -24,6 +27,9 @@ extern "C" #include "../object_list.h" } +int scenario_save_network(SDL_RWops* rw, const std::vector &objects); +int scenario_write_packed_objects(SDL_RWops* rw, std::vector &s, bool export_all); + /** * Class to export RollerCoaster Tycoon 2 scenarios (*.SC6) and saved games (*.SV6). */ @@ -32,6 +38,7 @@ class S6Exporter final public: bool ExportObjects; bool RemoveTracklessRides; + std::vector ExportObjectsList; S6Exporter(); @@ -40,6 +47,7 @@ public: void SaveScenario(const utf8 * path); void SaveScenario(SDL_RWops *rw); void Export(); + void Export(const std::vector &objects, bool export_all = false); private: rct_s6_data _s6; diff --git a/src/scenario.c b/src/scenario.c index f3a0f74ca7..160027fe98 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -696,30 +696,15 @@ int scenario_get_num_packed_objects_to_write(rct_object_entry * object_list) const rct_object_entry *entry = get_loaded_object_entry(i); void *entryData = get_loaded_object_chunk(i); if (entryData != (void*)-1 && !(entry->flags & 0xF0)) { + if (object_list != NULL) { + object_list[count] = *entry; + } count++; } } return count; } -/** - * - * rct2: 0x006AA26E - */ -int scenario_write_packed_objects(SDL_RWops* rw) -{ - for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) { - const rct_object_entry *entry = get_loaded_object_entry(i); - void *entryData = get_loaded_object_chunk(i); - if (entryData != (void*)-1 && !(entry->flags & 0xF0)) { - if (!object_saved_packed(rw, entry)) { - return 0; - } - } - } - return 1; -} - /** * * rct2: 0x006AA039 diff --git a/src/scenario.h b/src/scenario.h index f198fc08b2..4b14a36468 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -416,9 +416,7 @@ unsigned int scenario_rand(); unsigned int scenario_rand_max(unsigned int max); int scenario_prepare_for_save(); int scenario_save(SDL_RWops* rw, int flags); -int scenario_save_network(SDL_RWops* rw); int scenario_get_num_packed_objects_to_write(rct_object_entry *object_list); -int scenario_write_packed_objects(SDL_RWops* rw); void scenario_remove_trackless_rides(rct_s6_data *s6); void scenario_fix_ghosts(rct_s6_data *s6); void scenario_set_filename(const char *value);