From c82c4ca3a30a657a1f730c7ab94c382353d68f9d Mon Sep 17 00:00:00 2001 From: spacek531 Date: Sat, 7 Jan 2023 14:25:39 -0800 Subject: [PATCH] Load object version into a tuple --- src/openrct2/object/Object.cpp | 48 ++++++++++++++++++++++++++ src/openrct2/object/Object.h | 15 +++++--- src/openrct2/object/ObjectFactory.cpp | 2 +- src/openrct2/object/ObjectRepository.h | 2 +- src/openrct2/park/ParkFile.cpp | 4 +-- 5 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/openrct2/object/Object.cpp b/src/openrct2/object/Object.cpp index cc598f6d76..417a45b066 100644 --- a/src/openrct2/object/Object.cpp +++ b/src/openrct2/object/Object.cpp @@ -329,6 +329,54 @@ std::unique_ptr ObjectAsset::GetStream() const return {}; } +u8string VersionString(const ObjectVersion& version) +{ + return std::to_string(std::get<0>(version)) + "." + std::to_string(std::get<1>(version)) + "." + + std::to_string(std::get<2>(version)); +} + +ObjectVersion VersionTuple(std::string_view version) +{ + if (version.empty()) + { + return std::make_tuple(0, 0, 0); + } + + auto nums = String::Split(version, "."); + uint16_t versions[VersionNumFields] = {}; + if (nums.size() > VersionNumFields) + { + log_warning("%i fields found in version string '%s', expected X.Y.Z", nums.size(), version); + } + if (nums.size() == 0) + { + log_warning("No fields found in version string '%s', expected X.Y.Z", version); + return std::make_tuple(0, 0, 0); + } + try + { + size_t highestIndex = std::min(nums.size(), VersionNumFields); + for (size_t i = 0; i < highestIndex; i++) + { + auto value = stoi(nums.at(i)); + constexpr auto maxValue = std::numeric_limits().max(); + if (value > maxValue) + { + log_warning( + "Version value too high in version string '%s', version value will be capped to %i.", version, maxValue); + value = maxValue; + } + versions[i] = value; + } + } + catch (const std::exception&) + { + log_warning("Malformed version string '%s', expected X.Y.Z", version); + } + + return std::make_tuple(versions[0], versions[1], versions[2]); +} + #ifdef __WARN_SUGGEST_FINAL_METHODS__ # pragma GCC diagnostic pop #endif diff --git a/src/openrct2/object/Object.h b/src/openrct2/object/Object.h index 866afaecec..9838bd34b4 100644 --- a/src/openrct2/object/Object.h +++ b/src/openrct2/object/Object.h @@ -29,6 +29,10 @@ constexpr const ObjectEntryIndex OBJECT_ENTRY_INDEX_NULL = std::numeric_limits; +static_assert(std::tuple_size{} == VersionNumFields); + // First 0xF of rct_object_entry->flags enum class ObjectType : uint8_t { @@ -192,7 +196,7 @@ struct ObjectEntryDescriptor // JSON ObjectType Type{}; std::string Identifier; - std::string Version; + ObjectVersion Version; ObjectEntryDescriptor() = default; explicit ObjectEntryDescriptor(const rct_object_entry& newEntry); @@ -250,7 +254,7 @@ class Object { private: std::string _identifier; - std::string _version; + ObjectVersion _version; ObjectEntryDescriptor _descriptor{}; StringTable _stringTable; ImageTable _imageTable; @@ -364,11 +368,11 @@ public: const std::vector& GetAuthors() const; void SetAuthors(std::vector&& authors); - const std::string& GetVersion() const + const ObjectVersion& GetVersion() const { return _version; } - void SetVersion(const std::string& version) + void SetVersion(const ObjectVersion& version) { _version = version; } @@ -406,3 +410,6 @@ constexpr bool IsIntransientObjectType(ObjectType type) { return type == ObjectType::Audio; } + +u8string VersionString(const ObjectVersion& version); +ObjectVersion VersionTuple(std::string_view version); diff --git a/src/openrct2/object/ObjectFactory.cpp b/src/openrct2/object/ObjectFactory.cpp index 44ef0052f7..b150a0ec6a 100644 --- a/src/openrct2/object/ObjectFactory.cpp +++ b/src/openrct2/object/ObjectFactory.cpp @@ -521,7 +521,7 @@ namespace ObjectFactory if (id == OpenRCT2::Audio::AudioObjectIdentifiers::Rct2cBase) id = OpenRCT2::Audio::AudioObjectIdentifiers::Rct2Base; - auto version = Json::GetString(jRoot["version"]); + auto version = VersionTuple(Json::GetString(jRoot["version"])); ObjectEntryDescriptor descriptor; auto originalId = Json::GetString(jRoot["originalId"]); if (originalId.length() == 8 + 1 + 8 + 1 + 8) diff --git a/src/openrct2/object/ObjectRepository.h b/src/openrct2/object/ObjectRepository.h index 260fcaa341..6d36314e19 100644 --- a/src/openrct2/object/ObjectRepository.h +++ b/src/openrct2/object/ObjectRepository.h @@ -43,7 +43,7 @@ struct ObjectRepositoryItem rct_object_entry ObjectEntry; std::string Path; std::string Name; - std::string Version; + ObjectVersion Version; std::vector Authors; std::vector Sources; std::shared_ptr LoadedObject{}; diff --git a/src/openrct2/park/ParkFile.cpp b/src/openrct2/park/ParkFile.cpp index 5ba40961ff..ce67c872f4 100644 --- a/src/openrct2/park/ParkFile.cpp +++ b/src/openrct2/park/ParkFile.cpp @@ -346,7 +346,7 @@ namespace OpenRCT2 } } desc.Identifier = identifier; - desc.Version = cs.Read(); + desc.Version = VersionTuple(cs.Read()); if (version <= 2) { @@ -395,7 +395,7 @@ namespace OpenRCT2 { cs.Write(DESCRIPTOR_JSON); cs.Write(entry.Identifier); - cs.Write(entry.Version); + cs.Write(VersionString(entry.Version)); } else {