#pragma once #include #include #include #include #include #include "input_types.h" // Solo incluimos los tipos compartidos struct GamepadConfig { std::string name; // Nombre del dispositivo std::unordered_map bindings; // Asociación acción-botón GamepadConfig(std::string name = "") : name(name), 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; } }; using GamepadConfigs = std::vector; class GamepadConfigManager { public: // Escribir vector de GamepadConfig a archivo JSON static bool writeToJson(const GamepadConfigs& configs, const std::string& filename) { try { nlohmann::json j; j["gamepads"] = nlohmann::json::array(); for (const auto& config : configs) { nlohmann::json gamepadJson; gamepadJson["name"] = config.name; gamepadJson["bindings"] = nlohmann::json::object(); // Convertir bindings a JSON for (const auto& [action, button] : config.bindings) { auto actionIt = actionToString.find(action); auto buttonIt = buttonToString.find(button); if (actionIt != actionToString.end() && buttonIt != buttonToString.end()) { gamepadJson["bindings"][actionIt->second] = buttonIt->second; } } j["gamepads"].push_back(gamepadJson); } // 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 bool readFromJson(GamepadConfigs& configs, const std::string& filename) { 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& gamepadJson : j["gamepads"]) { if (!gamepadJson.contains("name") || !gamepadJson.contains("bindings")) { continue; // Saltar configuraciones malformadas } GamepadConfig config(gamepadJson["name"]); // Limpiar bindings por defecto para cargar los del archivo config.bindings.clear(); // Cargar bindings desde JSON for (const auto& [actionStr, buttonStr] : gamepadJson["bindings"].items()) { auto actionIt = stringToAction.find(actionStr); auto buttonIt = stringToButton.find(buttonStr); if (actionIt != stringToAction.end() && buttonIt != stringToButton.end()) { config.bindings[actionIt->second] = buttonIt->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 bool fileExists(const std::string& filename) { std::ifstream file(filename); return file.good(); } };