Files
jaildoctors_dilemma/source/game/options.cpp

273 lines
8.5 KiB
C++

#include "game/options.hpp"
#include <SDL3/SDL.h>
#include <fstream> // Para ifstream, ofstream
#include <iostream> // Para cout, cerr
#include <string> // Para string
#include "external/fkyaml_node.hpp" // Para fkyaml::node
#include "game/defaults.hpp" // Para GameDefaults::VERSION
namespace Options {
// Crea e inicializa las opciones del programa
void init() {
#ifdef _DEBUG
console = true;
#else
console = false;
#endif
}
// Establece la ruta del fichero de configuración
void setConfigFile(const std::string& path) {
config_file_path_ = path;
}
// Carga las opciones desde el fichero configurado
auto loadFromFile() -> bool {
// Versión esperada del fichero
const std::string CONFIG_VERSION = GameDefaults::VERSION;
version = "";
// Intenta abrir y leer el fichero
std::ifstream file(config_file_path_);
if (!file.good()) {
if (console) {
std::cout << "Config file not found, creating default: " << config_file_path_ << '\n';
}
saveToFile();
return true;
}
// Lee todo el contenido del fichero
std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
try {
if (console) {
std::cout << "Reading config file: " << config_file_path_ << '\n';
}
// Parsea el YAML
auto yaml = fkyaml::node::deserialize(content);
// Lee la versión
if (yaml.contains("version")) {
version = yaml["version"].get_value<std::string>();
}
// Si la versión no coincide, crea un fichero nuevo con valores por defecto
if (CONFIG_VERSION != version) {
if (console) {
std::cout << "Config version mismatch (expected: " << CONFIG_VERSION << ", got: " << version << "), creating new config\n";
}
init();
saveToFile();
return true;
}
// Lee window
if (yaml.contains("window")) {
const auto& win = yaml["window"];
if (win.contains("zoom")) {
int val = win["zoom"].get_value<int>();
window.zoom = (val > 0) ? val : GameDefaults::WINDOW_ZOOM;
}
}
// Lee video
if (yaml.contains("video")) {
const auto& vid = yaml["video"];
if (vid.contains("mode")) {
video.fullscreen = vid["mode"].get_value<bool>();
}
if (vid.contains("filter")) {
int val = vid["filter"].get_value<int>();
if (val == static_cast<int>(Screen::Filter::NEAREST) || val == static_cast<int>(Screen::Filter::LINEAR)) {
video.filter = static_cast<Screen::Filter>(val);
}
}
if (vid.contains("shaders")) {
video.shaders = vid["shaders"].get_value<bool>();
}
if (vid.contains("vertical_sync")) {
video.vertical_sync = vid["vertical_sync"].get_value<bool>();
}
if (vid.contains("integer_scale")) {
video.integer_scale = vid["integer_scale"].get_value<bool>();
}
if (vid.contains("keep_aspect")) {
video.keep_aspect = vid["keep_aspect"].get_value<bool>();
}
if (vid.contains("palette")) {
video.palette = vid["palette"].get_value<std::string>();
}
// Lee border
if (vid.contains("border")) {
const auto& border = vid["border"];
if (border.contains("enabled")) {
video.border.enabled = border["enabled"].get_value<bool>();
}
if (border.contains("width")) {
float val = border["width"].get_value<float>();
video.border.width = (val > 0) ? val : GameDefaults::BORDER_WIDTH;
}
if (border.contains("height")) {
float val = border["height"].get_value<float>();
video.border.height = (val > 0) ? val : GameDefaults::BORDER_HEIGHT;
}
}
}
// Lee controls
if (yaml.contains("controls")) {
const auto& ctrl = yaml["controls"];
if (ctrl.contains("left")) {
int val = ctrl["left"].get_value<int>();
controls.key_left = static_cast<SDL_Scancode>(val);
}
if (ctrl.contains("right")) {
int val = ctrl["right"].get_value<int>();
controls.key_right = static_cast<SDL_Scancode>(val);
}
if (ctrl.contains("jump")) {
int val = ctrl["jump"].get_value<int>();
controls.key_jump = static_cast<SDL_Scancode>(val);
}
}
// Lee gamepad_controls
if (yaml.contains("gamepad_controls")) {
const auto& gp = yaml["gamepad_controls"];
if (gp.contains("left")) {
gamepad_controls.button_left = gp["left"].get_value<int>();
}
if (gp.contains("right")) {
gamepad_controls.button_right = gp["right"].get_value<int>();
}
if (gp.contains("jump")) {
gamepad_controls.button_jump = gp["jump"].get_value<int>();
}
}
if (console) {
std::cout << "Config file loaded successfully\n\n";
}
return true;
} catch (const fkyaml::exception& e) {
if (console) {
std::cerr << "Error parsing YAML config: " << e.what() << '\n';
std::cerr << "Creating new config with defaults\n";
}
init();
saveToFile();
return true;
}
}
// Guarda las opciones al fichero configurado
auto saveToFile() -> bool {
// Crea el nodo YAML raíz como mapping
fkyaml::node yaml(fkyaml::node_type::MAPPING);
// Establece la versión
yaml["version"] = GameDefaults::VERSION;
// Window
fkyaml::node window_node(fkyaml::node_type::MAPPING);
window_node["zoom"] = window.zoom;
yaml["window"] = window_node;
// Video
fkyaml::node video_node(fkyaml::node_type::MAPPING);
video_node["mode"] = video.fullscreen;
video_node["filter"] = static_cast<int>(video.filter);
video_node["shaders"] = video.shaders;
video_node["vertical_sync"] = video.vertical_sync;
video_node["integer_scale"] = video.integer_scale;
video_node["keep_aspect"] = video.keep_aspect;
video_node["palette"] = video.palette;
// Video border
fkyaml::node border_node(fkyaml::node_type::MAPPING);
border_node["enabled"] = video.border.enabled;
border_node["width"] = video.border.width;
border_node["height"] = video.border.height;
video_node["border"] = border_node;
yaml["video"] = video_node;
// Controls
fkyaml::node controls_node(fkyaml::node_type::MAPPING);
controls_node["left"] = static_cast<int>(controls.key_left);
controls_node["right"] = static_cast<int>(controls.key_right);
controls_node["jump"] = static_cast<int>(controls.key_jump);
yaml["controls"] = controls_node;
// Gamepad controls
fkyaml::node gamepad_node(fkyaml::node_type::MAPPING);
gamepad_node["left"] = gamepad_controls.button_left;
gamepad_node["right"] = gamepad_controls.button_right;
gamepad_node["jump"] = gamepad_controls.button_jump;
yaml["gamepad_controls"] = gamepad_node;
// Serializa a string
std::string yaml_content = fkyaml::node::serialize(yaml);
// Abre el fichero para escritura
std::ofstream file(config_file_path_);
if (!file.is_open()) {
if (console) {
std::cerr << "Error: Unable to open file " << config_file_path_ << " for writing\n";
}
return false;
}
if (console) {
std::cout << "Writing config file: " << config_file_path_ << '\n';
}
// Escribe el encabezado con comentarios
file << "# JailDoctor's Dilemma - Configuration File\n";
file << "# This file is automatically generated and managed by the game\n";
file << "#\n";
file << "# Video filters: 0 = Nearest (pixel perfect), 1 = Linear (smooth)\n";
file << "# SDL_Scancode values for keyboard controls (see SDL documentation)\n";
file << "# Gamepad button values: 0-20+ = SDL_GamepadButton, 100 = L2, 101 = R2, 200+ = Axes\n";
file << "\n";
// Escribe el contenido YAML
file << yaml_content;
file.close();
if (console) {
std::cout << "Config file saved successfully\n\n";
}
return true;
}
} // namespace Options