#pragma once #include #include #include #include #include #include "external/json.hpp" #include "input_types.h" // Solo incluimos los tipos compartidos // --- Estructuras --- struct GamepadConfig { std::string name; // Nombre del dispositivo std::string path; // Ruta física del dispositivo std::unordered_map bindings; // Asociación acción-botón GamepadConfig(std::string name, std::string path) : name(std::move(name)), path(std::move(path)), bindings{ {InputAction::FIRE_LEFT, SDL_GAMEPAD_BUTTON_WEST}, {InputAction::FIRE_CENTER, SDL_GAMEPAD_BUTTON_NORTH}, {InputAction::FIRE_RIGHT, SDL_GAMEPAD_BUTTON_EAST}, {InputAction::START, SDL_GAMEPAD_BUTTON_START}, {InputAction::SERVICE, SDL_GAMEPAD_BUTTON_BACK}} {} // Reasigna un botón a una acción void rebindAction(InputAction action, SDL_GamepadButton new_button) { bindings[action] = new_button; } }; // --- Tipos --- using GamepadConfigs = std::vector; // Vector de configuraciones de gamepad // --- Clase GamepadConfigManager: gestor de configuraciones de gamepad --- class GamepadConfigManager { public: // --- Métodos estáticos --- static auto writeToJson(const GamepadConfigs& configs, const std::string& filename) -> bool { // Escribir configuraciones a JSON try { nlohmann::json j; j["gamepads"] = nlohmann::json::array(); for (const auto& config : configs) { nlohmann::json gamepad_json; gamepad_json["name"] = config.name; gamepad_json["path"] = config.path; gamepad_json["bindings"] = nlohmann::json::object(); // Convertir bindings a JSON for (const auto& [action, button] : config.bindings) { auto action_it = ACTION_TO_STRING.find(action); auto button_it = BUTTON_TO_STRING.find(button); if (action_it != ACTION_TO_STRING.end() && button_it != BUTTON_TO_STRING.end()) { gamepad_json["bindings"][action_it->second] = button_it->second; } } j["gamepads"].push_back(gamepad_json); } // Escribir al archivo std::ofstream file(filename); if (!file.is_open()) { return false; } file << j.dump(4); // Formato con indentación de 4 espacios file.close(); return true; } catch (const std::exception& e) { // Log del error si tienes sistema de logging return false; } } // Leer vector de GamepadConfig desde archivo JSON static auto readFromJson(GamepadConfigs& configs, const std::string& filename) -> bool { try { std::ifstream file(filename); if (!file.is_open()) { return false; } nlohmann::json j; file >> j; file.close(); configs.clear(); if (!j.contains("gamepads") || !j["gamepads"].is_array()) { return false; } for (const auto& gamepad_json : j["gamepads"]) { if (!gamepad_json.contains("name") || !gamepad_json.contains("bindings")) { continue; // Saltar configuraciones malformadas } // Leer el campo path si existe, si no dejarlo vacío std::string path = gamepad_json.contains("path") ? gamepad_json["path"].get() : ""; GamepadConfig config(gamepad_json["name"], path); // Limpiar bindings por defecto para cargar los del archivo config.bindings.clear(); // Cargar bindings desde JSON for (const auto& [actionStr, buttonStr] : gamepad_json["bindings"].items()) { auto action_it = STRING_TO_ACTION.find(actionStr); auto button_it = STRING_TO_BUTTON.find(buttonStr); if (action_it != STRING_TO_ACTION.end() && button_it != STRING_TO_BUTTON.end()) { config.bindings[action_it->second] = button_it->second; } } configs.push_back(config); } return true; } catch (const std::exception& e) { // Log del error si tienes sistema de logging return false; } } // Método auxiliar para verificar si un archivo existe static auto fileExists(const std::string& filename) -> bool { std::ifstream file(filename); return file.good(); } };