From 52e54d5274e89b007d231d3645d0ffb301366e30 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Sat, 18 Jun 2022 04:51:44 +0800 Subject: [PATCH] Add support for saving control profiles --- CMakeLists.txt | 1 - src/game/controls.cpp | 192 ++++++++++++++++++ src/game/controls.hpp | 7 + src/game/states/controls-menu.cpp | 18 +- ...onfig-menu.cpp => gamepad-config-menu.cpp} | 24 ++- ...onfig-menu.hpp => gamepad-config-menu.hpp} | 12 +- src/game/states/keyboard-config-menu.cpp | 16 +- src/input/event-router.hpp | 3 +- 8 files changed, 239 insertions(+), 34 deletions(-) rename src/game/states/{controller-config-menu.cpp => gamepad-config-menu.cpp} (95%) rename src/game/states/{controller-config-menu.hpp => gamepad-config-menu.hpp} (75%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d3614e6..7f0f857 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,5 @@ cmake_minimum_required(VERSION 3.7) - option(VERSION_STRING "Project version string" "0.0.0") project(antkeeper VERSION ${VERSION_STRING} LANGUAGES CXX) diff --git a/src/game/controls.cpp b/src/game/controls.cpp index 5479406..393fc3b 100644 --- a/src/game/controls.cpp +++ b/src/game/controls.cpp @@ -19,6 +19,7 @@ #include "controls.hpp" #include "resources/resource-manager.hpp" +#include "resources/json.hpp" #include "application.hpp" #include @@ -345,6 +346,197 @@ void apply_control_profile(game::context* ctx, const json& profile) } } +void save_control_profile(game::context* ctx) +{ + std::string control_profile_path; + if (ctx->config->contains("control_profile")) + control_profile_path = ctx->config_path + "controls/" + (*ctx->config)["control_profile"].get(); + + ctx->logger->push_task("Saving control profile to \"" + control_profile_path + "\""); + try + { + json control_profile; + + // Add controls element + auto& controls_element = control_profile["controls"]; + controls_element = json::object(); + + for (auto controls_it = ctx->controls.begin(); controls_it != ctx->controls.end(); ++controls_it) + { + const std::string& control_name = controls_it->first; + input::control* control = controls_it->second; + + // Add control element + auto& control_element = controls_element[control_name]; + control_element = json::array(); + + // Add control mappings + auto mappings = ctx->input_event_router->get_mappings(control); + for (input::mapping* mapping: *mappings) + { + json mapping_element; + + switch (mapping->get_type()) + { + case input::mapping_type::key: + { + const input::key_mapping* key_mapping = static_cast(mapping); + mapping_element["device"] = "keyboard"; + mapping_element["key"] = input::keyboard::get_scancode_name(key_mapping->scancode); + break; + } + + case input::mapping_type::mouse_wheel: + { + const input::mouse_wheel_mapping* wheel_mapping = static_cast(mapping); + + mapping_element["device"] = "mouse"; + switch (wheel_mapping->axis) + { + case input::mouse_wheel_axis::negative_x: + mapping_element["device"] = "x-"; + break; + case input::mouse_wheel_axis::positive_x: + mapping_element["device"] = "x+"; + break; + case input::mouse_wheel_axis::negative_y: + mapping_element["device"] = "y-"; + break; + case input::mouse_wheel_axis::positive_y: + mapping_element["device"] = "y+"; + break; + default: + break; + } + break; + } + + case input::mapping_type::mouse_button: + { + const input::mouse_button_mapping* button_mapping = static_cast(mapping); + mapping_element["device"] = "mouse"; + mapping_element["button"] = button_mapping->button; + break; + } + + case input::mapping_type::gamepad_axis: + { + const input::gamepad_axis_mapping* axis_mapping = static_cast(mapping); + mapping_element["device"] = "gamepad"; + switch (axis_mapping->axis) + { + case input::gamepad_axis::left_x: + if (axis_mapping->negative) + mapping_element["axis"] = "leftx-"; + else + mapping_element["axis+"] = "leftx+"; + break; + case input::gamepad_axis::left_y: + if (axis_mapping->negative) + mapping_element["axis"] = "lefty-"; + else + mapping_element["axis"] = "lefty+"; + break; + case input::gamepad_axis::right_x: + if (axis_mapping->negative) + mapping_element["axis"] = "rightx-"; + else + mapping_element["axis+"] = "rightx+"; + break; + case input::gamepad_axis::right_y: + if (axis_mapping->negative) + mapping_element["axis"] = "righty-"; + else + mapping_element["axis"] = "righty+"; + break; + case input::gamepad_axis::left_trigger: + mapping_element["axis"] = "lefttrigger+"; + break; + case input::gamepad_axis::right_trigger: + mapping_element["axis"] = "righttrigger+"; + break; + default: + break; + } + break; + } + + case input::mapping_type::gamepad_button: + { + const input::gamepad_button_mapping* button_mapping = static_cast(mapping); + mapping_element["device"] = "gamepad"; + + switch (button_mapping->button) + { + case input::gamepad_button::a: + mapping_element["button"] = "a"; + break; + case input::gamepad_button::b: + mapping_element["button"] = "b"; + break; + case input::gamepad_button::x: + mapping_element["button"] = "x"; + break; + case input::gamepad_button::y: + mapping_element["button"] = "y"; + break; + case input::gamepad_button::back: + mapping_element["button"] = "back"; + break; + case input::gamepad_button::guide: + mapping_element["button"] = "guide"; + break; + case input::gamepad_button::start: + mapping_element["button"] = "start"; + break; + case input::gamepad_button::left_stick: + mapping_element["button"] = "leftstick"; + break; + case input::gamepad_button::right_stick: + mapping_element["button"] = "rightstick"; + break; + case input::gamepad_button::left_shoulder: + mapping_element["button"] = "leftshoulder"; + break; + case input::gamepad_button::right_shoulder: + mapping_element["button"] = "rightshoulder"; + break; + case input::gamepad_button::dpad_up: + mapping_element["button"] = "dpup"; + break; + case input::gamepad_button::dpad_down: + mapping_element["button"] = "dpdown"; + break; + case input::gamepad_button::dpad_left: + mapping_element["button"] = "dpleft"; + break; + case input::gamepad_button::dpad_right: + mapping_element["button"] = "dpright"; + break; + default: + break; + } + break; + } + + default: + break; + } + + control_element.push_back(mapping_element); + } + } + + std::ofstream control_profile_file(control_profile_path); + control_profile_file << control_profile; + } + catch (...) + { + ctx->logger->pop_task(EXIT_FAILURE); + } + ctx->logger->pop_task(EXIT_SUCCESS); +} + void apply_gamepad_calibration(input::gamepad* gamepad, const json& calibration) { // Parse and apply activation thresholds diff --git a/src/game/controls.hpp b/src/game/controls.hpp index c266bc5..cd17c1d 100644 --- a/src/game/controls.hpp +++ b/src/game/controls.hpp @@ -34,6 +34,13 @@ namespace game { */ void apply_control_profile(game::context* ctx, const json& profile); +/** + * Saves the current control profile. + * + * @param ctx Game context. + */ +void save_control_profile(game::context* ctx); + /** * Generates a default control profile. * diff --git a/src/game/states/controls-menu.cpp b/src/game/states/controls-menu.cpp index 68ac127..5327977 100644 --- a/src/game/states/controls-menu.cpp +++ b/src/game/states/controls-menu.cpp @@ -19,7 +19,7 @@ #include "game/states/controls-menu.hpp" #include "game/states/keyboard-config-menu.hpp" -#include "game/states/controller-config-menu.hpp" +#include "game/states/gamepad-config-menu.hpp" #include "game/states/options-menu.hpp" #include "application.hpp" #include "scene/text.hpp" @@ -38,17 +38,17 @@ void enter(game::context* ctx) // Construct menu item texts scene::text* keyboard_text = new scene::text(); - scene::text* controller_text = new scene::text(); + scene::text* gamepad_text = new scene::text(); scene::text* back_text = new scene::text(); // Build list of menu item texts ctx->menu_item_texts.push_back({keyboard_text, nullptr}); - ctx->menu_item_texts.push_back({controller_text, nullptr}); + ctx->menu_item_texts.push_back({gamepad_text, nullptr}); ctx->menu_item_texts.push_back({back_text, nullptr}); // Set content of menu item texts keyboard_text->set_content((*ctx->strings)["controls_menu_keyboard"]); - controller_text->set_content((*ctx->strings)["controls_menu_controller"]); + gamepad_text->set_content((*ctx->strings)["controls_menu_gamepad"]); back_text->set_content((*ctx->strings)["back"]); // Init menu item index @@ -69,12 +69,12 @@ void enter(game::context* ctx) next_state.exit = std::bind(game::state::keyboard_config_menu::exit, ctx); ctx->app->change_state(next_state); }; - auto select_controller_callback = [ctx]() + auto select_gamepad_callback = [ctx]() { application::state next_state; - next_state.name = "controller_config_menu"; - next_state.enter = std::bind(game::state::controller_config_menu::enter, ctx); - next_state.exit = std::bind(game::state::controller_config_menu::exit, ctx); + next_state.name = "gamepad_config_menu"; + next_state.enter = std::bind(game::state::gamepad_config_menu::enter, ctx); + next_state.exit = std::bind(game::state::gamepad_config_menu::exit, ctx); ctx->app->change_state(next_state); }; auto select_back_callback = [ctx]() @@ -88,7 +88,7 @@ void enter(game::context* ctx) // Build list of menu select callbacks ctx->menu_select_callbacks.push_back(select_keyboard_callback); - ctx->menu_select_callbacks.push_back(select_controller_callback); + ctx->menu_select_callbacks.push_back(select_gamepad_callback); ctx->menu_select_callbacks.push_back(select_back_callback); // Build list of menu left callbacks diff --git a/src/game/states/controller-config-menu.cpp b/src/game/states/gamepad-config-menu.cpp similarity index 95% rename from src/game/states/controller-config-menu.cpp rename to src/game/states/gamepad-config-menu.cpp index fea7de7..10186f6 100644 --- a/src/game/states/controller-config-menu.cpp +++ b/src/game/states/gamepad-config-menu.cpp @@ -17,7 +17,7 @@ * along with Antkeeper source code. If not, see . */ -#include "game/states/controller-config-menu.hpp" +#include "game/states/gamepad-config-menu.hpp" #include "game/states/controls-menu.hpp" #include "application.hpp" #include "scene/text.hpp" @@ -25,11 +25,12 @@ #include "debug/logger.hpp" #include "resources/resource-manager.hpp" #include "game/menu.hpp" +#include "game/controls.hpp" #include "animation/timeline.hpp" namespace game { namespace state { -namespace controller_config_menu { +namespace gamepad_config_menu { static std::string get_binding_string(game::context* ctx, input::control* control) { @@ -273,12 +274,12 @@ void enter(game::context* ctx) ctx->ui_clear_pass->set_cleared_buffers(true, true, false); // Add camera control menu items - add_control_item(ctx, "dolly_forward"); - add_control_item(ctx, "dolly_backward"); - add_control_item(ctx, "truck_left"); - add_control_item(ctx, "truck_right"); - add_control_item(ctx, "pedestal_up"); - add_control_item(ctx, "pedestal_down"); + add_control_item(ctx, "move_forward"); + add_control_item(ctx, "move_back"); + add_control_item(ctx, "move_left"); + add_control_item(ctx, "move_right"); + add_control_item(ctx, "move_up"); + add_control_item(ctx, "move_down"); // Add application control menu items add_control_item(ctx, "toggle_fullscreen"); @@ -294,7 +295,7 @@ void enter(game::context* ctx) back_text->set_content((*ctx->strings)["back"]); // Init menu item index - game::menu::init_menu_item_index(ctx, "controller_config"); + game::menu::init_menu_item_index(ctx, "gamepad_config"); game::menu::update_text_color(ctx); game::menu::update_text_font(ctx); @@ -338,9 +339,12 @@ void exit(game::context* ctx) game::menu::remove_text_from_ui(ctx); game::menu::delete_text(ctx); + // Save control profile + game::save_control_profile(ctx); + ctx->ui_clear_pass->set_cleared_buffers(false, true, false); } -} // namespace controller_config_menu +} // namespace gamepad_config_menu } // namespace state } // namespace game diff --git a/src/game/states/controller-config-menu.hpp b/src/game/states/gamepad-config-menu.hpp similarity index 75% rename from src/game/states/controller-config-menu.hpp rename to src/game/states/gamepad-config-menu.hpp index 453c89c..dc5f56b 100644 --- a/src/game/states/controller-config-menu.hpp +++ b/src/game/states/gamepad-config-menu.hpp @@ -17,23 +17,23 @@ * along with Antkeeper source code. If not, see . */ -#ifndef ANTKEEPER_GAME_STATE_CONTROLLER_CONFIG_MENU_HPP -#define ANTKEEPER_GAME_STATE_CONTROLLER_CONFIG_MENU_HPP +#ifndef ANTKEEPER_GAME_STATE_GAMEPAD_CONFIG_MENU_HPP +#define ANTKEEPER_GAME_STATE_GAMEPAD_CONFIG_MENU_HPP #include "game/context.hpp" namespace game { namespace state { -/// Game controller config menu screen game state functions. -namespace controller_config_menu { +/// Gamepad config menu screen game state functions. +namespace gamepad_config_menu { void enter(game::context* ctx); void exit(game::context* ctx); -} // namespace controller_config_menu +} // namespace gamepad_config_menu } // namespace state } // namespace game -#endif // ANTKEEPER_GAME_STATE_CONTROLLER_CONFIG_MENU_HPP +#endif // ANTKEEPER_GAME_STATE_GAMEPAD_CONFIG_MENU_HPP diff --git a/src/game/states/keyboard-config-menu.cpp b/src/game/states/keyboard-config-menu.cpp index ab79c54..69cba9c 100644 --- a/src/game/states/keyboard-config-menu.cpp +++ b/src/game/states/keyboard-config-menu.cpp @@ -25,6 +25,7 @@ #include "debug/logger.hpp" #include "resources/resource-manager.hpp" #include "game/menu.hpp" +#include "game/controls.hpp" #include "animation/timeline.hpp" namespace game { @@ -234,12 +235,12 @@ void enter(game::context* ctx) ctx->ui_clear_pass->set_cleared_buffers(true, true, false); // Add camera control menu items - add_control_item(ctx, "dolly_forward"); - add_control_item(ctx, "dolly_backward"); - add_control_item(ctx, "truck_left"); - add_control_item(ctx, "truck_right"); - add_control_item(ctx, "pedestal_up"); - add_control_item(ctx, "pedestal_down"); + add_control_item(ctx, "move_forward"); + add_control_item(ctx, "move_back"); + add_control_item(ctx, "move_left"); + add_control_item(ctx, "move_right"); + add_control_item(ctx, "move_up"); + add_control_item(ctx, "move_down"); // Add application control menu items add_control_item(ctx, "toggle_fullscreen"); @@ -299,6 +300,9 @@ void exit(game::context* ctx) game::menu::remove_text_from_ui(ctx); game::menu::delete_text(ctx); + // Save control profile + game::save_control_profile(ctx); + ctx->ui_clear_pass->set_cleared_buffers(false, true, false); } diff --git a/src/input/event-router.hpp b/src/input/event-router.hpp index 00ba571..22f5dc6 100644 --- a/src/input/event-router.hpp +++ b/src/input/event-router.hpp @@ -71,8 +71,7 @@ public: * @param mapping Input mapping to add. */ void add_mapping(const mapping& mapping); - - + /** * Removes all input mappings from the router that are associated with the specified control. *