Close #6326: Add support for RCTC SV6 files with 15000 entities

This commit is contained in:
Gymnasiast 2022-08-21 23:19:14 +02:00
parent 2062084dab
commit fdf6e1fca7
No known key found for this signature in database
GPG Key ID: DBFFF47AB2CA3EDD
4 changed files with 31 additions and 11 deletions

View File

@ -1,5 +1,6 @@
0.4.2 (in development)
------------------------------------------------------------------------
- Feature: [#6326] Ability to load .SV6 files from RCT Classic that have more than 9601 guests.
- Feature: [#13634] Add ability to sell merchandise in random colours.
- Feature: [#16164] Add new track elements for Flying Coaster and Lay-Down Coaster and add paint code for more elements.
- Feature: [#16283] Added parkinfo command line tool to list objects in a save file.

View File

@ -18,6 +18,7 @@ namespace RCT2::Limits
constexpr const uint8_t MaxTrainsPerRide = 32;
constexpr const uint8_t DowntimeHistorySize = 8;
constexpr const uint16_t MaxEntities = 10000;
constexpr const uint16_t MaxEntitiesFlag15 = 15000;
constexpr const uint32_t MaxTileElements = 0x30000;
constexpr const uint16_t MaxAnimatedObjects = 2000;
constexpr const uint8_t MaxResearchedRideTypeQuads = 8; // With 32 bits per uint32_t, this means there is room for

View File

@ -834,7 +834,7 @@ namespace RCT2
// SC6[6]
uint32_t next_free_tile_element_pointer_index;
Entity sprites[Limits::MaxEntities];
Entity sprites[Limits::MaxEntitiesFlag15];
uint16_t sprite_lists_head[static_cast<uint8_t>(EntityListId::Count)];
uint16_t sprite_lists_count[static_cast<uint8_t>(EntityListId::Count)];
StringId park_name;
@ -1019,7 +1019,7 @@ namespace RCT2
uint16_t wide_path_tile_loop_y;
uint8_t pad_13CE778[434];
};
assert_struct_size(S6Data, 0x46b44a);
assert_struct_size(S6Data, 0x5a3c4a);
struct StexEntry
{

View File

@ -18,6 +18,7 @@
#include "../core/Console.hpp"
#include "../core/FileStream.h"
#include "../core/IStream.hpp"
#include "../core/MemoryStream.h"
#include "../core/Numerics.hpp"
#include "../core/Path.hpp"
#include "../core/Random.hpp"
@ -166,11 +167,6 @@ namespace RCT2
}
}
if (_s6.header.classic_flag == 0xf)
{
throw UnsupportedRCTCFlagException(_s6.header.classic_flag);
}
// Read packed objects
// TODO try to contain this more and not store objects until later
for (uint16_t i = 0; i < _s6.header.num_packed_objects; i++)
@ -190,7 +186,7 @@ namespace RCT2
{
chunkReader.ReadChunk(&_s6.elapsed_months, 16);
chunkReader.ReadChunk(&_s6.tile_elements, sizeof(_s6.tile_elements));
chunkReader.ReadChunk(&_s6.next_free_tile_element_pointer_index, 2560076);
ReadChunk6(chunkReader, 76);
chunkReader.ReadChunk(&_s6.guests_in_park, 4);
chunkReader.ReadChunk(&_s6.last_guests_in_park, 8);
chunkReader.ReadChunk(&_s6.park_rating, 2);
@ -203,7 +199,7 @@ namespace RCT2
{
chunkReader.ReadChunk(&_s6.elapsed_months, 16);
chunkReader.ReadChunk(&_s6.tile_elements, sizeof(_s6.tile_elements));
chunkReader.ReadChunk(&_s6.next_free_tile_element_pointer_index, 3048816);
ReadChunk6(chunkReader, 488816);
}
_isScenario = isScenario;
@ -212,6 +208,22 @@ namespace RCT2
return ParkLoadResult(GetRequiredObjects());
}
void ReadChunk6(SawyerChunkReader& chunkReader, uint32_t sizeWithoutEntities)
{
uint32_t entitiesSize = GetMaxEntities() * sizeof(Entity);
auto bufferSize = sizeWithoutEntities + entitiesSize;
uint8_t buffer[bufferSize];
chunkReader.ReadChunk(&buffer, bufferSize);
auto stream = OpenRCT2::MemoryStream(&buffer, bufferSize);
uint32_t preEntitiesSize = sizeof(_s6.next_free_tile_element_pointer_index);
uint32_t postEntitiesSize = sizeWithoutEntities - preEntitiesSize;
stream.Read(&_s6.next_free_tile_element_pointer_index, preEntitiesSize);
stream.Read(&_s6.sprites, entitiesSize);
stream.Read(&_s6.sprite_lists_head, postEntitiesSize);
}
bool GetDetails(scenario_index_entry* dst) override
{
*dst = {};
@ -1168,8 +1180,9 @@ namespace RCT2
{
// The number of riders might have overflown or underflown. Re-calculate the value.
uint16_t numRiders = 0;
for (const auto& sprite : _s6.sprites)
for (int32_t i = 0; i < GetMaxEntities(); i++)
{
const auto& sprite = _s6.sprites[i];
if (sprite.unknown.sprite_identifier == RCT12SpriteIdentifier::Peep)
{
if (sprite.peep.current_ride == static_cast<RCT12RideId>(rideIndex.ToUnderlying())
@ -1592,12 +1605,17 @@ namespace RCT2
void ImportEntities()
{
for (int32_t i = 0; i < Limits::MaxEntities; i++)
for (int32_t i = 0; i < GetMaxEntities(); i++)
{
ImportEntity(_s6.sprites[i].unknown);
}
}
uint16_t GetMaxEntities()
{
return (_s6.header.classic_flag == 0xf) ? Limits::MaxEntitiesFlag15 : Limits::MaxEntities;
}
template<typename OpenRCT2_T> void ImportEntity(const RCT12SpriteBase& src);
void ImportEntityPeep(::Peep* dst, const Peep* src)