mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-19 13:03:11 +01:00
Get some saving working
This commit is contained in:
@@ -201,13 +201,13 @@ static const char* getFilterPatternByType(const int32_t type, const bool isSave)
|
||||
switch (type & 0x0E)
|
||||
{
|
||||
case LOADSAVETYPE_GAME:
|
||||
return isSave ? "*.sv6" : "*.sv6;*.sc6;*.sc4;*.sv4;*.sv7;*.sea;";
|
||||
return isSave ? "*.park" : "*.sv6;*.sc6;*.sc4;*.sv4;*.sv7;*.sea;";
|
||||
|
||||
case LOADSAVETYPE_LANDSCAPE:
|
||||
return isSave ? "*.sc6" : "*.sc6;*.sv6;*.sc4;*.sv4;*.sv7;*.sea;";
|
||||
return isSave ? "*.park" : "*.sc6;*.sv6;*.sc4;*.sv4;*.sv7;*.sea;";
|
||||
|
||||
case LOADSAVETYPE_SCENARIO:
|
||||
return "*.sc6";
|
||||
return "*.park";
|
||||
|
||||
case LOADSAVETYPE_TRACK:
|
||||
return isSave ? "*.td6" : "*.td6;*.td4";
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
#include "ParkFile.h"
|
||||
|
||||
#include "OpenRCT2.h"
|
||||
#include "Version.h"
|
||||
#include "core/Crypt.h"
|
||||
#include "drawing/Drawing.h"
|
||||
#include "interface/Viewport.h"
|
||||
#include "interface/Window.h"
|
||||
#include "localisation/Date.h"
|
||||
#include "scenario/Scenario.h"
|
||||
#include "world/Map.h"
|
||||
#include "world/Park.h"
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
constexpr uint32_t PARK_FILE_MAGIC = 0x4B526550; // PARK
|
||||
constexpr uint32_t PARK_FILE_MAGIC = 0x4B524150; // PARK
|
||||
|
||||
// Current version that is saved.
|
||||
constexpr uint32_t PARK_FILE_CURRENT_VERSION = 0x0;
|
||||
@@ -46,14 +56,164 @@ void ParkFile::Save(const std::string_view& path)
|
||||
_header.TargetVersion = PARK_FILE_CURRENT_VERSION;
|
||||
_header.MinVersion = PARK_FILE_MIN_VERSION;
|
||||
_header.Compression = COMPRESSION_NONE;
|
||||
|
||||
WriteAuthoringChunk();
|
||||
WriteGeneralChunk();
|
||||
|
||||
// TODO avoid copying the buffer
|
||||
auto uncompressedData = _buffer.str();
|
||||
|
||||
_header.NumChunks = (uint32_t)_chunks.size();
|
||||
_header.UncompressedSize = _buffer.tellp();
|
||||
_header.Sha1 = Crypt::SHA1(uncompressedData.data(), uncompressedData.size());
|
||||
|
||||
std::ofstream fs(std::string(path).c_str(), std::ios::binary);
|
||||
WriteHeader(fs);
|
||||
fs.write(uncompressedData.data(), uncompressedData.size());
|
||||
}
|
||||
|
||||
void ParkFile::WriteHeader(std::ostream& stream, const Header& header, const std::vector<ChunkEntry>& chunks)
|
||||
void ParkFile::WriteHeader(std::ostream& fs)
|
||||
{
|
||||
stream.seekp(0);
|
||||
stream.write((const char*)&header, sizeof(header));
|
||||
for (const auto& chunk : chunks)
|
||||
fs.seekp(0);
|
||||
fs.write((const char*)&_header, sizeof(_header));
|
||||
for (const auto& chunk : _chunks)
|
||||
{
|
||||
stream.write((const char*)&chunk, sizeof(chunk));
|
||||
fs.write((const char*)&chunk, sizeof(chunk));
|
||||
}
|
||||
}
|
||||
|
||||
void ParkFile::BeginChunk(uint32_t id)
|
||||
{
|
||||
_currentChunk.Id = id;
|
||||
_currentChunk.Offset = _buffer.tellp();
|
||||
_currentChunk.Length = 0;
|
||||
}
|
||||
|
||||
void ParkFile::EndChunk()
|
||||
{
|
||||
_currentChunk.Length = (uint64_t)_buffer.tellp() - _currentChunk.Offset;
|
||||
_chunks.push_back(_currentChunk);
|
||||
}
|
||||
|
||||
void ParkFile::BeginArray(size_t count, size_t elementSize)
|
||||
{
|
||||
WriteValue((uint32_t)count);
|
||||
WriteValue((uint32_t)elementSize);
|
||||
}
|
||||
|
||||
void ParkFile::EndArray()
|
||||
{
|
||||
}
|
||||
|
||||
void ParkFile::WriteBuffer(const void* buffer, size_t len)
|
||||
{
|
||||
_buffer.write((char*)buffer, len);
|
||||
}
|
||||
|
||||
void ParkFile::WriteString(const std::string_view& s)
|
||||
{
|
||||
char nullt = '\0';
|
||||
_buffer.write(s.data(), s.size());
|
||||
_buffer.write(&nullt, sizeof(nullt));
|
||||
}
|
||||
|
||||
void ParkFile::WriteAuthoringChunk()
|
||||
{
|
||||
BeginChunk(ParkFileChunkType::AUTHORING);
|
||||
WriteString(gVersionInfoFull);
|
||||
WriteString("Some notes...");
|
||||
EndChunk();
|
||||
}
|
||||
|
||||
void ParkFile::WriteGeneralChunk()
|
||||
{
|
||||
BeginChunk(ParkFileChunkType::GENERAL);
|
||||
WriteValue<uint64_t>(gScenarioTicks);
|
||||
WriteValue<uint32_t>(gDateMonthTicks);
|
||||
WriteValue(gDateMonthsElapsed);
|
||||
WriteValue(gScenarioSrand0);
|
||||
WriteValue(gScenarioSrand1);
|
||||
WriteValue(gInitialCash);
|
||||
WriteValue(gGuestInitialCash);
|
||||
WriteValue(gGuestInitialHunger);
|
||||
WriteValue(gGuestInitialThirst);
|
||||
|
||||
auto numSpawns = (gPeepSpawns[0].isNull() ? 1 : 0) + (gPeepSpawns[1].isNull() ? 1 : 0);
|
||||
BeginArray(numSpawns, 13);
|
||||
for (const auto& spawn : gPeepSpawns)
|
||||
{
|
||||
if (!gPeepSpawns->isNull())
|
||||
{
|
||||
WriteValue(spawn.x);
|
||||
WriteValue(spawn.y);
|
||||
WriteValue(spawn.z);
|
||||
WriteValue(spawn.direction);
|
||||
}
|
||||
}
|
||||
EndArray();
|
||||
|
||||
WriteValue(gLandPrice);
|
||||
WriteValue(gConstructionRightsPrice);
|
||||
EndChunk();
|
||||
}
|
||||
|
||||
enum : uint32_t
|
||||
{
|
||||
S6_SAVE_FLAG_EXPORT = 1 << 0,
|
||||
S6_SAVE_FLAG_SCENARIO = 1 << 1,
|
||||
S6_SAVE_FLAG_AUTOMATIC = 1u << 31,
|
||||
};
|
||||
|
||||
int32_t scenario_save(const utf8* path, int32_t flags)
|
||||
{
|
||||
if (flags & S6_SAVE_FLAG_SCENARIO)
|
||||
{
|
||||
log_verbose("saving scenario");
|
||||
}
|
||||
else
|
||||
{
|
||||
log_verbose("saving game");
|
||||
}
|
||||
|
||||
if (!(flags & S6_SAVE_FLAG_AUTOMATIC))
|
||||
{
|
||||
window_close_construction_windows();
|
||||
}
|
||||
|
||||
map_reorganise_elements();
|
||||
viewport_set_saved_view();
|
||||
|
||||
bool result = false;
|
||||
auto parkFile = std::make_unique<ParkFile>();
|
||||
try
|
||||
{
|
||||
// if (flags & S6_SAVE_FLAG_EXPORT)
|
||||
// {
|
||||
// auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
|
||||
// s6exporter->ExportObjectsList = objManager.GetPackableObjects();
|
||||
// }
|
||||
// s6exporter->RemoveTracklessRides = true;
|
||||
// s6exporter->Export();
|
||||
if (flags & S6_SAVE_FLAG_SCENARIO)
|
||||
{
|
||||
// s6exporter->SaveScenario(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
// s6exporter->SaveGame(path);
|
||||
}
|
||||
parkFile->Save(path);
|
||||
result = true;
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
}
|
||||
|
||||
gfx_invalidate_screen();
|
||||
|
||||
if (result && !(flags & S6_SAVE_FLAG_AUTOMATIC))
|
||||
{
|
||||
gScreenAge = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
@@ -20,7 +22,7 @@ namespace OpenRCT2
|
||||
uint32_t NumChunks{};
|
||||
uint64_t UncompressedSize{};
|
||||
uint32_t Compression{};
|
||||
uint8_t Sha1{};
|
||||
std::array<uint8_t, 20> Sha1;
|
||||
};
|
||||
|
||||
struct ChunkEntry
|
||||
@@ -33,10 +35,25 @@ namespace OpenRCT2
|
||||
|
||||
Header _header;
|
||||
std::vector<ChunkEntry> _chunks;
|
||||
std::stringstream _buffer;
|
||||
ChunkEntry _currentChunk;
|
||||
|
||||
void WriteHeader(std::ostream& stream, const Header& header, const std::vector<ChunkEntry>& chunks);
|
||||
void BeginChunk(std::ostream& stream);
|
||||
uint64_t EndChunk();
|
||||
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(size_t count, size_t elementSize);
|
||||
void EndArray();
|
||||
|
||||
template<typename T>
|
||||
void WriteValue(T v)
|
||||
{
|
||||
WriteBuffer(&v, sizeof(T));
|
||||
}
|
||||
|
||||
void WriteAuthoringChunk();
|
||||
void WriteGeneralChunk();
|
||||
};
|
||||
} // namespace OpenRCT2
|
||||
|
||||
@@ -1815,7 +1815,7 @@ enum : uint32_t
|
||||
* rct2: 0x006754F5
|
||||
* @param flags bit 0: pack objects, 1: save as scenario
|
||||
*/
|
||||
int32_t scenario_save(const utf8* path, int32_t flags)
|
||||
int32_t scenario_save_old(const utf8* path, int32_t flags)
|
||||
{
|
||||
if (flags & S6_SAVE_FLAG_SCENARIO)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user