mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-17 20:13:07 +01:00
Merge pull request #15378 from ZehMatt/refactor/object-importexport
Refactor object storage in s6
This commit is contained in:
@@ -137,28 +137,6 @@ void get_type_entry_index(size_t index, ObjectType* outObjectType, ObjectEntryIn
|
||||
*outEntryIndex = static_cast<ObjectEntryIndex>(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<size_t>(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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<ObjectType TObjectType, size_t TMaxEntries, typename T>
|
||||
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<void*>(-1))
|
||||
{
|
||||
std::memset(&_s6.objects[i], 0xFF, sizeof(rct_object_entry));
|
||||
}
|
||||
else
|
||||
{
|
||||
_s6.objects[i] = *entry;
|
||||
}
|
||||
}
|
||||
auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager();
|
||||
ExportObjectList<ObjectType::Ride, RCT12_MAX_RIDE_OBJECTS>(objectMgr, _s6.RideObjects);
|
||||
ExportObjectList<ObjectType::SmallScenery, RCT2_MAX_SMALL_SCENERY_OBJECTS>(objectMgr, _s6.SceneryObjects);
|
||||
ExportObjectList<ObjectType::LargeScenery, RCT2_MAX_LARGE_SCENERY_OBJECTS>(objectMgr, _s6.LargeSceneryObjects);
|
||||
ExportObjectList<ObjectType::Walls, RCT2_MAX_WALL_SCENERY_OBJECTS>(objectMgr, _s6.WallSceneryObjects);
|
||||
ExportObjectList<ObjectType::Banners, RCT2_MAX_BANNER_OBJECTS>(objectMgr, _s6.BannerObjects);
|
||||
ExportObjectList<ObjectType::Paths, RCT2_MAX_PATH_OBJECTS>(objectMgr, _s6.PathObjects);
|
||||
ExportObjectList<ObjectType::PathBits, RCT2_MAX_PATH_ADDITION_OBJECTS>(objectMgr, _s6.PathAdditionObjects);
|
||||
ExportObjectList<ObjectType::SceneryGroup, RCT2_MAX_SCENERY_GROUP_OBJECTS>(objectMgr, _s6.SceneryGroupObjects);
|
||||
ExportObjectList<ObjectType::ParkEntrance, RCT2_MAX_PARK_ENTRANCE_OBJECTS>(objectMgr, _s6.ParkEntranceObjects);
|
||||
ExportObjectList<ObjectType::Water, RCT2_MAX_WATER_OBJECTS>(objectMgr, _s6.WaterObjects);
|
||||
ExportObjectList<ObjectType::ScenarioText, RCT2_MAX_SCENARIO_TEXT_OBJECTS>(objectMgr, _s6.ScenarioTextObjects);
|
||||
|
||||
_s6.elapsed_months = static_cast<uint16_t>(gDateMonthsElapsed);
|
||||
_s6.current_day = gDateMonthTicks;
|
||||
|
||||
@@ -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<rct_object_entry> GetRequiredObjects()
|
||||
template<size_t TInternalLimit, typename T>
|
||||
static void AddRequiredObjects(std::vector<rct_object_entry>& required, const T& list)
|
||||
{
|
||||
std::vector<rct_object_entry> 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<rct_object_entry> GetRequiredObjects()
|
||||
{
|
||||
std::vector<rct_object_entry> result;
|
||||
|
||||
AddRequiredObjects<MAX_RIDE_OBJECTS>(result, _s6.RideObjects);
|
||||
AddRequiredObjects<MAX_SMALL_SCENERY_OBJECTS>(result, _s6.SceneryObjects);
|
||||
AddRequiredObjects<MAX_LARGE_SCENERY_OBJECTS>(result, _s6.LargeSceneryObjects);
|
||||
AddRequiredObjects<MAX_WALL_SCENERY_OBJECTS>(result, _s6.WallSceneryObjects);
|
||||
AddRequiredObjects<MAX_BANNER_OBJECTS>(result, _s6.BannerObjects);
|
||||
AddRequiredObjects<MAX_PATH_OBJECTS>(result, _s6.PathObjects);
|
||||
AddRequiredObjects<MAX_PATH_ADDITION_OBJECTS>(result, _s6.PathAdditionObjects);
|
||||
AddRequiredObjects<MAX_SCENERY_GROUP_OBJECTS>(result, _s6.SceneryGroupObjects);
|
||||
AddRequiredObjects<MAX_PARK_ENTRANCE_OBJECTS>(result, _s6.ParkEntranceObjects);
|
||||
AddRequiredObjects<MAX_WATER_OBJECTS>(result, _s6.WaterObjects);
|
||||
AddRequiredObjects<MAX_SCENARIO_TEXT_OBJECTS>(result, _s6.ScenarioTextObjects);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user