From 3a0e3c04e1041b1330c7633fe88ca626a0bd0ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Thu, 13 Oct 2016 14:57:40 +0200 Subject: [PATCH 1/7] network send map refactor --- src/network/network.cpp | 93 ++++++++++++++++++++++------------------- src/network/network.h | 2 + 2 files changed, 52 insertions(+), 43 deletions(-) diff --git a/src/network/network.cpp b/src/network/network.cpp index cc9df35ad4..456d157733 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -429,7 +429,7 @@ void Network::UpdateClient() } break; } - case NETWORK_STATUS_CONNECTED: + case SOCKET_STATUS_CONNECTED: { status = NETWORK_STATUS_CONNECTED; server_connection.ResetLastPacketTime(); @@ -886,56 +886,22 @@ void Network::Server_Send_AUTH(NetworkConnection& connection) void Network::Server_Send_MAP(NetworkConnection* connection) { - bool RLEState = gUseRLE; - gUseRLE = false; FILE* temp = tmpfile(); if (!temp) { log_warning("Failed to create temporary file to save map."); return; } SDL_RWops* rw = SDL_RWFromFP(temp, SDL_TRUE); - scenario_save_network(rw); - gUseRLE = RLEState; - int size = (int)SDL_RWtell(rw); - std::vector buffer(size); - SDL_RWseek(rw, 0, RW_SEEK_SET); - if (SDL_RWread(rw, &buffer[0], size, 1) == 0) { - log_warning("Failed to read temporary map file into memory."); - SDL_RWclose(rw); + size_t out_size; + unsigned char *header; + header = save_for_network(rw, out_size); + SDL_RWclose(rw); + if (header == nullptr) { + connection->SetLastDisconnectReason(STR_MULTIPLAYER_CONNECTION_CLOSED); + connection->Socket->Disconnect(); return; } size_t chunksize = 65000; - size_t out_size = size; - unsigned char *compressed = util_zlib_deflate(&buffer[0], size, &out_size); - unsigned char *header; - if (compressed != NULL) - { - header = (unsigned char *)_strdup("open2_sv6_zlib"); - size_t header_len = strlen((char *)header) + 1; // account for null terminator - header = (unsigned char *)realloc(header, header_len + out_size); - if (header == nullptr) { - log_error("Failed to allocate %u bytes.", header_len + out_size); - connection->SetLastDisconnectReason(STR_MULTIPLAYER_CONNECTION_CLOSED); - connection->Socket->Disconnect(); - free(compressed); - return; - } - memcpy(&header[header_len], compressed, out_size); - out_size += header_len; - free(compressed); - log_verbose("Sending map of size %u bytes, compressed to %u bytes", size, out_size); - } else { - log_warning("Failed to compress the data, falling back to non-compressed sv6."); - header = (unsigned char *)malloc(size); - if (header == nullptr) { - log_error("Failed to allocate %u bytes.", size); - connection->SetLastDisconnectReason(STR_MULTIPLAYER_CONNECTION_CLOSED); - connection->Socket->Disconnect(); - return; - } - out_size = size; - memcpy(header, &buffer[0], size); - } for (size_t i = 0; i < out_size; i += chunksize) { size_t datasize = Math::Min(chunksize, out_size - i); std::unique_ptr packet(NetworkPacket::Allocate()); @@ -948,7 +914,48 @@ void Network::Server_Send_MAP(NetworkConnection* connection) } } free(header); - SDL_RWclose(rw); +} + +unsigned char * Network::save_for_network(SDL_RWops *rw_buffer, size_t &out_size) const +{ + unsigned char * header = nullptr; + out_size = 0; + bool RLEState = gUseRLE; + gUseRLE = false; + scenario_save_network(rw_buffer); + gUseRLE = RLEState; + int size = (int)SDL_RWtell(rw_buffer); + std::vector buffer(size); + SDL_RWseek(rw_buffer, 0, RW_SEEK_SET); + if (SDL_RWread(rw_buffer, &buffer[0], size, 1) == 0) { + log_warning("Failed to read temporary map file into memory."); + return nullptr; + } + unsigned char *compressed = util_zlib_deflate(&buffer[0], size, &out_size); + if (compressed != NULL) + { + header = (unsigned char *)_strdup("open2_sv6_zlib"); + size_t header_len = strlen((char *)header) + 1; // account for null terminator + header = (unsigned char *)realloc(header, header_len + out_size); + if (header == nullptr) { + log_error("Failed to allocate %u bytes.", header_len + out_size); + } else { + memcpy(&header[header_len], compressed, out_size); + out_size += header_len; + log_verbose("Sending map of size %u bytes, compressed to %u bytes", size, out_size); + } + free(compressed); + } else { + log_warning("Failed to compress the data, falling back to non-compressed sv6."); + header = (unsigned char *)malloc(size); + if (header == nullptr) { + log_error("Failed to allocate %u bytes.", size); + } else { + out_size = size; + memcpy(header, &buffer[0], size); + } + } + return header; } void Network::Client_Send_CHAT(const char* text) diff --git a/src/network/network.h b/src/network/network.h index 2ef7ee687a..0db5f98a0f 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -236,6 +236,8 @@ 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); + + unsigned char * save_for_network(SDL_RWops *buffer, size_t &out_size) const; }; namespace Convert From f3a2eb024703acae50ac2d6794f4c33746746fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Thu, 13 Oct 2016 18:15:25 +0200 Subject: [PATCH 2/7] Allow selecting only subset of loaded objects for export --- src/scenario.c | 2 +- src/scenario.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scenario.c b/src/scenario.c index c5689d500b..f3a0f74ca7 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -689,7 +689,7 @@ int scenario_prepare_for_save() * * rct2: 0x006AA244 */ -int scenario_get_num_packed_objects_to_write() +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++) { diff --git a/src/scenario.h b/src/scenario.h index 15f486c31b..f198fc08b2 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -417,7 +417,7 @@ 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(); +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); 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 3/7] 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); From 65c6cd5412e607ab41f6a88f8e2f8e622e235cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Tue, 18 Oct 2016 23:23:43 +0200 Subject: [PATCH 4/7] Implement review suggestions --- src/network/NetworkConnection.h | 2 +- src/network/network.cpp | 32 ++++++++++++++++++++------------ src/network/network.h | 2 +- src/rct2/S6Exporter.cpp | 2 +- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/network/NetworkConnection.h b/src/network/NetworkConnection.h index 982e8dd38e..87e9b2b09b 100644 --- a/src/network/NetworkConnection.h +++ b/src/network/NetworkConnection.h @@ -39,7 +39,7 @@ public: uint32 PingTime = 0; NetworkKey Key; std::vector Challenge; - std::vector RequestedObjects; + std::vector RequestedObjects; NetworkConnection(); ~NetworkConnection(); diff --git a/src/network/network.cpp b/src/network/network.cpp index 71853a38e6..8b31443b88 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -883,7 +883,7 @@ 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) +void Network::Server_Send_OBJECTS(NetworkConnection& connection, const rct_object_entry * object_list, uint32 size) const { log_verbose("Server sends objects list with %u items", size); std::unique_ptr packet(NetworkPacket::Allocate()); @@ -892,7 +892,7 @@ void Network::Server_Send_OBJECTS(NetworkConnection& connection, rct_object_entr { 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; + *packet << object_list[i].checksum << object_list[i].flags; } connection.QueuePacket(std::move(packet)); } @@ -1456,10 +1456,9 @@ 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); - Server_Send_MAP(&connection); - gNetwork.Server_Send_EVENT_PLAYER_JOINED(player_name); - Server_Send_GROUPLIST(connection); - Server_Send_PLAYERLIST(); + 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); } } @@ -1470,9 +1469,6 @@ 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); } @@ -1486,14 +1482,20 @@ void Network::Client_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket for (uint32 i = 0; i < size; i++) { const char * name = (const char *)packet.Read(8); - uint32 checksum; - packet >> checksum; + // Required, as packet has no null terminators. std::string s(name, name + 8); + uint32 checksum, flags; + packet >> checksum >> flags; const ObjectRepositoryItem * ori = repo->FindObject(s.c_str()); - if (ori == nullptr || ori->ObjectEntry.checksum != checksum) { + // 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); requested_objects.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); } } Client_Send_OBJECTS(requested_objects); @@ -1511,6 +1513,12 @@ void Network::Server_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket log_verbose("Client requested object %s", s.c_str()); connection.RequestedObjects.push_back(s); } + + const char * player_name = (const char *) connection.Player->name.c_str(); + Server_Send_MAP(&connection); + gNetwork.Server_Send_EVENT_PLAYER_JOINED(player_name); + Server_Send_GROUPLIST(connection); + Server_Send_PLAYERLIST(); } void Network::Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet) diff --git a/src/network/network.h b/src/network/network.h index b9e932a5f0..c6cc8bcded 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -143,7 +143,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, rct_object_entry * object_list, uint32 size); + void Server_Send_OBJECTS(NetworkConnection& connection, const rct_object_entry *object_list, uint32 size) const; std::vector> player_list; std::vector> group_list; diff --git a/src/rct2/S6Exporter.cpp b/src/rct2/S6Exporter.cpp index 250afd39cf..2ccfc8e443 100644 --- a/src/rct2/S6Exporter.cpp +++ b/src/rct2/S6Exporter.cpp @@ -92,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 ? uint16(ExportObjectsList.size()) : scenario_get_num_packed_objects_to_write(nullptr); + _s6.header.num_packed_objects = ExportObjects ? scenario_get_num_packed_objects_to_write(nullptr) : uint16(ExportObjectsList.size()); _s6.header.version = S6_RCT2_VERSION; _s6.header.magic_number = S6_MAGIC_NUMBER; From 194c9aed0139349e3fe4cf4fccee0aae753bf7b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Wed, 19 Oct 2016 23:36:20 +0200 Subject: [PATCH 5/7] Refactor scenario_write_packed_objects and friends --- src/network/NetworkConnection.h | 17 +++---- src/network/network.cpp | 30 +++++++----- src/network/network.h | 6 ++- src/rct2/S6Exporter.cpp | 81 ++++++++++++++++++++------------- src/rct2/S6Exporter.h | 11 +++-- src/scenario.c | 20 -------- src/scenario.h | 1 - 7 files changed, 86 insertions(+), 80 deletions(-) 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); From 8b5024a8932db450a923c96830f2081b4a0ad5d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Fri, 21 Oct 2016 08:31:59 +0200 Subject: [PATCH 6/7] Update network version --- src/network/network.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/network.h b/src/network/network.h index 919be48a59..9b73431d3f 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -55,7 +55,7 @@ extern "C" { // This define 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 "15" +#define NETWORK_STREAM_VERSION "16" #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION #ifdef __cplusplus From 18ff83fd6cff0f9fbf4437fc4472396c7ca88093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Fri, 21 Oct 2016 11:21:42 +0200 Subject: [PATCH 7/7] Fix forward declaraction of ObjectRepositoryItem --- src/network/network.h | 2 +- src/rct2/S6Exporter.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/network.h b/src/network/network.h index 9b73431d3f..7d1b62f0ca 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -83,7 +83,7 @@ enum { NETWORK_TICK_FLAG_CHECKSUMS = 1 << 0, }; -class ObjectRepositoryItem; +struct ObjectRepositoryItem; class Network { diff --git a/src/rct2/S6Exporter.h b/src/rct2/S6Exporter.h index 9218855cdd..96cba63b6e 100644 --- a/src/rct2/S6Exporter.h +++ b/src/rct2/S6Exporter.h @@ -27,7 +27,7 @@ extern "C" #include "../object_list.h" } -class ObjectRepositoryItem; +struct ObjectRepositoryItem; int scenario_save_network(SDL_RWops* rw, const std::vector &objects); int scenario_write_packed_objects(SDL_RWops* rw, std::vector &objects);