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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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).
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user