diff --git a/source/core/resources/resource_list.cpp b/source/core/resources/resource_list.cpp index 64d1b75..ef25380 100644 --- a/source/core/resources/resource_list.cpp +++ b/source/core/resources/resource_list.cpp @@ -16,6 +16,71 @@ namespace Resource { + namespace { + // Un item del format modern: pot ser string (path) o mapping ({path, required?, absolute?}) + void parseAssetItem(List& list, const fkyaml::node& item, List::Type type, const std::string& prefix, const std::string& system_folder, const std::string& category, const std::string& type_str) { + try { + if (item.is_string()) { + auto path = List::replaceVariables(item.get_value(), prefix, system_folder); + list.add(path, type, true, false); + return; + } + if (item.is_mapping() && item.contains("path")) { + auto path = List::replaceVariables(item["path"].get_value(), prefix, system_folder); + const bool REQUIRED = !item.contains("required") || item["required"].get_value(); + const bool ABSOLUTE = item.contains("absolute") && item["absolute"].get_value(); + list.add(path, type, REQUIRED, ABSOLUTE); + return; + } + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: Invalid item in type '%s', category '%s', skipping", type_str.c_str(), category.c_str()); + } catch (const std::exception& e) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error parsing asset in category '%s', type '%s': %s", category.c_str(), type_str.c_str(), e.what()); + } + } + + // (TIPO: [items...]) del format modern. Itera els items i delega a parseAssetItem. + void parseModernType(List& list, const fkyaml::node& items_node, List::Type type, const std::string& type_str, const std::string& category, const std::string& prefix, const std::string& system_folder) { + if (!items_node.is_sequence()) { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: Type '%s' in category '%s' is not a sequence, skipping", type_str.c_str(), category.c_str()); + return; + } + for (const auto& item : items_node) { + parseAssetItem(list, item, type, prefix, system_folder, category, type_str); + } + } + + // {type, path, required?, absolute?} del format antic + void parseLegacyAsset(List& list, const fkyaml::node& asset, const std::string& category, const std::string& prefix, const std::string& system_folder) { + try { + if (!asset.contains("type") || !asset.contains("path")) { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: Asset in category '%s' missing 'type' or 'path', skipping", category.c_str()); + return; + } + auto type_str = asset["type"].get_value(); + auto path = asset["path"].get_value(); + const bool REQUIRED = !asset.contains("required") || asset["required"].get_value(); + const bool ABSOLUTE = asset.contains("absolute") && asset["absolute"].get_value(); + path = List::replaceVariables(path, prefix, system_folder); + list.add(path, List::parseAssetType(type_str), REQUIRED, ABSOLUTE); + } catch (const std::exception& e) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error parsing asset in category '%s': %s", category.c_str(), e.what()); + } + } + + // Categoria amb format modern (TIPO → [items]). Itera els tipus. + void parseModernCategory(List& list, const fkyaml::node& category_assets, const std::string& category, const std::string& prefix, const std::string& system_folder) { + for (auto type_it = category_assets.begin(); type_it != category_assets.end(); ++type_it) { + try { + auto type_str = type_it.key().get_value(); + const List::Type TYPE = List::parseAssetType(type_str); + parseModernType(list, type_it.value(), TYPE, type_str, category, prefix, system_folder); + } catch (const std::exception& e) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error parsing type in category '%s': %s", category.c_str(), e.what()); + } + } + } + } // namespace + // Singleton List* List::instance = nullptr; @@ -160,17 +225,13 @@ namespace Resource { } // Carga recursos desde un string de configuración (para release con pack) - void List::loadFromString(const std::string& config_content, const std::string& prefix, const std::string& system_folder) { // NOLINT(readability-function-cognitive-complexity) + void List::loadFromString(const std::string& config_content, const std::string& prefix, const std::string& system_folder) { try { - // Parsear YAML auto yaml = fkyaml::node::deserialize(config_content); - - // Verificar estructura básica if (!yaml.contains("assets")) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Invalid assets.yaml format - missing 'assets' key"); return; } - const auto& assets = yaml["assets"]; // Iterar sobre cada categoría (fonts, palettes, etc.) @@ -179,105 +240,19 @@ namespace Resource { const auto& category_assets = it.value(); if (category_assets.is_mapping()) { - // Nuevo formato: categoría → { TIPO: [paths...], TIPO2: [paths...] } - for (auto type_it = category_assets.begin(); type_it != category_assets.end(); ++type_it) { - try { - auto type_str = type_it.key().get_value(); - Type type = parseAssetType(type_str); - const auto& items = type_it.value(); - - if (!items.is_sequence()) { - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, - "Warning: Type '%s' in category '%s' is not a sequence, skipping", - type_str.c_str(), - category.c_str()); - continue; - } - - for (const auto& item : items) { - try { - if (item.is_string()) { - // Formato simple: solo el path - auto path = replaceVariables(item.get_value(), prefix, system_folder); - addToMap(path, type, true, false); - } else if (item.is_mapping() && item.contains("path")) { - // Formato expandido: { path, required?, absolute? } - auto path = replaceVariables(item["path"].get_value(), prefix, system_folder); - bool required = !item.contains("required") || item["required"].get_value(); - bool absolute = item.contains("absolute") && item["absolute"].get_value(); - addToMap(path, type, required, absolute); - } else { - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, - "Warning: Invalid item in type '%s', category '%s', skipping", - type_str.c_str(), - category.c_str()); - } - } catch (const std::exception& e) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "Error parsing asset in category '%s', type '%s': %s", - category.c_str(), - type_str.c_str(), - e.what()); - } - } - } catch (const std::exception& e) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "Error parsing type in category '%s': %s", - category.c_str(), - e.what()); - } - } + parseModernCategory(*this, category_assets, category, prefix, system_folder); } else if (category_assets.is_sequence()) { - // Formato antiguo (retrocompatibilidad): categoría → [{type, path}, ...] - for (const auto& asset : category_assets) { - try { - if (!asset.contains("type") || !asset.contains("path")) { - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, - "Warning: Asset in category '%s' missing 'type' or 'path', skipping", - category.c_str()); - continue; - } - - auto type_str = asset["type"].get_value(); - auto path = asset["path"].get_value(); - bool required = true; - bool absolute = false; - - if (asset.contains("required")) { - required = asset["required"].get_value(); - } - if (asset.contains("absolute")) { - absolute = asset["absolute"].get_value(); - } - - path = replaceVariables(path, prefix, system_folder); - Type type = parseAssetType(type_str); - addToMap(path, type, required, absolute); - - } catch (const std::exception& e) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "Error parsing asset in category '%s': %s", - category.c_str(), - e.what()); - } - } + for (const auto& asset : category_assets) { parseLegacyAsset(*this, asset, category, prefix, system_folder); } } else { - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, - "Warning: Category '%s' has invalid format, skipping", - category.c_str()); + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: Category '%s' has invalid format, skipping", category.c_str()); } } std::cout << "Loaded " << file_list_.size() << " assets from YAML config" << '\n'; - } catch (const fkyaml::exception& e) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "YAML parsing error: %s", - e.what()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "YAML parsing error: %s", e.what()); } catch (const std::exception& e) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "Error loading assets: %s", - e.what()); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error loading assets: %s", e.what()); } } diff --git a/source/core/resources/resource_list.hpp b/source/core/resources/resource_list.hpp index 731e0de..c791f79 100644 --- a/source/core/resources/resource_list.hpp +++ b/source/core/resources/resource_list.hpp @@ -42,6 +42,10 @@ namespace Resource { [[nodiscard]] auto getListByType(Type type) const -> std::vector; [[nodiscard]] auto exists(const std::string& filename) const -> bool; // Verifica si un asset existe + // --- Helpers static (públics perquè els fan servir parsers externs del .cpp) --- + [[nodiscard]] static auto parseAssetType(const std::string& type_str) -> Type; // Convierte string a tipo + [[nodiscard]] static auto replaceVariables(const std::string& path, const std::string& prefix, const std::string& system_folder) -> std::string; // Reemplaza variables en la ruta + private: // --- Estructuras privadas --- struct Item { @@ -62,11 +66,9 @@ namespace Resource { std::string prefix_; // Prefijo para rutas (${PREFIX}) // --- Métodos internos --- - [[nodiscard]] static auto getTypeName(Type type) -> std::string; // Obtiene el nombre del tipo - [[nodiscard]] static auto parseAssetType(const std::string& type_str) -> Type; // Convierte string a tipo - void addToMap(const std::string& file_path, Type type, bool required, bool absolute); // Añade archivo al mapa - [[nodiscard]] static auto replaceVariables(const std::string& path, const std::string& prefix, const std::string& system_folder) -> std::string; // Reemplaza variables en la ruta - static auto parseOptions(const std::string& options, bool& required, bool& absolute) -> void; // Parsea opciones + [[nodiscard]] static auto getTypeName(Type type) -> std::string; // Obtiene el nombre del tipo + void addToMap(const std::string& file_path, Type type, bool required, bool absolute); // Añade archivo al mapa + static auto parseOptions(const std::string& options, bool& required, bool& absolute) -> void; // Parsea opciones // --- Constructores y destructor privados (singleton) --- explicit List(std::string executable_path) // Constructor privado