afegit resources.pack y prefixe a les rutes de recursos
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -18,6 +18,11 @@ asteroids
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Releases
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.dmg
|
||||
|
||||
# Compiled Object files
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
@@ -73,6 +73,11 @@ target_compile_options(${PROJECT_NAME} PRIVATE $<$<CONFIG:RELEASE>:-O2 -ffunctio
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<CONFIG:DEBUG>:_DEBUG>)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<CONFIG:RELEASE>:RELEASE_BUILD>)
|
||||
|
||||
# Definir MACOS_BUNDLE si es un bundle de macOS
|
||||
if(APPLE AND MACOSX_BUNDLE)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUNDLE)
|
||||
endif()
|
||||
|
||||
# Configuración específica para cada plataforma
|
||||
if(WIN32)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE WINDOWS_BUILD)
|
||||
|
||||
22
Makefile
22
Makefile
@@ -58,6 +58,20 @@ else
|
||||
UNAME_S := $(shell uname -s)
|
||||
endif
|
||||
|
||||
# ==============================================================================
|
||||
# PACKING TOOL
|
||||
# ==============================================================================
|
||||
PACK_TOOL := tools/pack_resources/pack_resources
|
||||
|
||||
.PHONY: pack_tool resources.pack
|
||||
|
||||
pack_tool:
|
||||
@$(MAKE) -C tools/pack_resources
|
||||
|
||||
resources.pack: pack_tool
|
||||
@echo "Creating resources.pack..."
|
||||
@./$(PACK_TOOL) data resources.pack
|
||||
|
||||
# ==============================================================================
|
||||
# TARGETS
|
||||
# ==============================================================================
|
||||
@@ -87,7 +101,7 @@ debug:
|
||||
|
||||
# macOS Release (Apple Silicon)
|
||||
.PHONY: macos_release
|
||||
macos_release:
|
||||
macos_release: pack_tool resources.pack
|
||||
@echo "Creating macOS release - Version: $(VERSION)"
|
||||
|
||||
# Check/install create-dmg
|
||||
@@ -104,8 +118,8 @@ macos_release:
|
||||
@$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
@$(MKDIR) Frameworks
|
||||
|
||||
# Copy resources
|
||||
@cp -r resources "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources/"
|
||||
# Copy resources.pack to Resources
|
||||
@cp resources.pack "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources/"
|
||||
@ditto release/frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks/SDL3.framework"
|
||||
@ditto release/frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework Frameworks/SDL3.framework
|
||||
|
||||
@@ -313,6 +327,8 @@ else
|
||||
@$(RMFILE) $(TARGET_FILE) $(TARGET_FILE)_debug
|
||||
@$(RMDIR) build $(RELEASE_FOLDER)
|
||||
@$(RMFILE) *.dmg *.zip *.tar.gz 2>/dev/null || true
|
||||
@$(RMFILE) resources.pack 2>/dev/null || true
|
||||
@$(MAKE) -C tools/pack_resources clean 2>/dev/null || true
|
||||
endif
|
||||
@echo "Clean complete"
|
||||
|
||||
|
||||
BIN
resources.pack
Normal file
BIN
resources.pack
Normal file
Binary file not shown.
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "core/audio/audio_cache.hpp"
|
||||
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// Inicialització de variables estàtiques
|
||||
@@ -19,17 +21,28 @@ JA_Sound_t* AudioCache::getSound(const std::string& name) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Cache miss - cargar archivo
|
||||
std::string fullpath = resolveSoundPath(name);
|
||||
JA_Sound_t* sound = JA_LoadSound(fullpath.c_str());
|
||||
// Normalize path: "laser_shoot.wav" → "sounds/laser_shoot.wav"
|
||||
std::string normalized = name;
|
||||
if (normalized.find("sounds/") != 0 && normalized.find('/') == std::string::npos) {
|
||||
normalized = "sounds/" + normalized;
|
||||
}
|
||||
|
||||
// Load from resource system
|
||||
std::vector<uint8_t> data = Resource::Helper::loadFile(normalized);
|
||||
if (data.empty()) {
|
||||
std::cerr << "[AudioCache] Error: no s'ha pogut carregar " << normalized << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Load sound from memory
|
||||
JA_Sound_t* sound = JA_LoadSound(data.data(), static_cast<uint32_t>(data.size()));
|
||||
if (sound == nullptr) {
|
||||
std::cerr << "[AudioCache] Error: no s'ha pogut carregar " << fullpath
|
||||
std::cerr << "[AudioCache] Error: no s'ha pogut decodificar " << normalized
|
||||
<< std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::cout << "[AudioCache] Sound loaded: " << name << std::endl;
|
||||
std::cout << "[AudioCache] Sound loaded: " << normalized << std::endl;
|
||||
sounds_[name] = sound;
|
||||
return sound;
|
||||
}
|
||||
@@ -42,17 +55,28 @@ JA_Music_t* AudioCache::getMusic(const std::string& name) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Cache miss - cargar archivo
|
||||
std::string fullpath = resolveMusicPath(name);
|
||||
JA_Music_t* music = JA_LoadMusic(fullpath.c_str());
|
||||
// Normalize path: "title.ogg" → "music/title.ogg"
|
||||
std::string normalized = name;
|
||||
if (normalized.find("music/") != 0 && normalized.find('/') == std::string::npos) {
|
||||
normalized = "music/" + normalized;
|
||||
}
|
||||
|
||||
// Load from resource system
|
||||
std::vector<uint8_t> data = Resource::Helper::loadFile(normalized);
|
||||
if (data.empty()) {
|
||||
std::cerr << "[AudioCache] Error: no s'ha pogut carregar " << normalized << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Load music from memory
|
||||
JA_Music_t* music = JA_LoadMusic(data.data(), static_cast<uint32_t>(data.size()));
|
||||
if (music == nullptr) {
|
||||
std::cerr << "[AudioCache] Error: no s'ha pogut carregar " << fullpath
|
||||
std::cerr << "[AudioCache] Error: no s'ha pogut decodificar " << normalized
|
||||
<< std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::cout << "[AudioCache] Music loaded: " << name << std::endl;
|
||||
std::cout << "[AudioCache] Music loaded: " << normalized << std::endl;
|
||||
musics_[name] = music;
|
||||
return music;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,9 @@ class Shape {
|
||||
// Carregar forma des de fitxer .shp
|
||||
bool carregar(const std::string& filepath);
|
||||
|
||||
// Parsejar forma des de buffer de memòria (per al sistema de recursos)
|
||||
bool parsejar_fitxer(const std::string& contingut);
|
||||
|
||||
// Getters
|
||||
const std::vector<ShapePrimitive>& get_primitives() const {
|
||||
return primitives_;
|
||||
@@ -50,9 +53,6 @@ class Shape {
|
||||
float escala_defecte_; // Escala per defecte (normalment 1.0)
|
||||
std::string nom_; // Nom de la forma (per depuració)
|
||||
|
||||
// Parsejador del fitxer
|
||||
bool parsejar_fitxer(const std::string& contingut);
|
||||
|
||||
// Helpers privats per parsejar
|
||||
std::string trim(const std::string& str) const;
|
||||
bool starts_with(const std::string& str, const std::string& prefix) const;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "core/graphics/shape_loader.hpp"
|
||||
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace Graphics {
|
||||
@@ -19,28 +21,40 @@ std::shared_ptr<Shape> ShapeLoader::load(const std::string& filename) {
|
||||
return it->second; // Cache hit
|
||||
}
|
||||
|
||||
// Resolve full path
|
||||
std::string fullpath = resolve_path(filename);
|
||||
// Normalize path: "ship.shp" → "shapes/ship.shp"
|
||||
// "logo/letra_j.shp" → "shapes/logo/letra_j.shp"
|
||||
std::string normalized = filename;
|
||||
if (normalized.find("shapes/") != 0) {
|
||||
// Doesn't start with "shapes/", so add it
|
||||
normalized = "shapes/" + normalized;
|
||||
}
|
||||
|
||||
// Create and load shape
|
||||
// Load from resource system
|
||||
std::vector<uint8_t> data = Resource::Helper::loadFile(normalized);
|
||||
if (data.empty()) {
|
||||
std::cerr << "[ShapeLoader] Error: no s'ha pogut carregar " << normalized
|
||||
<< std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Convert bytes to string and parse
|
||||
std::string file_content(data.begin(), data.end());
|
||||
auto shape = std::make_shared<Shape>();
|
||||
if (!shape->carregar(fullpath)) {
|
||||
std::cerr << "[ShapeLoader] Error: no s'ha pogut carregar " << filename
|
||||
if (!shape->parsejar_fitxer(file_content)) {
|
||||
std::cerr << "[ShapeLoader] Error: no s'ha pogut parsejar " << normalized
|
||||
<< std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Verify shape is valid
|
||||
if (!shape->es_valida()) {
|
||||
std::cerr << "[ShapeLoader] Error: forma invàlida " << filename
|
||||
<< std::endl;
|
||||
std::cerr << "[ShapeLoader] Error: forma invàlida " << normalized << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Cache and return
|
||||
std::cout << "[ShapeLoader] Carregat: " << filename << " ("
|
||||
<< shape->get_nom() << ", " << shape->get_num_primitives()
|
||||
<< " primitives)" << std::endl;
|
||||
std::cout << "[ShapeLoader] Carregat: " << normalized << " (" << shape->get_nom()
|
||||
<< ", " << shape->get_num_primitives() << " primitives)" << std::endl;
|
||||
|
||||
cache_[filename] = shape;
|
||||
return shape;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "core/defaults.hpp"
|
||||
#include "core/graphics/shape_loader.hpp"
|
||||
#include "core/rendering/shape_renderer.hpp"
|
||||
|
||||
namespace Graphics {
|
||||
@@ -21,11 +22,11 @@ Starfield::Starfield(SDL_Renderer* renderer,
|
||||
punt_fuga_(punt_fuga),
|
||||
area_(area),
|
||||
densitat_(densitat) {
|
||||
// Carregar forma d'estrella
|
||||
shape_estrella_ = std::make_shared<Shape>("data/shapes/star.shp");
|
||||
// Carregar forma d'estrella amb ShapeLoader
|
||||
shape_estrella_ = ShapeLoader::load("star.shp");
|
||||
|
||||
if (!shape_estrella_->es_valida()) {
|
||||
std::cerr << "ERROR: No s'ha pogut carregar data/shapes/star.shp" << std::endl;
|
||||
if (!shape_estrella_ || !shape_estrella_->es_valida()) {
|
||||
std::cerr << "ERROR: No s'ha pogut carregar star.shp" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
83
source/core/resources/resource_helper.cpp
Normal file
83
source/core/resources/resource_helper.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
// resource_helper.cpp - Implementació de funcions d'ajuda
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
|
||||
#include "resource_helper.hpp"
|
||||
|
||||
#include "resource_loader.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
namespace Resource {
|
||||
namespace Helper {
|
||||
|
||||
// Inicialitzar el sistema de recursos
|
||||
bool initializeResourceSystem(const std::string& pack_file, bool fallback) {
|
||||
return Loader::get().initialize(pack_file, fallback);
|
||||
}
|
||||
|
||||
// Carregar un fitxer
|
||||
std::vector<uint8_t> loadFile(const std::string& filepath) {
|
||||
// Normalitzar la ruta
|
||||
std::string normalized = normalizePath(filepath);
|
||||
|
||||
// Carregar del sistema de recursos
|
||||
return Loader::get().loadResource(normalized);
|
||||
}
|
||||
|
||||
// Comprovar si existeix un fitxer
|
||||
bool fileExists(const std::string& filepath) {
|
||||
std::string normalized = normalizePath(filepath);
|
||||
return Loader::get().resourceExists(normalized);
|
||||
}
|
||||
|
||||
// Obtenir ruta normalitzada per al paquet
|
||||
// Elimina prefixos "data/", rutes absolutes, etc.
|
||||
std::string getPackPath(const std::string& asset_path) {
|
||||
std::string path = asset_path;
|
||||
|
||||
// Eliminar rutes absolutes (detectar / o C:\ al principi)
|
||||
if (!path.empty() && path[0] == '/') {
|
||||
// Buscar "data/" i agafar el que ve després
|
||||
size_t data_pos = path.find("/data/");
|
||||
if (data_pos != std::string::npos) {
|
||||
path = path.substr(data_pos + 6); // Saltar "/data/"
|
||||
}
|
||||
}
|
||||
|
||||
// Eliminar "./" i "../" del principi
|
||||
while (path.starts_with("./")) {
|
||||
path = path.substr(2);
|
||||
}
|
||||
while (path.starts_with("../")) {
|
||||
path = path.substr(3);
|
||||
}
|
||||
|
||||
// Eliminar "data/" del principi
|
||||
if (path.starts_with("data/")) {
|
||||
path = path.substr(5);
|
||||
}
|
||||
|
||||
// Eliminar "Resources/" (macOS bundles)
|
||||
if (path.starts_with("Resources/")) {
|
||||
path = path.substr(10);
|
||||
}
|
||||
|
||||
// Convertir barres invertides a normals
|
||||
std::ranges::replace(path, '\\', '/');
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
// Normalitzar ruta (alias de getPackPath)
|
||||
std::string normalizePath(const std::string& path) {
|
||||
return getPackPath(path);
|
||||
}
|
||||
|
||||
// Comprovar si hi ha paquet carregat
|
||||
bool isPackLoaded() {
|
||||
return Loader::get().isPackLoaded();
|
||||
}
|
||||
|
||||
} // namespace Helper
|
||||
} // namespace Resource
|
||||
28
source/core/resources/resource_helper.hpp
Normal file
28
source/core/resources/resource_helper.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// resource_helper.hpp - Funcions d'ajuda per gestió de recursos
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// API simplificada i normalització de rutes
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Resource {
|
||||
namespace Helper {
|
||||
|
||||
// Inicialització del sistema
|
||||
bool initializeResourceSystem(const std::string& pack_file, bool fallback);
|
||||
|
||||
// Càrrega de fitxers
|
||||
std::vector<uint8_t> loadFile(const std::string& filepath);
|
||||
bool fileExists(const std::string& filepath);
|
||||
|
||||
// Normalització de rutes
|
||||
std::string getPackPath(const std::string& asset_path);
|
||||
std::string normalizePath(const std::string& path);
|
||||
|
||||
// Estat
|
||||
bool isPackLoaded();
|
||||
|
||||
} // namespace Helper
|
||||
} // namespace Resource
|
||||
143
source/core/resources/resource_loader.cpp
Normal file
143
source/core/resources/resource_loader.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
// resource_loader.cpp - Implementació del carregador de recursos
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
|
||||
#include "resource_loader.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace Resource {
|
||||
|
||||
// Singleton
|
||||
Loader& Loader::get() {
|
||||
static Loader instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
// Inicialitzar el sistema de recursos
|
||||
bool Loader::initialize(const std::string& pack_file, bool enable_fallback) {
|
||||
fallback_enabled_ = enable_fallback;
|
||||
|
||||
// Intentar carregar el paquet
|
||||
pack_ = std::make_unique<Pack>();
|
||||
|
||||
if (!pack_->loadPack(pack_file)) {
|
||||
if (!fallback_enabled_) {
|
||||
std::cerr << "[ResourceLoader] ERROR FATAL: No es pot carregar " << pack_file
|
||||
<< " i el fallback està desactivat\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "[ResourceLoader] Paquet no trobat, usant fallback al sistema de fitxers\n";
|
||||
pack_.reset(); // No hi ha paquet
|
||||
return true;
|
||||
}
|
||||
|
||||
std::cout << "[ResourceLoader] Paquet carregat: " << pack_file << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Carregar un recurs
|
||||
std::vector<uint8_t> Loader::loadResource(const std::string& filename) {
|
||||
// Intentar carregar del paquet primer
|
||||
if (pack_) {
|
||||
if (pack_->hasResource(filename)) {
|
||||
auto data = pack_->getResource(filename);
|
||||
if (!data.empty()) {
|
||||
return data;
|
||||
}
|
||||
std::cerr << "[ResourceLoader] Advertència: recurs buit al paquet: " << filename
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
// Si no està al paquet i no hi ha fallback, falla
|
||||
if (!fallback_enabled_) {
|
||||
std::cerr << "[ResourceLoader] ERROR: Recurs no trobat al paquet i fallback desactivat: "
|
||||
<< filename << "\n";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback al sistema de fitxers
|
||||
if (fallback_enabled_) {
|
||||
return loadFromFilesystem(filename);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// Comprovar si existeix un recurs
|
||||
bool Loader::resourceExists(const std::string& filename) {
|
||||
// Comprovar al paquet
|
||||
if (pack_ && pack_->hasResource(filename)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Comprovar al sistema de fitxers si està activat el fallback
|
||||
if (fallback_enabled_) {
|
||||
std::string fullpath = base_path_.empty() ? "data/" + filename : base_path_ + "/data/" + filename;
|
||||
return std::filesystem::exists(fullpath);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validar el paquet
|
||||
bool Loader::validatePack() {
|
||||
if (!pack_) {
|
||||
std::cerr << "[ResourceLoader] Advertència: no hi ha paquet carregat per validar\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return pack_->validatePack();
|
||||
}
|
||||
|
||||
// Comprovar si hi ha paquet carregat
|
||||
bool Loader::isPackLoaded() const {
|
||||
return pack_ != nullptr;
|
||||
}
|
||||
|
||||
// Establir la ruta base
|
||||
void Loader::setBasePath(const std::string& path) {
|
||||
base_path_ = path;
|
||||
std::cout << "[ResourceLoader] Ruta base establerta: " << base_path_ << "\n";
|
||||
}
|
||||
|
||||
// Obtenir la ruta base
|
||||
std::string Loader::getBasePath() const {
|
||||
return base_path_;
|
||||
}
|
||||
|
||||
// Carregar des del sistema de fitxers (fallback)
|
||||
std::vector<uint8_t> Loader::loadFromFilesystem(const std::string& filename) {
|
||||
// The filename is already normalized (e.g., "shapes/logo/letra_j.shp")
|
||||
// We need to prepend base_path + "data/"
|
||||
std::string fullpath;
|
||||
|
||||
if (base_path_.empty()) {
|
||||
fullpath = "data/" + filename;
|
||||
} else {
|
||||
fullpath = base_path_ + "/data/" + filename;
|
||||
}
|
||||
|
||||
std::ifstream file(fullpath, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
std::cerr << "[ResourceLoader] Error: no es pot obrir " << fullpath << "\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
std::streamsize file_size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<uint8_t> data(file_size);
|
||||
if (!file.read(reinterpret_cast<char*>(data.data()), file_size)) {
|
||||
std::cerr << "[ResourceLoader] Error: no es pot llegir " << fullpath << "\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
std::cout << "[ResourceLoader] Carregat des del sistema de fitxers: " << fullpath << "\n";
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace Resource
|
||||
53
source/core/resources/resource_loader.hpp
Normal file
53
source/core/resources/resource_loader.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// resource_loader.hpp - Carregador de recursos (Singleton)
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// Coordina càrrega des del paquet i/o sistema de fitxers
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "resource_pack.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Resource {
|
||||
|
||||
// Singleton per gestionar la càrrega de recursos
|
||||
class Loader {
|
||||
public:
|
||||
// Singleton
|
||||
static Loader& get();
|
||||
|
||||
// Inicialització
|
||||
bool initialize(const std::string& pack_file, bool enable_fallback);
|
||||
|
||||
// Càrrega de recursos
|
||||
std::vector<uint8_t> loadResource(const std::string& filename);
|
||||
bool resourceExists(const std::string& filename);
|
||||
|
||||
// Validació
|
||||
bool validatePack();
|
||||
bool isPackLoaded() const;
|
||||
|
||||
// Estat
|
||||
void setBasePath(const std::string& path);
|
||||
std::string getBasePath() const;
|
||||
|
||||
private:
|
||||
Loader() = default;
|
||||
~Loader() = default;
|
||||
|
||||
// No es pot copiar ni moure
|
||||
Loader(const Loader&) = delete;
|
||||
Loader& operator=(const Loader&) = delete;
|
||||
|
||||
// Dades
|
||||
std::unique_ptr<Pack> pack_;
|
||||
bool fallback_enabled_ = false;
|
||||
std::string base_path_;
|
||||
|
||||
// Funcions auxiliars
|
||||
std::vector<uint8_t> loadFromFilesystem(const std::string& filename);
|
||||
};
|
||||
|
||||
} // namespace Resource
|
||||
309
source/core/resources/resource_pack.cpp
Normal file
309
source/core/resources/resource_pack.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
// resource_pack.cpp - Implementació del sistema d'empaquetament
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
|
||||
#include "resource_pack.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace Resource {
|
||||
|
||||
// Calcular checksum CRC32 simplificat
|
||||
uint32_t Pack::calculateChecksum(const std::vector<uint8_t>& data) const {
|
||||
uint32_t checksum = 0x12345678;
|
||||
for (unsigned char byte : data) {
|
||||
checksum = ((checksum << 5) + checksum) + byte;
|
||||
}
|
||||
return checksum;
|
||||
}
|
||||
|
||||
// Encriptació XOR (simètrica)
|
||||
void Pack::encryptData(std::vector<uint8_t>& data, const std::string& key) {
|
||||
if (key.empty()) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < data.size(); ++i) {
|
||||
data[i] ^= key[i % key.length()];
|
||||
}
|
||||
}
|
||||
|
||||
void Pack::decryptData(std::vector<uint8_t>& data, const std::string& key) {
|
||||
// XOR és simètric
|
||||
encryptData(data, key);
|
||||
}
|
||||
|
||||
// Llegir fitxer complet a memòria
|
||||
std::vector<uint8_t> Pack::readFile(const std::string& filepath) {
|
||||
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
std::cerr << "[ResourcePack] Error: no es pot obrir " << filepath << '\n';
|
||||
return {};
|
||||
}
|
||||
|
||||
std::streamsize file_size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<uint8_t> data(file_size);
|
||||
if (!file.read(reinterpret_cast<char*>(data.data()), file_size)) {
|
||||
std::cerr << "[ResourcePack] Error: no es pot llegir " << filepath << '\n';
|
||||
return {};
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Afegir un fitxer individual al paquet
|
||||
bool Pack::addFile(const std::string& filepath, const std::string& pack_name) {
|
||||
auto file_data = readFile(filepath);
|
||||
if (file_data.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResourceEntry entry{
|
||||
.filename = pack_name,
|
||||
.offset = data_.size(),
|
||||
.size = file_data.size(),
|
||||
.checksum = calculateChecksum(file_data)};
|
||||
|
||||
// Afegir dades al bloc de dades
|
||||
data_.insert(data_.end(), file_data.begin(), file_data.end());
|
||||
|
||||
resources_[pack_name] = entry;
|
||||
|
||||
std::cout << "[ResourcePack] Afegit: " << pack_name << " (" << file_data.size()
|
||||
<< " bytes)\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Afegir tots els fitxers d'un directori recursivament
|
||||
bool Pack::addDirectory(const std::string& dir_path,
|
||||
const std::string& base_path) {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
if (!fs::exists(dir_path) || !fs::is_directory(dir_path)) {
|
||||
std::cerr << "[ResourcePack] Error: directori no trobat: " << dir_path << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string current_base = base_path.empty() ? "" : base_path + "/";
|
||||
|
||||
for (const auto& entry : fs::recursive_directory_iterator(dir_path)) {
|
||||
if (!entry.is_regular_file()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string full_path = entry.path().string();
|
||||
std::string relative_path = entry.path().lexically_relative(dir_path).string();
|
||||
|
||||
// Convertir barres invertides a normals (Windows)
|
||||
std::ranges::replace(relative_path, '\\', '/');
|
||||
|
||||
// Saltar fitxers de desenvolupament
|
||||
if (relative_path.find(".world") != std::string::npos ||
|
||||
relative_path.find(".tsx") != std::string::npos ||
|
||||
relative_path.find(".DS_Store") != std::string::npos ||
|
||||
relative_path.find(".git") != std::string::npos) {
|
||||
std::cout << "[ResourcePack] Saltant: " << relative_path << '\n';
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string pack_name = current_base + relative_path;
|
||||
addFile(full_path, pack_name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Guardar paquet a disc
|
||||
bool Pack::savePack(const std::string& pack_file) {
|
||||
std::ofstream file(pack_file, std::ios::binary);
|
||||
if (!file) {
|
||||
std::cerr << "[ResourcePack] Error: no es pot crear " << pack_file << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
// Escriure capçalera
|
||||
file.write(MAGIC_HEADER, 4);
|
||||
file.write(reinterpret_cast<const char*>(&VERSION), sizeof(VERSION));
|
||||
|
||||
// Escriure nombre de recursos
|
||||
auto resource_count = static_cast<uint32_t>(resources_.size());
|
||||
file.write(reinterpret_cast<const char*>(&resource_count), sizeof(resource_count));
|
||||
|
||||
// Escriure metadades de recursos
|
||||
for (const auto& [name, entry] : resources_) {
|
||||
// Nom del fitxer
|
||||
auto name_len = static_cast<uint32_t>(entry.filename.length());
|
||||
file.write(reinterpret_cast<const char*>(&name_len), sizeof(name_len));
|
||||
file.write(entry.filename.c_str(), name_len);
|
||||
|
||||
// Offset, mida, checksum
|
||||
file.write(reinterpret_cast<const char*>(&entry.offset), sizeof(entry.offset));
|
||||
file.write(reinterpret_cast<const char*>(&entry.size), sizeof(entry.size));
|
||||
file.write(reinterpret_cast<const char*>(&entry.checksum), sizeof(entry.checksum));
|
||||
}
|
||||
|
||||
// Encriptar dades
|
||||
std::vector<uint8_t> encrypted_data = data_;
|
||||
encryptData(encrypted_data, DEFAULT_ENCRYPT_KEY);
|
||||
|
||||
// Escriure mida de dades i dades encriptades
|
||||
auto data_size = static_cast<uint64_t>(encrypted_data.size());
|
||||
file.write(reinterpret_cast<const char*>(&data_size), sizeof(data_size));
|
||||
file.write(reinterpret_cast<const char*>(encrypted_data.data()), encrypted_data.size());
|
||||
|
||||
std::cout << "[ResourcePack] Guardat: " << pack_file << " (" << resources_.size()
|
||||
<< " recursos, " << data_size << " bytes)\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Carregar paquet des de disc
|
||||
bool Pack::loadPack(const std::string& pack_file) {
|
||||
std::ifstream file(pack_file, std::ios::binary);
|
||||
if (!file) {
|
||||
std::cerr << "[ResourcePack] Error: no es pot obrir " << pack_file << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
// Llegir capçalera
|
||||
char magic[4];
|
||||
file.read(magic, 4);
|
||||
if (std::string(magic, 4) != MAGIC_HEADER) {
|
||||
std::cerr << "[ResourcePack] Error: capçalera invàlida (esperava " << MAGIC_HEADER
|
||||
<< ")\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t version;
|
||||
file.read(reinterpret_cast<char*>(&version), sizeof(version));
|
||||
if (version != VERSION) {
|
||||
std::cerr << "[ResourcePack] Error: versió incompatible (esperava " << VERSION
|
||||
<< ", trobat " << version << ")\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Llegir nombre de recursos
|
||||
uint32_t resource_count;
|
||||
file.read(reinterpret_cast<char*>(&resource_count), sizeof(resource_count));
|
||||
|
||||
// Llegir metadades de recursos
|
||||
resources_.clear();
|
||||
for (uint32_t i = 0; i < resource_count; ++i) {
|
||||
// Nom del fitxer
|
||||
uint32_t name_len;
|
||||
file.read(reinterpret_cast<char*>(&name_len), sizeof(name_len));
|
||||
|
||||
std::string filename(name_len, '\0');
|
||||
file.read(&filename[0], name_len);
|
||||
|
||||
// Offset, mida, checksum
|
||||
ResourceEntry entry;
|
||||
entry.filename = filename;
|
||||
file.read(reinterpret_cast<char*>(&entry.offset), sizeof(entry.offset));
|
||||
file.read(reinterpret_cast<char*>(&entry.size), sizeof(entry.size));
|
||||
file.read(reinterpret_cast<char*>(&entry.checksum), sizeof(entry.checksum));
|
||||
|
||||
resources_[filename] = entry;
|
||||
}
|
||||
|
||||
// Llegir dades encriptades
|
||||
uint64_t data_size;
|
||||
file.read(reinterpret_cast<char*>(&data_size), sizeof(data_size));
|
||||
|
||||
data_.resize(data_size);
|
||||
file.read(reinterpret_cast<char*>(data_.data()), data_size);
|
||||
|
||||
// Desencriptar
|
||||
decryptData(data_, DEFAULT_ENCRYPT_KEY);
|
||||
|
||||
std::cout << "[ResourcePack] Carregat: " << pack_file << " (" << resources_.size()
|
||||
<< " recursos)\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Obtenir un recurs del paquet
|
||||
std::vector<uint8_t> Pack::getResource(const std::string& filename) {
|
||||
auto it = resources_.find(filename);
|
||||
if (it == resources_.end()) {
|
||||
std::cerr << "[ResourcePack] Error: recurs no trobat: " << filename << '\n';
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto& entry = it->second;
|
||||
|
||||
// Extreure dades
|
||||
if (entry.offset + entry.size > data_.size()) {
|
||||
std::cerr << "[ResourcePack] Error: offset/mida invàlid per " << filename << '\n';
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> resource_data(data_.begin() + entry.offset,
|
||||
data_.begin() + entry.offset + entry.size);
|
||||
|
||||
// Verificar checksum
|
||||
uint32_t computed_checksum = calculateChecksum(resource_data);
|
||||
if (computed_checksum != entry.checksum) {
|
||||
std::cerr << "[ResourcePack] ADVERTÈNCIA: checksum invàlid per " << filename
|
||||
<< " (esperat " << entry.checksum << ", calculat " << computed_checksum
|
||||
<< ")\n";
|
||||
// No falla, però adverteix
|
||||
}
|
||||
|
||||
return resource_data;
|
||||
}
|
||||
|
||||
// Comprovar si existeix un recurs
|
||||
bool Pack::hasResource(const std::string& filename) const {
|
||||
return resources_.find(filename) != resources_.end();
|
||||
}
|
||||
|
||||
// Obtenir llista de tots els recursos
|
||||
std::vector<std::string> Pack::getResourceList() const {
|
||||
std::vector<std::string> list;
|
||||
list.reserve(resources_.size());
|
||||
|
||||
for (const auto& [name, entry] : resources_) {
|
||||
list.push_back(name);
|
||||
}
|
||||
|
||||
std::ranges::sort(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
// Validar integritat del paquet
|
||||
bool Pack::validatePack() const {
|
||||
bool valid = true;
|
||||
|
||||
for (const auto& [name, entry] : resources_) {
|
||||
// Verificar offset i mida
|
||||
if (entry.offset + entry.size > data_.size()) {
|
||||
std::cerr << "[ResourcePack] Error de validació: " << name
|
||||
<< " té offset/mida invàlid\n";
|
||||
valid = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extreure i verificar checksum
|
||||
std::vector<uint8_t> resource_data(data_.begin() + entry.offset,
|
||||
data_.begin() + entry.offset + entry.size);
|
||||
|
||||
uint32_t computed_checksum = calculateChecksum(resource_data);
|
||||
if (computed_checksum != entry.checksum) {
|
||||
std::cerr << "[ResourcePack] Error de validació: " << name
|
||||
<< " té checksum invàlid\n";
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
std::cout << "[ResourcePack] Validació OK (" << resources_.size() << " recursos)\n";
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
} // namespace Resource
|
||||
67
source/core/resources/resource_pack.hpp
Normal file
67
source/core/resources/resource_pack.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
// resource_pack.hpp - Sistema d'empaquetament de recursos
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// Basat en el sistema de "pollo" amb adaptacions per Orni Attack
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace Resource {
|
||||
|
||||
// Capçalera del fitxer de paquet
|
||||
struct PackHeader {
|
||||
char magic[4]; // "ORNI"
|
||||
uint32_t version; // Versió del format (1)
|
||||
};
|
||||
|
||||
// Entrada de recurs dins el paquet
|
||||
struct ResourceEntry {
|
||||
std::string filename; // Nom del recurs (amb barres normals)
|
||||
uint64_t offset; // Posició dins el bloc de dades
|
||||
uint64_t size; // Mida en bytes
|
||||
uint32_t checksum; // Checksum CRC32 per verificació
|
||||
};
|
||||
|
||||
// Classe principal per gestionar paquets de recursos
|
||||
class Pack {
|
||||
public:
|
||||
Pack() = default;
|
||||
~Pack() = default;
|
||||
|
||||
// Afegir fitxers al paquet
|
||||
bool addFile(const std::string& filepath, const std::string& pack_name);
|
||||
bool addDirectory(const std::string& dir_path, const std::string& base_path = "");
|
||||
|
||||
// Guardar i carregar paquets
|
||||
bool savePack(const std::string& pack_file);
|
||||
bool loadPack(const std::string& pack_file);
|
||||
|
||||
// Accés a recursos
|
||||
std::vector<uint8_t> getResource(const std::string& filename);
|
||||
bool hasResource(const std::string& filename) const;
|
||||
std::vector<std::string> getResourceList() const;
|
||||
|
||||
// Validació
|
||||
bool validatePack() const;
|
||||
|
||||
private:
|
||||
// Constants
|
||||
static constexpr const char* MAGIC_HEADER = "ORNI";
|
||||
static constexpr uint32_t VERSION = 1;
|
||||
static constexpr const char* DEFAULT_ENCRYPT_KEY = "ORNI_RESOURCES_2025";
|
||||
|
||||
// Dades del paquet
|
||||
std::unordered_map<std::string, ResourceEntry> resources_;
|
||||
std::vector<uint8_t> data_;
|
||||
|
||||
// Funcions auxiliars
|
||||
std::vector<uint8_t> readFile(const std::string& filepath);
|
||||
uint32_t calculateChecksum(const std::vector<uint8_t>& data) const;
|
||||
void encryptData(std::vector<uint8_t>& data, const std::string& key);
|
||||
void decryptData(std::vector<uint8_t>& data, const std::string& key);
|
||||
};
|
||||
|
||||
} // namespace Resource
|
||||
@@ -11,6 +11,9 @@
|
||||
#include "core/audio/audio_cache.hpp"
|
||||
#include "core/defaults.hpp"
|
||||
#include "core/rendering/sdl_manager.hpp"
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "core/resources/resource_loader.hpp"
|
||||
#include "core/utils/path_utils.hpp"
|
||||
#include "game/escenes/escena_joc.hpp"
|
||||
#include "game/escenes/escena_logo.hpp"
|
||||
#include "game/escenes/escena_titol.hpp"
|
||||
@@ -37,6 +40,44 @@ Director::Director(std::vector<std::string> const& args) {
|
||||
// Comprovar arguments del programa
|
||||
executable_path_ = checkProgramArguments(args);
|
||||
|
||||
// Inicialitzar sistema de rutes
|
||||
Utils::initializePathSystem(args[0].c_str());
|
||||
|
||||
// Obtenir ruta base dels recursos
|
||||
std::string resource_base = Utils::getResourceBasePath();
|
||||
|
||||
// Inicialitzar sistema de recursos
|
||||
#ifdef RELEASE_BUILD
|
||||
// Mode release: paquet obligatori, sense fallback
|
||||
std::string pack_path = resource_base + "/resources.pack";
|
||||
if (!Resource::Helper::initializeResourceSystem(pack_path, false)) {
|
||||
std::cerr << "ERROR FATAL: No es pot carregar " << pack_path << "\n";
|
||||
std::cerr << "El joc no pot continuar sense els recursos.\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Validar integritat del paquet
|
||||
if (!Resource::Loader::get().validatePack()) {
|
||||
std::cerr << "ERROR FATAL: El paquet de recursos està corromput\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
std::cout << "Sistema de recursos inicialitzat (mode release)\n";
|
||||
#else
|
||||
// Mode desenvolupament: intentar paquet amb fallback a data/
|
||||
std::string pack_path = resource_base + "/resources.pack";
|
||||
Resource::Helper::initializeResourceSystem(pack_path, true);
|
||||
|
||||
if (Resource::Helper::isPackLoaded()) {
|
||||
std::cout << "Sistema de recursos inicialitzat (mode dev amb paquet)\n";
|
||||
} else {
|
||||
std::cout << "Sistema de recursos inicialitzat (mode dev, fallback a data/)\n";
|
||||
}
|
||||
|
||||
// Establir ruta base per al fallback
|
||||
Resource::Loader::get().setBasePath(resource_base);
|
||||
#endif
|
||||
|
||||
// Crear carpetes del sistema
|
||||
createSystemFolder("jailgames");
|
||||
createSystemFolder(std::string("jailgames/") + Project::NAME);
|
||||
|
||||
92
source/core/utils/path_utils.cpp
Normal file
92
source/core/utils/path_utils.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// path_utils.cpp - Implementació de utilitats de rutes
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
|
||||
#include "path_utils.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
namespace Utils {
|
||||
|
||||
// Variables globals per guardar argv[0]
|
||||
static std::string executable_path_;
|
||||
static std::string executable_directory_;
|
||||
|
||||
// Inicialitzar el sistema de rutes amb argv[0]
|
||||
void initializePathSystem(const char* argv0) {
|
||||
if (!argv0) {
|
||||
std::cerr << "[PathUtils] ADVERTÈNCIA: argv[0] és nullptr\n";
|
||||
executable_path_ = "";
|
||||
executable_directory_ = ".";
|
||||
return;
|
||||
}
|
||||
|
||||
executable_path_ = argv0;
|
||||
|
||||
// Extreure el directori
|
||||
std::filesystem::path path(argv0);
|
||||
executable_directory_ = path.parent_path().string();
|
||||
|
||||
if (executable_directory_.empty()) {
|
||||
executable_directory_ = ".";
|
||||
}
|
||||
|
||||
std::cout << "[PathUtils] Executable: " << executable_path_ << "\n";
|
||||
std::cout << "[PathUtils] Directori: " << executable_directory_ << "\n";
|
||||
}
|
||||
|
||||
// Obtenir el directori de l'executable
|
||||
std::string getExecutableDirectory() {
|
||||
if (executable_directory_.empty()) {
|
||||
std::cerr << "[PathUtils] ADVERTÈNCIA: Sistema de rutes no inicialitzat\n";
|
||||
return ".";
|
||||
}
|
||||
return executable_directory_;
|
||||
}
|
||||
|
||||
// Detectar si estem dins un bundle de macOS
|
||||
bool isMacOSBundle() {
|
||||
#ifdef MACOS_BUNDLE
|
||||
return true;
|
||||
#else
|
||||
// Detecció en temps d'execució
|
||||
// Cercar ".app/Contents/MacOS" a la ruta de l'executable
|
||||
std::string exe_dir = getExecutableDirectory();
|
||||
return exe_dir.find(".app/Contents/MacOS") != std::string::npos;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Obtenir la ruta base dels recursos
|
||||
std::string getResourceBasePath() {
|
||||
std::string exe_dir = getExecutableDirectory();
|
||||
|
||||
if (isMacOSBundle()) {
|
||||
// Bundle de macOS: recursos a ../Resources des de MacOS/
|
||||
std::cout << "[PathUtils] Detectat bundle de macOS\n";
|
||||
return exe_dir + "/../Resources";
|
||||
} else {
|
||||
// Executable normal: recursos al mateix directori
|
||||
return exe_dir;
|
||||
}
|
||||
}
|
||||
|
||||
// Normalitzar ruta (convertir barres, etc.)
|
||||
std::string normalizePath(const std::string& path) {
|
||||
std::string normalized = path;
|
||||
|
||||
// Convertir barres invertides a normals
|
||||
std::ranges::replace(normalized, '\\', '/');
|
||||
|
||||
// Simplificar rutes amb filesystem
|
||||
try {
|
||||
std::filesystem::path fs_path(normalized);
|
||||
normalized = fs_path.lexically_normal().string();
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[PathUtils] Error normalitzant ruta: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
} // namespace Utils
|
||||
24
source/core/utils/path_utils.hpp
Normal file
24
source/core/utils/path_utils.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
// path_utils.hpp - Utilitats de gestió de rutes
|
||||
// © 2025 Port a C++20 amb SDL3
|
||||
// Detecció de directoris i bundles multiplataforma
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Utils {
|
||||
|
||||
// Inicialització amb argv[0]
|
||||
void initializePathSystem(const char* argv0);
|
||||
|
||||
// Obtenció de rutes
|
||||
std::string getExecutableDirectory();
|
||||
std::string getResourceBasePath();
|
||||
|
||||
// Detecció de plataforma
|
||||
bool isMacOSBundle();
|
||||
|
||||
// Normalització
|
||||
std::string normalizePath(const std::string& path);
|
||||
|
||||
} // namespace Utils
|
||||
@@ -2,24 +2,37 @@
|
||||
// © 2025 Orni Attack
|
||||
|
||||
#include "stage_loader.hpp"
|
||||
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "external/fkyaml_node.hpp"
|
||||
#include <iostream>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace StageSystem {
|
||||
|
||||
std::unique_ptr<ConfigSistemaStages> StageLoader::carregar(const std::string& path) {
|
||||
try {
|
||||
// Llegir fitxer YAML
|
||||
std::ifstream file(path);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "[StageLoader] Error: no es pot obrir el fitxer " << path << std::endl;
|
||||
// Normalize path: "data/stages/stages.yaml" → "stages/stages.yaml"
|
||||
std::string normalized = path;
|
||||
if (normalized.starts_with("data/")) {
|
||||
normalized = normalized.substr(5);
|
||||
}
|
||||
|
||||
// Load from resource system
|
||||
std::vector<uint8_t> data = Resource::Helper::loadFile(normalized);
|
||||
if (data.empty()) {
|
||||
std::cerr << "[StageLoader] Error: no es pot carregar " << normalized << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Convert to string
|
||||
std::string yaml_content(data.begin(), data.end());
|
||||
std::stringstream stream(yaml_content);
|
||||
|
||||
// Parse YAML
|
||||
fkyaml::node yaml = fkyaml::node::deserialize(file);
|
||||
fkyaml::node yaml = fkyaml::node::deserialize(stream);
|
||||
auto config = std::make_unique<ConfigSistemaStages>();
|
||||
|
||||
// Parse metadata
|
||||
|
||||
20
tools/pack_resources/Makefile
Normal file
20
tools/pack_resources/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
# Makefile per a pack_resources
|
||||
# © 2025 Orni Attack
|
||||
|
||||
CXX = clang++
|
||||
CXXFLAGS = -std=c++20 -Wall -Wextra -I../../source
|
||||
TARGET = pack_resources
|
||||
|
||||
SOURCES = pack_resources.cpp \
|
||||
../../source/core/resources/resource_pack.cpp
|
||||
|
||||
$(TARGET): $(SOURCES)
|
||||
@echo "Compilant $(TARGET)..."
|
||||
@$(CXX) $(CXXFLAGS) -o $(TARGET) $(SOURCES)
|
||||
@echo "✓ $(TARGET) compilat"
|
||||
|
||||
clean:
|
||||
@rm -f $(TARGET)
|
||||
@echo "✓ Netejat"
|
||||
|
||||
.PHONY: clean
|
||||
BIN
tools/pack_resources/pack_resources
Executable file
BIN
tools/pack_resources/pack_resources
Executable file
Binary file not shown.
92
tools/pack_resources/pack_resources.cpp
Normal file
92
tools/pack_resources/pack_resources.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// pack_resources.cpp - Utilitat per crear paquets de recursos
|
||||
// © 2025 Orni Attack
|
||||
|
||||
#include "../../source/core/resources/resource_pack.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
void print_usage(const char* program_name) {
|
||||
std::cout << "Ús: " << program_name << " [opcions] [directori_entrada] [fitxer_sortida]\n";
|
||||
std::cout << "\nOpcions:\n";
|
||||
std::cout << " --list <fitxer> Llistar contingut d'un paquet\n";
|
||||
std::cout << "\nExemples:\n";
|
||||
std::cout << " " << program_name << " data resources.pack\n";
|
||||
std::cout << " " << program_name << " --list resources.pack\n";
|
||||
std::cout << "\nSi no s'especifiquen arguments, empaqueta 'data/' a 'resources.pack'\n";
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::string input_dir = "data";
|
||||
std::string output_file = "resources.pack";
|
||||
|
||||
// Processar arguments
|
||||
if (argc == 2 && std::string(argv[1]) == "--help") {
|
||||
print_usage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Mode --list
|
||||
if (argc == 3 && std::string(argv[1]) == "--list") {
|
||||
Resource::Pack pack;
|
||||
if (!pack.loadPack(argv[2])) {
|
||||
std::cerr << "ERROR: No es pot carregar " << argv[2] << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Contingut de " << argv[2] << ":\n";
|
||||
auto resources = pack.getResourceList();
|
||||
std::cout << "Total: " << resources.size() << " recursos\n\n";
|
||||
|
||||
for (const auto& name : resources) {
|
||||
std::cout << " " << name << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Mode empaquetar
|
||||
if (argc >= 3) {
|
||||
input_dir = argv[1];
|
||||
output_file = argv[2];
|
||||
}
|
||||
|
||||
// Verificar que existeix el directori
|
||||
if (!std::filesystem::exists(input_dir)) {
|
||||
std::cerr << "ERROR: Directori no trobat: " << input_dir << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!std::filesystem::is_directory(input_dir)) {
|
||||
std::cerr << "ERROR: " << input_dir << " no és un directori\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Crear paquet
|
||||
std::cout << "Creant paquet de recursos...\n";
|
||||
std::cout << " Entrada: " << input_dir << "\n";
|
||||
std::cout << " Sortida: " << output_file << "\n\n";
|
||||
|
||||
Resource::Pack pack;
|
||||
if (!pack.addDirectory(input_dir)) {
|
||||
std::cerr << "ERROR: No s'ha pogut afegir el directori\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!pack.savePack(output_file)) {
|
||||
std::cerr << "ERROR: No s'ha pogut guardar el paquet\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Resum
|
||||
auto resources = pack.getResourceList();
|
||||
std::cout << "\n";
|
||||
std::cout << "✓ Paquet creat amb èxit!\n";
|
||||
std::cout << " Recursos: " << resources.size() << "\n";
|
||||
|
||||
// Mostrar mida del fitxer
|
||||
auto file_size = std::filesystem::file_size(output_file);
|
||||
std::cout << " Mida: " << (file_size / 1024) << " KB\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user