From 2935a3d71bdd7cef7a665fb9983e5562e24aac43 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 21 Dec 2025 16:14:20 +1000 Subject: [PATCH] Common: Add additional ryml helpers --- src/common/ryml_helpers.h | 58 +++++++++++++++++++++++++++++++++++-- src/core/game_database.cpp | 8 ++--- src/core/gpu_presenter.cpp | 12 ++++---- src/core/memory_scanner.cpp | 2 +- 4 files changed, 67 insertions(+), 13 deletions(-) diff --git a/src/common/ryml_helpers.h b/src/common/ryml_helpers.h index 2911dd42c..1c6c85951 100644 --- a/src/common/ryml_helpers.h +++ b/src/common/ryml_helpers.h @@ -2,10 +2,11 @@ // SPDX-License-Identifier: CC-BY-NC-ND-4.0 #include "log.h" -#include "small_string.h" #include "string_util.h" #include "types.h" +#include "common/small_string.h" + #include "ryml.hpp" #include @@ -56,8 +57,34 @@ inline bool GetStringFromObject(const ryml::ConstNodeRef& object, std::string_vi return true; } +inline bool GetBoolFromObject(const ryml::ConstNodeRef& object, std::string_view key, bool* dest) +{ + *dest = 0; + + const ryml::ConstNodeRef member = object.find_child(to_csubstr(key)); + if (!member.valid()) + return false; + + const c4::csubstr val = member.val(); + if (val.empty()) + { + GENERIC_LOG(Log::Channel::Log, Log::Level::Error, Log::Color::StrongOrange, "Unexpected empty value in {}", key); + return false; + } + + const std::optional opt_value = StringUtil::FromChars(to_stringview(val)); + if (!opt_value.has_value()) + { + GENERIC_LOG(Log::Channel::Log, Log::Level::Error, Log::Color::StrongOrange, "Unexpected non-bool value in {}", key); + return false; + } + + *dest = opt_value.value(); + return true; +} + template -inline bool GetUIntFromObject(const ryml::ConstNodeRef& object, std::string_view key, T* dest) +inline bool GetIntFromObject(const ryml::ConstNodeRef& object, std::string_view key, T* dest) { *dest = 0; @@ -83,6 +110,33 @@ inline bool GetUIntFromObject(const ryml::ConstNodeRef& object, std::string_view return true; } +static inline bool GetFloatFromObject(const ryml::ConstNodeRef& object, std::string_view key, float* dest) +{ + *dest = 0; + + const ryml::ConstNodeRef member = object.find_child(to_csubstr(key)); + if (!member.valid()) + return false; + + const c4::csubstr val = member.val(); + if (val.empty()) + { + GENERIC_LOG(Log::Channel::Log, Log::Level::Error, Log::Color::StrongOrange, "Unexpected empty value in {}", key); + return false; + } + + const std::optional opt_value = StringUtil::FromChars(to_stringview(val)); + if (!opt_value.has_value()) + { + GENERIC_LOG(Log::Channel::Log, Log::Level::Error, Log::Color::StrongOrange, "Unexpected non-float value in {}", + key); + return false; + } + + *dest = opt_value.value(); + return true; +} + template inline std::optional GetOptionalTFromObject(const ryml::ConstNodeRef& object, std::string_view key) { diff --git a/src/core/game_database.cpp b/src/core/game_database.cpp index f73b46b5d..f43fd40e6 100644 --- a/src/core/game_database.cpp +++ b/src/core/game_database.cpp @@ -1467,10 +1467,10 @@ bool GameDatabase::ParseYamlEntry(Entry* entry, const ryml::ConstNodeRef& value) GetStringFromObject(metadata, "developer", &entry->developer); GetStringFromObject(metadata, "publisher", &entry->publisher); - GetUIntFromObject(metadata, "minPlayers", &entry->min_players); - GetUIntFromObject(metadata, "maxPlayers", &entry->max_players); - GetUIntFromObject(metadata, "minBlocks", &entry->min_blocks); - GetUIntFromObject(metadata, "maxBlocks", &entry->max_blocks); + GetIntFromObject(metadata, "minPlayers", &entry->min_players); + GetIntFromObject(metadata, "maxPlayers", &entry->max_players); + GetIntFromObject(metadata, "minBlocks", &entry->min_blocks); + GetIntFromObject(metadata, "maxBlocks", &entry->max_blocks); if (const ryml::ConstNodeRef languages = metadata.find_child(to_csubstr("languages")); languages.valid()) { diff --git a/src/core/gpu_presenter.cpp b/src/core/gpu_presenter.cpp index fa5e78f27..40ceb1d4a 100644 --- a/src/core/gpu_presenter.cpp +++ b/src/core/gpu_presenter.cpp @@ -1670,12 +1670,12 @@ bool GPUPresenter::LoadOverlayPreset(Error* error, Image* image) bool alpha_blend = false; bool destination_alpha_blend = false; if (!GetStringFromObject(root, "image", &image_filename) || - !GetUIntFromObject(root, "displayStartX", &display_area.x) || - !GetUIntFromObject(root, "displayStartY", &display_area.y) || - !GetUIntFromObject(root, "displayEndX", &display_area.z) || - !GetUIntFromObject(root, "displayEndY", &display_area.w) || - !GetUIntFromObject(root, "alphaBlend", &alpha_blend) || - !GetUIntFromObject(root, "destinationAlphaBlend", &destination_alpha_blend)) + !GetIntFromObject(root, "displayStartX", &display_area.x) || + !GetIntFromObject(root, "displayStartY", &display_area.y) || + !GetIntFromObject(root, "displayEndX", &display_area.z) || + !GetIntFromObject(root, "displayEndY", &display_area.w) || + !GetIntFromObject(root, "alphaBlend", &alpha_blend) || + !GetIntFromObject(root, "destinationAlphaBlend", &destination_alpha_blend)) { Error::SetStringView(error, "One or more parameters is missing."); return false; diff --git a/src/core/memory_scanner.cpp b/src/core/memory_scanner.cpp index c2dd509c5..f1ec92e9c 100644 --- a/src/core/memory_scanner.cpp +++ b/src/core/memory_scanner.cpp @@ -522,7 +522,7 @@ bool MemoryWatchList::LoadFromFile(const char* path, Error* error) std::optional parsed_address; if (!GetStringFromObject(child, "description", &entry.description) || !GetStringFromObject(child, "address", &address) || !GetStringFromObject(child, "size", &size) || - !GetUIntFromObject(child, "isSigned", &entry.is_signed) || !GetUIntFromObject(child, "freeze", &entry.freeze) || + !GetIntFromObject(child, "isSigned", &entry.is_signed) || !GetIntFromObject(child, "freeze", &entry.freeze) || !(parsed_address = StringUtil::FromCharsWithOptionalBase(address)).has_value() || (size != "byte" && size != "halfword" && size != "word")) {