config/ dins del pack: assets, params, stages, pools, formations

This commit is contained in:
2026-05-17 08:38:46 +02:00
parent a39cd45bf1
commit 0d14e10de5
18 changed files with 95 additions and 2282 deletions
-2
View File
@@ -254,7 +254,6 @@ _macos-release:
$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
# Copia carpetas y ficheros
cp -R config "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
cp build/resources.pack "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
cp -R release/macos/frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
cp release/icons/*.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
@@ -358,7 +357,6 @@ _linux-release:
$(MKDIR) "$(RELEASE_FOLDER)"
# Copia ficheros
cp -R config "$(RELEASE_FOLDER)"
cp build/resources.pack "$(RELEASE_FOLDER)"
cp LICENSE "$(RELEASE_FOLDER)"
cp README.md "$(RELEASE_FOLDER)"
File diff suppressed because it is too large Load Diff
+7 -8
View File
@@ -10,14 +10,13 @@ DATA|${SYSTEM_FOLDER}/postfx.yaml|optional,absolute
DATA|${SYSTEM_FOLDER}/crtpi.yaml|optional,absolute
DATA|${SYSTEM_FOLDER}/score.bin|optional,absolute
# Archivos de configuración del juego
DATA|${PREFIX}/config/formations.txt
DATA|${PREFIX}/config/gamecontrollerdb.txt
DATA|${PREFIX}/config/param_320x240.txt
DATA|${PREFIX}/config/param_320x256.txt
DATA|${PREFIX}/config/param_red.txt
DATA|${PREFIX}/config/pools.txt
DATA|${PREFIX}/config/stages.txt
# Archivos de configuración del juego (viatgen dins el pack)
DATA|/data/config/formations.txt
DATA|/data/config/param_320x240.txt
DATA|/data/config/param_320x256.txt
DATA|/data/config/param_red.txt
DATA|/data/config/pools.txt
DATA|/data/config/stages.txt
# Archivos con los datos de la demo
DEMODATA|/data/demo/demo1.bin
+8 -4
View File
@@ -20,10 +20,14 @@
#include "core/rendering/text.hpp" // Para Text
#include "core/rendering/texture.hpp" // Para Texture
#include "core/resources/asset.hpp" // Para Asset
#include "game/options.hpp" // Para Video, video, Window, window
#include "game/ui/notifier.hpp" // Para Notifier
#include "game/ui/service_menu.hpp" // Para ServiceMenu
#include "utils/param.hpp" // Para Param, param, ParamGame, ParamDebug
#ifdef _DEBUG
#include "core/resources/resource.hpp" // Para Resource (només a debug, font 8bithud)
#include "core/system/director.hpp" // Para Director::debug_config (només a debug)
#endif
#include "game/options.hpp" // Para Video, video, Window, window
#include "game/ui/notifier.hpp" // Para Notifier
#include "game/ui/service_menu.hpp" // Para ServiceMenu
#include "utils/param.hpp" // Para Param, param, ParamGame, ParamDebug
// Singleton
Screen* Screen::instance = nullptr;
+17 -7
View File
@@ -47,27 +47,39 @@ void Asset::add(const std::string& file_path, Type type, bool required, bool abs
addToMap(file_path, type, required, absolute);
}
// Carga recursos desde un archivo de configuración con soporte para variables
// Carga recursos desde un archivo de configuración en el filesystem
void Asset::loadFromFile(const std::string& config_file_path, const std::string& prefix, const std::string& system_folder) {
std::ifstream file(config_file_path);
if (!file.is_open()) {
std::cout << "Error: Cannot open config file: " << config_file_path << '\n';
return;
}
parseConfigStream(file, prefix, system_folder);
}
// Carga recursos desde un buffer en memoria (p.ex. obtenido del pack)
void Asset::loadFromBuffer(const std::vector<uint8_t>& buffer, const std::string& prefix, const std::string& system_folder) {
if (buffer.empty()) {
std::cout << "Error: Asset index buffer is empty" << '\n';
return;
}
std::string content(buffer.begin(), buffer.end());
std::istringstream stream(content);
parseConfigStream(stream, prefix, system_folder);
}
// Parsea el contenido del índice (formato común a loadFromFile y loadFromBuffer)
void Asset::parseConfigStream(std::istream& stream, const std::string& prefix, const std::string& system_folder) {
std::string line;
int line_number = 0;
while (std::getline(file, line)) {
while (std::getline(stream, line)) {
++line_number;
// Limpiar espacios en blanco al principio y final
line.erase(0, line.find_first_not_of(" \t\r"));
line.erase(line.find_last_not_of(" \t\r") + 1);
// DEBUG: mostrar línea leída (opcional, puedes comentar esta línea)
// SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Line %d: '%s'", line_number, line.c_str());
// Ignorar líneas vacías y comentarios
if (line.empty() || line[0] == '#' || line[0] == ';') {
continue;
@@ -114,8 +126,6 @@ void Asset::loadFromFile(const std::string& config_file_path, const std::string&
std::cout << "Error parsing line " << line_number << " in config file: " << e.what() << '\n';
}
}
file.close();
}
// Devuelve la ruta completa a un fichero (búsqueda O(1))
+4 -1
View File
@@ -1,6 +1,7 @@
#pragma once
#include <cstdint> // Para uint8_t
#include <iosfwd> // Para istream (forward decl)
#include <string> // Para string
#include <unordered_map> // Para unordered_map
#include <utility> // Para move
@@ -32,7 +33,8 @@ class Asset {
// --- Métodos para la gestión de recursos ---
void add(const std::string& file_path, Type type, bool required = true, bool absolute = false);
void loadFromFile(const std::string& config_file_path, const std::string& prefix = "", const std::string& system_folder = ""); // Con soporte para variables
void loadFromFile(const std::string& config_file_path, const std::string& prefix = "", const std::string& system_folder = ""); // Carga el índice desde el filesystem
void loadFromBuffer(const std::vector<uint8_t>& buffer, const std::string& prefix = "", const std::string& system_folder = ""); // Carga el índice desde memoria (p.ex. desde el pack)
[[nodiscard]] auto getPath(const std::string& filename) const -> std::string;
[[nodiscard]] auto loadData(const std::string& filename) const -> std::vector<uint8_t>; // Carga datos del archivo
[[nodiscard]] auto check() const -> bool;
@@ -63,6 +65,7 @@ class Asset {
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
void parseConfigStream(std::istream& stream, const std::string& prefix, const std::string& system_folder); // Lógica común de parseo del índice
// --- Constructores y destructor privados (singleton) ---
explicit Asset(std::string executable_path) // Constructor privado
+6 -15
View File
@@ -88,20 +88,11 @@ auto AssetIntegrated::getSystemPath(const std::string& filename) -> std::string
}
auto AssetIntegrated::shouldUseResourcePack(const std::string& filepath) -> bool {
// Los archivos que NO van al pack:
// - Archivos de config/ (ahora están fuera de data/)
// - Archivos con absolute=true en assets.txt
// - Archivos de sistema (${SYSTEM_FOLDER})
// Els fitxers que NO van al pack:
// - Fitxers amb absolute=true a assets.txt
// - Fitxers de sistema (${SYSTEM_FOLDER})
// - Fitxers al costat del binari (com gamecontrollerdb.txt)
if (filepath.find("/config/") != std::string::npos ||
filepath.starts_with("config/")) {
return false;
}
if (filepath.find("/data/") != std::string::npos ||
filepath.starts_with("data/")) {
return true;
}
return false;
return filepath.find("/data/") != std::string::npos ||
filepath.starts_with("data/");
}
+4 -14
View File
@@ -59,20 +59,10 @@ namespace ResourceHelper {
}
auto shouldUseResourcePack(const std::string& filepath) -> bool {
// Archivos que NO van al pack:
// - config/ (ahora está fuera de data/)
// - archivos absolutos del sistema
if (filepath.find("config/") != std::string::npos) {
return false;
}
// Si contiene "data/" es candidato para el pack
if (filepath.find("data/") != std::string::npos) {
return true;
}
return false;
// Si la ruta conté "data/" és candidat al pack. La resta (paths absoluts del
// SYSTEM_FOLDER o relatives al binari com gamecontrollerdb.txt) van sempre al
// filesystem.
return filepath.find("data/") != std::string::npos;
}
auto getPackPath(const std::string& asset_path) -> std::string {
+11 -5
View File
@@ -141,7 +141,9 @@ void Director::init() {
loadAssets(); // Crea el índice de archivos
Input::init(Asset::get()->getPath("gamecontrollerdb.txt"), Asset::get()->getPath("controllers.json")); // Carga configuración de controles
// gamecontrollerdb.txt no pot anar al pack (SDL_AddGamepadMappingsFromFile només llegeix del FS).
// Sempre viu al costat del binari, fora del índex d'assets.
Input::init(executable_path_ + "gamecontrollerdb.txt", Asset::get()->getPath("controllers.json")); // Carga configuración de controles
Options::setConfigFile(Asset::get()->getPath("config.yaml")); // Establece el fichero de configuración
Options::setControllersFile(Asset::get()->getPath("controllers.json")); // Establece el fichero de configuración de mandos
@@ -256,7 +258,7 @@ void Director::loadScoreFile() {
#endif
}
// Carga el indice de ficheros desde un fichero
// Carga el indice de ficheros desde el pack (o filesystem como fallback)
void Director::loadAssets() {
#ifdef MACOS_BUNDLE
const std::string PREFIX = "/../Resources";
@@ -264,9 +266,13 @@ void Director::loadAssets() {
const std::string PREFIX;
#endif
// Cargar la configuración de assets (también aplicar el prefijo al archivo de configuración)
std::string config_path = executable_path_ + PREFIX + "/config/assets.txt";
Asset::get()->loadFromFile(config_path, PREFIX, system_folder_);
// El índice ahora vive dins el pack a "config/assets.txt" (ResourceHelper li trau el "data/" prefix).
// ResourceHelper::loadFile fa fallback automàtic al filesystem si el pack no està o no conté el fitxer.
auto buffer = ResourceHelper::loadFile("/data/config/assets.txt");
if (buffer.empty()) {
throw std::runtime_error("No s'ha pogut carregar l'índex d'assets (data/config/assets.txt)");
}
Asset::get()->loadFromBuffer(buffer, PREFIX, system_folder_);
// Si falta algun fichero, sale del programa
if (!Asset::get()->check()) {
+17 -14
View File
@@ -5,17 +5,17 @@
#include <cctype> // Para isdigit
#include <cstddef> // Para size_t
#include <exception> // Para exception
#include <fstream> // Para basic_istream, basic_ifstream, ifstream, istringstream
#include <iterator> // Para reverse_iterator
#include <map> // Para map, operator==, _Rb_tree_iterator
#include <sstream> // Para basic_istringstream
#include <string> // Para string, char_traits, allocator, operator==, stoi, getline, operator<=>, basic_string
#include <utility> // Para std::cmp_less
#include "core/resources/asset.hpp" // Para Asset
#include "game/entities/balloon.hpp" // Para Balloon
#include "utils/param.hpp" // Para Param, ParamGame, param
#include "utils/utils.hpp" // Para Zone, BLOCK
#include "core/resources/asset.hpp" // Para Asset
#include "core/resources/resource_helper.hpp" // Para ResourceHelper::loadFile
#include "game/entities/balloon.hpp" // Para Balloon
#include "utils/param.hpp" // Para Param, ParamGame, param
#include "utils/utils.hpp" // Para Zone, BLOCK
void BalloonFormations::initFormations() {
// Calcular posiciones base
@@ -60,16 +60,19 @@ void BalloonFormations::initFormations() {
}
auto BalloonFormations::loadFormationsFromFile(const std::string& filename, const std::map<std::string, float>& variables) -> bool {
std::ifstream file(filename);
if (!file.is_open()) {
auto buffer = ResourceHelper::loadFile(filename);
if (buffer.empty()) {
return false;
}
std::string content(buffer.begin(), buffer.end());
std::istringstream stream(content);
std::string line;
int current_formation = -1;
std::vector<SpawnParams> current_params;
while (std::getline(file, line)) {
while (std::getline(stream, line)) {
// Eliminar espacios en blanco al inicio y final
line = trim(line);
@@ -113,7 +116,6 @@ auto BalloonFormations::loadFormationsFromFile(const std::string& filename, cons
addTestFormation();
#endif
file.close();
return true;
}
@@ -272,18 +274,21 @@ void BalloonFormations::initFormationPools() {
}
auto BalloonFormations::loadPoolsFromFile(const std::string& filename) -> bool {
std::ifstream file(filename);
if (!file.is_open()) {
auto buffer = ResourceHelper::loadFile(filename);
if (buffer.empty()) {
return false;
}
std::string content(buffer.begin(), buffer.end());
std::istringstream stream(content);
std::string line;
pools_.clear(); // Limpiar pools existentes
// Map temporal para ordenar los pools por ID
std::map<int, std::vector<int>> temp_pools;
while (std::getline(file, line)) {
while (std::getline(stream, line)) {
// Eliminar espacios en blanco al inicio y final
line = trim(line);
@@ -299,8 +304,6 @@ auto BalloonFormations::loadPoolsFromFile(const std::string& filename) -> bool {
}
}
file.close();
// Convertir el map ordenado a vector
// Redimensionar el vector para el pool con ID más alto
if (!temp_pools.empty()) {
+10 -8
View File
@@ -2,11 +2,12 @@
#include <algorithm> // Para max, min
#include <exception> // Para exception
#include <fstream> // Para basic_istream, basic_ifstream, ifstream, stringstream
#include <numeric> // Para accumulate
#include <sstream> // Para basic_stringstream
#include <sstream> // Para basic_stringstream, istringstream
#include <utility> // Para move
#include "core/resources/resource_helper.hpp" // Para ResourceHelper::loadFile
// Implementación de StageData
StageData::StageData(int power_to_complete, int min_menace, int max_menace, std::string name)
: name_(std::move(name)),
@@ -57,14 +58,17 @@ void StageManager::createDefaultStages() {
}
auto StageManager::loadStagesFromFile(const std::string& filename) -> bool {
std::ifstream file(filename);
if (!file.is_open()) {
return false; // No se pudo abrir el archivo
auto buffer = ResourceHelper::loadFile(filename);
if (buffer.empty()) {
return false;
}
std::string content(buffer.begin(), buffer.end());
std::istringstream stream(content);
std::string line;
while (std::getline(file, line)) {
while (std::getline(stream, line)) {
// Ignorar líneas vacías y comentarios (líneas que empiezan con #)
if (line.empty() || line[0] == '#') {
continue;
@@ -110,8 +114,6 @@ auto StageManager::loadStagesFromFile(const std::string& filename) -> bool {
}
}
file.close();
// Verificar que se cargó al menos una fase
return !stages_.empty();
}
+11 -10
View File
@@ -10,9 +10,10 @@
#include <string> // Para string, basic_string, stoi, stof, hash, allocator, operator==, char_traits, operator+, operator>>, getline
#include <unordered_map> // Para unordered_map, operator==, _Node_iterator_base
#include "game/ui/notifier.hpp" // Para Notifier
#include "utils/color.hpp" // Para Color
#include "utils/utils.hpp" // Para Zone, stringToBool, getFileName
#include "core/resources/resource_helper.hpp" // Para ResourceHelper::loadFile
#include "game/ui/notifier.hpp" // Para Notifier
#include "utils/color.hpp" // Para Color
#include "utils/utils.hpp" // Para Zone, stringToBool, getFileName
// Variable global - ahora se inicializa automáticamente con valores por defecto
Param param;
@@ -42,22 +43,24 @@ void Param::precalculateZones() {
game.game_area.third_quarter_y = game.game_area.rect.h / 4 * 3;
}
// Carga los parámetros desde un archivo
// Carga los parámetros desde un archivo (busca primer al pack, fallback al filesystem)
void loadParamsFromFile(const std::string& file_path) {
// Los parámetros ya están inicializados con valores por defecto
// Solo necesitamos abrir el archivo y sobrescribir los valores que aparezcan
std::ifstream file(file_path);
if (!file.is_open()) {
auto buffer = ResourceHelper::loadFile(file_path);
if (buffer.empty()) {
std::cout << "Error: No se pudo abrir el archivo " << file_path << '\n';
throw std::runtime_error("No se pudo abrir el archivo: " + file_path);
}
std::string content(buffer.begin(), buffer.end());
std::istringstream stream(content);
std::string line;
std::string param_name;
std::string param_value;
while (std::getline(file, line)) {
while (std::getline(stream, line)) {
// Elimina comentarios
auto comment_pos = line.find('#');
if (comment_pos != std::string::npos) {
@@ -73,8 +76,6 @@ void loadParamsFromFile(const std::string& file_path) {
}
}
file.close();
// Recalcula las zonas después de cargar todos los parámetros
param.precalculateZones();
}