#include "core/resources/asset.h" #include #include // for size_t #include // for basic_ostream, operator<<, cout, endl #include "core/resources/resource_helper.h" #include "core/resources/skin_manager.hpp" // Instancia única Asset *Asset::instance = nullptr; // Singleton API void Asset::init(const std::string &executable_path) { Asset::instance = new Asset(executable_path); } void Asset::destroy() { delete Asset::instance; Asset::instance = nullptr; } auto Asset::get() -> Asset * { return Asset::instance; } // Constructor Asset::Asset(const std::string &executable_path) : executable_path_(executable_path.substr(0, executable_path.find_last_of("\\/"))) { } // Añade un elemento a la lista void Asset::add(const std::string &file, Type type, bool required, bool absolute) { Item temp; temp.file = absolute ? file : executable_path_ + file; temp.type = type; temp.required = required; file_list_.push_back(temp); const std::string FILE_NAME = file.substr(file.find_last_of("\\/") + 1); longest_name_ = SDL_max(longest_name_, FILE_NAME.size()); } // Afegeix un asset gfx skin-aware: el path complet es composa via // SkinManager (que ja inclou el PREFIX de plataforma) i guardem el // basename per a poder-lo recomposar quan canviï la skin activa. void Asset::addSkinAware(const std::string &basename, Type type, bool required) { Item temp; temp.file = executable_path_ + SkinManager::get()->gfxPath(basename); temp.type = type; temp.required = required; temp.skin_basename = basename; file_list_.push_back(temp); longest_name_ = SDL_max(longest_name_, basename.size()); } // Recomposa els paths dels items skin-aware amb l'skin actual del // SkinManager. Cridat per Resource::reloadForSkin després d'un canvi. void Asset::onSkinChanged() { for (auto &it : file_list_) { if (!it.skin_basename.empty()) { it.file = executable_path_ + SkinManager::get()->gfxPath(it.skin_basename); } } } // Devuelve el fichero de un elemento de la lista a partir de una cadena auto Asset::get(const std::string &text) -> std::string { for (const auto &f : file_list_) { const size_t LAST_INDEX = f.file.find_last_of('/') + 1; const std::string FILE_NAME = f.file.substr(LAST_INDEX); if (FILE_NAME == text) { return f.file; } } if (verbose_) { std::cout << "Warning: file " << text.c_str() << " not found" << '\n'; } return ""; } // Comprueba que existen todos los elementos auto Asset::check() -> bool { bool success = true; if (verbose_) { std::cout << "\n** Checking files" << '\n'; std::cout << "Executable path is: " << executable_path_ << '\n'; std::cout << "Sample filepath: " << file_list_.back().file << '\n'; } // Comprueba la lista de ficheros clasificandolos por tipo for (int i = 0; i < static_cast(Type::COUNT); ++i) { const Type TYPE = static_cast(i); // Comprueba si hay ficheros de ese tipo bool any = false; for (const auto &f : file_list_) { if (f.required && f.type == TYPE) { any = true; } } // Si hay ficheros de ese tipo, comprueba si existen if (any) { if (verbose_) { std::cout << "\n>> " << getTypeName(TYPE).c_str() << " FILES" << '\n'; } for (const auto &f : file_list_) { if (f.required && f.type == TYPE) { success &= checkFile(f.file); } } } } // Resultado if (verbose_) { if (success) { std::cout << "\n** All files OK.\n" << '\n'; } else { std::cout << "\n** A file is missing. Exiting.\n" << '\n'; } } return success; } // Comprueba que existe un fichero auto Asset::checkFile(const std::string &path) const -> bool { bool success = false; std::string result = "ERROR"; // Comprueba si existe el fichero (pack o filesystem) const std::string FILE_NAME = path.substr(path.find_last_of("\\/") + 1); if (ResourceHelper::shouldUseResourcePack(path)) { auto bytes = ResourceHelper::loadFile(path); if (!bytes.empty()) { result = "OK"; success = true; } } else { SDL_IOStream *file = SDL_IOFromFile(path.c_str(), "rb"); if (file != nullptr) { result = "OK"; success = true; SDL_CloseIO(file); } } if (verbose_) { std::cout.setf(std::ios::left, std::ios::adjustfield); std::cout << "Checking file: "; std::cout.width(longest_name_ + 2); std::cout.fill('.'); std::cout << FILE_NAME + " "; std::cout << " [" + result + "]" << '\n'; } return success; } // Devuelve el nombre del tipo de recurso auto Asset::getTypeName(Type type) -> std::string { switch (type) { case Type::BITMAP: return "BITMAP"; case Type::MUSIC: return "MUSIC"; case Type::SOUND: return "SOUND"; case Type::FONT: return "FONT"; case Type::LANG: return "LANG"; case Type::DATA: return "DATA"; case Type::ROOM: return "ROOM"; case Type::ENEMY: return "ENEMY"; case Type::ITEM: return "ITEM"; case Type::COUNT: default: return "ERROR"; } } // Establece si ha de mostrar texto por pantalla void Asset::setVerbose(bool value) { verbose_ = value; }