From 0f5408d70cc030e1d3b56d11f33bb1dc1c97e3be Mon Sep 17 00:00:00 2001 From: praydog Date: Sun, 19 Nov 2023 20:27:05 -0800 Subject: [PATCH] UObjectHook: Add camera offsets and relative button --- shared/sdk/AActor.cpp | 3 +- shared/sdk/Math.hpp | 22 +++---- shared/sdk/USceneComponent.cpp | 34 ++++++++++- shared/sdk/USceneComponent.hpp | 4 ++ src/mods/UObjectHook.cpp | 104 +++++++++++++++++++++++---------- src/mods/UObjectHook.hpp | 17 ++++-- 6 files changed, 134 insertions(+), 50 deletions(-) diff --git a/shared/sdk/AActor.cpp b/shared/sdk/AActor.cpp index d1407c94..6e288075 100644 --- a/shared/sdk/AActor.cpp +++ b/shared/sdk/AActor.cpp @@ -17,7 +17,8 @@ namespace sdk { UClass* AActor::static_class() { - return sdk::find_uobject(L"Class /Script/Engine.Actor"); + static auto result = sdk::find_uobject(L"Class /Script/Engine.Actor"); + return result; } bool AActor::set_actor_location(const glm::vec3& location, bool sweep, bool teleport) { diff --git a/shared/sdk/Math.hpp b/shared/sdk/Math.hpp index 70cb74b9..ed59c6b8 100644 --- a/shared/sdk/Math.hpp +++ b/shared/sdk/Math.hpp @@ -212,15 +212,15 @@ static nlohmann::json to_json(const glm::quat& q) { static glm::vec3 from_json_vec3(const nlohmann::json& j) { glm::vec3 result{}; - if (j.contains("x")) { + if (j.contains("x") && j["x"].is_number()) { result.x = j["x"].get(); } - if (j.contains("y")) { + if (j.contains("y") && j["y"].is_number()) { result.y = j["y"].get(); } - if (j.contains("z")) { + if (j.contains("z") && j["z"].is_number()) { result.z = j["z"].get(); } @@ -230,19 +230,19 @@ static glm::vec3 from_json_vec3(const nlohmann::json& j) { static glm::vec4 from_json_vec4(const nlohmann::json& j) { glm::vec4 result{}; - if (j.contains("x")) { + if (j.contains("x") && j["x"].is_number()) { result.x = j["x"].get(); } - if (j.contains("y")) { + if (j.contains("y") && j["y"].is_number()) { result.y = j["y"].get(); } - if (j.contains("z")) { + if (j.contains("z") && j["z"].is_number()) { result.z = j["z"].get(); } - if (j.contains("w")) { + if (j.contains("w") && j["w"].is_number()) { result.w = j["w"].get(); } @@ -252,19 +252,19 @@ static glm::vec4 from_json_vec4(const nlohmann::json& j) { static glm::quat from_json_quat(const nlohmann::json& j) { glm::quat result{}; - if (j.contains("x")) { + if (j.contains("x") && j["x"].is_number()) { result.x = j["x"].get(); } - if (j.contains("y")) { + if (j.contains("y") && j["y"].is_number()) { result.y = j["y"].get(); } - if (j.contains("z")) { + if (j.contains("z") && j["z"].is_number()) { result.z = j["z"].get(); } - if (j.contains("w")) { + if (j.contains("w") && j["w"].is_number()) { result.w = j["w"].get(); } diff --git a/shared/sdk/USceneComponent.cpp b/shared/sdk/USceneComponent.cpp index bc6746a4..fe0fdefe 100644 --- a/shared/sdk/USceneComponent.cpp +++ b/shared/sdk/USceneComponent.cpp @@ -12,7 +12,8 @@ namespace sdk { UClass* USceneComponent::static_class() { - return sdk::find_uobject(L"Class /Script/Engine.SceneComponent"); + static auto result = sdk::find_uobject(L"Class /Script/Engine.SceneComponent"); + return result; } void USceneComponent::set_world_rotation(const glm::vec3& rotation, bool sweep, bool teleport) { @@ -362,4 +363,35 @@ void USceneComponent::set_visibility(bool visible, bool propagate) { this->process_event(func, ¶ms); } + +void USceneComponent::detach_from_parent(bool maintain_world_position, bool call_modify) { + static const auto func1 = static_class()->find_function(L"K2_DetachFromParent"); + static const auto func2 = static_class()->find_function(L"DetachFromParent"); + + const auto func = func1 != nullptr ? func1 : func2; + + if (func == nullptr) { + return; + } + + struct { + bool maintain_world_position{}; + bool call_modify{}; + } params{}; + + params.maintain_world_position = maintain_world_position; + params.call_modify = call_modify; + + this->process_event(func, ¶ms); +} + +USceneComponent* USceneComponent::get_attach_parent() { + const auto data = (USceneComponent**)this->get_property_data(L"AttachParent"); + + if (data == nullptr) { + return nullptr; + } + + return *data; +} } \ No newline at end of file diff --git a/shared/sdk/USceneComponent.hpp b/shared/sdk/USceneComponent.hpp index 418f0d18..d1c404cd 100644 --- a/shared/sdk/USceneComponent.hpp +++ b/shared/sdk/USceneComponent.hpp @@ -26,6 +26,10 @@ class USceneComponent : public UActorComponent { bool is_visible(); void set_visibility(bool visible, bool propagate_to_children = true); + + void detach_from_parent(bool maintain_world_position = true, bool call_modify = true); + + USceneComponent* get_attach_parent(); }; class UPrimitiveComponent : public USceneComponent { diff --git a/src/mods/UObjectHook.cpp b/src/mods/UObjectHook.cpp index 3dbbc0ce..22fe9891 100644 --- a/src/mods/UObjectHook.cpp +++ b/src/mods/UObjectHook.cpp @@ -51,7 +51,7 @@ UObjectHook::MotionControllerState::~MotionControllerState() { } } -nlohmann::json UObjectHook::MotionControllerStateBase::serialize() const { +nlohmann::json UObjectHook::MotionControllerStateBase::to_json() const { return { {"rotation_offset", utility::math::to_json(rotation_offset)}, {"location_offset", utility::math::to_json(location_offset)}, @@ -59,7 +59,7 @@ nlohmann::json UObjectHook::MotionControllerStateBase::serialize() const { }; } -void UObjectHook::MotionControllerStateBase::deserialize(const nlohmann::json& data) { +void UObjectHook::MotionControllerStateBase::from_json(const nlohmann::json& data) { if (data.contains("rotation_offset")) { rotation_offset = utility::math::from_json_quat(data["rotation_offset"]); } @@ -257,24 +257,30 @@ void UObjectHook::on_pre_calculate_stereo_view_offset(void* stereo_device, const auto view_d = (Vector3d*)view_location; auto rot_d = (Rotator*)view_rotation; - if (m_camera_attached_object != nullptr) { - if (m_camera_attached_object->is_a(sdk::AActor::static_class())) { - const auto actor = (sdk::AActor*)m_camera_attached_object; + if (is_double) { + m_last_camera_location = glm::vec3{*view_d}; + } else { + m_last_camera_location = *view_location; + } + + if (m_camera_attach.object != nullptr) { + if (m_camera_attach.object->is_a(sdk::AActor::static_class())) { + const auto actor = (sdk::AActor*)m_camera_attach.object; const auto location = actor->get_actor_location(); if (is_double) { - *view_d = glm::vec<3, double>{location}; + *view_d = glm::vec<3, double>{location + m_camera_attach.offset}; } else { - *view_location = location; + *view_location = location + m_camera_attach.offset; } - } else if (m_camera_attached_object->is_a(sdk::USceneComponent::static_class())) { - const auto comp = (sdk::USceneComponent*)m_camera_attached_object; + } else if (m_camera_attach.object->is_a(sdk::USceneComponent::static_class())) { + const auto comp = (sdk::USceneComponent*)m_camera_attach.object; const auto location = comp->get_world_location(); if (is_double) { - *view_d = glm::vec<3, double>{location}; + *view_d = glm::vec<3, double>{location + m_camera_attach.offset}; } else { - *view_location = location; + *view_location = location + m_camera_attach.offset; } } // else todo? } @@ -872,16 +878,17 @@ nlohmann::json UObjectHook::serialize_mc_state(const std::vector& p nlohmann::json result{}; result["path"] = path; - result["state"] = state->serialize(); + result["state"] = state->to_json(); result["type"] = "motion_controller"; return result; } -nlohmann::json UObjectHook::serialize_camera(const std::vector& path, sdk::UObject* object) { +nlohmann::json UObjectHook::serialize_camera(const std::vector& path) { nlohmann::json result{}; result["path"] = path; + result["offset"] = utility::math::to_json(m_camera_attach.offset); result["type"] = "camera"; // todo: adjustments/offsets, etc...? all it needs is the camera object which is fine @@ -889,8 +896,8 @@ nlohmann::json UObjectHook::serialize_camera(const std::vector& pat return result; } -void UObjectHook::save_camera_state(const std::vector& path, sdk::UObject* object) { - auto json = serialize_camera(path, object); +void UObjectHook::save_camera_state(const std::vector& path) { + auto json = serialize_camera(path); const auto wanted_dir = UObjectHook::get_persistent_dir() / "camera_state.json"; @@ -970,7 +977,7 @@ std::shared_ptr UObjectHook::deserialize_mc_state( persistent_state->path = path; SPDLOG_INFO("[UObjectHook] Deserializing state..."); - persistent_state->state.deserialize(data["state"]); + persistent_state->state.from_json(data["state"]); return persistent_state; } @@ -1060,6 +1067,10 @@ std::shared_ptr UObjectHook::deserialize_cam auto persistent_state = std::make_shared(); persistent_state->path = path.value(); + if (data.contains("offset") && data["offset"].is_object()) { + persistent_state->offset = utility::math::from_json_vec3(data["offset"]); + } + return persistent_state; } @@ -1105,7 +1116,8 @@ void UObjectHook::update_persistent_states() { auto obj = m_persistent_camera_state->path.resolve(); if (obj != nullptr) { - m_camera_attached_object = obj; + m_camera_attach.object = obj; + m_camera_attach.offset = m_persistent_camera_state->offset; } } @@ -1924,7 +1936,7 @@ void UObjectHook::ui_handle_scene_component(sdk::USceneComponent* comp) { } } } else { - if (m_camera_attached_object != comp) { + if (m_camera_attach.object != comp) { if (ImGui::Button("Attach left")) { m_motion_controller_attached_components[comp] = std::make_shared(); m_motion_controller_attached_components[comp]->hand = 0; @@ -1937,20 +1949,33 @@ void UObjectHook::ui_handle_scene_component(sdk::USceneComponent* comp) { m_motion_controller_attached_components[comp]->hand = 1; } + if (ImGui::Button("Attach Camera to")) { + m_camera_attach.object = comp; + m_camera_attach.offset = glm::vec3{0.0f, 0.0f, 0.0f}; + } + ImGui::SameLine(); - if (ImGui::Button("Attach Camera to")) { - m_camera_attached_object = comp; + if (ImGui::Button("Attach Camera to (Relative)")) { + m_camera_attach.object = comp; + m_camera_attach.offset = glm::vec3{0.0f, 0.0f, m_last_camera_location.z - comp->get_world_location().z}; } } else { if (ImGui::Button("Detach")) { - m_camera_attached_object = nullptr; + m_camera_attach.object = nullptr; + m_camera_attach.offset = glm::vec3{0.0f, 0.0f, 0.0f}; } ImGui::SameLine(); if (ImGui::Button("Save state")) { - save_camera_state(m_path.path(), m_camera_attached_object); + save_camera_state(m_path.path()); + } + + if (ImGui::DragFloat3("Camera Offset", &m_camera_attach.offset.x, 0.1f)) { + if (m_persistent_camera_state != nullptr) { + m_persistent_camera_state->offset = m_camera_attach.offset; + } } } } @@ -2082,21 +2107,36 @@ void UObjectHook::ui_handle_actor(sdk::UObject* object) { return; } - /*if (ImGui::Button("Attach to motion controller")) { - m_motion_controller_attached_objects.insert(object); - }*/ + auto actor = (sdk::AActor*)object; - if (m_camera_attached_object != object ){ + if (m_camera_attach.object != object ){ if (ImGui::Button("Attach Camera to")) { - m_camera_attached_object = object; + m_camera_attach.object = object; + m_camera_attach.offset = glm::vec3{0.0f, 0.0f, 0.0f}; + } + + ImGui::SameLine(); + + if (ImGui::Button("Attach Camera to (Relative)")) { + m_camera_attach.object = object; + m_camera_attach.offset = glm::vec3{0.0f, 0.0f, m_last_camera_location.z - actor->get_actor_location().z}; } } else { + if (ImGui::Button("Detach")) { + m_camera_attach.object = nullptr; + m_camera_attach.offset = glm::vec3{0.0f, 0.0f, 0.0f}; + } + if (ImGui::Button("Save state")) { - save_camera_state(m_path.path(), m_camera_attached_object); + save_camera_state(m_path.path()); } - } - auto actor = (sdk::AActor*)object; + if (ImGui::DragFloat3("Camera Offset", &m_camera_attach.offset.x, 0.1f)) { + if (m_persistent_camera_state != nullptr) { + m_persistent_camera_state->offset = m_camera_attach.offset; + } + } + } static char component_add_name[256]{}; @@ -2622,8 +2662,8 @@ void* UObjectHook::destructor(sdk::UObjectBase* object, void* rdx, void* r8, voi hook->m_overlap_detection_actor_left = nullptr; } - if (object == hook->m_camera_attached_object) { - hook->m_camera_attached_object = nullptr; + if (object == hook->m_camera_attach.object) { + hook->m_camera_attach.object = nullptr; } for (auto super = (sdk::UStruct*)it->second->uclass; super != nullptr;) { diff --git a/src/mods/UObjectHook.hpp b/src/mods/UObjectHook.hpp index 4df5a5ec..3c2d6d79 100644 --- a/src/mods/UObjectHook.hpp +++ b/src/mods/UObjectHook.hpp @@ -93,8 +93,8 @@ class UObjectHook : public Mod { std::filesystem::path get_persistent_dir() const; nlohmann::json serialize_mc_state(const std::vector& path, const std::shared_ptr& state); - nlohmann::json serialize_camera(const std::vector& path, sdk::UObject* object); - void save_camera_state(const std::vector& path, sdk::UObject* object); + nlohmann::json serialize_camera(const std::vector& path); + void save_camera_state(const std::vector& path); std::optional deserialize_path(const nlohmann::json& data); std::shared_ptr deserialize_mc_state(nlohmann::json& data); std::shared_ptr deserialize_mc_state(std::filesystem::path json_path); @@ -136,8 +136,8 @@ class UObjectHook : public Mod { std::unordered_set m_motion_controller_attached_objects{}; struct MotionControllerStateBase { - nlohmann::json serialize() const; - void deserialize(const nlohmann::json& data); + nlohmann::json to_json() const; + void from_json(const nlohmann::json& data); // State that can be parsed from disk glm::quat rotation_offset{glm::identity()}; @@ -156,7 +156,11 @@ class UObjectHook : public Mod { std::unordered_map> m_motion_controller_attached_components{}; sdk::AActor* m_overlap_detection_actor{nullptr}; sdk::AActor* m_overlap_detection_actor_left{nullptr}; - sdk::UObject* m_camera_attached_object{nullptr}; + + struct CameraState { + sdk::UObject* object{nullptr}; + glm::vec3 offset{}; + } m_camera_attach{}; std::shared_ptr get_or_add_motion_controller_state(sdk::USceneComponent* component) { { @@ -279,6 +283,7 @@ class UObjectHook : public Mod { struct PersistentCameraState { StatePath path{}; + glm::vec3 offset{}; }; struct PersistentProperties { @@ -302,6 +307,8 @@ class UObjectHook : public Mod { std::vector> properties{}; }; + glm::vec3 m_last_camera_location{}; + std::shared_ptr m_persistent_camera_state{}; std::vector> m_persistent_states{}; std::vector> m_persistent_properties{};