Refactor ParkFile to just a source file

This commit is contained in:
Ted John 2018-12-15 14:49:53 +00:00
parent 3aaef84392
commit 0b519c68f2
2 changed files with 450 additions and 483 deletions

View File

@ -1,5 +1,3 @@
#include "ParkFile.h"
#include "Context.h" #include "Context.h"
#include "GameState.h" #include "GameState.h"
#include "OpenRCT2.h" #include "OpenRCT2.h"
@ -10,6 +8,7 @@
#include "interface/Viewport.h" #include "interface/Viewport.h"
#include "interface/Window.h" #include "interface/Window.h"
#include "localisation/Date.h" #include "localisation/Date.h"
#include "object/Object.h"
#include "object/ObjectManager.h" #include "object/ObjectManager.h"
#include "object/ObjectRepository.h" #include "object/ObjectRepository.h"
#include "scenario/Scenario.h" #include "scenario/Scenario.h"
@ -17,21 +16,28 @@
#include "world/Map.h" #include "world/Map.h"
#include "world/Park.h" #include "world/Park.h"
using namespace OpenRCT2; #include <array>
#include <cstdint>
#include <fstream>
#include <sstream>
#include <string_view>
#include <vector>
constexpr uint32_t PARK_FILE_MAGIC = 0x4B524150; // PARK namespace OpenRCT2
// Current version that is saved.
constexpr uint32_t PARK_FILE_CURRENT_VERSION = 0x0;
// The minimum version that is forwards compatible with the current version.
constexpr uint32_t PARK_FILE_MIN_VERSION = 0x0;
constexpr uint32_t COMPRESSION_NONE = 0;
constexpr uint32_t COMPRESSION_GZIP = 1;
namespace ParkFileChunkType
{ {
constexpr uint32_t PARK_FILE_MAGIC = 0x4B524150; // PARK
// Current version that is saved.
constexpr uint32_t PARK_FILE_CURRENT_VERSION = 0x0;
// The minimum version that is forwards compatible with the current version.
constexpr uint32_t PARK_FILE_MIN_VERSION = 0x0;
constexpr uint32_t COMPRESSION_NONE = 0;
constexpr uint32_t COMPRESSION_GZIP = 1;
namespace ParkFileChunkType
{
// clang-format off // clang-format off
constexpr uint32_t RESERVED_0 = 0x00; constexpr uint32_t RESERVED_0 = 0x00;
constexpr uint32_t AUTHORING = 0x01; constexpr uint32_t AUTHORING = 0x01;
@ -53,10 +59,59 @@ namespace ParkFileChunkType
constexpr uint32_t EDITOR = 0x11; constexpr uint32_t EDITOR = 0x11;
constexpr uint32_t DERIVED = 0x12; constexpr uint32_t DERIVED = 0x12;
// clang-format on // clang-format on
}; // namespace ParkFileChunkType }; // namespace ParkFileChunkType
void ParkFile::Save(const std::string_view& path) class ParkFile
{ {
public:
std::vector<rct_object_entry> RequiredObjects;
private:
#pragma pack(push, 1)
struct Header
{
uint32_t Magic{};
uint32_t TargetVersion{};
uint32_t MinVersion{};
uint32_t NumChunks{};
uint64_t UncompressedSize{};
uint32_t Compression{};
std::array<uint8_t, 20> Sha1{};
};
struct ChunkEntry
{
uint32_t Id{};
uint64_t Offset{};
uint64_t Length{};
};
#pragma pack(pop)
Header _header;
std::vector<ChunkEntry> _chunks;
std::stringstream _buffer;
ChunkEntry _currentChunk;
std::streampos _currentArrayStartPos;
std::streampos _currentArrayLastPos;
size_t _currentArrayCount;
size_t _currentArrayElementSize;
private:
template<typename T> void WriteValue(T v)
{
WriteBuffer(&v, sizeof(T));
}
template<typename T> T ReadValue()
{
T v{};
ReadBuffer(&v, sizeof(v));
return v;
}
public:
void Save(const std::string_view& path)
{
_header = {}; _header = {};
_header.Magic = PARK_FILE_MAGIC; _header.Magic = PARK_FILE_MAGIC;
_header.TargetVersion = PARK_FILE_CURRENT_VERSION; _header.TargetVersion = PARK_FILE_CURRENT_VERSION;
@ -81,43 +136,44 @@ void ParkFile::Save(const std::string_view& path)
std::ofstream fs(std::string(path).c_str(), std::ios::binary); std::ofstream fs(std::string(path).c_str(), std::ios::binary);
WriteHeader(fs); WriteHeader(fs);
fs.write(uncompressedData.data(), uncompressedData.size()); fs.write(uncompressedData.data(), uncompressedData.size());
} }
void ParkFile::WriteHeader(std::ostream& fs) private:
{ void WriteHeader(std::ostream& fs)
{
fs.seekp(0); fs.seekp(0);
fs.write((const char*)&_header, sizeof(_header)); fs.write((const char*)&_header, sizeof(_header));
for (const auto& chunk : _chunks) for (const auto& chunk : _chunks)
{ {
fs.write((const char*)&chunk, sizeof(chunk)); fs.write((const char*)&chunk, sizeof(chunk));
} }
} }
void ParkFile::BeginChunk(uint32_t id) void BeginChunk(uint32_t id)
{ {
_currentChunk.Id = id; _currentChunk.Id = id;
_currentChunk.Offset = _buffer.tellp(); _currentChunk.Offset = _buffer.tellp();
_currentChunk.Length = 0; _currentChunk.Length = 0;
} }
void ParkFile::EndChunk() void EndChunk()
{ {
_currentChunk.Length = (uint64_t)_buffer.tellp() - _currentChunk.Offset; _currentChunk.Length = (uint64_t)_buffer.tellp() - _currentChunk.Offset;
_chunks.push_back(_currentChunk); _chunks.push_back(_currentChunk);
} }
void ParkFile::BeginArray() void BeginArray()
{ {
_currentArrayCount = 0; _currentArrayCount = 0;
_currentArrayElementSize = 0; _currentArrayElementSize = 0;
_currentArrayStartPos = _buffer.tellp(); _currentArrayStartPos = _buffer.tellp();
WriteValue<uint32_t>(0); WriteValue<uint32_t>(0);
WriteValue<uint32_t>(0); WriteValue<uint32_t>(0);
_currentArrayLastPos = _buffer.tellp(); _currentArrayLastPos = _buffer.tellp();
} }
void ParkFile::NextArrayElement() void NextArrayElement()
{ {
auto lastElSize = (size_t)_buffer.tellp() - _currentArrayLastPos; auto lastElSize = (size_t)_buffer.tellp() - _currentArrayLastPos;
if (_currentArrayCount == 0) if (_currentArrayCount == 0)
{ {
@ -132,10 +188,10 @@ void ParkFile::NextArrayElement()
} }
_currentArrayCount++; _currentArrayCount++;
_currentArrayLastPos = _buffer.tellp(); _currentArrayLastPos = _buffer.tellp();
} }
void ParkFile::EndArray() void EndArray()
{ {
auto backupPos = _buffer.tellp(); auto backupPos = _buffer.tellp();
if ((size_t)backupPos != (size_t)_currentArrayStartPos + 8 && _currentArrayCount == 0) if ((size_t)backupPos != (size_t)_currentArrayStartPos + 8 && _currentArrayCount == 0)
{ {
@ -145,15 +201,15 @@ void ParkFile::EndArray()
WriteValue((uint32_t)_currentArrayCount); WriteValue((uint32_t)_currentArrayCount);
WriteValue((uint32_t)_currentArrayElementSize); WriteValue((uint32_t)_currentArrayElementSize);
_buffer.seekp(backupPos); _buffer.seekp(backupPos);
} }
void ParkFile::WriteBuffer(const void* buffer, size_t len) void WriteBuffer(const void* buffer, size_t len)
{ {
_buffer.write((char*)buffer, len); _buffer.write((char*)buffer, len);
} }
void ParkFile::WriteString(const std::string_view& s) void WriteString(const std::string_view& s)
{ {
char nullt = '\0'; char nullt = '\0';
auto len = s.find('\0'); auto len = s.find('\0');
if (len == std::string_view::npos) if (len == std::string_view::npos)
@ -162,18 +218,18 @@ void ParkFile::WriteString(const std::string_view& s)
} }
_buffer.write(s.data(), len); _buffer.write(s.data(), len);
_buffer.write(&nullt, sizeof(nullt)); _buffer.write(&nullt, sizeof(nullt));
} }
void ParkFile::WriteAuthoringChunk() void WriteAuthoringChunk()
{ {
BeginChunk(ParkFileChunkType::AUTHORING); BeginChunk(ParkFileChunkType::AUTHORING);
WriteString(gVersionInfoFull); WriteString(gVersionInfoFull);
WriteString("Some notes..."); WriteString("Some notes...");
EndChunk(); EndChunk();
} }
void ParkFile::WriteObjectsChunk() void WriteObjectsChunk()
{ {
BeginChunk(ParkFileChunkType::OBJECTS); BeginChunk(ParkFileChunkType::OBJECTS);
BeginArray(); BeginArray();
// TODO do not hard code object count // TODO do not hard code object count
@ -200,10 +256,10 @@ void ParkFile::WriteObjectsChunk()
} }
EndArray(); EndArray();
EndChunk(); EndChunk();
} }
void ParkFile::WriteGeneralChunk() void WriteGeneralChunk()
{ {
BeginChunk(ParkFileChunkType::GENERAL); BeginChunk(ParkFileChunkType::GENERAL);
WriteValue<uint64_t>(gScenarioTicks); WriteValue<uint64_t>(gScenarioTicks);
WriteValue<uint32_t>(gDateMonthTicks); WriteValue<uint32_t>(gDateMonthTicks);
@ -232,10 +288,10 @@ void ParkFile::WriteGeneralChunk()
WriteValue(gLandPrice); WriteValue(gLandPrice);
WriteValue(gConstructionRightsPrice); WriteValue(gConstructionRightsPrice);
EndChunk(); EndChunk();
} }
void ParkFile::WriteInterfaceChunk() void WriteInterfaceChunk()
{ {
BeginChunk(ParkFileChunkType::INTERFACE); BeginChunk(ParkFileChunkType::INTERFACE);
WriteValue(gSavedViewX); WriteValue(gSavedViewX);
WriteValue(gSavedViewY); WriteValue(gSavedViewY);
@ -243,10 +299,10 @@ void ParkFile::WriteInterfaceChunk()
WriteValue(gSavedViewRotation); WriteValue(gSavedViewRotation);
WriteValue<uint32_t>(gLastEntranceStyle); WriteValue<uint32_t>(gLastEntranceStyle);
EndChunk(); EndChunk();
} }
void ParkFile::WriteTilesChunk() void WriteTilesChunk()
{ {
BeginChunk(ParkFileChunkType::TILES); BeginChunk(ParkFileChunkType::TILES);
WriteValue<uint32_t>(gMapSize); WriteValue<uint32_t>(gMapSize);
WriteValue<uint32_t>(gMapSize); WriteValue<uint32_t>(gMapSize);
@ -259,10 +315,11 @@ void ParkFile::WriteTilesChunk()
} }
EndArray(); EndArray();
EndChunk(); EndChunk();
} }
void ParkFile::Load(const std::string_view& path) public:
{ void Load(const std::string_view& path)
{
std::ifstream fs(std::string(path).c_str(), std::ios::binary); std::ifstream fs(std::string(path).c_str(), std::ios::binary);
_header = ReadHeader(fs); _header = ReadHeader(fs);
@ -305,24 +362,25 @@ void ParkFile::Load(const std::string_view& path)
ReadNextArrayElement(); ReadNextArrayElement();
} }
} }
} }
void ParkFile::Import() void Import()
{ {
ReadTilesChunk(); ReadTilesChunk();
ReadGeneralChunk(); ReadGeneralChunk();
ReadInterfaceChunk(); ReadInterfaceChunk();
} }
ParkFile::Header ParkFile::ReadHeader(std::istream& fs) private:
{ Header ReadHeader(std::istream& fs)
{
Header header; Header header;
fs.read((char*)&header, sizeof(header)); fs.read((char*)&header, sizeof(header));
return header; return header;
} }
bool ParkFile::SeekChunk(uint32_t id) bool SeekChunk(uint32_t id)
{ {
auto result = std::find_if(_chunks.begin(), _chunks.end(), [id](const ChunkEntry& e) { return e.Id == id; }); auto result = std::find_if(_chunks.begin(), _chunks.end(), [id](const ChunkEntry& e) { return e.Id == id; });
if (result != _chunks.end()) if (result != _chunks.end())
{ {
@ -331,18 +389,18 @@ bool ParkFile::SeekChunk(uint32_t id)
return true; return true;
} }
return false; return false;
} }
size_t ParkFile::ReadArray() size_t ReadArray()
{ {
_currentArrayCount = ReadValue<uint32_t>(); _currentArrayCount = ReadValue<uint32_t>();
_currentArrayElementSize = ReadValue<uint32_t>(); _currentArrayElementSize = ReadValue<uint32_t>();
_currentArrayLastPos = _buffer.tellg(); _currentArrayLastPos = _buffer.tellg();
return _currentArrayCount; return _currentArrayCount;
} }
bool ParkFile::ReadNextArrayElement() bool ReadNextArrayElement()
{ {
if (_currentArrayCount == 0) if (_currentArrayCount == 0)
{ {
return false; return false;
@ -353,15 +411,15 @@ bool ParkFile::ReadNextArrayElement()
} }
_currentArrayCount--; _currentArrayCount--;
return _currentArrayCount == 0; return _currentArrayCount == 0;
} }
void ParkFile::ReadBuffer(void* dst, size_t len) void ReadBuffer(void* dst, size_t len)
{ {
_buffer.read((char*)dst, len); _buffer.read((char*)dst, len);
} }
std::string ParkFile::ReadString() std::string ReadString()
{ {
std::string buffer; std::string buffer;
buffer.reserve(64); buffer.reserve(64);
char c; char c;
@ -371,10 +429,10 @@ std::string ParkFile::ReadString()
} }
buffer.shrink_to_fit(); buffer.shrink_to_fit();
return buffer; return buffer;
} }
void ParkFile::ReadGeneralChunk() void ReadGeneralChunk()
{ {
if (SeekChunk(ParkFileChunkType::GENERAL)) if (SeekChunk(ParkFileChunkType::GENERAL))
{ {
gScenarioTicks = ReadValue<uint64_t>(); gScenarioTicks = ReadValue<uint64_t>();
@ -404,10 +462,10 @@ void ParkFile::ReadGeneralChunk()
{ {
throw std::runtime_error("No general chunk found."); throw std::runtime_error("No general chunk found.");
} }
} }
void ParkFile::ReadInterfaceChunk() void ReadInterfaceChunk()
{ {
if (SeekChunk(ParkFileChunkType::INTERFACE)) if (SeekChunk(ParkFileChunkType::INTERFACE))
{ {
gSavedViewX = ReadValue<uint16_t>(); gSavedViewX = ReadValue<uint16_t>();
@ -416,10 +474,10 @@ void ParkFile::ReadInterfaceChunk()
gSavedViewRotation = ReadValue<uint8_t>(); gSavedViewRotation = ReadValue<uint8_t>();
gLastEntranceStyle = ReadValue<uint32_t>(); gLastEntranceStyle = ReadValue<uint32_t>();
} }
} }
void ParkFile::ReadTilesChunk() void ReadTilesChunk()
{ {
if (SeekChunk(ParkFileChunkType::TILES)) if (SeekChunk(ParkFileChunkType::TILES))
{ {
auto mapWidth = ReadValue<uint32_t>(); auto mapWidth = ReadValue<uint32_t>();
@ -437,7 +495,9 @@ void ParkFile::ReadTilesChunk()
{ {
throw std::runtime_error("No tiles chunk found."); throw std::runtime_error("No tiles chunk found.");
} }
} }
};
} // namespace OpenRCT2
enum : uint32_t enum : uint32_t
{ {
@ -466,7 +526,7 @@ int32_t scenario_save(const utf8* path, int32_t flags)
viewport_set_saved_view(); viewport_set_saved_view();
bool result = false; bool result = false;
auto parkFile = std::make_unique<ParkFile>(); auto parkFile = std::make_unique<OpenRCT2::ParkFile>();
try try
{ {
// if (flags & S6_SAVE_FLAG_EXPORT) // if (flags & S6_SAVE_FLAG_EXPORT)
@ -504,7 +564,7 @@ class ParkFileImporter : public IParkImporter
{ {
private: private:
const IObjectRepository& _objectRepository; const IObjectRepository& _objectRepository;
std::unique_ptr<ParkFile> _parkFile; std::unique_ptr<OpenRCT2::ParkFile> _parkFile;
public: public:
ParkFileImporter(IObjectRepository& objectRepository) ParkFileImporter(IObjectRepository& objectRepository)
@ -514,7 +574,7 @@ public:
ParkLoadResult Load(const utf8* path) override ParkLoadResult Load(const utf8* path) override
{ {
_parkFile = std::make_unique<ParkFile>(); _parkFile = std::make_unique<OpenRCT2::ParkFile>();
_parkFile->Load(path); _parkFile->Load(path);
return ParkLoadResult(std::move(_parkFile->RequiredObjects)); return ParkLoadResult(std::move(_parkFile->RequiredObjects));
} }

View File

@ -1,93 +0,0 @@
#pragma once
#include <array>
#include <cstdint>
#include <fstream>
#include <sstream>
#include <string_view>
#include <vector>
#include "object/Object.h"
namespace OpenRCT2
{
class ParkFile
{
public:
std::vector<rct_object_entry> RequiredObjects;
void Load(const std::string_view& path);
void Save(const std::string_view& path);
void Import();
private:
#pragma pack(push, 1)
struct Header
{
uint32_t Magic{};
uint32_t TargetVersion{};
uint32_t MinVersion{};
uint32_t NumChunks{};
uint64_t UncompressedSize{};
uint32_t Compression{};
std::array<uint8_t, 20> Sha1{};
};
struct ChunkEntry
{
uint32_t Id{};
uint64_t Offset{};
uint64_t Length{};
};
#pragma pack(pop)
Header _header;
std::vector<ChunkEntry> _chunks;
std::stringstream _buffer;
ChunkEntry _currentChunk;
std::streampos _currentArrayStartPos;
std::streampos _currentArrayLastPos;
size_t _currentArrayCount;
size_t _currentArrayElementSize;
void WriteHeader(std::ostream& fs);
void BeginChunk(uint32_t id);
void EndChunk();
void WriteBuffer(const void* buffer, size_t len);
void WriteString(const std::string_view& s);
void BeginArray();
void NextArrayElement();
void EndArray();
template<typename T>
void WriteValue(T v)
{
WriteBuffer(&v, sizeof(T));
}
void WriteAuthoringChunk();
void WriteObjectsChunk();
void WriteGeneralChunk();
void WriteInterfaceChunk();
void WriteTilesChunk();
void ReadGeneralChunk();
void ReadInterfaceChunk();
void ReadTilesChunk();
Header ReadHeader(std::istream& fs);
bool SeekChunk(uint32_t id);
size_t ReadArray();
bool ReadNextArrayElement();
void ReadBuffer(void* dst, size_t len);
std::string ReadString();
template<typename T>
T ReadValue()
{
T v{};
ReadBuffer(&v, sizeof(v));
return v;
}
};
} // namespace OpenRCT2