diff --git a/shared/sdk/AActor.cpp b/shared/sdk/AActor.cpp index e70ffd26..f5fb5d6a 100644 --- a/shared/sdk/AActor.cpp +++ b/shared/sdk/AActor.cpp @@ -68,6 +68,7 @@ glm::vec3 AActor::get_actor_location() { return *(glm::vec<3, double>*)params.data(); } + bool AActor::set_actor_rotation(const glm::vec3& rotation, bool teleport) { static const auto func = static_class()->find_function(L"K2_SetActorRotation"); const auto frotator = sdk::ScriptRotator::static_struct(); @@ -98,5 +99,30 @@ bool AActor::set_actor_rotation(const glm::vec3& rotation, bool teleport) { this->process_event(func, params.data()); return ret; +} + +glm::vec3 AActor::get_actor_rotation() { + static const auto func = static_class()->find_function(L"K2_GetActorRotation"); + const auto frotator = sdk::ScriptVector::static_struct(); + + const auto is_ue5 = frotator->get_struct_size() == sizeof(glm::vec<3, double>); + + std::vector params{}; + + // add a vec3 + if (!is_ue5) { + params.insert(params.end(), sizeof(glm::vec3), 0); + } else { + params.insert(params.end(), sizeof(glm::vec<3, double>), 0); + } + + this->process_event(func, params.data()); + + if (!is_ue5) { + return *(glm::vec3*)params.data(); + } + + return *(glm::vec<3, double>*)params.data(); }; + } \ No newline at end of file diff --git a/shared/sdk/AActor.hpp b/shared/sdk/AActor.hpp index a4e304ed..bd19d086 100644 --- a/shared/sdk/AActor.hpp +++ b/shared/sdk/AActor.hpp @@ -14,6 +14,7 @@ class AActor : public UObject { glm::vec3 get_actor_location(); bool set_actor_rotation(const glm::vec3& rotation, bool teleport); + glm::vec3 get_actor_rotation(); protected: }; diff --git a/shared/sdk/APlayerController.cpp b/shared/sdk/APlayerController.cpp index 01944a5c..28c22566 100644 --- a/shared/sdk/APlayerController.cpp +++ b/shared/sdk/APlayerController.cpp @@ -1,7 +1,60 @@ +#include +#include "UObjectArray.hpp" +#include "ScriptVector.hpp" +#include "ScriptRotator.hpp" + #include "APlayerController.hpp" namespace sdk { +UClass* AController::static_class() { + return sdk::find_uobject(L"Class /Script/Engine.Controller"); +} + +void AController::set_control_rotation(const glm::vec3& newrotation) { + static const auto func = static_class()->find_function(L"SetControlRotation"); + const auto frotator = sdk::ScriptRotator::static_struct(); + + const auto is_ue5 = frotator->get_struct_size() == sizeof(glm::vec<3, double>); + + // Need to dynamically allocate the params because of unknown FRotator size + std::vector params{}; + // add a vec3 + if (!is_ue5) { + params.insert(params.end(), (uint8_t*)&newrotation, (uint8_t*)&newrotation + sizeof(glm::vec3)); + } else { + glm::vec<3, double> rot = newrotation; + params.insert(params.end(), (uint8_t*)&rot, (uint8_t*)&rot + sizeof(glm::vec<3, double>)); + } + + this->process_event(func, params.data()); +} + +glm::vec3 AController::get_control_rotation() { + static const auto func = static_class()->find_function(L"GetControlRotation"); + const auto frotator = sdk::ScriptVector::static_struct(); + + const auto is_ue5 = frotator->get_struct_size() == sizeof(glm::vec<3, double>); + std::vector params{}; + + // add a vec3 + if (!is_ue5) { + params.insert(params.end(), sizeof(glm::vec3), 0); + } else { + params.insert(params.end(), sizeof(glm::vec<3, double>), 0); + } + this->process_event(func, params.data()); + + if (!is_ue5) { + return *(glm::vec3*)params.data(); + } + return *(glm::vec<3, double>*)params.data(); +} + +UClass* APlayerController::static_class() { + return sdk::find_uobject(L"Class /Script/Engine.PlayerController"); +} + APawn* APlayerController::get_acknowledged_pawn() const { return get_property(L"AcknowledgedPawn"); } -} \ No newline at end of file +} diff --git a/shared/sdk/APlayerController.hpp b/shared/sdk/APlayerController.hpp index 2dd4a5fd..e79cf754 100644 --- a/shared/sdk/APlayerController.hpp +++ b/shared/sdk/APlayerController.hpp @@ -2,13 +2,27 @@ #include "UObject.hpp" +#include + namespace sdk { class APawn; -class APlayerController : public UObject { +class AController : public UObject { +public: + static UClass* static_class(); + + void set_control_rotation(const glm::vec3& newrotation); + glm::vec3 get_control_rotation(); + +protected: +}; + +class APlayerController : public AController { public: + static UClass* static_class(); + APawn* get_acknowledged_pawn() const; protected: }; -} \ No newline at end of file +} diff --git a/src/mods/vr/FFakeStereoRenderingHook.cpp b/src/mods/vr/FFakeStereoRenderingHook.cpp index 5008db0a..54f74ce4 100644 --- a/src/mods/vr/FFakeStereoRenderingHook.cpp +++ b/src/mods/vr/FFakeStereoRenderingHook.cpp @@ -4047,36 +4047,104 @@ __forceinline void FFakeStereoRenderingHook::calculate_stereo_view_offset( } } - // Roomscale movement - // only do it on the right eye pass + // Snapturn frame check + // we check if this is enabled and if the required input is active here + // so that the variables shared between it and roomscale do not have to be found twice per frame + bool snapturn_on_frame{false}; + if (vr->is_snapturn_enabled()) { + const auto left_thumbrest_handle = vr->get_action_handle(VR::s_action_thumbrest_touch_left); + const auto right_thumbrest_handle = vr->get_action_handle(VR::s_action_thumbrest_touch_right); + + const auto dpad_method = vr->get_dpad_method(); + const auto snapturn_deadzone = vr->get_snapturn_js_deadzone(); + if (!m_was_snapturn_run_on_input) { + if (dpad_method == VR::RIGHT_TOUCH && vr->is_action_active(left_thumbrest_handle)) { + if (abs(vr->get_right_stick_axis().x) >= snapturn_deadzone) { + snapturn_on_frame = true; + m_was_snapturn_run_on_input = true; + } + } + else if (dpad_method == VR::LEFT_TOUCH && vr->is_action_active(right_thumbrest_handle)) { + if (abs(vr->get_left_stick_axis().x) >= snapturn_deadzone) { + snapturn_on_frame = true; + m_was_snapturn_run_on_input = true; + } + } + } + else { + if (dpad_method == VR::RIGHT_TOUCH) { + if (abs(vr->get_right_stick_axis().x) < snapturn_deadzone) { + m_was_snapturn_run_on_input = false; + } + } + else if (dpad_method == VR::LEFT_TOUCH) { + if (abs(vr->get_left_stick_axis().x) < snapturn_deadzone) { + m_was_snapturn_run_on_input = false; + } + } + } + } + + + + // Roomscale frame check + // only do roomscale movement on the right eye pass // if we did it on the left, there would be eye desyncs when the right eye is rendered - if (true_index == 1 && vr->is_roomscale_enabled()) { - const auto world = sdk::UEngine::get()->get_world(); + // we check this here to avoid duplicate code later + bool roomscale_movement_on_frame = true_index == 1 && vr->is_roomscale_enabled(); + + // Roomscale and snap turn movement + // we handle both of these within one if statement to avoid duplicative searches + // TODO: consider if commonly used variables such as player controller should get cached globally if any more universal systems using these are added, to avoid this code growing unwieldy + // + if (roomscale_movement_on_frame || 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) { if (const auto pawn = controller->get_acknowledged_pawn(); pawn != nullptr) { - const auto pawn_pos = pawn->get_actor_location(); - const auto new_pos = pawn_pos - head_offset_flat; - - pawn->set_actor_location(new_pos, false, false); - - // Recenter the standing origin - auto current_standing_origin = vr->get_standing_origin(); - const auto hmd_pos = vr->get_position(0); - // dont touch the Y axis - current_standing_origin.x = hmd_pos.x; - current_standing_origin.z = hmd_pos.z; - vr->set_standing_origin(current_standing_origin); + if (roomscale_movement_on_frame) { + const auto pawn_pos = pawn->get_actor_location(); + const auto new_pos = pawn_pos - head_offset_flat; + + pawn->set_actor_location(new_pos, false, false); + + // Recenter the standing origin + auto current_standing_origin = vr->get_standing_origin(); + const auto hmd_pos = vr->get_position(0); + // dont touch the Y axis + current_standing_origin.x = hmd_pos.x; + current_standing_origin.z = hmd_pos.z; + vr->set_standing_origin(current_standing_origin); - // testing - if (vr->is_roomscale_using_actor_rotation()) { - if (!has_double_precision) { - pawn->set_actor_rotation(*(glm::vec3*)view_rotation, false); - } else { - pawn->set_actor_rotation(glm::vec3{rot_d->pitch, rot_d->yaw, rot_d->roll}, false); + // testing + if (vr->is_roomscale_using_actor_rotation()) { + if (!has_double_precision) { + pawn->set_actor_rotation(*(glm::vec3*)view_rotation, false); + } else { + pawn->set_actor_rotation(glm::vec3{rot_d->pitch, rot_d->yaw, rot_d->roll}, false); + } + + vr->recenter_view(); } + } - vr->recenter_view(); + if (snapturn_on_frame) { + auto controller_rot = controller->get_control_rotation(); + const auto dpad_method = vr->get_dpad_method(); + + auto turn_degrees = vr->get_snapturn_degrees(); + if (dpad_method == VR::RIGHT_TOUCH) { + if (vr->get_right_stick_axis().x < 0) { + turn_degrees = -turn_degrees; + } + } + else if (dpad_method == VR::LEFT_TOUCH) { + if (vr->get_left_stick_axis().x < 0) { + turn_degrees = -turn_degrees; + } + } + controller_rot.y += turn_degrees; + controller->set_control_rotation(controller_rot); } } } diff --git a/src/mods/vr/FFakeStereoRenderingHook.hpp b/src/mods/vr/FFakeStereoRenderingHook.hpp index 57ae5389..0f48a954 100644 --- a/src/mods/vr/FFakeStereoRenderingHook.hpp +++ b/src/mods/vr/FFakeStereoRenderingHook.hpp @@ -430,6 +430,9 @@ class FFakeStereoRenderingHook : public ModComponent { std::chrono::time_point m_analyze_view_extensions_start_time{}; + // UE Framework Globals + static inline bool m_was_snapturn_run_on_input{false}; + /*FFakeStereoRendering m_stereo_recreation { 90.0f, (int32_t)1920,