#include "core/resources/resource_helper.hpp" #include #include #include #include #include "core/resources/resource_pack.hpp" namespace Resource::Helper { namespace { std::string g_data_root; Pack g_pack; bool g_pack_loaded = false; bool g_fallback_enabled = true; // Inverteix la prioritat (disc abans que pack). Activat en Debug // per defecte; veure setPreferDisk al header. bool g_prefer_disk = false; auto readFromDisk(const std::string& filepath, bool verbose = true) -> std::vector { const auto FULL = resolve(filepath); std::ifstream file(FULL, std::ios::binary | std::ios::ate); if (!file) { // Silenciem si veníem de prefer_disk: aleshores caurem // al pack i no és cap error real que el fitxer no estigui // al disc. if (verbose) { std::cerr << "Resource::Helper: cannot open " << FULL << '\n'; } return {}; } std::streamsize size = file.tellg(); file.seekg(0, std::ios::beg); std::vector data(static_cast(size)); if (!file.read(reinterpret_cast(data.data()), size)) { std::cerr << "Resource::Helper: failed to read " << FULL << '\n'; return {}; } return data; } } // namespace auto initializeResourceSystem(const std::string& pack_file, bool enable_fallback) -> bool { g_fallback_enabled = enable_fallback; // En el flux Debug típic (fallback actiu, source tree disponible) // preferim sempre disc: el desenvolupador edita YAML/GIF a `data/` // i ho veu reflectit al següent reload sense re-packejar. En // Release el fallback està desactivat i aquest flag és inert. g_prefer_disk = enable_fallback; g_pack_loaded = g_pack.loadPack(pack_file); if (g_pack_loaded) { std::cout << "Resource::Helper: pack loaded (" << g_pack.getResourceCount() << " entries) from " << pack_file << '\n'; } else if (enable_fallback) { std::cout << "Resource::Helper: no pack at " << pack_file << " — using filesystem fallback\n"; } else { std::cerr << "Resource::Helper: FATAL — no pack at " << pack_file << " and fallback disabled\n"; return false; } return true; } void shutdownResourceSystem() { g_pack.clear(); g_pack_loaded = false; } auto hasPack() -> bool { return g_pack_loaded; } void setDataRoot(const std::string& absolute_path) { g_data_root = absolute_path; if (!g_data_root.empty() && g_data_root.back() != '/') { g_data_root += '/'; } } auto resolve(const std::string& filepath) -> std::string { if (filepath.empty() || filepath.front() == '/') { return filepath; } if (g_data_root.empty()) { return filepath; } return g_data_root + filepath; } auto loadFile(const std::string& filepath) -> std::vector { // Helper local: lookup al pack normalitzant la clau (els callers // passen "data/foo.yaml" però l'índex del pack és relatiu a la // carpeta `data/`). const auto FROM_PACK = [&filepath]() -> std::vector { if (!g_pack_loaded) { return {}; } constexpr std::string_view PREFIX = "data/"; std::string key = filepath; if (key.starts_with(PREFIX)) { key.erase(0, PREFIX.size()); } if (g_pack.hasResource(key)) { return g_pack.getResource(key); } return {}; }; if (g_prefer_disk && g_fallback_enabled) { // En Debug volem que el disc guanyi: així les edicions del // editor in-game (i les manuals del repo) es vegen al pròxim // reload sense rebuild del pack. Si el fitxer no és al disc, // caiem al pack — útil per a recursos que només s'han // empaquetat (cas estrany). El silenci a `readFromDisk` evita // emplenar el log amb "cannot open" en aquest camí esperat. auto bytes = readFromDisk(filepath, false); if (!bytes.empty()) { return bytes; } return FROM_PACK(); } // Política original: pack primer; disc com a fallback si el // recurs no està empaquetat (típic d'arrencada en Debug abans // del primer pack). auto packed = FROM_PACK(); if (!packed.empty()) { return packed; } if (g_fallback_enabled) { return readFromDisk(filepath); } return {}; } void setPreferDisk(bool prefer) { g_prefer_disk = prefer; } auto preferDisk() -> bool { return g_prefer_disk; } } // namespace Resource::Helper