1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-10 09:32:29 +01:00

Don't Double-Compress Park Chunks in Replay File (#24728)

This commit is contained in:
LRFLEW
2025-07-20 19:03:52 -05:00
committed by GitHub
parent 9d5b21cebf
commit c79eb0609b
4 changed files with 58 additions and 39 deletions

View File

@@ -261,7 +261,7 @@ namespace OpenRCT2
auto exporter = std::make_unique<ParkFileExporter>(); auto exporter = std::make_unique<ParkFileExporter>();
exporter->ExportObjectsList = objects; exporter->ExportObjectsList = objects;
exporter->Export(gameState, replayData->parkData); exporter->Export(gameState, replayData->parkData, Compression::kNoCompressionLevel);
replayData->timeRecorded = std::chrono::seconds(std::time(nullptr)).count(); replayData->timeRecorded = std::chrono::seconds(std::time(nullptr)).count();
@@ -314,8 +314,7 @@ namespace OpenRCT2
MemoryStream compressed; MemoryStream compressed;
stream.SetPosition(0); stream.SetPosition(0);
bool compressStatus = Compression::zlibCompress( bool compressStatus = Compression::zlibCompress(
stream, static_cast<size_t>(stream.GetLength()), compressed, Compression::ZlibHeaderType::zlib, stream, stream.GetLength(), compressed, Compression::ZlibHeaderType::zlib, kReplayCompressionLevel);
kReplayCompressionLevel);
if (!compressStatus) if (!compressStatus)
throw IOException("Compression Error"); throw IOException("Compression Error");
@@ -567,8 +566,8 @@ namespace OpenRCT2
recFile.data.SetPosition(0); recFile.data.SetPosition(0);
decompressStatus = Compression::zlibDecompress( decompressStatus = Compression::zlibDecompress(
recFile.data, static_cast<size_t>(recFile.data.GetLength()), decompressed, recFile.data, recFile.data.GetLength(), decompressed, recFile.uncompressedSize,
static_cast<size_t>(recFile.uncompressedSize), Compression::ZlibHeaderType::zlib); Compression::ZlibHeaderType::zlib);
if (!decompressStatus) if (!decompressStatus)
throw IOException("Decompression Error"); throw IOException("Decompression Error");

View File

@@ -73,12 +73,14 @@ namespace OpenRCT2
sfl::small_vector<ChunkEntry, 32> _chunks; sfl::small_vector<ChunkEntry, 32> _chunks;
MemoryStream _buffer; MemoryStream _buffer;
ChunkEntry _currentChunk; ChunkEntry _currentChunk;
int16_t _compressionLevel;
public: public:
OrcaStream(IStream& stream, const Mode mode) OrcaStream(IStream& stream, const Mode mode, int16_t compressionLevel = Compression::kZlibDefaultCompressionLevel)
{ {
_stream = &stream; _stream = &stream;
_mode = mode; _mode = mode;
_compressionLevel = compressionLevel;
if (mode == Mode::READING) if (mode == Mode::READING)
{ {
_header = _stream->ReadValue<Header>(); _header = _stream->ReadValue<Header>();
@@ -93,15 +95,14 @@ namespace OpenRCT2
// Uncompress // Uncompress
if (_header.Compression != CompressionType::none) if (_header.Compression != CompressionType::none)
{ {
size_t compressedSize = static_cast<size_t>(_header.CompressedSize);
size_t uncompressedSize = static_cast<size_t>(_header.UncompressedSize);
bool decompressStatus = false; bool decompressStatus = false;
switch (_header.Compression) switch (_header.Compression)
{ {
case CompressionType::gzip: case CompressionType::gzip:
decompressStatus = Compression::zlibDecompress( decompressStatus = Compression::zlibDecompress(
*_stream, compressedSize, _buffer, uncompressedSize, Compression::ZlibHeaderType::gzip); *_stream, _header.CompressedSize, _buffer, _header.UncompressedSize,
Compression::ZlibHeaderType::gzip);
break; break;
default: default:
throw IOException("Unknown Park Compression Type"); throw IOException("Unknown Park Compression Type");
@@ -129,7 +130,8 @@ namespace OpenRCT2
else else
{ {
_header = {}; _header = {};
_header.Compression = CompressionType::gzip; _header.Compression = _compressionLevel == Compression::kNoCompressionLevel ? CompressionType::none
: CompressionType::gzip;
_buffer = MemoryStream{}; _buffer = MemoryStream{};
} }
} }
@@ -145,11 +147,13 @@ namespace OpenRCT2
_header.CompressedSize = _buffer.GetLength(); _header.CompressedSize = _buffer.GetLength();
_header.FNV1a = Crypt::FNV1a(_buffer.GetData(), _buffer.GetLength()); _header.FNV1a = Crypt::FNV1a(_buffer.GetData(), _buffer.GetLength());
if (_compressionLevel == Compression::kNoCompressionLevel)
_header.Compression = CompressionType::none;
// Compress data // Compress data
if (_header.Compression != CompressionType::none) if (_header.Compression != CompressionType::none)
{ {
MemoryStream compressed; MemoryStream compressed;
size_t bufferLength = static_cast<size_t>(_buffer.GetLength());
bool compressStatus = false; bool compressStatus = false;
_buffer.SetPosition(0); _buffer.SetPosition(0);
@@ -157,7 +161,7 @@ namespace OpenRCT2
{ {
case CompressionType::gzip: case CompressionType::gzip:
compressStatus = Compression::zlibCompress( compressStatus = Compression::zlibCompress(
_buffer, bufferLength, compressed, Compression::ZlibHeaderType::gzip); _buffer, _buffer.GetLength(), compressed, Compression::ZlibHeaderType::gzip, _compressionLevel);
break; break;
default: default:
break; break;
@@ -199,6 +203,16 @@ namespace OpenRCT2
return _header; return _header;
} }
int16_t GetCompressionLevel() const
{
return _compressionLevel;
}
void SetCompressionLevel(int16_t compressionLevel)
{
_compressionLevel = compressionLevel;
}
template<typename TFunc> template<typename TFunc>
bool ReadWriteChunk(const uint32_t chunkId, TFunc f) bool ReadWriteChunk(const uint32_t chunkId, TFunc f)
{ {

View File

@@ -177,9 +177,9 @@ namespace OpenRCT2
gameState.initialCash = gameState.cash; gameState.initialCash = gameState.cash;
} }
void Save(GameState_t& gameState, IStream& stream) void Save(GameState_t& gameState, IStream& stream, int16_t compressionLevel)
{ {
OrcaStream os(stream, OrcaStream::Mode::WRITING); OrcaStream os(stream, OrcaStream::Mode::WRITING, compressionLevel);
auto& header = os.GetHeader(); auto& header = os.GetHeader();
header.Magic = kParkFileMagic; header.Magic = kParkFileMagic;
@@ -206,10 +206,10 @@ namespace OpenRCT2
ReadWritePackedObjectsChunk(os); ReadWritePackedObjectsChunk(os);
} }
void Save(GameState_t& gameState, const std::string_view path) void Save(GameState_t& gameState, const std::string_view path, int16_t compressionLevel)
{ {
FileStream fs(path, FileMode::write); FileStream fs(path, FileMode::write);
Save(gameState, fs); Save(gameState, fs, compressionLevel);
} }
ScenarioIndexEntry ReadScenarioChunk() ScenarioIndexEntry ReadScenarioChunk()
@@ -2706,21 +2706,21 @@ namespace OpenRCT2
} }
}); });
} }
void ParkFileExporter::Export(GameState_t& gameState, std::string_view path, int16_t compressionLevel)
{
auto parkFile = std::make_unique<OpenRCT2::ParkFile>();
parkFile->Save(gameState, path, compressionLevel);
}
void ParkFileExporter::Export(GameState_t& gameState, IStream& stream, int16_t compressionLevel)
{
auto parkFile = std::make_unique<OpenRCT2::ParkFile>();
parkFile->ExportObjectsList = ExportObjectsList;
parkFile->Save(gameState, stream, compressionLevel);
}
} // namespace OpenRCT2 } // namespace OpenRCT2
void ParkFileExporter::Export(GameState_t& gameState, std::string_view path)
{
auto parkFile = std::make_unique<OpenRCT2::ParkFile>();
parkFile->Save(gameState, path);
}
void ParkFileExporter::Export(GameState_t& gameState, IStream& stream)
{
auto parkFile = std::make_unique<OpenRCT2::ParkFile>();
parkFile->ExportObjectsList = ExportObjectsList;
parkFile->Save(gameState, stream);
}
enum : uint32_t enum : uint32_t
{ {
S6_SAVE_FLAG_EXPORT = 1 << 0, S6_SAVE_FLAG_EXPORT = 1 << 0,
@@ -2766,7 +2766,7 @@ int32_t ScenarioSave(GameState_t& gameState, u8string_view path, int32_t flags)
{ {
// s6exporter->SaveGame(path); // s6exporter->SaveGame(path);
} }
parkFile->Save(gameState, path); parkFile->Save(gameState, path, Compression::kZlibDefaultCompressionLevel);
result = true; result = true;
} }
catch (const std::exception& e) catch (const std::exception& e)

View File

@@ -9,6 +9,8 @@
#pragma once #pragma once
#include "../core/Compression.h"
#include <cstdint> #include <cstdint>
#include <string_view> #include <string_view>
#include <vector> #include <vector>
@@ -54,13 +56,17 @@ namespace OpenRCT2
constexpr uint16_t kExtendedGoKartsVersion = 54; constexpr uint16_t kExtendedGoKartsVersion = 54;
constexpr uint16_t kHigherInversionsHolesHelicesStatsVersion = 55; constexpr uint16_t kHigherInversionsHolesHelicesStatsVersion = 55;
constexpr uint16_t kFixedObsoleteFootpathsVersion = 56; constexpr uint16_t kFixedObsoleteFootpathsVersion = 56;
class ParkFileExporter
{
public:
std::vector<const ObjectRepositoryItem*> ExportObjectsList;
void Export(
OpenRCT2::GameState_t& gameState, std::string_view path,
int16_t compressionLevel = Compression::kZlibDefaultCompressionLevel);
void Export(
OpenRCT2::GameState_t& gameState, OpenRCT2::IStream& stream,
int16_t compressionLevel = Compression::kZlibDefaultCompressionLevel);
};
} // namespace OpenRCT2 } // namespace OpenRCT2
class ParkFileExporter
{
public:
std::vector<const ObjectRepositoryItem*> ExportObjectsList;
void Export(OpenRCT2::GameState_t& gameState, std::string_view path);
void Export(OpenRCT2::GameState_t& gameState, OpenRCT2::IStream& stream);
};