Fix nested arrays and ride measurement

This commit is contained in:
Ted John 2019-07-15 22:04:59 +01:00
parent ccb2eed939
commit 48f5515a55
2 changed files with 49 additions and 47 deletions

View File

@ -548,6 +548,16 @@ namespace OpenRCT2
// Stats // Stats
if (cs.GetMode() == OrcaStream::Mode::READING) if (cs.GetMode() == OrcaStream::Mode::READING)
{
auto hasMeasurement = cs.Read<uint8_t>();
if (hasMeasurement != 0)
{
ride.measurement = std::make_unique<RideMeasurement>();
ride.measurement->ride = &ride;
ReadWriteRideMeasurement(cs, *ride.measurement);
}
}
else
{ {
if (ride.measurement == nullptr) if (ride.measurement == nullptr)
{ {
@ -559,18 +569,6 @@ namespace OpenRCT2
ReadWriteRideMeasurement(cs, *ride.measurement); ReadWriteRideMeasurement(cs, *ride.measurement);
} }
} }
else
{
auto hasMeasurement = cs.Read<uint8_t>();
if (hasMeasurement)
{
ride.measurement = std::make_unique<RideMeasurement>();
ride.measurement->ride = &ride;
ReadWriteRideMeasurement(cs, *ride.measurement);
}
}
cs.ReadWrite(ride.measurement);
cs.ReadWrite(ride.special_track_elements); cs.ReadWrite(ride.special_track_elements);
cs.ReadWrite(ride.max_speed); cs.ReadWrite(ride.max_speed);
@ -673,12 +671,6 @@ namespace OpenRCT2
static void ReadWriteRideMeasurement(OrcaStream::ChunkStream& cs, RideMeasurement& measurement) static void ReadWriteRideMeasurement(OrcaStream::ChunkStream& cs, RideMeasurement& measurement)
{ {
if (cs.GetMode() == OrcaStream::Mode::READING)
{
// Initialise measurement (mainly just for the fixed arrays)
measurement = {};
}
cs.ReadWrite(measurement.flags); cs.ReadWrite(measurement.flags);
cs.ReadWrite(measurement.last_use_tick); cs.ReadWrite(measurement.last_use_tick);
cs.ReadWrite(measurement.num_items); cs.ReadWrite(measurement.num_items);

View File

@ -15,6 +15,7 @@
#include <cstdint> #include <cstdint>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <stack>
#include <vector> #include <vector>
namespace OpenRCT2 namespace OpenRCT2
@ -189,12 +190,17 @@ namespace OpenRCT2
class ChunkStream class ChunkStream
{ {
private: private:
struct ArrayState
{
std::streampos StartPos{};
std::streampos LastPos{};
size_t Count{};
size_t ElementSize{};
};
std::stringstream& _buffer; std::stringstream& _buffer;
Mode _mode; Mode _mode;
std::streampos _currentArrayStartPos; std::stack<ArrayState> _arrayStack;
std::streampos _currentArrayLastPos;
size_t _currentArrayCount;
size_t _currentArrayElementSize;
public: public:
ChunkStream(std::stringstream& buffer, Mode mode) ChunkStream(std::stringstream& buffer, Mode mode)
@ -388,78 +394,82 @@ namespace OpenRCT2
size_t BeginArray() size_t BeginArray()
{ {
auto& arrayState = _arrayStack.emplace();
if (_mode == Mode::READING) if (_mode == Mode::READING)
{ {
_currentArrayCount = Read<uint32_t>(); arrayState.Count = Read<uint32_t>();
_currentArrayElementSize = Read<uint32_t>(); arrayState.ElementSize = Read<uint32_t>();
_currentArrayLastPos = _buffer.tellg(); arrayState.LastPos = _buffer.tellg();
return _currentArrayCount; return arrayState.Count;
} }
else else
{ {
_currentArrayCount = 0; arrayState.Count = 0;
_currentArrayElementSize = 0; arrayState.ElementSize = 0;
_currentArrayStartPos = _buffer.tellp(); arrayState.StartPos = _buffer.tellp();
Write<uint32_t>(0); Write<uint32_t>(0);
Write<uint32_t>(0); Write<uint32_t>(0);
_currentArrayLastPos = _buffer.tellp(); arrayState.LastPos = _buffer.tellp();
return 0; return 0;
} }
} }
bool NextArrayElement() bool NextArrayElement()
{ {
auto& arrayState = _arrayStack.top();
if (_mode == Mode::READING) if (_mode == Mode::READING)
{ {
if (_currentArrayCount == 0) if (arrayState.Count == 0)
{ {
return false; return false;
} }
if (_currentArrayElementSize != 0) if (arrayState.ElementSize != 0)
{ {
_currentArrayLastPos += _currentArrayElementSize; arrayState.LastPos += arrayState.ElementSize;
_buffer.seekg(_currentArrayLastPos); _buffer.seekg(arrayState.LastPos);
} }
_currentArrayCount--; arrayState.Count--;
return _currentArrayCount == 0; return arrayState.Count == 0;
} }
else else
{ {
auto lastElSize = (size_t)_buffer.tellp() - _currentArrayLastPos; auto lastElSize = (size_t)_buffer.tellp() - arrayState.LastPos;
if (_currentArrayCount == 0) if (arrayState.Count == 0)
{ {
// Set array element size based on first element size // Set array element size based on first element size
_currentArrayElementSize = lastElSize; arrayState.ElementSize = lastElSize;
} }
else if (_currentArrayElementSize != lastElSize) else if (arrayState.ElementSize != lastElSize)
{ {
// Array element size was different from first element so reset it // Array element size was different from first element so reset it
// to dynamic // to dynamic
_currentArrayElementSize = 0; arrayState.ElementSize = 0;
} }
_currentArrayCount++; arrayState.Count++;
_currentArrayLastPos = _buffer.tellp(); arrayState.LastPos = _buffer.tellp();
return true; return true;
} }
} }
void EndArray() void EndArray()
{ {
auto& arrayState = _arrayStack.top();
if (_mode == Mode::READING) if (_mode == Mode::READING)
{ {
} }
else else
{ {
auto backupPos = _buffer.tellp(); auto backupPos = _buffer.tellp();
if ((size_t)backupPos != (size_t)_currentArrayStartPos + 8 && _currentArrayCount == 0) if ((size_t)backupPos != (size_t)arrayState.StartPos + 8 && arrayState.Count == 0)
{ {
throw std::runtime_error("Array data was written but no elements were added."); throw std::runtime_error("Array data was written but no elements were added.");
} }
_buffer.seekp(_currentArrayStartPos); _buffer.seekp(arrayState.StartPos);
Write((uint32_t)_currentArrayCount); Write((uint32_t)arrayState.Count);
Write((uint32_t)_currentArrayElementSize); Write((uint32_t)arrayState.ElementSize);
_buffer.seekp(backupPos); _buffer.seekp(backupPos);
} }
_arrayStack.pop();
} }
}; };
}; };