1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-19 04:53:12 +01:00

Use streams for network load and save

This commit is contained in:
Ted John
2017-02-08 18:16:33 +00:00
parent de0e6bf521
commit d124f4fad0
10 changed files with 127 additions and 145 deletions

View File

@@ -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);
}

View File

@@ -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();
///////////////////////////////////////////////////////////////////////////

View File

@@ -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);

View File

@@ -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<const ObjectRepositoryItem *> 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<const ObjectRepositoryItem *> &objects) const
uint8 * Network::save_for_network(size_t &out_size, const std::vector<const ObjectRepositoryItem *> &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<uint8> 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<IParkImporter>(ParkImporter::CreateS6());
importer->LoadFromStream(stream, false);
importer->Import();
sprite_position_tween_reset();
// Read checksum
uint32 checksum = stream->ReadValue<uint32>();
UNUSED(checksum);
// Read other data not in normal save files
stream->Read(gSpriteSpatialIndex, 0x10001 * sizeof(uint16));
gGamePaused = stream->ReadValue<uint32>();
_guestGenerationProbability = stream->ReadValue<uint32>();
_suggestedGuestMaximum = stream->ReadValue<uint32>();
gCheatsSandboxMode = stream->ReadValue<uint8>() != 0;
gCheatsDisableClearanceChecks = stream->ReadValue<uint8>() != 0;
gCheatsDisableSupportLimits = stream->ReadValue<uint8>() != 0;
gCheatsDisableTrainLengthLimit = stream->ReadValue<uint8>() != 0;
gCheatsEnableChainLiftOnAllTrack = stream->ReadValue<uint8>() != 0;
gCheatsShowAllOperatingModes = stream->ReadValue<uint8>() != 0;
gCheatsShowVehiclesFromOtherTrackTypes = stream->ReadValue<uint8>() != 0;
gCheatsFastLiftHill = stream->ReadValue<uint8>() != 0;
gCheatsDisableBrakesFailure = stream->ReadValue<uint8>() != 0;
gCheatsDisableAllBreakdowns = stream->ReadValue<uint8>() != 0;
gCheatsUnlockAllPrices = stream->ReadValue<uint8>() != 0;
gCheatsBuildInPauseMode = stream->ReadValue<uint8>() != 0;
gCheatsIgnoreRideIntensity = stream->ReadValue<uint8>() != 0;
gCheatsDisableVandalism = stream->ReadValue<uint8>() != 0;
gCheatsDisableLittering = stream->ReadValue<uint8>() != 0;
gCheatsNeverendingMarketing = stream->ReadValue<uint8>() != 0;
gCheatsFreezeClimate = stream->ReadValue<uint8>() != 0;
gCheatsDisablePlantAging = stream->ReadValue<uint8>() != 0;
gCheatsAllowArbitraryRideTypeChanges = stream->ReadValue<uint8>() != 0;
gLastAutoSaveUpdate = AUTOSAVE_PAUSE;
result = true;
}
catch (const Exception &)
{
}
return result;
}
bool Network::SaveMap(IStream * stream, const std::vector<const ObjectRepositoryItem *> &objects) const
{
bool result = false;
viewport_set_saved_view();
try
{
auto s6exporter = std::make_unique<S6Exporter>();
s6exporter->ExportObjectsList = objects;
s6exporter->Export();
s6exporter->SaveGame(stream);
// Write other data not in normal save files
stream->Write(gSpriteSpatialIndex, 0x10001 * sizeof(uint16));
stream->WriteValue<uint32>(gGamePaused);
stream->WriteValue<uint32>(_guestGenerationProbability);
stream->WriteValue<uint32>(_suggestedGuestMaximum);
stream->WriteValue<uint8>(gCheatsSandboxMode);
stream->WriteValue<uint8>(gCheatsDisableClearanceChecks);
stream->WriteValue<uint8>(gCheatsDisableSupportLimits);
stream->WriteValue<uint8>(gCheatsDisableTrainLengthLimit);
stream->WriteValue<uint8>(gCheatsEnableChainLiftOnAllTrack);
stream->WriteValue<uint8>(gCheatsShowAllOperatingModes);
stream->WriteValue<uint8>(gCheatsShowVehiclesFromOtherTrackTypes);
stream->WriteValue<uint8>(gCheatsFastLiftHill);
stream->WriteValue<uint8>(gCheatsDisableBrakesFailure);
stream->WriteValue<uint8>(gCheatsDisableAllBreakdowns);
stream->WriteValue<uint8>(gCheatsUnlockAllPrices);
stream->WriteValue<uint8>(gCheatsBuildInPauseMode);
stream->WriteValue<uint8>(gCheatsIgnoreRideIntensity);
stream->WriteValue<uint8>(gCheatsDisableVandalism);
stream->WriteValue<uint8>(gCheatsDisableLittering);
stream->WriteValue<uint8>(gCheatsNeverendingMarketing);
stream->WriteValue<uint8>(gCheatsFreezeClimate);
stream->WriteValue<uint8>(gCheatsDisablePlantAging);
stream->WriteValue<uint8>(gCheatsAllowArbitraryRideTypeChanges);
result = true;
}
catch (const Exception &)
{
}
return result;
}
void Network::Client_Handle_CHAT(NetworkConnection& connection, NetworkPacket& packet)
{
const char* text = packet.ReadString();

View File

@@ -174,6 +174,9 @@ private:
std::string GenerateAdvertiseKey();
void SetupDefaultGroups();
bool LoadMap(IStream * stream);
bool SaveMap(IStream * stream, const std::vector<const ObjectRepositoryItem *> &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<const ObjectRepositoryItem *> &objects) const;
uint8 * save_for_network(size_t &out_size, const std::vector<const ObjectRepositoryItem *> &objects) const;
};
namespace Convert

View File

@@ -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<const ObjectRepositoryItem *> &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 {

View File

@@ -30,8 +30,6 @@ extern "C"
interface IStream;
struct ObjectRepositoryItem;
sint32 scenario_save_network(SDL_RWops* rw, const std::vector<const ObjectRepositoryItem *> &objects);
/**
* Class to export RollerCoaster Tycoon 2 scenarios (*.SC6) and saved games (*.SV6).
*/

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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