diff --git a/src/openrct2/object/ObjectList.cpp b/src/openrct2/object/ObjectList.cpp index 76f1a92a74..ab94ef62f4 100644 --- a/src/openrct2/object/ObjectList.cpp +++ b/src/openrct2/object/ObjectList.cpp @@ -137,28 +137,6 @@ void get_type_entry_index(size_t index, ObjectType* outObjectType, ObjectEntryIn *outEntryIndex = static_cast(index); } -const rct_object_entry* get_loaded_object_entry(size_t index) -{ - ObjectType objectType; - ObjectEntryIndex entryIndex; - get_type_entry_index(index, &objectType, &entryIndex); - auto obj = object_entry_get_object(objectType, entryIndex); - if (obj == nullptr) - { - return nullptr; - } - - return obj->GetObjectEntry(); -} - -void* get_loaded_object_chunk(size_t index) -{ - ObjectType objectType; - ObjectEntryIndex entryIndex; - get_type_entry_index(index, &objectType, &entryIndex); - return object_entry_get_chunk(objectType, entryIndex); -} - void object_entry_get_name_fixed(utf8* buffer, size_t bufferSize, const rct_object_entry* entry) { bufferSize = std::min(static_cast(DAT_NAME_LENGTH) + 1, bufferSize); @@ -168,20 +146,13 @@ void object_entry_get_name_fixed(utf8* buffer, size_t bufferSize, const rct_obje void* object_entry_get_chunk(ObjectType objectType, ObjectEntryIndex index) { - ObjectEntryIndex objectIndex = index; - for (int32_t i = 0; i < EnumValue(objectType); i++) - { - objectIndex += object_entry_group_counts[i]; - } - - void* result = nullptr; auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager(); - auto obj = objectMgr.GetLoadedObject(objectIndex); - if (obj != nullptr) + auto* object = objectMgr.GetLoadedObject(objectType, index); + if (object != nullptr) { - result = obj->GetLegacyData(); + return object->GetLegacyData(); } - return result; + return nullptr; } const Object* object_entry_get_object(ObjectType objectType, ObjectEntryIndex index) diff --git a/src/openrct2/object/ObjectList.h b/src/openrct2/object/ObjectList.h index 62cbe2cdca..b1048fd82c 100644 --- a/src/openrct2/object/ObjectList.h +++ b/src/openrct2/object/ObjectList.h @@ -18,5 +18,3 @@ #include "ObjectLimits.h" void get_type_entry_index(size_t index, ObjectType* outObjectType, ObjectEntryIndex* outEntryIndex); -const rct_object_entry* get_loaded_object_entry(size_t index); -void* get_loaded_object_chunk(size_t index); diff --git a/src/openrct2/rct2/RCT2.h b/src/openrct2/rct2/RCT2.h index 84218c1cf5..22575fe640 100644 --- a/src/openrct2/rct2/RCT2.h +++ b/src/openrct2/rct2/RCT2.h @@ -836,7 +836,24 @@ struct rct_s6_data // packed objects // SC6[3] - rct_object_entry objects[RCT2_OBJECT_ENTRY_COUNT]; + union + { + rct_object_entry Objects[RCT2_OBJECT_ENTRY_COUNT]; + struct + { + rct_object_entry RideObjects[RCT12_MAX_RIDE_OBJECTS]; + rct_object_entry SceneryObjects[RCT2_MAX_SMALL_SCENERY_OBJECTS]; + rct_object_entry LargeSceneryObjects[RCT2_MAX_LARGE_SCENERY_OBJECTS]; + rct_object_entry WallSceneryObjects[RCT2_MAX_WALL_SCENERY_OBJECTS]; + rct_object_entry BannerObjects[RCT2_MAX_BANNER_OBJECTS]; + rct_object_entry PathObjects[RCT2_MAX_PATH_OBJECTS]; + rct_object_entry PathAdditionObjects[RCT2_MAX_PATH_ADDITION_OBJECTS]; + rct_object_entry SceneryGroupObjects[RCT2_MAX_SCENERY_GROUP_OBJECTS]; + rct_object_entry ParkEntranceObjects[RCT2_MAX_PARK_ENTRANCE_OBJECTS]; + rct_object_entry WaterObjects[RCT2_MAX_WATER_OBJECTS]; + rct_object_entry ScenarioTextObjects[RCT2_MAX_SCENARIO_TEXT_OBJECTS]; + }; + }; // SC6[4] uint16_t elapsed_months; diff --git a/src/openrct2/rct2/S6Exporter.cpp b/src/openrct2/rct2/S6Exporter.cpp index d646534def..2b155cc33f 100644 --- a/src/openrct2/rct2/S6Exporter.cpp +++ b/src/openrct2/rct2/S6Exporter.cpp @@ -120,7 +120,7 @@ void S6Exporter::Save(OpenRCT2::IStream* stream, bool isScenario) } // 3: Write available objects chunk - chunkWriter.WriteChunk(_s6.objects, sizeof(_s6.objects), SAWYER_ENCODING::ROTATE); + chunkWriter.WriteChunk(_s6.Objects, sizeof(_s6.Objects), SAWYER_ENCODING::ROTATE); // 4: Misc fields (data, rand...) chunk chunkWriter.WriteChunk(&_s6.elapsed_months, 16, SAWYER_ENCODING::RLECOMPRESSED); @@ -255,6 +255,26 @@ static void scenario_fix_ghosts(rct_s6_data* s6) } } +template +static void ExportObjectList(IObjectManager& objMgr, T& objects) +{ + for (size_t i = 0; i < TMaxEntries; i++) + { + auto& dst = objects[i]; + + const auto* object = objMgr.GetLoadedObject(TObjectType, i); + if (object == nullptr || object->GetObjectEntry() == nullptr) + { + // The sv6 format expects null/invalid entries to be filled with 0xFF. + std::memset(&dst, 0xFF, sizeof(dst)); + } + else + { + dst = *object->GetObjectEntry(); + } + } +} + void S6Exporter::Export() { _s6.info = {}; @@ -278,20 +298,18 @@ void S6Exporter::Export() uint32_t researchedTrackPiecesA[128] = {}; uint32_t researchedTrackPiecesB[128] = {}; - for (int32_t i = 0; i < RCT2_OBJECT_ENTRY_COUNT; i++) - { - const rct_object_entry* entry = get_loaded_object_entry(i); - void* entryData = get_loaded_object_chunk(i); - // RCT2 uses (void *)-1 to mark NULL. Make sure it's written in a vanilla-compatible way. - if (entry == nullptr || entryData == nullptr || entryData == reinterpret_cast(-1)) - { - std::memset(&_s6.objects[i], 0xFF, sizeof(rct_object_entry)); - } - else - { - _s6.objects[i] = *entry; - } - } + auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager(); + ExportObjectList(objectMgr, _s6.RideObjects); + ExportObjectList(objectMgr, _s6.SceneryObjects); + ExportObjectList(objectMgr, _s6.LargeSceneryObjects); + ExportObjectList(objectMgr, _s6.WallSceneryObjects); + ExportObjectList(objectMgr, _s6.BannerObjects); + ExportObjectList(objectMgr, _s6.PathObjects); + ExportObjectList(objectMgr, _s6.PathAdditionObjects); + ExportObjectList(objectMgr, _s6.SceneryGroupObjects); + ExportObjectList(objectMgr, _s6.ParkEntranceObjects); + ExportObjectList(objectMgr, _s6.WaterObjects); + ExportObjectList(objectMgr, _s6.ScenarioTextObjects); _s6.elapsed_months = static_cast(gDateMonthsElapsed); _s6.current_day = gDateMonthTicks; diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 1ae9885831..bee403a492 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -169,9 +169,10 @@ public: _isSV7 = _stricmp(extension, ".sv7") == 0; } + chunkReader.ReadChunk(&_s6.Objects, sizeof(_s6.Objects)); + if (isScenario) { - chunkReader.ReadChunk(&_s6.objects, sizeof(_s6.objects)); 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); @@ -185,7 +186,6 @@ public: } else { - chunkReader.ReadChunk(&_s6.objects, sizeof(_s6.objects)); 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); @@ -1563,25 +1563,41 @@ public: return justText.data(); } - std::vector GetRequiredObjects() + template + static void AddRequiredObjects(std::vector& required, const T& list) { - std::vector result; rct_object_entry nullEntry = {}; std::memset(&nullEntry, 0xFF, sizeof(nullEntry)); - int objectIt = 0; - for (int16_t objectType = EnumValue(ObjectType::Ride); objectType <= EnumValue(ObjectType::Water); objectType++) + for (const auto& entry : list) { - for (int16_t i = 0; i < rct2_object_entry_group_counts[objectType]; i++, objectIt++) - { - result.push_back(_s6.objects[objectIt]); - } - for (int16_t i = rct2_object_entry_group_counts[objectType]; i < object_entry_group_counts[objectType]; i++) - { - result.push_back(nullEntry); - } + required.push_back(entry); } + // NOTE: The segment of this object type needs to be filled to the internal limit + // the object manager currently expects this. + for (size_t i = std::size(list); i < TInternalLimit; i++) + { + required.push_back(nullEntry); + } + } + + std::vector GetRequiredObjects() + { + std::vector result; + + AddRequiredObjects(result, _s6.RideObjects); + AddRequiredObjects(result, _s6.SceneryObjects); + AddRequiredObjects(result, _s6.LargeSceneryObjects); + AddRequiredObjects(result, _s6.WallSceneryObjects); + AddRequiredObjects(result, _s6.BannerObjects); + AddRequiredObjects(result, _s6.PathObjects); + AddRequiredObjects(result, _s6.PathAdditionObjects); + AddRequiredObjects(result, _s6.SceneryGroupObjects); + AddRequiredObjects(result, _s6.ParkEntranceObjects); + AddRequiredObjects(result, _s6.WaterObjects); + AddRequiredObjects(result, _s6.ScenarioTextObjects); + return result; } };