diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index d08f936948..7f414c61d0 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -107,7 +107,7 @@ static constexpr const ObjectPageDesc ObjectSelectionPages[] = { { STR_OBJECT_SELECTION_TERRAIN_SURFACES, SPR_G2_TAB_LAND, false }, { STR_OBJECT_SELECTION_TERRAIN_EDGES, SPR_G2_TAB_LAND, false }, { STR_OBJECT_SELECTION_STATIONS, SPR_TAB_PARK, false }, -// { STR_OBJECT_SELECTION_MUSIC, SPR_TAB_MUSIC_0, false }, + { STR_OBJECT_SELECTION_MUSIC, SPR_TAB_MUSIC_0, false }, }; #pragma region Widgets diff --git a/src/openrct2/Editor.cpp b/src/openrct2/Editor.cpp index 11a55f0e15..462fc111d5 100644 --- a/src/openrct2/Editor.cpp +++ b/src/openrct2/Editor.cpp @@ -70,7 +70,6 @@ namespace Editor // Reset loaded objects to just defaults auto& objectManager = context->GetObjectManager(); objectManager.UnloadAll(); - objectManager.LoadDefaultObjects(); } /** diff --git a/src/openrct2/ParkFile.cpp b/src/openrct2/ParkFile.cpp index 0b27ea63a2..56d5d9d95a 100644 --- a/src/openrct2/ParkFile.cpp +++ b/src/openrct2/ParkFile.cpp @@ -87,7 +87,7 @@ namespace OpenRCT2 class ParkFile { public: - std::vector RequiredObjects; + ObjectList RequiredObjects; private: std::unique_ptr _os; @@ -96,7 +96,7 @@ namespace OpenRCT2 void Load(const std::string_view& path) { _os = std::make_unique(path, OrcaStream::Mode::READING); - RequiredObjects.clear(); + RequiredObjects = {}; ReadWriteObjectsChunk(*_os); } @@ -174,59 +174,76 @@ namespace OpenRCT2 if (os.GetMode() == OrcaStream::Mode::READING) { - std::vector requiredObjects; + ObjectList requiredObjects; os.ReadWriteChunk(ParkFileChunkType::OBJECTS, [&requiredObjects](OrcaStream::ChunkStream& cs) { - cs.ReadWriteVector(requiredObjects, [&cs](ObjectEntryDescriptor& objectDesc) { - auto kind = cs.Read(); - switch (kind) + auto numSubLists = cs.Read(); + for (size_t i = 0; i < numSubLists; i++) + { + auto objectType = static_cast(cs.Read()); + auto subListSize = static_cast(cs.Read()); + for (ObjectEntryIndex j = 0; j < subListSize; j++) { - case DESCRIPTOR_NONE: - break; - case DESCRIPTOR_DAT: - objectDesc.Entry = cs.Read(); - break; - case DESCRIPTOR_JSON: - objectDesc.Type = static_cast(cs.Read()); - objectDesc.Identifier = cs.Read(); - objectDesc.Version = cs.Read(); - break; - default: - throw std::runtime_error("Unknown object descriptor kind."); + auto kind = cs.Read(); + + ObjectEntryDescriptor desc; + switch (kind) + { + case DESCRIPTOR_NONE: + break; + case DESCRIPTOR_DAT: + desc.Entry = cs.Read(); + requiredObjects.SetObject(j, desc); + break; + case DESCRIPTOR_JSON: + desc.Type = objectType; + desc.Identifier = cs.Read(); + desc.Version = cs.Read(); + requiredObjects.SetObject(j, desc); + break; + default: + throw std::runtime_error("Unknown object descriptor kind."); + } } - }); + } }); - RequiredObjects = requiredObjects; + RequiredObjects = std::move(requiredObjects); } else { - std::vector objectIds(OBJECT_ENTRY_COUNT); - std::iota(objectIds.begin(), objectIds.end(), 0); - os.ReadWriteChunk(ParkFileChunkType::OBJECTS, [&objectIds](OrcaStream::ChunkStream& cs) { + os.ReadWriteChunk(ParkFileChunkType::OBJECTS, [](OrcaStream::ChunkStream& cs) { auto& objManager = GetContext()->GetObjectManager(); - cs.ReadWriteVector(objectIds, [&cs, &objManager](size_t& i) { - auto obj = objManager.GetLoadedObject(i); - if (obj != nullptr) + auto objectList = objManager.GetLoadedObjects(); + + // Write number of object sub lists + cs.Write(static_cast(ObjectType::Count)); + for (auto objectType = ObjectType::Ride; objectType < ObjectType::Count; objectType++) + { + // Write sub list + const auto& list = objectList.GetList(objectType); + cs.Write(static_cast(objectType)); + cs.Write(static_cast(list.size())); + for (const auto& entry : list) { - if (obj->IsJsonObject()) + if (entry.HasValue()) { - cs.Write(DESCRIPTOR_JSON); - cs.Write(static_cast(obj->GetObjectType())); - cs.Write(obj->GetIdentifier()); - cs.Write(""); // reserved for version + if (entry.Generation == ObjectGeneration::JSON) + { + cs.Write(DESCRIPTOR_JSON); + cs.Write(entry.Identifier); + cs.Write(""); // reserved for version + } + else + { + cs.Write(DESCRIPTOR_DAT); + cs.Write(entry.Entry); + } } else { - auto entry = obj->GetObjectEntry(); - assert(entry != nullptr); - cs.Write(DESCRIPTOR_DAT); - cs.Write(entry); + cs.Write(DESCRIPTOR_NONE); } } - else - { - cs.Write(DESCRIPTOR_NONE); - } - }); + } }); } } diff --git a/src/openrct2/ParkImporter.h b/src/openrct2/ParkImporter.h index 89bc30dcdb..9f4ea70332 100644 --- a/src/openrct2/ParkImporter.h +++ b/src/openrct2/ParkImporter.h @@ -12,6 +12,7 @@ #include "common.h" #include "core/String.hpp" #include "object/Object.h" +#include "object/ObjectList.h" #include #include @@ -19,6 +20,7 @@ struct IObjectManager; struct IObjectRepository; + namespace OpenRCT2 { struct IStream; @@ -29,9 +31,9 @@ struct scenario_index_entry; struct ParkLoadResult final { public: - std::vector RequiredObjects; + ObjectList RequiredObjects; - explicit ParkLoadResult(std::vector&& requiredObjects) + explicit ParkLoadResult(ObjectList&& requiredObjects) : RequiredObjects(std::move(requiredObjects)) { } diff --git a/src/openrct2/core/OrcaStream.hpp b/src/openrct2/core/OrcaStream.hpp index bbe6e6dd2b..c72781a5f1 100644 --- a/src/openrct2/core/OrcaStream.hpp +++ b/src/openrct2/core/OrcaStream.hpp @@ -305,6 +305,14 @@ namespace OpenRCT2 } } +#if defined(_MSC_VER) + template<> +#endif + void Write(const std::string& v) + { + Write(std::string_view(v)); + } + template void ReadWriteVector(TVec& vec, TFunc f) { if (_mode == Mode::READING) diff --git a/src/openrct2/object/ObjectLimits.h b/src/openrct2/object/ObjectLimits.h index 06f9f9830c..ffa9a56bd0 100644 --- a/src/openrct2/object/ObjectLimits.h +++ b/src/openrct2/object/ObjectLimits.h @@ -39,7 +39,11 @@ constexpr const uint16_t OBJECT_ENTRY_COUNT = MAX_SCENERY_GROUP_OBJECTS + MAX_PARK_ENTRANCE_OBJECTS + MAX_WATER_OBJECTS + - MAX_SCENARIO_TEXT_OBJECTS; + MAX_SCENARIO_TEXT_OBJECTS + + MAX_TERRAIN_SURFACE_OBJECTS + + MAX_TERRAIN_EDGE_OBJECTS + + MAX_STATION_OBJECTS + + MAX_MUSIC_OBJECTS; // clang-format on constexpr const uint8_t DAT_NAME_LENGTH = 8; diff --git a/src/openrct2/object/ObjectList.cpp b/src/openrct2/object/ObjectList.cpp index 26035d97f6..34d421c062 100644 --- a/src/openrct2/object/ObjectList.cpp +++ b/src/openrct2/object/ObjectList.cpp @@ -56,6 +56,123 @@ int32_t object_entry_group_encoding[] = { }; // clang-format on +ObjectList::const_iterator::const_iterator(const ObjectList* parent, bool end) +{ + _parent = parent; + _subList = _parent->_subLists.size(); + _index = 0; +} + +void ObjectList::const_iterator::MoveToNextEntry() +{ + do + { + if (_subList < _parent->_subLists.size()) + { + auto subListSize = _parent->_subLists[_subList].size(); + if (_index < subListSize) + { + _index++; + if (_index == subListSize) + { + _subList++; + _index = 0; + } + } + } + else + { + break; + } + } while (!_parent->_subLists[_subList][_index].HasValue()); +} + +ObjectList::const_iterator& ObjectList::const_iterator::operator++() +{ + MoveToNextEntry(); + return *this; +} + +ObjectList::const_iterator ObjectList::const_iterator::operator++(int) +{ + return *this; +} + +const ObjectEntryDescriptor& ObjectList::const_iterator::operator*() +{ + return _parent->_subLists[_subList][_index]; +} + +bool ObjectList::const_iterator::operator==(const_iterator& rhs) +{ + return _parent == rhs._parent && _subList == rhs._subList && _index == rhs._index; +} + +bool ObjectList::const_iterator::operator!=(const_iterator& rhs) +{ + return !(*this == rhs); +} + +ObjectList::const_iterator ObjectList::begin() const +{ + return const_iterator(this, false); +} + +ObjectList::const_iterator ObjectList::end() const +{ + return const_iterator(this, true); +} + +std::vector& ObjectList::GetList(ObjectType type) +{ + auto index = static_cast(type); + while (_subLists.size() <= index) + { + _subLists.resize(static_cast(index) + 1); + } + return _subLists[index]; +} + +std::vector& ObjectList::GetList(ObjectType type) const +{ + return const_cast(this)->GetList(type); +} + +const ObjectEntryDescriptor& ObjectList::GetObject(ObjectType type, ObjectEntryIndex index) const +{ + const auto& subList = GetList(type); + if (subList.size() > index) + { + return subList[index]; + } + + static ObjectEntryDescriptor placeholder; + return placeholder; +} + +void ObjectList::Add(const ObjectEntryDescriptor& entry) +{ + auto& subList = GetList(entry.GetType()); + subList.push_back(entry); +} + +void ObjectList::SetObject(ObjectEntryIndex index, const ObjectEntryDescriptor& entry) +{ + auto& subList = GetList(entry.GetType()); + if (subList.size() <= index) + { + subList.resize(static_cast(index) + 1); + } + subList[index] = entry; +} + +void ObjectList::SetObject(ObjectType type, ObjectEntryIndex index, std::string_view identifier) +{ + auto entry = ObjectEntryDescriptor(identifier); + entry.Type = type; + SetObject(index, entry); +} + bool object_entry_is_empty(const rct_object_entry* entry) { uint64_t a, b; diff --git a/src/openrct2/object/ObjectList.h b/src/openrct2/object/ObjectList.h index 62cbe2cdca..532b1656a6 100644 --- a/src/openrct2/object/ObjectList.h +++ b/src/openrct2/object/ObjectList.h @@ -15,8 +15,46 @@ #include "../world/Footpath.h" #include "../world/Scenery.h" #include "../world/Water.h" +#include "Object.h" #include "ObjectLimits.h" +#include + +class ObjectList +{ +private: + std::vector> _subLists; + +public: + void Add(const ObjectEntryDescriptor& entry); + std::vector& GetList(ObjectType type); + std::vector& GetList(ObjectType type) const; + const ObjectEntryDescriptor& GetObject(ObjectType type, ObjectEntryIndex index) const; + void SetObject(ObjectEntryIndex index, const ObjectEntryDescriptor& entry); + void SetObject(ObjectType type, ObjectEntryIndex index, std::string_view identifier); + + struct const_iterator + { + private: + const ObjectList* _parent; + size_t _subList; + size_t _index; + + void MoveToNextEntry(); + + public: + const_iterator(const ObjectList* parent, bool end); + const ObjectEntryDescriptor& operator*(); + bool operator==(const_iterator& rhs); + bool operator!=(const_iterator& rhs); + const_iterator& operator++(); + const_iterator operator++(int); + }; + + const_iterator begin() const; + const_iterator end() const; +}; + 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/object/ObjectManager.cpp b/src/openrct2/object/ObjectManager.cpp index 1ce486e517..50733d204c 100644 --- a/src/openrct2/object/ObjectManager.cpp +++ b/src/openrct2/object/ObjectManager.cpp @@ -102,6 +102,26 @@ public: return result; } + ObjectList GetLoadedObjects() override + { + ObjectList objectList; + for (auto objectType = ObjectType::Ride; objectType < ObjectType::Count; objectType++) + { + auto maxObjectsOfType = static_cast(object_entry_group_counts[EnumValue(objectType)]); + for (ObjectEntryIndex i = 0; i < maxObjectsOfType; i++) + { + auto obj = GetLoadedObject(objectType, i); + if (obj != nullptr) + { + auto entry = ObjectEntryDescriptor(obj->GetIdentifier()); + entry.Type = obj->GetObjectType(); + objectList.SetObject(i, entry); + } + } + } + return objectList; + } + Object* LoadObject(std::string_view identifier) override { const ObjectRepositoryItem* ori = _objectRepository.FindObject(identifier); @@ -114,17 +134,16 @@ public: return RepositoryItemToObject(ori); } - void LoadObjects(const std::vector& entries) override + void LoadObjects(const ObjectList& objectList) override { // Find all the required objects - auto requiredObjects = GetRequiredObjects(entries); + auto requiredObjects = GetRequiredObjects(objectList); // Load the required objects size_t numNewLoadedObjects = 0; auto loadedObjects = LoadObjects(requiredObjects, &numNewLoadedObjects); SetNewLoadedObjectList(std::move(loadedObjects)); - LoadDefaultObjects(); UpdateSceneryGroupIndexes(); ResetTypeToRideEntryIndexMap(); log_verbose("%u / %u new objects loaded", numNewLoadedObjects, requiredObjects.size()); @@ -198,99 +217,6 @@ public: return objects; } - void LoadDefaultObjects() override - { - // We currently will load new object types here that apply to all - // loaded RCT1 and RCT2 save files. - - // Surfaces - LoadObject("rct2.surface.grass"); - LoadObject("rct2.surface.sand"); - LoadObject("rct2.surface.dirt"); - LoadObject("rct2.surface.rock"); - LoadObject("rct2.surface.martian"); - LoadObject("rct2.surface.chequerboard"); - LoadObject("rct2.surface.grassclumps"); - LoadObject("rct2.surface.ice"); - LoadObject("rct2.surface.gridred"); - LoadObject("rct2.surface.gridyellow"); - LoadObject("rct2.surface.gridpurple"); - LoadObject("rct2.surface.gridgreen"); - LoadObject("rct2.surface.sandred"); - LoadObject("rct2.surface.sandbrown"); - LoadObject("rct1.aa.surface.roofred"); - LoadObject("rct1.ll.surface.roofgrey"); - LoadObject("rct1.ll.surface.rust"); - LoadObject("rct1.ll.surface.wood"); - - // Edges - LoadObject("rct2.edge.rock"); - LoadObject("rct2.edge.woodred"); - LoadObject("rct2.edge.woodblack"); - LoadObject("rct2.edge.ice"); - LoadObject("rct1.edge.brick"); - LoadObject("rct1.edge.iron"); - LoadObject("rct1.aa.edge.grey"); - LoadObject("rct1.aa.edge.yellow"); - LoadObject("rct1.aa.edge.red"); - LoadObject("rct1.ll.edge.purple"); - LoadObject("rct1.ll.edge.green"); - LoadObject("rct1.ll.edge.stonebrown"); - LoadObject("rct1.ll.edge.stonegrey"); - LoadObject("rct1.ll.edge.skyscrapera"); - LoadObject("rct1.ll.edge.skyscraperb"); - - // Stations - LoadObject("rct2.station.plain"); - LoadObject("rct2.station.wooden"); - LoadObject("rct2.station.canvastent"); - LoadObject("rct2.station.castlegrey"); - LoadObject("rct2.station.castlebrown"); - LoadObject("rct2.station.jungle"); - LoadObject("rct2.station.log"); - LoadObject("rct2.station.classical"); - LoadObject("rct2.station.abstract"); - LoadObject("rct2.station.snow"); - LoadObject("rct2.station.pagoda"); - LoadObject("rct2.station.space"); - LoadObject("openrct2.station.noentrance"); - - // Music - auto baseIndex = GetIndexFromTypeEntry(ObjectType::Music, 0); - LoadObject(baseIndex + MUSIC_STYLE_DODGEMS_BEAT, "rct2.music.dodgems"); - LoadObject(baseIndex + MUSIC_STYLE_FAIRGROUND_ORGAN, "rct2.music.fairground"); - LoadObject(baseIndex + MUSIC_STYLE_ROMAN_FANFARE, "rct2.music.roman"); - LoadObject(baseIndex + MUSIC_STYLE_ORIENTAL, "rct2.music.oriental"); - LoadObject(baseIndex + MUSIC_STYLE_MARTIAN, "rct2.music.martian"); - LoadObject(baseIndex + MUSIC_STYLE_JUNGLE_DRUMS, "rct2.music.jungle"); - LoadObject(baseIndex + MUSIC_STYLE_EGYPTIAN, "rct2.music.egyptian"); - LoadObject(baseIndex + MUSIC_STYLE_TOYLAND, "rct2.music.toyland"); - LoadObject(baseIndex + MUSIC_STYLE_SPACE, "rct2.music.space"); - LoadObject(baseIndex + MUSIC_STYLE_HORROR, "rct2.music.horror"); - LoadObject(baseIndex + MUSIC_STYLE_TECHNO, "rct2.music.techno"); - LoadObject(baseIndex + MUSIC_STYLE_GENTLE, "rct2.music.gentle"); - LoadObject(baseIndex + MUSIC_STYLE_SUMMER, "rct2.music.summer"); - LoadObject(baseIndex + MUSIC_STYLE_WATER, "rct2.music.water"); - LoadObject(baseIndex + MUSIC_STYLE_WILD_WEST, "rct2.music.wildwest"); - LoadObject(baseIndex + MUSIC_STYLE_JURASSIC, "rct2.music.jurassic"); - LoadObject(baseIndex + MUSIC_STYLE_ROCK, "rct2.music.rock1"); - LoadObject(baseIndex + MUSIC_STYLE_RAGTIME, "rct2.music.ragtime"); - LoadObject(baseIndex + MUSIC_STYLE_FANTASY, "rct2.music.fantasy"); - LoadObject(baseIndex + MUSIC_STYLE_ROCK_STYLE_2, "rct2.music.rock2"); - LoadObject(baseIndex + MUSIC_STYLE_ICE, "rct2.music.ice"); - LoadObject(baseIndex + MUSIC_STYLE_SNOW, "rct2.music.snow"); - LoadObject(baseIndex + MUSIC_STYLE_CUSTOM_MUSIC_1, "rct2.music.custom1"); - LoadObject(baseIndex + MUSIC_STYLE_CUSTOM_MUSIC_2, "rct2.music.custom2"); - LoadObject(baseIndex + MUSIC_STYLE_MEDIEVAL, "rct2.music.medieval"); - LoadObject(baseIndex + MUSIC_STYLE_URBAN, "rct2.music.urban"); - LoadObject(baseIndex + MUSIC_STYLE_ORGAN, "rct2.music.organ"); - LoadObject(baseIndex + MUSIC_STYLE_MECHANICAL, "rct2.music.mechanical"); - LoadObject(baseIndex + MUSIC_STYLE_MODERN, "rct2.music.modern"); - LoadObject(baseIndex + MUSIC_STYLE_PIRATES, "rct2.music.pirate"); - LoadObject(baseIndex + MUSIC_STYLE_ROCK_STYLE_3, "rct2.music.rock3"); - LoadObject(baseIndex + MUSIC_STYLE_CANDY_STYLE, "rct2.music.candy"); - } - static rct_string_id GetObjectSourceGameString(const ObjectSourceGame sourceGame) { switch (sourceGame) @@ -554,25 +480,29 @@ private: return duplicate; } - std::vector GetRequiredObjects(const std::vector& objectList) + std::vector GetRequiredObjects(const ObjectList& objectList) { std::vector requiredObjects; std::vector missingObjects; - for (size_t i = 0; i < objectList.size(); i++) + for (auto objectType = ObjectType::Ride; objectType < ObjectType::Count; objectType++) { - const auto& entry = objectList[i]; - const ObjectRepositoryItem* ori = nullptr; - if (entry.HasValue()) + auto maxObjectsOfType = static_cast(object_entry_group_counts[EnumValue(objectType)]); + for (ObjectEntryIndex i = 0; i < maxObjectsOfType; i++) { - ori = _objectRepository.FindObject(entry); - if (ori == nullptr && entry.GetType() != ObjectType::ScenarioText) + const ObjectRepositoryItem* ori = nullptr; + const auto& entry = objectList.GetObject(objectType, i); + if (entry.HasValue()) { - missingObjects.push_back(entry); - ReportMissingObject(entry); + ori = _objectRepository.FindObject(entry); + if (ori == nullptr && entry.GetType() != ObjectType::ScenarioText) + { + missingObjects.push_back(entry); + ReportMissingObject(entry); + } } + requiredObjects.push_back(ori); } - requiredObjects.push_back(ori); } if (!missingObjects.empty()) diff --git a/src/openrct2/object/ObjectManager.h b/src/openrct2/object/ObjectManager.h index 85f1e399c4..fe0a61382a 100644 --- a/src/openrct2/object/ObjectManager.h +++ b/src/openrct2/object/ObjectManager.h @@ -16,6 +16,7 @@ struct IObjectRepository; class Object; +class ObjectList; struct ObjectRepositoryItem; struct IObjectManager @@ -28,11 +29,11 @@ struct IObjectManager virtual Object* GetLoadedObject(ObjectType objectType, size_t index) abstract; virtual Object* GetLoadedObject(const ObjectEntryDescriptor& entry) abstract; virtual ObjectEntryIndex GetLoadedObjectEntryIndex(const Object* object) abstract; + virtual ObjectList GetLoadedObjects() abstract; virtual Object* LoadObject(std::string_view identifier) abstract; virtual Object* LoadObject(const rct_object_entry* entry) abstract; - virtual void LoadObjects(const std::vector& entries) abstract; - virtual void LoadDefaultObjects() abstract; + virtual void LoadObjects(const ObjectList& entries) abstract; virtual void UnloadObjects(const std::vector& entries) abstract; virtual void UnloadAll() abstract; diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index f6645744da..4df4cbafa0 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -189,7 +189,6 @@ public: Initialise(); CreateAvailableObjectMappings(); - LoadObjects(); ImportRides(); ImportRideMeasurements(); @@ -339,7 +338,6 @@ private: // Do map initialisation, same kind of stuff done when loading scenario editor auto context = OpenRCT2::GetContext(); - context->GetObjectManager().UnloadAll(); context->GetGameState()->InitAll(mapSize); gS6Info.editor_step = EditorStep::ObjectSelection; gParkFlags |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; @@ -1486,83 +1484,25 @@ private: } } - void LoadObjects() + void AppendRequiredObjects(ObjectList& objectList, ObjectType objectType, const EntryList& entryList) { - auto& objectManager = OpenRCT2::GetContext()->GetObjectManager(); - objectManager.LoadDefaultObjects(); - - LoadObjects(ObjectType::Ride, _rideEntries); - LoadObjects(ObjectType::SmallScenery, _smallSceneryEntries); - LoadObjects(ObjectType::LargeScenery, _largeSceneryEntries); - LoadObjects(ObjectType::Walls, _wallEntries); - LoadObjects(ObjectType::Paths, _pathEntries); - LoadObjects(ObjectType::PathBits, _pathAdditionEntries); - LoadObjects(ObjectType::SceneryGroup, _sceneryGroupEntries); - LoadObjects( - ObjectType::Banners, - std::vector({ - "BN1 ", - "BN2 ", - "BN3 ", - "BN4 ", - "BN5 ", - "BN6 ", - "BN7 ", - "BN8 ", - "BN9 ", - })); - LoadObjects(ObjectType::ParkEntrance, std::vector({ "PKENT1 " })); - LoadObjects(ObjectType::Water, _waterEntry); + AppendRequiredObjects(objectList, objectType, entryList.GetEntries()); } - void LoadObjects(ObjectType objectType, const EntryList& entries) - { - LoadObjects(objectType, entries.GetEntries()); - } - - void LoadObjects(ObjectType objectType, const std::vector& entries) - { - auto& objectManager = OpenRCT2::GetContext()->GetObjectManager(); - - uint32_t entryIndex = 0; - for (const char* objectName : entries) - { - rct_object_entry entry; - entry.flags = 0x00008000 + EnumValue(objectType); - std::copy_n(objectName, 8, entry.name); - entry.checksum = 0; - - Object* object = objectManager.LoadObject(&entry); - if (object == nullptr && objectType != ObjectType::SceneryGroup) - { - log_error("Failed to load %s.", objectName); - throw std::runtime_error("Failed to load object."); - } - - entryIndex++; - } - } - - void AppendRequiredObjects(std::vector& entries, ObjectType objectType, const EntryList& entryList) - { - AppendRequiredObjects(entries, objectType, entryList.GetEntries()); - } - - void AppendRequiredObjects( - std::vector& entries, ObjectType objectType, const std::vector& objectNames) + void AppendRequiredObjects(ObjectList& objectList, ObjectType objectType, const std::vector& objectNames) { for (const auto objectName : objectNames) { rct_object_entry entry{}; entry.flags = ((static_cast(ObjectSourceGame::RCT2) << 4) & 0xF0) | (EnumValue(objectType) & 0x0F); entry.SetName(objectName); - entries.push_back(ObjectEntryDescriptor(entry)); + objectList.Add(ObjectEntryDescriptor(entry)); } } - std::vector GetRequiredObjects() + ObjectList GetRequiredObjects() { - std::vector result; + ObjectList result; AppendRequiredObjects(result, ObjectType::Ride, _rideEntries); AppendRequiredObjects(result, ObjectType::SmallScenery, _smallSceneryEntries); AppendRequiredObjects(result, ObjectType::LargeScenery, _largeSceneryEntries); @@ -1585,6 +1525,7 @@ private: })); AppendRequiredObjects(result, ObjectType::ParkEntrance, std::vector({ "PKENT1 " })); AppendRequiredObjects(result, ObjectType::Water, _waterEntry); + RCT12AddDefaultObjects(result); return result; } diff --git a/src/openrct2/rct12/RCT12.cpp b/src/openrct2/rct12/RCT12.cpp index 10bd0012ee..59ecac3142 100644 --- a/src/openrct2/rct12/RCT12.cpp +++ b/src/openrct2/rct12/RCT12.cpp @@ -12,6 +12,7 @@ #include "../core/String.hpp" #include "../localisation/Formatting.h" #include "../localisation/Localisation.h" +#include "../object/ObjectList.h" #include "../ride/Track.h" #include "../world/Banner.h" #include "../world/Footpath.h" @@ -1347,3 +1348,93 @@ RCT12TrackType OpenRCT2FlatTrackTypeToRCT12(track_type_t origTrackType) return origTrackType; } + +void RCT12AddDefaultObjects(ObjectList& objectList) +{ + // Surfaces + objectList.SetObject(ObjectType::TerrainSurface, 0, "rct2.surface.grass"); + objectList.SetObject(ObjectType::TerrainSurface, 1, "rct2.surface.sand"); + objectList.SetObject(ObjectType::TerrainSurface, 2, "rct2.surface.dirt"); + objectList.SetObject(ObjectType::TerrainSurface, 3, "rct2.surface.rock"); + objectList.SetObject(ObjectType::TerrainSurface, 4, "rct2.surface.martian"); + objectList.SetObject(ObjectType::TerrainSurface, 5, "rct2.surface.chequerboard"); + objectList.SetObject(ObjectType::TerrainSurface, 6, "rct2.surface.grassclumps"); + objectList.SetObject(ObjectType::TerrainSurface, 7, "rct2.surface.ice"); + objectList.SetObject(ObjectType::TerrainSurface, 8, "rct2.surface.gridred"); + objectList.SetObject(ObjectType::TerrainSurface, 9, "rct2.surface.gridyellow"); + objectList.SetObject(ObjectType::TerrainSurface, 10, "rct2.surface.gridpurple"); + objectList.SetObject(ObjectType::TerrainSurface, 11, "rct2.surface.gridgreen"); + objectList.SetObject(ObjectType::TerrainSurface, 12, "rct2.surface.sandred"); + objectList.SetObject(ObjectType::TerrainSurface, 13, "rct2.surface.sandbrown"); + objectList.SetObject(ObjectType::TerrainSurface, 14, "rct1.aa.surface.roofred"); + objectList.SetObject(ObjectType::TerrainSurface, 15, "rct1.ll.surface.roofgrey"); + objectList.SetObject(ObjectType::TerrainSurface, 16, "rct1.ll.surface.rust"); + objectList.SetObject(ObjectType::TerrainSurface, 17, "rct1.ll.surface.wood"); + + // Edges + objectList.SetObject(ObjectType::TerrainEdge, 0, "rct2.edge.rock"); + objectList.SetObject(ObjectType::TerrainEdge, 1, "rct2.edge.woodred"); + objectList.SetObject(ObjectType::TerrainEdge, 2, "rct2.edge.woodblack"); + objectList.SetObject(ObjectType::TerrainEdge, 3, "rct2.edge.ice"); + objectList.SetObject(ObjectType::TerrainEdge, 4, "rct1.edge.brick"); + objectList.SetObject(ObjectType::TerrainEdge, 5, "rct1.edge.iron"); + objectList.SetObject(ObjectType::TerrainEdge, 6, "rct1.aa.edge.grey"); + objectList.SetObject(ObjectType::TerrainEdge, 7, "rct1.aa.edge.yellow"); + objectList.SetObject(ObjectType::TerrainEdge, 8, "rct1.aa.edge.red"); + objectList.SetObject(ObjectType::TerrainEdge, 9, "rct1.ll.edge.purple"); + objectList.SetObject(ObjectType::TerrainEdge, 10, "rct1.ll.edge.green"); + objectList.SetObject(ObjectType::TerrainEdge, 11, "rct1.ll.edge.stonebrown"); + objectList.SetObject(ObjectType::TerrainEdge, 12, "rct1.ll.edge.stonegrey"); + objectList.SetObject(ObjectType::TerrainEdge, 13, "rct1.ll.edge.skyscrapera"); + objectList.SetObject(ObjectType::TerrainEdge, 14, "rct1.ll.edge.skyscraperb"); + + // Stations + objectList.SetObject(ObjectType::Station, 0, "rct2.station.plain"); + objectList.SetObject(ObjectType::Station, 1, "rct2.station.wooden"); + objectList.SetObject(ObjectType::Station, 2, "rct2.station.canvastent"); + objectList.SetObject(ObjectType::Station, 3, "rct2.station.castlegrey"); + objectList.SetObject(ObjectType::Station, 4, "rct2.station.castlebrown"); + objectList.SetObject(ObjectType::Station, 5, "rct2.station.jungle"); + objectList.SetObject(ObjectType::Station, 6, "rct2.station.log"); + objectList.SetObject(ObjectType::Station, 7, "rct2.station.classical"); + objectList.SetObject(ObjectType::Station, 8, "rct2.station.abstract"); + objectList.SetObject(ObjectType::Station, 9, "rct2.station.snow"); + objectList.SetObject(ObjectType::Station, 10, "rct2.station.pagoda"); + objectList.SetObject(ObjectType::Station, 11, "rct2.station.space"); + objectList.SetObject(ObjectType::Station, 12, "openrct2.station.noentrance"); + + // Music + objectList.SetObject(ObjectType::Music, 0, "rct2.music.dodgems"); + objectList.SetObject(ObjectType::Music, 1, "rct2.music.fairground"); + objectList.SetObject(ObjectType::Music, 2, "rct2.music.roman"); + objectList.SetObject(ObjectType::Music, 3, "rct2.music.oriental"); + objectList.SetObject(ObjectType::Music, 4, "rct2.music.martian"); + objectList.SetObject(ObjectType::Music, 5, "rct2.music.jungle"); + objectList.SetObject(ObjectType::Music, 6, "rct2.music.egyptian"); + objectList.SetObject(ObjectType::Music, 7, "rct2.music.toyland"); + // Original ID: 8 was circus + objectList.SetObject(ObjectType::Music, 9, "rct2.music.space"); + objectList.SetObject(ObjectType::Music, 10, "rct2.music.horror"); + objectList.SetObject(ObjectType::Music, 11, "rct2.music.techno"); + objectList.SetObject(ObjectType::Music, 12, "rct2.music.gentle"); + objectList.SetObject(ObjectType::Music, 13, "rct2.music.summer"); + objectList.SetObject(ObjectType::Music, 14, "rct2.music.water"); + objectList.SetObject(ObjectType::Music, 15, "rct2.music.wildwest"); + objectList.SetObject(ObjectType::Music, 16, "rct2.music.jurassic"); + objectList.SetObject(ObjectType::Music, 17, "rct2.music.rock1"); + objectList.SetObject(ObjectType::Music, 18, "rct2.music.ragtime"); + objectList.SetObject(ObjectType::Music, 19, "rct2.music.fantasy"); + objectList.SetObject(ObjectType::Music, 20, "rct2.music.rock2"); + objectList.SetObject(ObjectType::Music, 21, "rct2.music.ice"); + objectList.SetObject(ObjectType::Music, 22, "rct2.music.snow"); + objectList.SetObject(ObjectType::Music, 23, "rct2.music.custom1"); + objectList.SetObject(ObjectType::Music, 24, "rct2.music.custom2"); + objectList.SetObject(ObjectType::Music, 25, "rct2.music.medieval"); + objectList.SetObject(ObjectType::Music, 26, "rct2.music.urban"); + objectList.SetObject(ObjectType::Music, 27, "rct2.music.organ"); + objectList.SetObject(ObjectType::Music, 28, "rct2.music.mechanical"); + objectList.SetObject(ObjectType::Music, 29, "rct2.music.modern"); + objectList.SetObject(ObjectType::Music, 30, "rct2.music.pirate"); + objectList.SetObject(ObjectType::Music, 31, "rct2.music.rock3"); + objectList.SetObject(ObjectType::Music, 32, "rct2.music.candy"); +} diff --git a/src/openrct2/rct12/RCT12.h b/src/openrct2/rct12/RCT12.h index fe0ff85f2f..f0e45e9997 100644 --- a/src/openrct2/rct12/RCT12.h +++ b/src/openrct2/rct12/RCT12.h @@ -18,6 +18,8 @@ #include #include +class ObjectList; + using track_type_t = uint16_t; using RCT12TrackType = uint8_t; @@ -927,3 +929,4 @@ std::string ConvertFormattedStringToRCT2(std::string_view buffer, size_t maxLeng std::string GetTruncatedRCT2String(std::string_view src, size_t maxLength); track_type_t RCT12FlatTrackTypeToOpenRCT2(RCT12TrackType origTrackType); RCT12TrackType OpenRCT2FlatTrackTypeToRCT12(track_type_t origTrackType); +void RCT12AddDefaultObjects(ObjectList& objectList); diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index d7f6bacaee..69bc02d567 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -30,6 +30,7 @@ #include "../management/Research.h" #include "../network/network.h" #include "../object/ObjectLimits.h" +#include "../object/ObjectList.h" #include "../object/ObjectManager.h" #include "../object/ObjectRepository.h" #include "../peep/Staff.h" @@ -1549,23 +1550,24 @@ public: return justText.data(); } - std::vector GetRequiredObjects() + ObjectList GetRequiredObjects() { - std::vector result; + ObjectList objectList; int objectIt = 0; for (int16_t objectType = EnumValue(ObjectType::Ride); objectType <= EnumValue(ObjectType::Water); objectType++) { for (int16_t i = 0; i < rct2_object_entry_group_counts[objectType]; i++, objectIt++) { - result.push_back(ObjectEntryDescriptor(_s6.objects[objectIt])); - } - for (int16_t i = rct2_object_entry_group_counts[objectType]; i < object_entry_group_counts[objectType]; i++) - { - result.push_back({}); + auto entry = ObjectEntryDescriptor(_s6.objects[objectIt]); + if (entry.HasValue()) + { + objectList.SetObject(i, entry); + } } } - return result; + RCT12AddDefaultObjects(objectList); + return objectList; } };