From 3cb9b25a4330aa90767166d059e7a30fc54a13b3 Mon Sep 17 00:00:00 2001 From: praydog Date: Mon, 18 Dec 2023 12:53:15 -0800 Subject: [PATCH] Aiming: Filter out other player controllers (MP support) --- shared/sdk/APlayerCameraManager.cpp | 21 ++++++++++++ shared/sdk/APlayerCameraManager.hpp | 4 ++- shared/sdk/APlayerController.cpp | 22 ++++++++++++ shared/sdk/APlayerController.hpp | 2 ++ src/mods/VR.cpp | 1 + src/mods/VR.hpp | 6 ++++ src/mods/vr/IXRTrackingSystemHook.cpp | 49 ++++++++++++++++++++++----- src/mods/vr/IXRTrackingSystemHook.hpp | 10 +++--- 8 files changed, 101 insertions(+), 14 deletions(-) diff --git a/shared/sdk/APlayerCameraManager.cpp b/shared/sdk/APlayerCameraManager.cpp index 725b9a65..ff9da128 100644 --- a/shared/sdk/APlayerCameraManager.cpp +++ b/shared/sdk/APlayerCameraManager.cpp @@ -1,4 +1,5 @@ #include +#include #include "APlayerCameraManager.hpp" @@ -6,4 +7,24 @@ namespace sdk { sdk::UClass* APlayerCameraManager::static_class() { return (UClass*)sdk::find_uobject(L"Class /Script/Engine.PlayerCameraManager"); } + +sdk::APlayerController* APlayerCameraManager::get_owning_player_controller() { + static const auto sc = static_class(); + if (sc == nullptr) { + return nullptr; + } + + static const auto func = sc->find_function(L"GetOwningPlayerController"); + + if (func == nullptr) { + return nullptr; + } + + struct { + APlayerController* result{}; + } params; + + this->process_event(func, ¶ms); + return params.result; +} } \ No newline at end of file diff --git a/shared/sdk/APlayerCameraManager.hpp b/shared/sdk/APlayerCameraManager.hpp index 7f60cdf7..472ff088 100644 --- a/shared/sdk/APlayerCameraManager.hpp +++ b/shared/sdk/APlayerCameraManager.hpp @@ -4,10 +4,12 @@ namespace sdk { class UClass; +class APlayerController; class APlayerCameraManager : public UObject { public: static UClass* static_class(); - // TODO + + APlayerController* get_owning_player_controller(); }; } \ No newline at end of file diff --git a/shared/sdk/APlayerController.cpp b/shared/sdk/APlayerController.cpp index e805e4e1..cead2d46 100644 --- a/shared/sdk/APlayerController.cpp +++ b/shared/sdk/APlayerController.cpp @@ -53,6 +53,28 @@ glm::vec3 AController::get_control_rotation() { return *(glm::vec<3, double>*)params.data(); } +bool AController::is_local_player_controller() { + static const auto sc = static_class(); + + if (sc == nullptr) { + return true; // whatever + } + + static const auto func = sc->find_function(L"IsLocalPlayerController"); + + if (func == nullptr) { + return true; // whatever + } + + struct { + bool result{}; + } params; + + this->process_event(func, ¶ms); + + return params.result; +} + UClass* APlayerController::static_class() { return sdk::find_uobject(L"Class /Script/Engine.PlayerController"); } diff --git a/shared/sdk/APlayerController.hpp b/shared/sdk/APlayerController.hpp index d871ccc3..294803bb 100644 --- a/shared/sdk/APlayerController.hpp +++ b/shared/sdk/APlayerController.hpp @@ -15,6 +15,8 @@ class AController : public UObject { void set_control_rotation(const glm::vec3& newrotation); glm::vec3 get_control_rotation(); + bool is_local_player_controller(); + protected: }; diff --git a/src/mods/VR.cpp b/src/mods/VR.cpp index 90846433..025d0946 100644 --- a/src/mods/VR.cpp +++ b/src/mods/VR.cpp @@ -2104,6 +2104,7 @@ void VR::on_draw_sidebar_entry(std::string_view name) { m_previous_aim_method = (AimMethod)m_aim_method->value(); } + m_aim_multiplayer_support->draw("Multiplayer Support"); m_aim_interp->draw("Smoothing"); m_aim_speed->draw("Speed"); diff --git a/src/mods/VR.hpp b/src/mods/VR.hpp index 040dfdeb..1233d6c4 100644 --- a/src/mods/VR.hpp +++ b/src/mods/VR.hpp @@ -420,6 +420,10 @@ class VR : public Mod { float get_aim_speed() const { return m_aim_speed->value(); } + + bool is_aim_multiplayer_support_enabled() const { + return m_aim_multiplayer_support->value(); + } bool is_aim_interpolation_enabled() const { return m_aim_interp->value(); @@ -757,6 +761,7 @@ class VR : public Mod { 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) }; AimMethod m_previous_aim_method{ AimMethod::GAME }; + const ModToggle::Ptr m_aim_multiplayer_support{ ModToggle::create(generate_name("AimMPSupport"), true) }; const ModToggle::Ptr m_aim_interp{ ModToggle::create(generate_name("AimInterp"), true, true) }; const ModSlider::Ptr m_aim_speed{ ModSlider::create(generate_name("AimSpeed"), 0.01f, 25.0f, 15.0f) }; const ModToggle::Ptr m_dpad_shifting{ ModToggle::create(generate_name("DPadShifting"), true) }; @@ -830,6 +835,7 @@ class VR : public Mod { *m_snapturn_angle, *m_aim_method, *m_movement_orientation, + *m_aim_multiplayer_support, *m_aim_speed, *m_aim_interp, *m_dpad_shifting, diff --git a/src/mods/vr/IXRTrackingSystemHook.cpp b/src/mods/vr/IXRTrackingSystemHook.cpp index 54dc95ad..d4e61cd3 100644 --- a/src/mods/vr/IXRTrackingSystemHook.cpp +++ b/src/mods/vr/IXRTrackingSystemHook.cpp @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include #include "../VR.hpp" @@ -1266,7 +1269,7 @@ IXRTrackingSystemHook::SharedPtr* IXRTrackingSystemHook::get_view_extension(sdk: return out; } -void IXRTrackingSystemHook::apply_hmd_rotation(sdk::IXRCamera*, void* player_controller, Rotator* rot) { +void IXRTrackingSystemHook::apply_hmd_rotation(sdk::IXRCamera*, sdk::APlayerController* player_controller, Rotator* rot) { SPDLOG_INFO_ONCE("apply_hmd_rotation {:x}", (uintptr_t)_ReturnAddress()); if (VR::get()->is_hmd_active() && !g_hook->m_process_view_rotation_hook && !g_hook->m_attempted_hook_view_rotation) { @@ -1294,7 +1297,7 @@ void IXRTrackingSystemHook::apply_hmd_rotation(sdk::IXRCamera*, void* player_con func.calls_apply_hmd_rotation = true; } - g_hook->update_view_rotation(rot); + g_hook->update_view_rotation(player_controller, rot); } /*if (g_hook->m_stereo_hook == nullptr) { @@ -1429,11 +1432,11 @@ void* IXRTrackingSystemHook::process_view_rotation_analyzer(void* a1, size_t a2, } void IXRTrackingSystemHook::process_view_rotation( - void* player_controller, float delta_time, Rotator* rot, Rotator* delta_rot) { + sdk::APlayerCameraManager* pcm, float delta_time, Rotator* rot, Rotator* delta_rot) { SPDLOG_INFO_ONCE("process_view_rotation {:x}", (uintptr_t)_ReturnAddress()); auto call_orig = [&]() { - g_hook->m_process_view_rotation_hook.call(player_controller, delta_time, rot, delta_rot); + g_hook->m_process_view_rotation_hook.call(pcm, delta_time, rot, delta_rot); }; auto& vr = VR::get(); @@ -1447,10 +1450,10 @@ void IXRTrackingSystemHook::process_view_rotation( call_orig(); - g_hook->update_view_rotation(rot); + g_hook->update_view_rotation(pcm, rot); } -void IXRTrackingSystemHook::pre_update_view_rotation(Rotator* rot) { +void IXRTrackingSystemHook::pre_update_view_rotation(sdk::UObject* reference_obj, Rotator* rot) { auto& vr = VR::get(); if (m_stereo_hook->has_double_precision()) { @@ -1462,15 +1465,43 @@ void IXRTrackingSystemHook::pre_update_view_rotation(Rotator* rot) { } } -void IXRTrackingSystemHook::update_view_rotation(Rotator* rot) { +void IXRTrackingSystemHook::update_view_rotation(sdk::UObject* reference_obj, Rotator* rot) { + auto& vr = VR::get(); + + // Double check that the player controller passed through here is the local player controller + static bool had_detection_error = false; + if (!had_detection_error && vr->is_aim_multiplayer_support_enabled()) try { + const auto engine = sdk::UEngine::get(); + if (engine != nullptr && reference_obj != nullptr && sdk::FUObjectArray::get() != nullptr) { + const auto reference_obj_c = reference_obj->get_class(); + + static const auto player_controller_class = sdk::APlayerController::static_class(); + static const auto player_camera_manager_class = sdk::APlayerCameraManager::static_class(); + + sdk::APlayerController* pc = nullptr; + + if (player_controller_class != nullptr && reference_obj_c != nullptr && reference_obj_c->is_a(player_controller_class)) { + pc = (sdk::APlayerController*)reference_obj; + } else if (player_camera_manager_class != nullptr && reference_obj_c != nullptr && reference_obj_c->is_a(player_camera_manager_class)) { + const auto pcm = (sdk::APlayerCameraManager*)reference_obj; + pc = pcm->get_owning_player_controller(); + } + + if (pc != nullptr && !pc->is_local_player_controller()) { + return; + } + } + } catch(...) { + had_detection_error = true; + SPDLOG_ERROR("[IXRTrackingSystemHook] Error detecting reference object, cannot support multiplayer"); + } + const auto now = std::chrono::high_resolution_clock::now(); const auto delta_time = now - m_process_view_rotation_data.last_update; const auto delta_float = glm::min(std::chrono::duration_cast>(delta_time).count(), 0.1f); m_process_view_rotation_data.last_update = now; m_process_view_rotation_data.was_called = true; - auto& vr = VR::get(); - if (!vr->is_hmd_active() || !vr->is_any_aim_method_active()) { return; } diff --git a/src/mods/vr/IXRTrackingSystemHook.hpp b/src/mods/vr/IXRTrackingSystemHook.hpp index d93ba516..297a6bea 100644 --- a/src/mods/vr/IXRTrackingSystemHook.hpp +++ b/src/mods/vr/IXRTrackingSystemHook.hpp @@ -14,6 +14,8 @@ class UEngine; class IXRTrackingSystem; class IXRCamera; class IHeadMountedDisplay; +class APlayerController; +class APlayerCameraManager; } class FFakeStereoRenderingHook; @@ -71,17 +73,17 @@ class IXRTrackingSystemHook : public ModComponent { static SharedPtr* get_view_extension(sdk::IHeadMountedDisplay*, SharedPtr* out); // IXRCamera - static void apply_hmd_rotation(sdk::IXRCamera*, void* player_controller, Rotator* rot); + static void apply_hmd_rotation(sdk::IXRCamera*, sdk::APlayerController* player_controller, Rotator* rot); static bool update_player_camera(sdk::IXRCamera*, Quat* rel_rot, glm::vec3* rel_pos); // This function is the precursor to actually hooking ProcessViewRotation // Because there's a very real possibility that we can accidentally hook the wrong function // We need to verify that arg 2 and 3 are on the stack // And the function that calls it is also a virtual function (APlayerController::UpdateRotation) static void* process_view_rotation_analyzer(void*, size_t, size_t, size_t, size_t, size_t); - static void process_view_rotation(void* player_controller, float delta_time, Rotator* rot, Rotator* delta_rot); + static void process_view_rotation(sdk::APlayerCameraManager* pcm, float delta_time, Rotator* rot, Rotator* delta_rot); - void pre_update_view_rotation(Rotator* rot); - void update_view_rotation(Rotator* rot); + void pre_update_view_rotation(sdk::UObject* reference_obj, Rotator* rot); + void update_view_rotation(sdk::UObject* reference_obj, Rotator* rot); FFakeStereoRenderingHook* m_stereo_hook{nullptr};