diff --git a/src/openrct2/core/MemoryStream.cpp b/src/openrct2/core/MemoryStream.cpp index 341387300a..d6dcfe75fe 100644 --- a/src/openrct2/core/MemoryStream.cpp +++ b/src/openrct2/core/MemoryStream.cpp @@ -63,7 +63,12 @@ MemoryStream::~MemoryStream() _data = nullptr; } -void * MemoryStream::GetData() const +const void * MemoryStream::GetData() const +{ + return _data; +} + +void * MemoryStream::GetDataCopy() const { return Memory::Duplicate(_data, _dataSize); } diff --git a/src/openrct2/core/MemoryStream.h b/src/openrct2/core/MemoryStream.h index f7d490872c..81c6b64082 100644 --- a/src/openrct2/core/MemoryStream.h +++ b/src/openrct2/core/MemoryStream.h @@ -46,7 +46,8 @@ public: MemoryStream(const void * data, size_t dataSize); virtual ~MemoryStream(); - void * GetData() const; + const void * GetData() const; + void * GetDataCopy() const; void * TakeData(); /////////////////////////////////////////////////////////////////////////// diff --git a/src/openrct2/game.h b/src/openrct2/game.h index 8c70bbb44d..87336a8db6 100644 --- a/src/openrct2/game.h +++ b/src/openrct2/game.h @@ -168,7 +168,6 @@ sint32 game_do_command_p(sint32 command, sint32 *eax, sint32 *ebx, sint32 *ecx, void game_load_or_quit_no_save_prompt(); bool game_load_sv6_path(const char * path); bool game_load_sv6(SDL_RWops* rw); -sint32 game_load_network(SDL_RWops* rw); bool game_load_save(const utf8 *path); void game_load_init(); void game_pause_toggle(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *edx, sint32 *esi, sint32 *edi, sint32 *ebp); diff --git a/src/openrct2/network/network.cpp b/src/openrct2/network/network.cpp index 3ff79f2c21..a102008205 100644 --- a/src/openrct2/network/network.cpp +++ b/src/openrct2/network/network.cpp @@ -47,6 +47,7 @@ sint32 _pickup_peep_old_x = SPRITE_LOCATION_NULL; #include "../core/Util.hpp" #include "../object/ObjectManager.h" #include "../object/ObjectRepository.h" +#include "../ParkImporter.h" #include "../rct2/S6Exporter.h" extern "C" { @@ -909,14 +910,6 @@ void Network::Server_Send_AUTH(NetworkConnection& connection) void Network::Server_Send_MAP(NetworkConnection* connection) { - FILE* temp = tmpfile(); - if (!temp) { - log_warning("Failed to create temporary file to save map."); - return; - } - SDL_RWops* rw = SDL_RWFromFP(temp, SDL_TRUE); - size_t out_size; - uint8 *header; std::vector objects; if (connection) { objects = connection->RequestedObjects; @@ -926,8 +919,9 @@ void Network::Server_Send_MAP(NetworkConnection* connection) IObjectManager * objManager = GetObjectManager(); objects = objManager->GetPackableObjects(); } - header = save_for_network(rw, out_size, objects); - SDL_RWclose(rw); + + size_t out_size; + uint8 * header = save_for_network(out_size, objects); if (header == nullptr) { if (connection) { connection->SetLastDisconnectReason(STR_MULTIPLAYER_CONNECTION_CLOSED); @@ -950,22 +944,24 @@ void Network::Server_Send_MAP(NetworkConnection* connection) free(header); } -uint8 * Network::save_for_network(SDL_RWops *rw_buffer, size_t &out_size, const std::vector &objects) const +uint8 * Network::save_for_network(size_t &out_size, const std::vector &objects) const { uint8 * header = nullptr; out_size = 0; bool RLEState = gUseRLE; gUseRLE = false; - scenario_save_network(rw_buffer, objects); - gUseRLE = RLEState; - sint32 size = (sint32)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."); + + auto ms = MemoryStream(); + if (!SaveMap(&ms, objects)) { + log_warning("Failed to export map."); return nullptr; } - uint8 *compressed = util_zlib_deflate(&buffer[0], size, &out_size); + gUseRLE = RLEState; + + const void * data = ms.GetData(); + sint32 size = ms.GetLength(); + + uint8 *compressed = util_zlib_deflate((const uint8 *)data, size, &out_size); if (compressed != NULL) { header = (uint8 *)_strdup("open2_sv6_zlib"); @@ -986,7 +982,7 @@ uint8 * Network::save_for_network(SDL_RWops *rw_buffer, size_t &out_size, const log_error("Failed to allocate %u bytes.", size); } else { out_size = size; - memcpy(header, &buffer[0], size); + memcpy(header, data, size); } } return header; @@ -1669,8 +1665,10 @@ void Network::Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& pa } else { log_verbose("Assuming received map is in plain sv6 format"); } - SDL_RWops* rw = SDL_RWFromMem(data, (sint32)data_size); - if (game_load_network(rw)) { + + auto ms = MemoryStream(data, data_size); + if (LoadMap(&ms)) + { game_load_init(); game_command_queue.clear(); server_tick = gCurrentTicks; @@ -1687,7 +1685,6 @@ void Network::Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& pa //Something went wrong, game is not loaded. Return to main screen. game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0); } - SDL_RWclose(rw); if (has_to_free) { free(data); @@ -1695,6 +1692,99 @@ void Network::Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& pa } } +bool Network::LoadMap(IStream * stream) +{ + bool result = false; + try + { + auto importer = std::unique_ptr(ParkImporter::CreateS6()); + importer->LoadFromStream(stream, false); + importer->Import(); + + sprite_position_tween_reset(); + + // Read checksum + uint32 checksum = stream->ReadValue(); + UNUSED(checksum); + + // Read other data not in normal save files + stream->Read(gSpriteSpatialIndex, 0x10001 * sizeof(uint16)); + gGamePaused = stream->ReadValue(); + _guestGenerationProbability = stream->ReadValue(); + _suggestedGuestMaximum = stream->ReadValue(); + gCheatsSandboxMode = stream->ReadValue() != 0; + gCheatsDisableClearanceChecks = stream->ReadValue() != 0; + gCheatsDisableSupportLimits = stream->ReadValue() != 0; + gCheatsDisableTrainLengthLimit = stream->ReadValue() != 0; + gCheatsEnableChainLiftOnAllTrack = stream->ReadValue() != 0; + gCheatsShowAllOperatingModes = stream->ReadValue() != 0; + gCheatsShowVehiclesFromOtherTrackTypes = stream->ReadValue() != 0; + gCheatsFastLiftHill = stream->ReadValue() != 0; + gCheatsDisableBrakesFailure = stream->ReadValue() != 0; + gCheatsDisableAllBreakdowns = stream->ReadValue() != 0; + gCheatsUnlockAllPrices = stream->ReadValue() != 0; + gCheatsBuildInPauseMode = stream->ReadValue() != 0; + gCheatsIgnoreRideIntensity = stream->ReadValue() != 0; + gCheatsDisableVandalism = stream->ReadValue() != 0; + gCheatsDisableLittering = stream->ReadValue() != 0; + gCheatsNeverendingMarketing = stream->ReadValue() != 0; + gCheatsFreezeClimate = stream->ReadValue() != 0; + gCheatsDisablePlantAging = stream->ReadValue() != 0; + gCheatsAllowArbitraryRideTypeChanges = stream->ReadValue() != 0; + + gLastAutoSaveUpdate = AUTOSAVE_PAUSE; + result = true; + } + catch (const Exception &) + { + } + return result; +} + +bool Network::SaveMap(IStream * stream, const std::vector &objects) const +{ + bool result = false; + viewport_set_saved_view(); + try + { + auto s6exporter = std::make_unique(); + s6exporter->ExportObjectsList = objects; + s6exporter->Export(); + s6exporter->SaveGame(stream); + + // Write other data not in normal save files + stream->Write(gSpriteSpatialIndex, 0x10001 * sizeof(uint16)); + stream->WriteValue(gGamePaused); + stream->WriteValue(_guestGenerationProbability); + stream->WriteValue(_suggestedGuestMaximum); + stream->WriteValue(gCheatsSandboxMode); + stream->WriteValue(gCheatsDisableClearanceChecks); + stream->WriteValue(gCheatsDisableSupportLimits); + stream->WriteValue(gCheatsDisableTrainLengthLimit); + stream->WriteValue(gCheatsEnableChainLiftOnAllTrack); + stream->WriteValue(gCheatsShowAllOperatingModes); + stream->WriteValue(gCheatsShowVehiclesFromOtherTrackTypes); + stream->WriteValue(gCheatsFastLiftHill); + stream->WriteValue(gCheatsDisableBrakesFailure); + stream->WriteValue(gCheatsDisableAllBreakdowns); + stream->WriteValue(gCheatsUnlockAllPrices); + stream->WriteValue(gCheatsBuildInPauseMode); + stream->WriteValue(gCheatsIgnoreRideIntensity); + stream->WriteValue(gCheatsDisableVandalism); + stream->WriteValue(gCheatsDisableLittering); + stream->WriteValue(gCheatsNeverendingMarketing); + stream->WriteValue(gCheatsFreezeClimate); + stream->WriteValue(gCheatsDisablePlantAging); + stream->WriteValue(gCheatsAllowArbitraryRideTypeChanges); + + result = true; + } + catch (const Exception &) + { + } + return result; +} + void Network::Client_Handle_CHAT(NetworkConnection& connection, NetworkPacket& packet) { const char* text = packet.ReadString(); diff --git a/src/openrct2/network/network.h b/src/openrct2/network/network.h index 2af7c1eca7..f965285832 100644 --- a/src/openrct2/network/network.h +++ b/src/openrct2/network/network.h @@ -174,6 +174,9 @@ private: std::string GenerateAdvertiseKey(); void SetupDefaultGroups(); + bool LoadMap(IStream * stream); + bool SaveMap(IStream * stream, const std::vector &objects) const; + struct GameCommand { GameCommand(uint32 t, uint32* args, uint8 p, uint8 cb) { @@ -245,7 +248,7 @@ private: void Client_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet); void Server_Handle_OBJECTS(NetworkConnection& connection, NetworkPacket& packet); - uint8 * save_for_network(SDL_RWops *buffer, size_t &out_size, const std::vector &objects) const; + uint8 * save_for_network(size_t &out_size, const std::vector &objects) const; }; namespace Convert diff --git a/src/openrct2/rct2/S6Exporter.cpp b/src/openrct2/rct2/S6Exporter.cpp index 2c4bef975c..d9c0edcd9a 100644 --- a/src/openrct2/rct2/S6Exporter.cpp +++ b/src/openrct2/rct2/S6Exporter.cpp @@ -396,61 +396,6 @@ uint32 S6Exporter::GetLoanHash(money32 initialCash, money32 bankLoan, uint32 max return value; } -// Save game state without modifying any of the state for multiplayer -sint32 scenario_save_network(SDL_RWops * rw, const std::vector &objects) -{ - viewport_set_saved_view(); - - bool result = false; - auto s6exporter = new S6Exporter(); - try - { - auto rwStream = FileStream(rw, FILE_MODE_WRITE); - - s6exporter->ExportObjectsList = objects; - s6exporter->Export(); - s6exporter->SaveGame(&rwStream); - result = true; - } - catch (const 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; -} - extern "C" { enum { diff --git a/src/openrct2/rct2/S6Exporter.h b/src/openrct2/rct2/S6Exporter.h index a0dc5a908b..af0e691bb1 100644 --- a/src/openrct2/rct2/S6Exporter.h +++ b/src/openrct2/rct2/S6Exporter.h @@ -30,8 +30,6 @@ extern "C" interface IStream; struct ObjectRepositoryItem; -sint32 scenario_save_network(SDL_RWops* rw, const std::vector &objects); - /** * Class to export RollerCoaster Tycoon 2 scenarios (*.SC6) and saved games (*.SV6). */ diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index e5db2d1309..c850a1c672 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -561,63 +561,4 @@ extern "C" gLastAutoSaveUpdate = AUTOSAVE_PAUSE; return result; } - - sint32 game_load_network(SDL_RWops* rw) - { - bool result = false; - auto stream = FileStream(rw, FILE_MODE_OPEN); - auto s6Importer = new S6Importer(); - try - { - s6Importer->LoadFromStream(&stream, false); - s6Importer->Import(); - - sprite_position_tween_reset(); - result = true; - } - catch (const ObjectLoadException &) - { - } - catch (const Exception &) - { - } - delete s6Importer; - - if (!result) - { - return 0; - } - - // Read checksum - uint32 checksum; - SDL_RWread(rw, &checksum, sizeof(uint32), 1); - - // Read other data not in normal save files - SDL_RWread(rw, gSpriteSpatialIndex, 0x10001 * sizeof(uint16), 1); - gGamePaused = SDL_ReadLE32(rw); - _guestGenerationProbability = SDL_ReadLE32(rw); - _suggestedGuestMaximum = SDL_ReadLE32(rw); - gCheatsSandboxMode = SDL_ReadU8(rw) != 0; - gCheatsDisableClearanceChecks = SDL_ReadU8(rw) != 0; - gCheatsDisableSupportLimits = SDL_ReadU8(rw) != 0; - gCheatsDisableTrainLengthLimit = SDL_ReadU8(rw) != 0; - gCheatsEnableChainLiftOnAllTrack = SDL_ReadU8(rw) != 0; - gCheatsShowAllOperatingModes = SDL_ReadU8(rw) != 0; - gCheatsShowVehiclesFromOtherTrackTypes = SDL_ReadU8(rw) != 0; - gCheatsFastLiftHill = SDL_ReadU8(rw) != 0; - gCheatsDisableBrakesFailure = SDL_ReadU8(rw) != 0; - gCheatsDisableAllBreakdowns = SDL_ReadU8(rw) != 0; - gCheatsUnlockAllPrices = SDL_ReadU8(rw) != 0; - gCheatsBuildInPauseMode = SDL_ReadU8(rw) != 0; - gCheatsIgnoreRideIntensity = SDL_ReadU8(rw) != 0; - gCheatsDisableVandalism = SDL_ReadU8(rw) != 0; - gCheatsDisableLittering = SDL_ReadU8(rw) != 0; - gCheatsNeverendingMarketing = SDL_ReadU8(rw) != 0; - gCheatsFreezeClimate = SDL_ReadU8(rw) != 0; - gCheatsDisablePlantAging = SDL_ReadU8(rw) != 0; - gCheatsAllowArbitraryRideTypeChanges = SDL_ReadU8(rw) != 0; - - gLastAutoSaveUpdate = AUTOSAVE_PAUSE; - return 1; - } } diff --git a/src/openrct2/util/util.c b/src/openrct2/util/util.c index 62616f8f52..514b7d8270 100644 --- a/src/openrct2/util/util.c +++ b/src/openrct2/util/util.c @@ -495,7 +495,7 @@ uint8 *util_zlib_inflate(uint8 *data, size_t data_in_size, size_t *data_out_size * @return Returns a pointer to memory holding compressed data or NULL on failure. * @note It is caller's responsibility to free() the returned pointer once done with it. */ -uint8 *util_zlib_deflate(uint8 *data, size_t data_in_size, size_t *data_out_size) +uint8 *util_zlib_deflate(const uint8 *data, size_t data_in_size, size_t *data_out_size) { sint32 ret = Z_OK; uLongf out_size = (uLongf)*data_out_size; diff --git a/src/openrct2/util/util.h b/src/openrct2/util/util.h index f33b483d7b..34d00a35b7 100644 --- a/src/openrct2/util/util.h +++ b/src/openrct2/util/util.h @@ -53,7 +53,7 @@ bool str_is_null_or_empty(const char *str); void util_srand(sint32 source); uint32 util_rand(); -uint8 *util_zlib_deflate(uint8 *data, size_t data_in_size, size_t *data_out_size); +uint8 *util_zlib_deflate(const uint8 *data, size_t data_in_size, size_t *data_out_size); uint8 *util_zlib_inflate(uint8 *data, size_t data_in_size, size_t *data_out_size); #endif