diff --git a/CMakeLists.txt b/CMakeLists.txt index 954428c5d..a82701153 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,13 +134,13 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(bddisasm) -message(STATUS "Fetching kananlib (0bf5781a38a857f0acea3935425d50a1a5a34d3a)...") +message(STATUS "Fetching kananlib (203dc31c5d8ba2cffdb780ae38b2eb2080bb099c)...") FetchContent_Declare( kananlib GIT_REPOSITORY https://github.com/cursey/kananlib GIT_TAG - 0bf5781a38a857f0acea3935425d50a1a5a34d3a + 203dc31c5d8ba2cffdb780ae38b2eb2080bb099c ) FetchContent_MakeAvailable(kananlib) diff --git a/cmake.toml b/cmake.toml index 504ebf90d..d1cf54c4b 100644 --- a/cmake.toml +++ b/cmake.toml @@ -184,7 +184,7 @@ tag = "v1.34.10" [fetch-content.kananlib] git = "https://github.com/cursey/kananlib" -tag = "0bf5781a38a857f0acea3935425d50a1a5a34d3a" +tag = "203dc31c5d8ba2cffdb780ae38b2eb2080bb099c" [target.utility] type = "static" diff --git a/shared/sdk/MurmurHash.cpp b/shared/sdk/MurmurHash.cpp index 26584d0cb..d34659520 100644 --- a/shared/sdk/MurmurHash.cpp +++ b/shared/sdk/MurmurHash.cpp @@ -20,4 +20,10 @@ uint32_t calc32(std::wstring_view str) { uint32_t calc32(std::string_view str) { return calc32(utility::widen(str)); } + +uint32_t calc32_as_utf8(std::string_view str) { + static auto calc_method = type()->get_method("calc32AsUTF8"); + + return calc_method->call(sdk::get_thread_context(), sdk::VM::create_managed_string(utility::widen(str)), str.length()); +} } diff --git a/shared/sdk/MurmurHash.hpp b/shared/sdk/MurmurHash.hpp index d6ecced93..b3f76550c 100644 --- a/shared/sdk/MurmurHash.hpp +++ b/shared/sdk/MurmurHash.hpp @@ -11,5 +11,6 @@ namespace murmur_hash { sdk::RETypeDefinition* type(); uint32_t calc32(std::wstring_view str); uint32_t calc32(std::string_view str); +uint32_t calc32_as_utf8(std::string_view str); } } \ No newline at end of file diff --git a/src/REFramework.cpp b/src/REFramework.cpp index c182be57b..eb24db68d 100644 --- a/src/REFramework.cpp +++ b/src/REFramework.cpp @@ -1816,6 +1816,13 @@ bool REFramework::initialize_game_data() { spdlog::error("Initialization of mods failed. Reason: {}", m_error); } + // Need to clean up local objects as this is our own thread, not under control by the engine + if (auto context = sdk::get_thread_context(); context != nullptr) try { + context->local_frame_gc(); + } catch(...) { + spdlog::error("Failed to run local frame GC."); + } + m_game_data_initialized = true; } catch(const std::exception& e) { m_error = e.what(); diff --git a/src/REFramework.hpp b/src/REFramework.hpp index dcbd49314..60b4deb8e 100644 --- a/src/REFramework.hpp +++ b/src/REFramework.hpp @@ -46,6 +46,7 @@ class REFramework { Address get_module() const { return m_game_module; } bool is_ready() const { return m_initialized && m_game_data_initialized; } + bool is_ui_focused() const { return m_is_ui_focused; } void run_imgui_frame(bool from_present); diff --git a/src/mods/FreeCam.cpp b/src/mods/FreeCam.cpp index afb7cb3ec..6f73c3469 100644 --- a/src/mods/FreeCam.cpp +++ b/src/mods/FreeCam.cpp @@ -123,7 +123,6 @@ void FreeCam::on_update_transform(RETransform* transform) { return; } - #if defined(RE2) || defined(RE3) static auto get_player_condition_method = sdk::find_method_definition(game_namespace("SurvivorManager"), "get_Player"); static auto get_action_orderer_method = sdk::find_method_definition(game_namespace("survivor.SurvivorCondition"), "get_ActionOrderer"); @@ -168,6 +167,7 @@ void FreeCam::on_update_transform(RETransform* transform) { m_first_time = false; m_custom_angles = math::euler_angles(glm::extractMatrixRotation(m_last_camera_matrix)); + m_twist = 0.0f; //m_custom_angles[1] *= -1.0f; //m_custom_angles[1] += glm::radians(180.0f); @@ -213,17 +213,64 @@ void FreeCam::on_update_transform(RETransform* transform) { // Controller support if (pad != nullptr) { + static const auto gamepad_device_t = sdk::find_type_definition("via.hid.GamePadDevice"); + static const auto is_down = gamepad_device_t != nullptr ? gamepad_device_t->get_method("isDown(via.hid.GamePadButton)") : nullptr; + // Move direction // It's not a Vector2f because via.vec2 is not actually 8 bytes, we don't want stack corruption to occur. const auto axis_l = *re_managed_object::get_field(pad, "AxisL"); const auto axis_r = *re_managed_object::get_field(pad, "AxisR"); - m_custom_angles[0] += axis_r.y * rotation_speed * delta * timescale_mult; - m_custom_angles[1] -= axis_r.x * rotation_speed * delta * timescale_mult; - m_custom_angles[2] = 0.0f; + bool is_using_up_down_modifier = false; + bool is_using_twist_modifier = false; + + if (is_down != nullptr) { + const auto dpad_up_is_down = is_down->call_safe(sdk::get_thread_context(), pad, via::hid::GamePadButton::LUp); + const auto dpad_down_is_down = is_down->call_safe(sdk::get_thread_context(), pad, via::hid::GamePadButton::LDown); + + if (dpad_up_is_down) { + dir.y = 1.0f; + } else if (dpad_down_is_down) { + dir.y = -1.0f; + } + + const auto dpad_left_is_down = is_down->call_safe(sdk::get_thread_context(), pad, via::hid::GamePadButton::LLeft); + const auto dpad_right_is_down = is_down->call_safe(sdk::get_thread_context(), pad, via::hid::GamePadButton::LRight); + + if (dpad_left_is_down) { + dir.x -= 1.0f; + } else if (dpad_right_is_down) { + dir.x += 1.0f; + } + + const auto l_trigger_is_down = is_down->call_safe(sdk::get_thread_context(), pad, via::hid::GamePadButton::LTrigBottom); + + if (l_trigger_is_down) { + if (glm::length(axis_r) > 0.0f) { + dir += Vector4f{ 0.0, axis_r.y, 0.0, 0.0f }; + is_using_up_down_modifier = true; + } + } + + const auto r_trigger_is_down = is_down->call_safe(sdk::get_thread_context(), pad, via::hid::GamePadButton::RTrigBottom); + + if (r_trigger_is_down) { + if (glm::length(axis_r) > 0.0f) { + //m_custom_angles[2] -= axis_r.x * rotation_speed * delta * timescale_mult; + m_twist += axis_r.x * rotation_speed * delta * timescale_mult; + is_using_twist_modifier = true; + } + } + } + + if (!is_using_up_down_modifier && !is_using_twist_modifier) { + m_custom_angles[0] += axis_r.y * rotation_speed * delta * timescale_mult; + m_custom_angles[1] -= axis_r.x * rotation_speed * delta * timescale_mult; + //m_custom_angles[2] = 0.0f; + } if (glm::length(axis_l) > 0.0f) { - dir = Vector4f{ axis_l.x, 0.0f, axis_l.y * -1.0f, 0.0f }; + dir += Vector4f{ axis_l.x, 0.0f, axis_l.y * -1.0f, 0.0f }; } } @@ -252,19 +299,26 @@ void FreeCam::on_update_transform(RETransform* transform) { dir_speed *= dir_speed_mod_slow; } - const auto& mouse_delta = g_framework->get_mouse_delta(); + if (!g_framework->is_ui_focused()) { + const auto& mouse_delta = g_framework->get_mouse_delta(); - m_custom_angles[0] -= mouse_delta[1] * rotation_speed_kbm * delta * timescale_mult; - m_custom_angles[1] -= mouse_delta[0] * rotation_speed_kbm * delta * timescale_mult; - m_custom_angles[2] = 0.0f; + if (keyboard_state[VK_RBUTTON]) { + //m_custom_angles[2] -= mouse_delta[0] * rotation_speed_kbm * delta * timescale_mult; + m_twist -= mouse_delta[0] * rotation_speed_kbm * delta * timescale_mult; + } else { + m_custom_angles[0] -= mouse_delta[1] * rotation_speed_kbm * delta * timescale_mult; + m_custom_angles[1] -= mouse_delta[0] * rotation_speed_kbm * delta * timescale_mult; + } + } math::fix_angles(m_custom_angles); - - const auto new_rotation = Matrix4x4f{ glm::quat{ m_custom_angles } }; + + auto new_rotation = glm::quat{ m_custom_angles }; + new_rotation = glm::rotate(new_rotation, m_twist, glm::vec3{0.0f, 0.0f, 1.0f}); const auto new_pos = m_last_camera_matrix[3] + new_rotation * dir * (dir_speed * delta * timescale_mult); // Keep track of the rotation if we want to lock the camera - m_last_camera_matrix = new_rotation; + m_last_camera_matrix = glm::mat4{new_rotation}; m_last_camera_matrix[3] = new_pos; } diff --git a/src/mods/FreeCam.hpp b/src/mods/FreeCam.hpp index df2ea2ce2..e7c1b9bca 100644 --- a/src/mods/FreeCam.hpp +++ b/src/mods/FreeCam.hpp @@ -36,7 +36,7 @@ class FreeCam : public Mod { const ModSlider::Ptr m_speed{ ModSlider::create(generate_name("Speed"), 0.0f, 1.0f, 0.1f) }; const ModSlider::Ptr m_speed_modifier{ ModSlider::create(generate_name("SpeedModifier"), 1.f, 50.f, 4.f) }; - const ModSlider::Ptr m_rotation_speed{ ModSlider::create(generate_name("RotationSpeed"), 0.0f, 1.0f, 1.0f) }; + const ModSlider::Ptr m_rotation_speed{ ModSlider::create(generate_name("RotationSpeed"), 0.0f, 1.0f, 0.1f) }; ValueList m_options{ *m_enabled, @@ -71,6 +71,7 @@ class FreeCam : public Mod { bool m_was_disabled{ false }; Vector3f m_custom_angles{}; + float m_twist{0.0f}; RECamera* m_camera{nullptr}; diff --git a/src/mods/ScriptRunner.cpp b/src/mods/ScriptRunner.cpp index 261987eda..da768d5f4 100644 --- a/src/mods/ScriptRunner.cpp +++ b/src/mods/ScriptRunner.cpp @@ -120,7 +120,7 @@ ScriptState::ScriptState(const ScriptState::GarbageCollectionData& gc_data,bool m_is_main_state = is_main_state; m_lua.registry()["state"] = this; m_lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::string, sol::lib::math, sol::lib::table, sol::lib::bit32, - sol::lib::utf8, sol::lib::os, sol::lib::coroutine); + sol::lib::utf8, sol::lib::os, sol::lib::coroutine, sol::lib::debug); // Disable garbage collection. We will manually do it at the end of each frame. gc_data_changed(gc_data);