From 725d1440b843ba0ba6d59881d69e81773c38d71a Mon Sep 17 00:00:00 2001 From: narknon <73571427+narknon@users.noreply.github.com> Date: Sun, 17 Dec 2023 16:13:05 -0500 Subject: [PATCH] Add snapturn and related settings (#3) * Snapturn: Add snapturn feature and related gui settings * Snapturn: Migrate processing code to VR, remove unnecessary statics * Snapturn: Nullptr checks * Snapturn: abs->glm::abs --------- Co-authored-by: praydog --- src/mods/VR.cpp | 94 ++++++++++++++++++++++++ src/mods/VR.hpp | 25 +++++++ src/mods/vr/FFakeStereoRenderingHook.cpp | 3 + 3 files changed, 122 insertions(+) diff --git a/src/mods/VR.cpp b/src/mods/VR.cpp index 8402323c..90846433 100644 --- a/src/mods/VR.cpp +++ b/src/mods/VR.cpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include @@ -886,6 +888,54 @@ void VR::on_xinput_get_state(uint32_t* retval, uint32_t user_index, XINPUT_STATE } } } + + // Determine if snapturn should be run on frame + if (m_snapturn->value()) { + DPadMethod dpad_method = get_dpad_method(); + const auto snapturn_deadzone = get_snapturn_js_deadzone(); + float stick_axis{}; + + if (!m_was_snapturn_run_on_input) { + if (dpad_method == RIGHT_JOYSTICK) { + stick_axis = get_left_stick_axis().x; + if (glm::abs(stick_axis) >= snapturn_deadzone) { + if (stick_axis < 0) { + m_snapturn_left = true; + } + m_snapturn_on_frame = true; + m_was_snapturn_run_on_input = true; + } + } + else { + stick_axis = get_right_stick_axis().x; + if (glm::abs(stick_axis) >= snapturn_deadzone && !(dpad_method == DPadMethod::LEFT_TOUCH && is_action_active_any_joystick(m_action_thumbrest_touch_left))) { + if (stick_axis < 0) { + m_snapturn_left = true; + } + m_snapturn_on_frame = true; + m_was_snapturn_run_on_input = true; + } + } + } + else { + if (dpad_method == RIGHT_JOYSTICK) { + if (glm::abs(get_left_stick_axis().x) < snapturn_deadzone) { + m_was_snapturn_run_on_input = false; + } else { + state->Gamepad.sThumbLY = 0; + state->Gamepad.sThumbLX = 0; + } + } + else { + if (glm::abs(get_right_stick_axis().x) < snapturn_deadzone) { + m_was_snapturn_run_on_input = false; + } else { + state->Gamepad.sThumbRY = 0; + state->Gamepad.sThumbRX = 0; + } + } + } + } // Do it again after all the VR buttons have been spoofed update_imgui_state_from_xinput_state(*state, true); @@ -2060,6 +2110,17 @@ void VR::on_draw_sidebar_entry(std::string_view name) { ImGui::TreePop(); } + ImGui::SetNextItemOpen(true, ImGuiCond_::ImGuiCond_Once); + if (ImGui::TreeNode("Snap Turn")) { + m_snapturn->draw("Enabled"); + ImGui::TextWrapped("Set Snap Turn Rotation Angle in Degrees."); + m_snapturn_angle->draw("Angle"); + ImGui::TextWrapped("Set Snap Turn Joystick Deadzone."); + m_snapturn_joystick_deadzone->draw("Deadzone"); + + ImGui::TreePop(); + } + ImGui::SetNextItemOpen(true, ImGuiCond_::ImGuiCond_Once); if (ImGui::TreeNode("Movement Orientation")) { m_movement_orientation->draw("Type"); @@ -2722,4 +2783,37 @@ void VR::recenter_view() { const auto new_rotation_offset = glm::normalize(glm::inverse(utility::math::flatten(glm::quat{get_rotation(0)}))); set_rotation_offset(new_rotation_offset); +} + +void VR::process_snapturn() { + if (!m_snapturn_on_frame) { + return; + } + + const auto engine = sdk::UEngine::get(); + + if (engine == nullptr) { + return; + } + + const auto world = engine->get_world(); + + if (world == nullptr) { + return; + } + + if (const auto controller = sdk::UGameplayStatics::get()->get_player_controller(world, 0); controller != nullptr) { + auto controller_rot = controller->get_control_rotation(); + auto turn_degrees = get_snapturn_angle(); + + if (m_snapturn_left) { + turn_degrees = -turn_degrees; + m_snapturn_left = false; + } + + controller_rot.y += turn_degrees; + controller->set_control_rotation(controller_rot); + } + + m_snapturn_on_frame = false; } \ No newline at end of file diff --git a/src/mods/VR.hpp b/src/mods/VR.hpp index 64018c3a..040dfdeb 100644 --- a/src/mods/VR.hpp +++ b/src/mods/VR.hpp @@ -497,6 +497,18 @@ class VR : public Mod { return (DPadMethod)m_dpad_shifting_method->value(); } + bool is_snapturn_enabled() const { + return m_snapturn->value(); + } + + float get_snapturn_js_deadzone() const { + return m_snapturn_joystick_deadzone->value(); + } + + int get_snapturn_angle() const { + return m_snapturn_angle->value(); + } + bool should_skip_post_init_properties() const { return m_compatibility_skip_pip->value(); } @@ -731,6 +743,16 @@ class VR : public Mod { const ModToggle::Ptr m_roomscale_movement{ ModToggle::create(generate_name("RoomscaleMovement"), false) }; const ModToggle::Ptr m_roomscale_movement_actor_rotation{ ModToggle::create(generate_name("RoomscaleMovementActorRotation"), false) }; + // Snap turn settings and globals + void process_snapturn(); + + const ModToggle::Ptr m_snapturn{ ModToggle::create(generate_name("SnapTurn"), false) }; + const ModSlider::Ptr m_snapturn_joystick_deadzone{ ModSlider::create(generate_name("SnapturnJoystickDeadzone"), 0.01f, 0.99f, 0.2f) }; + const ModInt32::Ptr m_snapturn_angle{ ModSliderInt32::create(generate_name("SnapturnTurnAngle"), 1, 359, 45) }; + bool m_snapturn_on_frame{false}; + bool m_snapturn_left{false}; + bool m_was_snapturn_run_on_input{false}; + // Aim method and movement orientation are not the same thing, but they can both have the same options const ModCombo::Ptr m_aim_method{ ModCombo::create(generate_name("AimMethod"), s_aim_method_names, AimMethod::GAME) }; const ModCombo::Ptr m_movement_orientation{ ModCombo::create(generate_name("MovementOrientation"), s_aim_method_names, AimMethod::GAME) }; @@ -803,6 +825,9 @@ class VR : public Mod { *m_2d_screen_mode, *m_roomscale_movement, *m_roomscale_movement_actor_rotation, + *m_snapturn, + *m_snapturn_joystick_deadzone, + *m_snapturn_angle, *m_aim_method, *m_movement_orientation, *m_aim_speed, diff --git a/src/mods/vr/FFakeStereoRenderingHook.cpp b/src/mods/vr/FFakeStereoRenderingHook.cpp index ad080ca1..582e6b08 100644 --- a/src/mods/vr/FFakeStereoRenderingHook.cpp +++ b/src/mods/vr/FFakeStereoRenderingHook.cpp @@ -4134,6 +4134,9 @@ __forceinline void FFakeStereoRenderingHook::calculate_stereo_view_offset( } } } + + // Process snapturn + vr->process_snapturn(); } if (!is_full_pass) {