resource_list: loadFromString delega a parsers en namespace anònim

This commit is contained in:
2026-05-17 16:47:37 +02:00
parent e89a664eed
commit 6fbd5988d4
2 changed files with 78 additions and 101 deletions
+71 -96
View File
@@ -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<std::string>(), 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<std::string>(), prefix, system_folder);
const bool REQUIRED = !item.contains("required") || item["required"].get_value<bool>();
const bool ABSOLUTE = item.contains("absolute") && item["absolute"].get_value<bool>();
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<std::string>();
auto path = asset["path"].get_value<std::string>();
const bool REQUIRED = !asset.contains("required") || asset["required"].get_value<bool>();
const bool ABSOLUTE = asset.contains("absolute") && asset["absolute"].get_value<bool>();
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<std::string>();
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<std::string>();
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<std::string>(), 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<std::string>(), prefix, system_folder);
bool required = !item.contains("required") || item["required"].get_value<bool>();
bool absolute = item.contains("absolute") && item["absolute"].get_value<bool>();
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<std::string>();
auto path = asset["path"].get_value<std::string>();
bool required = true;
bool absolute = false;
if (asset.contains("required")) {
required = asset["required"].get_value<bool>();
}
if (asset.contains("absolute")) {
absolute = asset["absolute"].get_value<bool>();
}
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());
}
}
+7 -5
View File
@@ -42,6 +42,10 @@ namespace Resource {
[[nodiscard]] auto getListByType(Type type) const -> std::vector<std::string>;
[[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