diff --git a/src/network/NetworkConnection.h b/src/network/NetworkConnection.h index 87e9b2b09b..f5e9487449 100644 --- a/src/network/NetworkConnection.h +++ b/src/network/NetworkConnection.h @@ -28,18 +28,19 @@ #include "TcpSocket.h" class NetworkPlayer; +struct ObjectRepositoryItem; class NetworkConnection final { public: - ITcpSocket * Socket = nullptr; - NetworkPacket InboundPacket; - NETWORK_AUTH AuthStatus = NETWORK_AUTH_NONE; - NetworkPlayer * Player = nullptr; - uint32 PingTime = 0; - NetworkKey Key; - std::vector Challenge; - std::vector RequestedObjects; + ITcpSocket * Socket = nullptr; + NetworkPacket InboundPacket; + NETWORK_AUTH AuthStatus = NETWORK_AUTH_NONE; + NetworkPlayer * Player = nullptr; + uint32 PingTime = 0; + NetworkKey Key; + std::vector Challenge; + std::vector RequestedObjects; NetworkConnection(); ~NetworkConnection(); diff --git a/src/network/network.cpp b/src/network/network.cpp index 8b31443b88..330485dc1d 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -883,16 +883,16 @@ void Network::Server_Send_TOKEN(NetworkConnection& connection) connection.QueuePacket(std::move(packet)); } -void Network::Server_Send_OBJECTS(NetworkConnection& connection, const rct_object_entry * object_list, uint32 size) const +void Network::Server_Send_OBJECTS(NetworkConnection& connection, const std::vector &objects) const { - log_verbose("Server sends objects list with %u items", size); + log_verbose("Server sends objects list with %u items", objects.size()); std::unique_ptr packet(NetworkPacket::Allocate()); - *packet << (uint32)NETWORK_COMMAND_OBJECTS << size; - for (uint32 i = 0; i < size; i++) + *packet << (uint32)NETWORK_COMMAND_OBJECTS << (uint32)objects.size(); + for (size_t i = 0; i < objects.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 << object_list[i].flags; + log_verbose("Object %.8s (checksum %x)", objects[i]->ObjectEntry.name, objects[i]->ObjectEntry.checksum); + packet->Write((const uint8 *)objects[i]->ObjectEntry.name, 8); + *packet << objects[i]->ObjectEntry.checksum << objects[i]->ObjectEntry.flags; } connection.QueuePacket(std::move(packet)); } @@ -947,7 +947,7 @@ void Network::Server_Send_MAP(NetworkConnection* connection) free(header); } -unsigned char * Network::save_for_network(SDL_RWops *rw_buffer, size_t &out_size, const std::vector &objects) 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; @@ -1456,9 +1456,8 @@ void Network::Server_Client_Joined(const char* name, const std::string &keyhash, const char * player_name = (const char *) player->name.c_str(); format_string(text, 256, STR_MULTIPLAYER_PLAYER_HAS_JOINED_THE_GAME, &player_name); chat_history_add(text); - 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); + std::vector objects = scenario_get_packable_objects(); + Server_Send_OBJECTS(connection, objects); } } @@ -1506,12 +1505,19 @@ void Network::Server_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket uint32 size; packet >> size; log_verbose("Client requested %u objects", size); + IObjectRepository * repo = GetObjectRepository(); for (uint32 i = 0; i < size; i++) { const char * name = (const char *)packet.Read(8); + // This is required, as packet does not have null terminator std::string s(name, name + 8); log_verbose("Client requested object %s", s.c_str()); - connection.RequestedObjects.push_back(s); + const ObjectRepositoryItem * item = repo->FindObject(s.c_str()); + if (item == nullptr) { + log_warning("Client tried getting non-existent object %s from us.", s.c_str()); + } else { + connection.RequestedObjects.push_back(item); + } } const char * player_name = (const char *) connection.Player->name.c_str(); diff --git a/src/network/network.h b/src/network/network.h index c6cc8bcded..919be48a59 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -83,6 +83,8 @@ enum { NETWORK_TICK_FLAG_CHECKSUMS = 1 << 0, }; +class ObjectRepositoryItem; + class Network { public: @@ -143,7 +145,7 @@ public: 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, const rct_object_entry *object_list, uint32 size) const; + void Server_Send_OBJECTS(NetworkConnection& connection, const std::vector &objects) const; std::vector> player_list; std::vector> group_list; @@ -241,7 +243,7 @@ private: 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 std::vector &objects) 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 2ccfc8e443..e6bcd7f81a 100644 --- a/src/rct2/S6Exporter.cpp +++ b/src/rct2/S6Exporter.cpp @@ -48,7 +48,6 @@ extern "C" S6Exporter::S6Exporter() { - ExportObjects = false; RemoveTracklessRides = false; memset(&_s6, 0, sizeof(_s6)); } @@ -92,7 +91,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(nullptr) : uint16(ExportObjectsList.size()); + _s6.header.num_packed_objects = uint16(ExportObjectsList.size()); _s6.header.version = S6_RCT2_VERSION; _s6.header.magic_number = S6_MAGIC_NUMBER; @@ -123,10 +122,11 @@ void S6Exporter::Save(SDL_RWops * rw, bool isScenario) SDL_RWwrite(rw, buffer, encodedLength, 1); } + log_warning("exporting %u objects", _s6.header.num_packed_objects); // 2: Write packed objects if (_s6.header.num_packed_objects > 0) { - if (!scenario_write_packed_objects(rw, ExportObjectsList, ExportObjects)) + if (!scenario_write_packed_objects(rw, ExportObjectsList)) { free(buffer); throw Exception("Unable to pack objects."); @@ -228,11 +228,6 @@ 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; @@ -337,7 +332,7 @@ void S6Exporter::Export(const std::vector &objects, bool export_all _s6.current_expenditure = gCurrentExpenditure; _s6.current_profit = gCurrentProfit; _s6.weekly_profit_average_dividend = gWeeklyProfitAverageDividend; - _s6.weekly_profit_average_divisor = gWeeklyProfitAverageDivisor; + _s6.weekly_profit_average_divisor = gWeeklyProfitAverageDivisor; // pad_0135833A memcpy(_s6.weekly_profit_history, gWeeklyProfitHistory, sizeof(_s6.weekly_profit_history)); @@ -460,7 +455,7 @@ uint32 S6Exporter::GetLoanHash(money32 initialCash, money32 bankLoan, uint32 max // Save game state without modifying any of the state for multiplayer -int scenario_save_network(SDL_RWops * rw, const std::vector &objects) +int scenario_save_network(SDL_RWops * rw, const std::vector &objects) { viewport_set_saved_view(); @@ -468,7 +463,6 @@ int scenario_save_network(SDL_RWops * rw, const std::vector &object auto s6exporter = new S6Exporter(); try { - s6exporter->ExportObjects = false; s6exporter->ExportObjectsList = objects; s6exporter->Export(); s6exporter->SaveGame(rw); @@ -513,37 +507,58 @@ int scenario_save_network(SDL_RWops * rw, const std::vector &object return 1; } -int scenario_write_packed_objects(SDL_RWops* rw, std::vector &objects, bool export_all) +static bool object_is_custom(const ObjectRepositoryItem * object) +{ + Guard::ArgumentNotNull(object); + + // Validate the object is not one from base game or expansion pack + return (object->LoadedObject != nullptr && + object->LoadedObject->GetLegacyData() != nullptr + && !(object->ObjectEntry.flags & 0xF0)); +} + +int scenario_write_packed_objects(SDL_RWops* rw, std::vector &objects) { log_verbose("exporting packed objects"); - if (export_all) + for (const auto &object : objects) { - 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; - } + Guard::ArgumentNotNull(object); + log_verbose("exporting object %.8s", object->ObjectEntry.name); + if (object_is_custom(object)) + { + if (!object_saved_packed(rw, &object->ObjectEntry)) + { + return 0; } } - } else { - IObjectRepository * repo = GetObjectRepository(); - for (const auto &name : objects) + else { - 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; - } - } + log_warning("Refusing to pack vanilla/expansion object \"%s\"", object->ObjectEntry.name); } } return 1; } +/** + * + * rct2: 0x006AA244 + */ +std::vector scenario_get_packable_objects() +{ + std::vector objects; + IObjectRepository * repo = GetObjectRepository(); + for (size_t i = 0; i < repo->GetNumObjects(); i++) + { + const ObjectRepositoryItem *item = &repo->GetObjects()[i]; + // Validate the object is not one from base game or expansion pack + if (object_is_custom(item)) + { + objects.push_back(item); + } + } + return objects; +} + extern "C" { enum { @@ -582,7 +597,9 @@ extern "C" auto s6exporter = new S6Exporter(); try { - s6exporter->ExportObjects = (flags & S6_SAVE_FLAG_EXPORT); + if (flags & S6_SAVE_FLAG_EXPORT) { + s6exporter->ExportObjectsList = scenario_get_packable_objects(); + } s6exporter->RemoveTracklessRides = true; s6exporter->Export(); if (flags & S6_SAVE_FLAG_SCENARIO) diff --git a/src/rct2/S6Exporter.h b/src/rct2/S6Exporter.h index b28d94d5cd..9218855cdd 100644 --- a/src/rct2/S6Exporter.h +++ b/src/rct2/S6Exporter.h @@ -27,8 +27,11 @@ 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 ObjectRepositoryItem; + +int scenario_save_network(SDL_RWops* rw, const std::vector &objects); +int scenario_write_packed_objects(SDL_RWops* rw, std::vector &objects); +std::vector scenario_get_packable_objects(); /** * Class to export RollerCoaster Tycoon 2 scenarios (*.SC6) and saved games (*.SV6). @@ -36,9 +39,8 @@ int scenario_write_packed_objects(SDL_RWops* rw, std::vector &s, bo class S6Exporter final { public: - bool ExportObjects; bool RemoveTracklessRides; - std::vector ExportObjectsList; + std::vector ExportObjectsList; S6Exporter(); @@ -47,7 +49,6 @@ 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 160027fe98..5bd2f30e26 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -685,26 +685,6 @@ int scenario_prepare_for_save() return 1; } -/** - * - * rct2: 0x006AA244 - */ -int scenario_get_num_packed_objects_to_write(rct_object_entry * object_list) -{ - int count = 0; - 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_list != NULL) { - object_list[count] = *entry; - } - count++; - } - } - return count; -} - /** * * rct2: 0x006AA039 diff --git a/src/scenario.h b/src/scenario.h index 4b14a36468..5b4531ebc4 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -416,7 +416,6 @@ 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_get_num_packed_objects_to_write(rct_object_entry *object_list); void scenario_remove_trackless_rides(rct_s6_data *s6); void scenario_fix_ghosts(rct_s6_data *s6); void scenario_set_filename(const char *value);