Files
coffee_crisis_arcade_edition/source/gamepad_config_manager.h

191 lines
6.9 KiB
C++

#pragma once
#include <external/json.hpp>
#include <fstream>
#include <string>
#include <unordered_map>
#include <vector>
#include "input.h" // Para Input
// Mapas para convertir entre enums y strings
std::unordered_map<Input::Action, std::string> actionToString = {
{Input::Action::FIRE_LEFT, "FIRE_LEFT"},
{Input::Action::FIRE_CENTER, "FIRE_CENTER"},
{Input::Action::FIRE_RIGHT, "FIRE_RIGHT"},
{Input::Action::START, "START"},
{Input::Action::SERVICE, "SERVICE"}};
std::unordered_map<std::string, Input::Action> stringToAction = {
{"FIRE_LEFT", Input::Action::FIRE_LEFT},
{"FIRE_CENTER", Input::Action::FIRE_CENTER},
{"FIRE_RIGHT", Input::Action::FIRE_RIGHT},
{"START", Input::Action::START},
{"SERVICE", Input::Action::SERVICE}};
std::unordered_map<SDL_GamepadButton, std::string> buttonToString = {
{SDL_GAMEPAD_BUTTON_WEST, "WEST"},
{SDL_GAMEPAD_BUTTON_NORTH, "NORTH"},
{SDL_GAMEPAD_BUTTON_EAST, "EAST"},
{SDL_GAMEPAD_BUTTON_SOUTH, "SOUTH"},
{SDL_GAMEPAD_BUTTON_START, "START"},
{SDL_GAMEPAD_BUTTON_BACK, "BACK"},
{SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, "LEFT_SHOULDER"},
{SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, "RIGHT_SHOULDER"}
// Añade todos los botones que necesites
};
std::unordered_map<std::string, SDL_GamepadButton> stringToButton = {
{"WEST", SDL_GAMEPAD_BUTTON_WEST},
{"NORTH", SDL_GAMEPAD_BUTTON_NORTH},
{"EAST", SDL_GAMEPAD_BUTTON_EAST},
{"SOUTH", SDL_GAMEPAD_BUTTON_SOUTH},
{"START", SDL_GAMEPAD_BUTTON_START},
{"BACK", SDL_GAMEPAD_BUTTON_BACK},
{"LEFT_SHOULDER", SDL_GAMEPAD_BUTTON_LEFT_SHOULDER},
{"RIGHT_SHOULDER", SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER}
// Añade todos los botones que necesites
};
struct GamepadConfig {
std::string name; // Nombre del dispositivo
std::unordered_map<Input::Action, SDL_GamepadButton> bindings; // Asociación acción-botón
GamepadConfig(std::string name = "")
: name(name),
bindings{
{Input::Action::FIRE_LEFT, SDL_GAMEPAD_BUTTON_WEST},
{Input::Action::FIRE_CENTER, SDL_GAMEPAD_BUTTON_NORTH},
{Input::Action::FIRE_RIGHT, SDL_GAMEPAD_BUTTON_EAST},
{Input::Action::START, SDL_GAMEPAD_BUTTON_START},
{Input::Action::SERVICE, SDL_GAMEPAD_BUTTON_BACK}} {}
// Reasigna un botón a una acción
void rebindAction(Input::Action action, SDL_GamepadButton new_button) {
bindings[action] = new_button;
}
};
class GamepadConfigManager {
public:
// Escribir vector de GamepadConfig a archivo JSON
static bool writeToJson(const std::vector<GamepadConfig>& 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) {
std::string actionStr = actionToString[action];
std::string buttonStr = buttonToString[button];
gamepadJson["bindings"][actionStr] = buttonStr;
}
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(std::vector<GamepadConfig>& 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();
}
};
/*
// Ejemplo de uso
void ejemploUso() {
std::vector<GamepadConfig> configs;
// Crear algunas configuraciones de ejemplo
GamepadConfig config1("Xbox Controller");
config1.rebindAction(Input::Action::FIRE_LEFT, SDL_GAMEPAD_BUTTON_SOUTH);
GamepadConfig config2("PS4 Controller");
config2.rebindAction(Input::Action::START, SDL_GAMEPAD_BUTTON_OPTIONS);
configs.push_back(config1);
configs.push_back(config2);
// Escribir a archivo
if (GamepadConfigManager::writeToJson(configs, "gamepad_config.json")) {
std::cout << "Configuración guardada exitosamente" << std::endl;
}
// Leer desde archivo
std::vector<GamepadConfig> loadedConfigs;
if (GamepadConfigManager::readFromJson(loadedConfigs, "gamepad_config.json")) {
std::cout << "Configuración cargada exitosamente" << std::endl;
std::cout << "Número de configuraciones: " << loadedConfigs.size() << std::endl;
}
}
*/