diff --git a/CMakeLists.txt b/CMakeLists.txt index 37810899e0..d1318d8d7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,8 +41,8 @@ set(CMAKE_MACOSX_RPATH 1) set(TITLE_SEQUENCE_URL "https://github.com/OpenRCT2/title-sequences/releases/download/v0.1.2c/title-sequences.zip") set(TITLE_SEQUENCE_SHA1 "304d13a126c15bf2c86ff13b81a2f2cc1856ac8d") -set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v1.0.18/objects.zip") -set(OBJECTS_SHA1 "4a3c32a0251c3babe014844f2c683fc32138b3f2") +set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v1.0.20/objects.zip") +set(OBJECTS_SHA1 "151424d24b1d49a167932b58319bedaa6ec368e9") set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v0.0.22/replays.zip") set(REPLAYS_SHA1 "7591db0a3842a7ac44fcbfbff9a573c9cb3ddc56") diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 2875a0204f..88435687e0 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -3908,7 +3908,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "version=\"1.0.18\"\nzipname=\"objects.zip\"\nliburl=\"https://github.com/OpenRCT2/objects/releases/download/v$version/$zipname\"\n\n[[ ! -d \"${SRCROOT}/data/object\" || ! -e \"${SRCROOT}/objectsversion\" || $(head -n 1 \"${SRCROOT}/objectsversion\") != $version ]]\noutdated=$?\n\nif [[ $outdated -eq 0 ]]; then\nif [[ -d \"${SRCROOT}/data/object\" ]]; then rm -r \"${SRCROOT}/data/object\"; fi\nmkdir -p \"${SRCROOT}/data/object\"\n\ncurl -L -o \"${SRCROOT}/data/object/$zipname\" \"$liburl\"\nunzip -uaq -d \"${SRCROOT}/data/object\" \"${SRCROOT}/data/object/$zipname\"\nrm \"${SRCROOT}/data/object/$zipname\"\n\necho $version > \"${SRCROOT}/objectsversion\"\nfi"; + shellScript = "version=\"1.0.20\"\nzipname=\"objects.zip\"\nliburl=\"https://github.com/OpenRCT2/objects/releases/download/v$version/$zipname\"\n\n[[ ! -d \"${SRCROOT}/data/object\" || ! -e \"${SRCROOT}/objectsversion\" || $(head -n 1 \"${SRCROOT}/objectsversion\") != $version ]]\noutdated=$?\n\nif [[ $outdated -eq 0 ]]; then\nif [[ -d \"${SRCROOT}/data/object\" ]]; then rm -r \"${SRCROOT}/data/object\"; fi\nmkdir -p \"${SRCROOT}/data/object\"\n\ncurl -L -o \"${SRCROOT}/data/object/$zipname\" \"$liburl\"\nunzip -uaq -d \"${SRCROOT}/data/object\" \"${SRCROOT}/data/object/$zipname\"\nrm \"${SRCROOT}/data/object/$zipname\"\n\necho $version > \"${SRCROOT}/objectsversion\"\nfi"; }; C68B2D471EC790710020651C /* Download Libraries */ = { isa = PBXShellScriptBuildPhase; diff --git a/openrct2.proj b/openrct2.proj index 8ddc9c7e6a..099197a8fa 100644 --- a/openrct2.proj +++ b/openrct2.proj @@ -46,8 +46,8 @@ 058b9df80244c03f1633cb06e9f70471a29ebb8e https://github.com/OpenRCT2/title-sequences/releases/download/v0.1.2c/title-sequences.zip 304d13a126c15bf2c86ff13b81a2f2cc1856ac8d - https://github.com/OpenRCT2/objects/releases/download/v1.0.18/objects.zip - 4a3c32a0251c3babe014844f2c683fc32138b3f2 + https://github.com/OpenRCT2/objects/releases/download/v1.0.20/objects.zip + 151424d24b1d49a167932b58319bedaa6ec368e9 https://github.com/OpenRCT2/replays/releases/download/v0.0.22/replays.zip 7591db0a3842a7ac44fcbfbff9a573c9cb3ddc56 diff --git a/shell.nix b/shell.nix index b8e64d8b20..d28e07e766 100644 --- a/shell.nix +++ b/shell.nix @@ -15,8 +15,8 @@ let objects-src = pkgs.fetchFromGitHub { owner = "OpenRCT2"; repo = "objects"; - rev = "v1.0.18"; - sha256 = "bf8a28b7ccebaf58e4e9eb2540534632830534cf0b3f73677521dc555878c682"; + rev = "v1.0.20"; + sha256 = "bc266ef589c60302105473499ac142dbf951847be15e65b692d165ce261aeae0"; }; title-sequences-src = pkgs.fetchFromGitHub { 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); };