diff --git a/src/mods/VR.cpp b/src/mods/VR.cpp index 8402323c..556acbe2 100644 --- a/src/mods/VR.cpp +++ b/src/mods/VR.cpp @@ -886,6 +886,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 (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 (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 (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 (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 +2108,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"); diff --git a/src/mods/VR.hpp b/src/mods/VR.hpp index 64018c3a..087b7917 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,14 @@ 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 + 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) }; + static inline bool m_snapturn_on_frame{false}; + static inline bool m_snapturn_left{false}; + static inline 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 +823,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..18b844a7 100644 --- a/src/mods/vr/FFakeStereoRenderingHook.cpp +++ b/src/mods/vr/FFakeStereoRenderingHook.cpp @@ -4134,6 +4134,23 @@ __forceinline void FFakeStereoRenderingHook::calculate_stereo_view_offset( } } } + + // Process snapturn + if (vr->m_snapturn_on_frame) { + const auto world = sdk::UEngine::get()->get_world(); + if (const auto controller = sdk::UGameplayStatics::get()->get_player_controller(world, 0); controller != nullptr) { + auto controller_rot = controller->get_control_rotation(); + auto turn_degrees = vr->get_snapturn_angle(); + + if (vr->m_snapturn_left) { + turn_degrees = -turn_degrees; + vr->m_snapturn_left = false; + } + controller_rot.y += turn_degrees; + controller->set_control_rotation(controller_rot); + } + vr->m_snapturn_on_frame = false; + } } if (!is_full_pass) {