diff --git a/src/openrct2/EditorObjectSelectionSession.cpp b/src/openrct2/EditorObjectSelectionSession.cpp index e9001e8356..3fe7a5db7d 100644 --- a/src/openrct2/EditorObjectSelectionSession.cpp +++ b/src/openrct2/EditorObjectSelectionSession.cpp @@ -455,7 +455,7 @@ bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_ { for (const auto& sgEntry : item->SceneryGroupInfo.Entries) { - window_editor_object_selection_select_object(++isMasterObject, flags, &sgEntry); + window_editor_object_selection_select_object(++isMasterObject, flags, sgEntry); } } @@ -494,7 +494,7 @@ bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_ { for (const auto& sgEntry : item->SceneryGroupInfo.Entries) { - if (!window_editor_object_selection_select_object(++isMasterObject, flags, &sgEntry)) + if (!window_editor_object_selection_select_object(++isMasterObject, flags, sgEntry)) { _maxObjectsWasHit = true; } @@ -537,6 +537,14 @@ bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_ return window_editor_object_selection_select_object(isMasterObject, flags, item); } +bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_t flags, const ObjectEntryDescriptor& entry) +{ + if (entry.Generation == ObjectGeneration::DAT) + return window_editor_object_selection_select_object(isMasterObject, flags, &entry.Entry); + + return window_editor_object_selection_select_object(isMasterObject, flags, entry.Identifier); +} + bool editor_check_object_group_at_least_one_selected(ObjectType checkObjectType) { int32_t numObjects = static_cast(object_repository_get_items_count()); diff --git a/src/openrct2/EditorObjectSelectionSession.h b/src/openrct2/EditorObjectSelectionSession.h index c93b940cd9..45f4f8b482 100644 --- a/src/openrct2/EditorObjectSelectionSession.h +++ b/src/openrct2/EditorObjectSelectionSession.h @@ -36,6 +36,7 @@ void finish_object_selection(); bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_t flags, const ObjectRepositoryItem* item); bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_t flags, std::string_view identifier); bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_t flags, const rct_object_entry* entry); +bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_t flags, const ObjectEntryDescriptor& entry); /** * Removes all unused objects from the object selection. diff --git a/src/openrct2/core/IStream.cpp b/src/openrct2/core/IStream.cpp index 85dace3ecb..7f355d1413 100644 --- a/src/openrct2/core/IStream.cpp +++ b/src/openrct2/core/IStream.cpp @@ -9,6 +9,7 @@ #include "IStream.hpp" +#include "../object/Object.h" #include "Memory.hpp" #include "String.hpp" @@ -61,4 +62,22 @@ namespace OpenRCT2 WriteString(str.c_str()); } + ObjectEntryDescriptor IStream::ReadObjectEntryDescriptor() + { + auto generation = ReadValue(); + if (generation == ObjectGeneration::DAT) + return ObjectEntryDescriptor(ReadValue()); + + return ObjectEntryDescriptor(ReadStdString()); + } + + void IStream::WriteObjectEntryDescriptor(const ObjectEntryDescriptor& oed) + { + WriteValue(oed.Generation); + if (oed.Generation == ObjectGeneration::DAT) + WriteValue(oed.Entry); + else + WriteString(oed.Identifier); + } + } // namespace OpenRCT2 diff --git a/src/openrct2/core/IStream.hpp b/src/openrct2/core/IStream.hpp index b3d729c4d6..fc71319dc3 100644 --- a/src/openrct2/core/IStream.hpp +++ b/src/openrct2/core/IStream.hpp @@ -10,6 +10,7 @@ #pragma once #include "../common.h" +#include "../object/Object.h" #include "Memory.hpp" #include @@ -206,6 +207,8 @@ namespace OpenRCT2 std::string ReadStdString(); void WriteString(const utf8* str); void WriteString(const std::string& string); + ObjectEntryDescriptor ReadObjectEntryDescriptor(); + void WriteObjectEntryDescriptor(const ObjectEntryDescriptor& oed); }; } // namespace OpenRCT2 diff --git a/src/openrct2/object/Object.h b/src/openrct2/object/Object.h index 1fc6a2e712..dccb485d0b 100644 --- a/src/openrct2/object/Object.h +++ b/src/openrct2/object/Object.h @@ -11,10 +11,12 @@ #include "../common.h" #include "../core/JsonFwd.hpp" +#include "../util/Util.h" #include "ImageTable.h" #include "StringTable.h" #include +#include #include #include #include @@ -126,6 +128,46 @@ struct rct_object_entry_group assert_struct_size(rct_object_entry_group, 8); #endif +enum class ObjectGeneration : uint8_t +{ + DAT, + JSON, +}; + +struct ObjectEntryDescriptor +{ + ObjectGeneration Generation; + union + { + rct_object_entry Entry; // For DAT objects + char Identifier[64]; // For JSON objects + }; + + ObjectEntryDescriptor() = default; + explicit ObjectEntryDescriptor(const rct_object_entry& newEntry) + { + Generation = ObjectGeneration::DAT; + Entry = newEntry; + } + + explicit ObjectEntryDescriptor(std::string_view newIdentifier) + { + Generation = ObjectGeneration::JSON; + safe_strcpy(const_cast(Identifier), std::string(newIdentifier).c_str(), 64); + } + + ObjectEntryDescriptor& operator=(const ObjectEntryDescriptor& newEntry) + { + Generation = newEntry.Generation; + if (newEntry.Generation == ObjectGeneration::DAT) + Entry = newEntry.Entry; + else + safe_strcpy(const_cast(Identifier), std::string(newEntry.Identifier).c_str(), 64); + + return *this; + } +}; + struct rct_ride_filters { uint8_t category[2]; diff --git a/src/openrct2/object/ObjectRepository.cpp b/src/openrct2/object/ObjectRepository.cpp index b7f893213c..e9cb36ef1c 100644 --- a/src/openrct2/object/ObjectRepository.cpp +++ b/src/openrct2/object/ObjectRepository.cpp @@ -75,7 +75,7 @@ class ObjectFileIndex final : public FileIndex { private: static constexpr uint32_t MAGIC_NUMBER = 0x5844494F; // OIDX - static constexpr uint16_t VERSION = 23; + static constexpr uint16_t VERSION = 24; static constexpr auto PATTERN = "*.dat;*.pob;*.json;*.parkobj"; IObjectRepository& _objectRepository; @@ -163,7 +163,7 @@ protected: stream->WriteValue(static_cast(item.SceneryGroupInfo.Entries.size())); for (const auto& entry : item.SceneryGroupInfo.Entries) { - stream->WriteValue(entry); + stream->WriteObjectEntryDescriptor(entry); } break; default: @@ -211,10 +211,10 @@ protected: case ObjectType::SceneryGroup: { auto numEntries = stream->ReadValue(); - item.SceneryGroupInfo.Entries = std::vector(numEntries); + item.SceneryGroupInfo.Entries = std::vector(numEntries); for (size_t i = 0; i < numEntries; i++) { - item.SceneryGroupInfo.Entries[i] = stream->ReadValue(); + item.SceneryGroupInfo.Entries[i] = stream->ReadObjectEntryDescriptor(); } break; } @@ -310,6 +310,14 @@ public: return nullptr; } + const ObjectRepositoryItem* FindObject(const ObjectEntryDescriptor& entry) const override final + { + if (entry.Generation == ObjectGeneration::DAT) + return FindObject(&entry.Entry); + + return FindObject(entry.Identifier); + } + std::unique_ptr LoadObject(const ObjectRepositoryItem* ori) override { Guard::ArgumentNotNull(ori, GUARD_LINE); diff --git a/src/openrct2/object/ObjectRepository.h b/src/openrct2/object/ObjectRepository.h index 5b3a7cf877..5a7783f6ae 100644 --- a/src/openrct2/object/ObjectRepository.h +++ b/src/openrct2/object/ObjectRepository.h @@ -52,7 +52,7 @@ struct ObjectRepositoryItem } RideInfo; struct { - std::vector Entries; + std::vector Entries; } SceneryGroupInfo; ObjectSourceGame GetFirstSourceGame() const @@ -75,6 +75,7 @@ struct IObjectRepository virtual const ObjectRepositoryItem* FindObjectLegacy(const std::string_view& legacyIdentifier) const abstract; virtual const ObjectRepositoryItem* FindObject(std::string_view identifier) const abstract; virtual const ObjectRepositoryItem* FindObject(const rct_object_entry* objectEntry) const abstract; + virtual const ObjectRepositoryItem* FindObject(const ObjectEntryDescriptor& oed) const abstract; virtual std::unique_ptr LoadObject(const ObjectRepositoryItem* ori) abstract; virtual void RegisterLoadedObject(const ObjectRepositoryItem* ori, Object* object) abstract; diff --git a/src/openrct2/object/SceneryGroupObject.cpp b/src/openrct2/object/SceneryGroupObject.cpp index 341e77c2d6..a9f63c57a4 100644 --- a/src/openrct2/object/SceneryGroupObject.cpp +++ b/src/openrct2/object/SceneryGroupObject.cpp @@ -75,7 +75,7 @@ void SceneryGroupObject::UpdateEntryIndexes() _legacyType.entry_count = 0; for (const auto& objectEntry : _items) { - auto ori = objectRepository.FindObject(&objectEntry); + auto ori = objectRepository.FindObject(objectEntry); if (ori == nullptr) continue; if (ori->LoadedObject == nullptr) @@ -98,14 +98,14 @@ void SceneryGroupObject::SetRepositoryItem(ObjectRepositoryItem* item) const item->SceneryGroupInfo.Entries = _items; } -std::vector SceneryGroupObject::ReadItems(IStream* stream) +std::vector SceneryGroupObject::ReadItems(IStream* stream) { - auto items = std::vector(); + auto items = std::vector(); while (stream->ReadValue() != 0xFF) { stream->Seek(-1, STREAM_SEEK_CURRENT); auto entry = stream->ReadValue(); - items.push_back(entry); + items.push_back(ObjectEntryDescriptor(entry)); } return items; } @@ -166,13 +166,13 @@ EntertainerCostume SceneryGroupObject::ParseEntertainerCostume(const std::string return EntertainerCostume::Panda; } -std::vector SceneryGroupObject::ReadJsonEntries(json_t& jEntries) +std::vector SceneryGroupObject::ReadJsonEntries(json_t& jEntries) { - std::vector entries; + std::vector entries; for (auto& jEntry : jEntries) { - auto entry = ParseObjectEntry(Json::GetString(jEntry)); + auto entry = ObjectEntryDescriptor(Json::GetString(jEntry)); entries.push_back(entry); } return entries; diff --git a/src/openrct2/object/SceneryGroupObject.h b/src/openrct2/object/SceneryGroupObject.h index 7361e2ef5b..e3e9d889a2 100644 --- a/src/openrct2/object/SceneryGroupObject.h +++ b/src/openrct2/object/SceneryGroupObject.h @@ -22,7 +22,7 @@ class SceneryGroupObject final : public Object { private: rct_scenery_group_entry _legacyType = {}; - std::vector _items; + std::vector _items; public: explicit SceneryGroupObject(const rct_object_entry& entry) @@ -46,8 +46,8 @@ public: void SetRepositoryItem(ObjectRepositoryItem* item) const override; private: - static std::vector ReadItems(OpenRCT2::IStream* stream); + static std::vector ReadItems(OpenRCT2::IStream* stream); static uint32_t ReadJsonEntertainerCostumes(json_t& jCostumes); static EntertainerCostume ParseEntertainerCostume(const std::string& s); - static std::vector ReadJsonEntries(json_t& jEntries); + static std::vector ReadJsonEntries(json_t& jEntries); };