From bb1d62f8c22a0c699fc89bd8567b09776650eebe Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 18 Oct 2024 01:07:46 +0300 Subject: [PATCH 01/29] Perfect Dark Zero support --- .../hid/winkey/hookables/PerfectDarkZero.cc | 152 ++++++++++++++++++ .../hid/winkey/hookables/PerfectDarkZero.h | 49 ++++++ src/xenia/hid/winkey/winkey_input_driver.cc | 2 + 3 files changed, 203 insertions(+) create mode 100644 src/xenia/hid/winkey/hookables/PerfectDarkZero.cc create mode 100644 src/xenia/hid/winkey/hookables/PerfectDarkZero.h diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc new file mode 100644 index 0000000000..d92259fdbf --- /dev/null +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -0,0 +1,152 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2023 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#define _USE_MATH_DEFINES + +#include "xenia/hid/winkey/hookables/PerfectDarkZero.h" + +#include "xenia/base/platform_win.h" +#include "xenia/cpu/processor.h" +#include "xenia/emulator.h" +#include "xenia/hid/hid_flags.h" +#include "xenia/hid/input_system.h" +#include "xenia/kernel/util/shim_utils.h" +#include "xenia/kernel/xmodule.h" +#include "xenia/kernel/xthread.h" +#include "xenia/xbox.h" + +using namespace xe::kernel; + +DECLARE_double(sensitivity); +DECLARE_bool(invert_y); +DECLARE_bool(invert_x); + +const uint32_t kTitleIdPerfectDarkZero = 0x4D5307D3; + +namespace xe { +namespace hid { +namespace winkey { +struct GameBuildAddrs { + const char* build_string; + uint32_t build_string_addr; + uint32_t base_address; + uint32_t x_offset; + uint32_t y_offset; +}; + +std::map supported_builds{ + {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU0, + {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BD7A4, 0x82D2AD38, 0x150, + 0x1674}}}; + +PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; + +bool PerfectDarkZeroGame::IsGameSupported() { + if (kernel_state()->title_id() != kTitleIdPerfectDarkZero) { + return false; + } + + const std::string current_version = + kernel_state()->emulator()->title_version(); + + for (auto& build : supported_builds) { + auto* build_ptr = kernel_memory()->TranslateVirtual( + build.second.build_string_addr); + + if (strcmp(build_ptr, build.second.build_string) == 0) { + game_build_ = build.first; + return true; + } + } + + return false; +} + +float PerfectDarkZeroGame::DegreetoRadians(float degree) { + return (float)(degree * (M_PI / 180)); +} + +float PerfectDarkZeroGame::RadianstoDegree(float radians) { + return (float)(radians * (180 / M_PI)); +} + +bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, + RawInputState& input_state, + X_INPUT_STATE* out_state) { + if (!IsGameSupported()) { + return false; + } + + if (supported_builds.count(game_build_) == 0) { + return false; + } + + XThread* current_thread = XThread::GetCurrentThread(); + + if (!current_thread) { + return false; + } + + xe::be* base_address = + kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].base_address); + + xe::be* radians_x_base = + kernel_memory()->TranslateVirtual*>(*base_address + + 0xE4); + + if (!base_address || *base_address == NULL) { + // Not in game + return false; + } + + xe::be x_address = + *radians_x_base + supported_builds[game_build_].x_offset; + xe::be y_address = + *base_address + supported_builds[game_build_].y_offset; + + xe::be* cam_x = + kernel_memory()->TranslateVirtual*>(x_address); + + xe::be* cam_y = + kernel_memory()->TranslateVirtual*>(y_address); + + float degree_x = RadianstoDegree(*cam_x); + float degree_y = (float)*cam_y; + + // X-axis = 0 to 360 + if (cvars::invert_x) { + degree_x += (input_state.mouse.x_delta / 7.5f) * (float)cvars::sensitivity; + + } else { + degree_x -= (input_state.mouse.x_delta / 7.5f) * (float)cvars::sensitivity; + } + *cam_x = DegreetoRadians(degree_x); + + // Y-axis = -90 to 90 + if (cvars::invert_y) { + degree_y -= (input_state.mouse.y_delta / 7.5f) * (float)cvars::sensitivity; + } else { + degree_y += (input_state.mouse.y_delta / 7.5f) * (float)cvars::sensitivity; + } + *cam_y = degree_y; + + return true; +} + +std::string PerfectDarkZeroGame::ChooseBinds() { return "Default"; } + +bool PerfectDarkZeroGame::ModifierKeyHandler(uint32_t user_index, + RawInputState& input_state, + X_INPUT_STATE* out_state) { + return false; +} +} // namespace winkey +} // namespace hid +} // namespace xe \ No newline at end of file diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h new file mode 100644 index 0000000000..bae5f584fe --- /dev/null +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h @@ -0,0 +1,49 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2023 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_HID_WINKEY_PerfectDarkZero_H_ +#define XENIA_HID_WINKEY_PerfectDarkZero_H_ + +#include "xenia/hid/winkey/hookables/hookable_game.h" + +namespace xe { +namespace hid { +namespace winkey { + +class PerfectDarkZeroGame : public HookableGame { + public: + enum class GameBuild { + Unknown, + PerfectDarkZero_TU0, + }; + + ~PerfectDarkZeroGame() override; + + bool IsGameSupported(); + + float RadianstoDegree(float radians); + float DegreetoRadians(float degree); + + bool DoHooks(uint32_t user_index, RawInputState& input_state, + X_INPUT_STATE* out_state); + + std::string ChooseBinds(); + + bool ModifierKeyHandler(uint32_t user_index, RawInputState& input_state, + X_INPUT_STATE* out_state); + + private: + GameBuild game_build_ = GameBuild::Unknown; +}; + +} // namespace winkey +} // namespace hid +} // namespace xe + +#endif // XENIA_HID_WINKEY_PerfectDarkZero_H_ diff --git a/src/xenia/hid/winkey/winkey_input_driver.cc b/src/xenia/hid/winkey/winkey_input_driver.cc index 741e6f1951..1349fe6cfe 100644 --- a/src/xenia/hid/winkey/winkey_input_driver.cc +++ b/src/xenia/hid/winkey/winkey_input_driver.cc @@ -25,6 +25,7 @@ #include "xenia/hid/winkey/hookables/GearsOfWars.h" #include "xenia/hid/winkey/hookables/JustCause.h" #include "xenia/hid/winkey/hookables/Minecraft.h" +#include "xenia/hid/winkey/hookables/PerfectDarkZero.h" #include "xenia/hid/winkey/hookables/RDR.h" #include "xenia/hid/winkey/hookables/SaintsRow1.h" #include "xenia/hid/winkey/hookables/SaintsRow2.h" @@ -465,6 +466,7 @@ WinKeyInputDriver::WinKeyInputDriver(xe::ui::Window* window, hookable_games_.push_back(std::move(std::make_unique())); hookable_games_.push_back(std::move(std::make_unique())); hookable_games_.push_back(std::move(std::make_unique())); + hookable_games_.push_back(std::move(std::make_unique())); hookable_games_.push_back(std::move(std::make_unique())); auto path = std::filesystem::current_path() / "bindings.ini"; From 1188ab0608aaf1bdd133391e02b7700bb66f97f8 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 18 Oct 2024 11:21:47 +0300 Subject: [PATCH 02/29] Add sway --- .../hid/winkey/hookables/PerfectDarkZero.cc | 108 +++++++++++++++++- .../hid/winkey/hookables/PerfectDarkZero.h | 6 + 2 files changed, 108 insertions(+), 6 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index d92259fdbf..668cef2d95 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -24,8 +24,10 @@ using namespace xe::kernel; DECLARE_double(sensitivity); +DECLARE_double(fov_sensitivity); DECLARE_bool(invert_y); DECLARE_bool(invert_x); +DECLARE_bool(ge_gun_sway); const uint32_t kTitleIdPerfectDarkZero = 0x4D5307D3; @@ -36,14 +38,20 @@ struct GameBuildAddrs { const char* build_string; uint32_t build_string_addr; uint32_t base_address; + uint32_t cover_flag_offset; uint32_t x_offset; uint32_t y_offset; + uint32_t cover_x_offset; + uint32_t gun_y_offset; // These in-game are tied to camera, we decouple them + // with a patch. + uint32_t gun_x_offset; + uint32_t fovscale_address; }; std::map supported_builds{ {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU0, - {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BD7A4, 0x82D2AD38, 0x150, - 0x1674}}}; + {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BD7A4, 0x82D2AD38, 0x14BB, 0x150, + 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82E1B930}}}; PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; @@ -120,26 +128,114 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, float degree_x = RadianstoDegree(*cam_x); float degree_y = (float)*cam_y; + xe::be* fovscale = kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].fovscale_address); + + const float a = (float)cvars::fov_sensitivity; + float fovscale_l = *fovscale; + + if (fovscale_l <= 1.006910563f) + fovscale_l = 1.006910563f; + else + fovscale_l = fovscale_l = + ((1 - a) * (fovscale_l * fovscale_l) + a * fovscale_l) * + 1.1f; //// Quadratic scaling to make fovscale effect sens stronger and + ///extra multiplier as it doesn't /feel/ enough. + // X-axis = 0 to 360 if (cvars::invert_x) { - degree_x += (input_state.mouse.x_delta / 7.5f) * (float)cvars::sensitivity; + degree_x += (input_state.mouse.x_delta / (8.405f * fovscale_l)) * + (float)cvars::sensitivity; } else { - degree_x -= (input_state.mouse.x_delta / 7.5f) * (float)cvars::sensitivity; + degree_x -= (input_state.mouse.x_delta / (8.405f * fovscale_l)) * + (float)cvars::sensitivity; } *cam_x = DegreetoRadians(degree_x); // Y-axis = -90 to 90 if (cvars::invert_y) { - degree_y -= (input_state.mouse.y_delta / 7.5f) * (float)cvars::sensitivity; + degree_y -= (input_state.mouse.y_delta / (8.405f * fovscale_l)) * + (float)cvars::sensitivity; } else { - degree_y += (input_state.mouse.y_delta / 7.5f) * (float)cvars::sensitivity; + degree_y += (input_state.mouse.y_delta / (8.405f * fovscale_l)) * + (float)cvars::sensitivity; } *cam_y = degree_y; + xe::be gun_x_address = + *base_address + supported_builds[game_build_].gun_x_offset; + xe::be gun_y_address = + *base_address + supported_builds[game_build_].gun_y_offset; + + // revised gun sway from goldeneye.cc + xe::be* gun_x = + kernel_memory()->TranslateVirtual*>(gun_x_address); + xe::be* gun_y = + kernel_memory()->TranslateVirtual*>(gun_y_address); + + float gun_x_val = *gun_x; + float gun_y_val = *gun_y; + + // Apply the mouse input to the gun sway + if (input_state.mouse.x_delta || input_state.mouse.y_delta) { + if (!cvars::invert_x) { + gun_x_val += ((float)input_state.mouse.x_delta / (10.f * fovscale_l)) * + (float)cvars::sensitivity; + } else { + gun_x_val -= ((float)input_state.mouse.x_delta / (10.f * fovscale_l)) * + (float)cvars::sensitivity; + } + + if (!cvars::invert_y) { + gun_y_val += ((float)input_state.mouse.y_delta / (10.f * fovscale_l)) * + (float)cvars::sensitivity; + } else { + gun_y_val -= ((float)input_state.mouse.y_delta / (10.f * fovscale_l)) * + (float)cvars::sensitivity; + } + + // Bound the gun sway movement within a range to prevent excessive movement + gun_x_val = std::min(gun_x_val, 2.5f); + gun_x_val = std::max(gun_x_val, -2.5f); + gun_y_val = std::min(gun_y_val, 2.5f); + gun_y_val = std::max(gun_y_val, -2.5f); + + // Set centering and disable sway flags + start_centering_ = true; + disable_sway_ = true; // Disable sway until centering is complete + } else if (start_centering_) { + // Apply gun centering if no input is detected + float centering_speed = 0.05f; // Adjust the speed of centering as needed + + if (gun_x_val > 0) { + gun_x_val -= std::min(centering_speed, gun_x_val); + } else if (gun_x_val < 0) { + gun_x_val += std::min(centering_speed, -gun_x_val); + } + + if (gun_y_val > 0) { + gun_y_val -= std::min(centering_speed, gun_y_val); + } else if (gun_y_val < 0) { + gun_y_val += std::min(centering_speed, -gun_y_val); + } + + // Stop centering once the gun is centered + if (gun_x_val == 0 && gun_y_val == 0) { + start_centering_ = false; + disable_sway_ = false; // Re-enable sway after centering + } + } + + // Write the updated values back to the gun_x and gun_y + *gun_x = gun_x_val; + *gun_y = gun_y_val; + return true; } +bool PerfectDarkZeroGame::InCover() {} + std::string PerfectDarkZeroGame::ChooseBinds() { return "Default"; } bool PerfectDarkZeroGame::ModifierKeyHandler(uint32_t user_index, diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h index bae5f584fe..544f76b5b8 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h @@ -33,6 +33,8 @@ class PerfectDarkZeroGame : public HookableGame { bool DoHooks(uint32_t user_index, RawInputState& input_state, X_INPUT_STATE* out_state); + bool InCover(); + std::string ChooseBinds(); bool ModifierKeyHandler(uint32_t user_index, RawInputState& input_state, @@ -40,6 +42,10 @@ class PerfectDarkZeroGame : public HookableGame { private: GameBuild game_build_ = GameBuild::Unknown; + + float centering_speed_ = 0.0125f; + bool start_centering_ = false; + bool disable_sway_ = false; // temporarily prevents sway being applied }; } // namespace winkey From a49618c220b826ccd55bc2823a5310366ba46583 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 18 Oct 2024 11:57:22 +0300 Subject: [PATCH 03/29] Add cover camera --- .../hid/winkey/hookables/PerfectDarkZero.cc | 180 +++++++++++------- 1 file changed, 107 insertions(+), 73 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 668cef2d95..0deb6161bb 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -50,7 +50,7 @@ struct GameBuildAddrs { std::map supported_builds{ {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU0, - {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BD7A4, 0x82D2AD38, 0x14BB, 0x150, + {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BD7A4, 0x82D2AD38, 0x16A7, 0x150, 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82E1B930}}}; PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; @@ -113,9 +113,15 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, // Not in game return false; } + xe::be x_address; + bool in_cover = InCover(); + + if (!in_cover) { + x_address = *radians_x_base + supported_builds[game_build_].x_offset; + } else { + x_address = *base_address + supported_builds[game_build_].cover_x_offset; + } - xe::be x_address = - *radians_x_base + supported_builds[game_build_].x_offset; xe::be y_address = *base_address + supported_builds[game_build_].y_offset; @@ -125,8 +131,17 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, xe::be* cam_y = kernel_memory()->TranslateVirtual*>(y_address); - float degree_x = RadianstoDegree(*cam_x); - float degree_y = (float)*cam_y; + float degree_x, degree_y; + + if (!in_cover) { + // Normal mode: convert radians to degrees + degree_x = RadianstoDegree(*cam_x); + } else { + // Cover mode: X-axis is already in degrees + degree_x = *cam_x; + } + + degree_y = (float)*cam_y; xe::be* fovscale = kernel_memory()->TranslateVirtual*>( supported_builds[game_build_].fovscale_address); @@ -146,12 +161,17 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, if (cvars::invert_x) { degree_x += (input_state.mouse.x_delta / (8.405f * fovscale_l)) * (float)cvars::sensitivity; - } else { degree_x -= (input_state.mouse.x_delta / (8.405f * fovscale_l)) * (float)cvars::sensitivity; } - *cam_x = DegreetoRadians(degree_x); + + if (!in_cover) { + *cam_x = DegreetoRadians( + degree_x); // Convert degrees back to radians for normal aiming + } else { + *cam_x = degree_x; // Directly store degrees for cover aiming + } // Y-axis = -90 to 90 if (cvars::invert_y) { @@ -162,80 +182,94 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, (float)cvars::sensitivity; } *cam_y = degree_y; - - xe::be gun_x_address = - *base_address + supported_builds[game_build_].gun_x_offset; - xe::be gun_y_address = - *base_address + supported_builds[game_build_].gun_y_offset; - - // revised gun sway from goldeneye.cc - xe::be* gun_x = - kernel_memory()->TranslateVirtual*>(gun_x_address); - xe::be* gun_y = - kernel_memory()->TranslateVirtual*>(gun_y_address); - - float gun_x_val = *gun_x; - float gun_y_val = *gun_y; - - // Apply the mouse input to the gun sway - if (input_state.mouse.x_delta || input_state.mouse.y_delta) { - if (!cvars::invert_x) { - gun_x_val += ((float)input_state.mouse.x_delta / (10.f * fovscale_l)) * - (float)cvars::sensitivity; - } else { - gun_x_val -= ((float)input_state.mouse.x_delta / (10.f * fovscale_l)) * - (float)cvars::sensitivity; + if (cvars::ge_gun_sway) { + xe::be gun_x_address = + *base_address + supported_builds[game_build_].gun_x_offset; + xe::be gun_y_address = + *base_address + supported_builds[game_build_].gun_y_offset; + + // revised gun sway from goldeneye.cc + xe::be* gun_x = + kernel_memory()->TranslateVirtual*>(gun_x_address); + xe::be* gun_y = + kernel_memory()->TranslateVirtual*>(gun_y_address); + + float gun_x_val = *gun_x; + float gun_y_val = *gun_y; + + // Apply the mouse input to the gun sway + if (input_state.mouse.x_delta || input_state.mouse.y_delta) { + if (!cvars::invert_x) { + gun_x_val += ((float)input_state.mouse.x_delta / (10.f * fovscale_l)) * + (float)cvars::sensitivity; + } else { + gun_x_val -= ((float)input_state.mouse.x_delta / (10.f * fovscale_l)) * + (float)cvars::sensitivity; + } + + if (!cvars::invert_y) { + gun_y_val += ((float)input_state.mouse.y_delta / (10.f * fovscale_l)) * + (float)cvars::sensitivity; + } else { + gun_y_val -= ((float)input_state.mouse.y_delta / (10.f * fovscale_l)) * + (float)cvars::sensitivity; + } + + // Bound the gun sway movement within a range to prevent excessive + // movement + gun_x_val = std::min(gun_x_val, 2.5f); + gun_x_val = std::max(gun_x_val, -2.5f); + gun_y_val = std::min(gun_y_val, 2.5f); + gun_y_val = std::max(gun_y_val, -2.5f); + + // Set centering and disable sway flags + start_centering_ = true; + disable_sway_ = true; // Disable sway until centering is complete + } else if (start_centering_) { + // Apply gun centering if no input is detected + float centering_speed = 0.05f; // Adjust the speed of centering as needed + + if (gun_x_val > 0) { + gun_x_val -= std::min(centering_speed, gun_x_val); + } else if (gun_x_val < 0) { + gun_x_val += std::min(centering_speed, -gun_x_val); + } + + if (gun_y_val > 0) { + gun_y_val -= std::min(centering_speed, gun_y_val); + } else if (gun_y_val < 0) { + gun_y_val += std::min(centering_speed, -gun_y_val); + } + + // Stop centering once the gun is centered + if (gun_x_val == 0 && gun_y_val == 0) { + start_centering_ = false; + disable_sway_ = false; // Re-enable sway after centering + } } - if (!cvars::invert_y) { - gun_y_val += ((float)input_state.mouse.y_delta / (10.f * fovscale_l)) * - (float)cvars::sensitivity; - } else { - gun_y_val -= ((float)input_state.mouse.y_delta / (10.f * fovscale_l)) * - (float)cvars::sensitivity; - } + // Write the updated values back to the gun_x and gun_y + *gun_x = gun_x_val; + *gun_y = gun_y_val; + } + return true; +} - // Bound the gun sway movement within a range to prevent excessive movement - gun_x_val = std::min(gun_x_val, 2.5f); - gun_x_val = std::max(gun_x_val, -2.5f); - gun_y_val = std::min(gun_y_val, 2.5f); - gun_y_val = std::max(gun_y_val, -2.5f); - - // Set centering and disable sway flags - start_centering_ = true; - disable_sway_ = true; // Disable sway until centering is complete - } else if (start_centering_) { - // Apply gun centering if no input is detected - float centering_speed = 0.05f; // Adjust the speed of centering as needed - - if (gun_x_val > 0) { - gun_x_val -= std::min(centering_speed, gun_x_val); - } else if (gun_x_val < 0) { - gun_x_val += std::min(centering_speed, -gun_x_val); - } +bool PerfectDarkZeroGame::InCover() { + xe::be* base_address = + kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].base_address); - if (gun_y_val > 0) { - gun_y_val -= std::min(centering_speed, gun_y_val); - } else if (gun_y_val < 0) { - gun_y_val += std::min(centering_speed, -gun_y_val); - } + uint8_t* cover_flag = kernel_memory()->TranslateVirtual( + *base_address + supported_builds[game_build_].cover_flag_offset); - // Stop centering once the gun is centered - if (gun_x_val == 0 && gun_y_val == 0) { - start_centering_ = false; - disable_sway_ = false; // Re-enable sway after centering - } + if (*cover_flag == 1) { + return true; + } else { + return false; } - - // Write the updated values back to the gun_x and gun_y - *gun_x = gun_x_val; - *gun_y = gun_y_val; - - return true; } -bool PerfectDarkZeroGame::InCover() {} - std::string PerfectDarkZeroGame::ChooseBinds() { return "Default"; } bool PerfectDarkZeroGame::ModifierKeyHandler(uint32_t user_index, From 0d08feb5c9bdd9269627036a74d0ea229aad65a9 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 18 Oct 2024 12:45:54 +0300 Subject: [PATCH 04/29] pause flag --- .../hid/winkey/hookables/PerfectDarkZero.cc | 19 ++++++++++++++++++- .../hid/winkey/hookables/PerfectDarkZero.h | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 0deb6161bb..785de3dd90 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -46,12 +46,13 @@ struct GameBuildAddrs { // with a patch. uint32_t gun_x_offset; uint32_t fovscale_address; + uint32_t pause_offset; }; std::map supported_builds{ {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU0, {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BD7A4, 0x82D2AD38, 0x16A7, 0x150, - 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82E1B930}}}; + 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82E1B930, 0x16A3}}}; PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; @@ -113,6 +114,8 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, // Not in game return false; } + + if (IsPaused()) return false; xe::be x_address; bool in_cover = InCover(); @@ -255,6 +258,20 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, return true; } +bool PerfectDarkZeroGame::IsPaused() { + xe::be* base_address = + kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].base_address); + + uint8_t* pause_flag = kernel_memory()->TranslateVirtual( + *base_address + supported_builds[game_build_].pause_offset); + if (*pause_flag != 0) { + return true; + } else { + return false; + } +} + bool PerfectDarkZeroGame::InCover() { xe::be* base_address = kernel_memory()->TranslateVirtual*>( diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h index 544f76b5b8..921544d672 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h @@ -33,6 +33,8 @@ class PerfectDarkZeroGame : public HookableGame { bool DoHooks(uint32_t user_index, RawInputState& input_state, X_INPUT_STATE* out_state); + bool IsPaused(); + bool InCover(); std::string ChooseBinds(); From 9a2fecb135f41bd0845b7ef1dce45f80a15310e9 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 18 Oct 2024 14:29:15 +0300 Subject: [PATCH 05/29] clamp cover --- src/xenia/hid/winkey/hookables/PerfectDarkZero.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 785de3dd90..79100e241a 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -173,6 +173,7 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, *cam_x = DegreetoRadians( degree_x); // Convert degrees back to radians for normal aiming } else { + degree_x = std::clamp(degree_x, -68.0f, 68.0f); *cam_x = degree_x; // Directly store degrees for cover aiming } From b1cd2fd3a57e51e4b81c7b68e8a414734628206a Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 18 Oct 2024 20:49:58 +0300 Subject: [PATCH 06/29] Change calculation of FOVscaling for FOV patch --- .../hid/winkey/hookables/PerfectDarkZero.cc | 52 +++++++++++++------ src/xenia/hid/winkey/winkey_input_driver.cc | 4 ++ 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 79100e241a..741c12a552 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -28,6 +28,7 @@ DECLARE_double(fov_sensitivity); DECLARE_bool(invert_y); DECLARE_bool(invert_x); DECLARE_bool(ge_gun_sway); +DECLARE_bool(pdz_scale_base_fov_sens); const uint32_t kTitleIdPerfectDarkZero = 0x4D5307D3; @@ -46,13 +47,14 @@ struct GameBuildAddrs { // with a patch. uint32_t gun_x_offset; uint32_t fovscale_address; + uint32_t current_set_fov; // Incase FOV is increased with a patch. uint32_t pause_offset; }; std::map supported_builds{ {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU0, {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BD7A4, 0x82D2AD38, 0x16A7, 0x150, - 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82E1B930, 0x16A3}}}; + 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82D68320, 0x820EC228, 0x16A3}}}; PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; @@ -146,26 +148,42 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, degree_y = (float)*cam_y; - xe::be* fovscale = kernel_memory()->TranslateVirtual*>( - supported_builds[game_build_].fovscale_address); + float set_fov_multiplier = 1.0f; + static float fovscale_l = 1.0f; + xe::be* base_address_fov = + kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].fovscale_address); + if (!base_address_fov || base_address_fov != NULL) { + xe::be fovscale_address = *base_address_fov + 0x440; + xe::be fovscale_sanity = *base_address_fov + 0x660; + + xe::be* set_fov = kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].current_set_fov); + + xe::be* fovscale = + kernel_memory()->TranslateVirtual*>(fovscale_address); - const float a = (float)cvars::fov_sensitivity; - float fovscale_l = *fovscale; + const float a = (float)cvars::fov_sensitivity; + fovscale_l = *fovscale; + if (cvars::pdz_scale_base_fov_sens && *set_fov != 58.f) + set_fov_multiplier = *set_fov / 58.f; - if (fovscale_l <= 1.006910563f) - fovscale_l = 1.006910563f; - else - fovscale_l = fovscale_l = - ((1 - a) * (fovscale_l * fovscale_l) + a * fovscale_l) * - 1.1f; //// Quadratic scaling to make fovscale effect sens stronger and - ///extra multiplier as it doesn't /feel/ enough. + fovscale_l = (*set_fov / *fovscale); + + if (fovscale_l > 1.f) { + fovscale_l = + (a * fovscale_l + (1 - a) * (fovscale_l * fovscale_l) * 1.1f); + } + } // X-axis = 0 to 360 if (cvars::invert_x) { - degree_x += (input_state.mouse.x_delta / (8.405f * fovscale_l)) * + degree_x += ((input_state.mouse.x_delta / set_fov_multiplier) / + (7.5f * fovscale_l)) * (float)cvars::sensitivity; } else { - degree_x -= (input_state.mouse.x_delta / (8.405f * fovscale_l)) * + degree_x -= ((input_state.mouse.x_delta / set_fov_multiplier) / + (7.5f * fovscale_l)) * (float)cvars::sensitivity; } @@ -179,10 +197,12 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, // Y-axis = -90 to 90 if (cvars::invert_y) { - degree_y -= (input_state.mouse.y_delta / (8.405f * fovscale_l)) * + degree_y -= ((input_state.mouse.y_delta / set_fov_multiplier) / + (7.5f * fovscale_l)) * (float)cvars::sensitivity; } else { - degree_y += (input_state.mouse.y_delta / (8.405f * fovscale_l)) * + degree_y += ((input_state.mouse.y_delta / set_fov_multiplier) / + (7.5f * fovscale_l)) * (float)cvars::sensitivity; } *cam_y = degree_y; diff --git a/src/xenia/hid/winkey/winkey_input_driver.cc b/src/xenia/hid/winkey/winkey_input_driver.cc index 1349fe6cfe..fc9ffe88b7 100644 --- a/src/xenia/hid/winkey/winkey_input_driver.cc +++ b/src/xenia/hid/winkey/winkey_input_driver.cc @@ -95,6 +95,10 @@ DEFINE_bool( rdr_snappy_wheel, true, "(Red Dead Redemption) Snaps the Weapon Wheel in 45 degree increments", "MouseHook"); +DEFINE_bool(pdz_scale_base_fov_sens, true, + "(Perfect Dark Zero) Scales base sentiviity if base FOV is " + "increased with a patch. ", + "MouseHook"); #define XE_HID_WINKEY_BINDING(button, description, cvar_name, \ cvar_default_value) \ From f419b51a2b6f812c013da096a9ca9137d207c6bf Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 18 Oct 2024 21:38:49 +0300 Subject: [PATCH 07/29] Patch gun sway --- src/xenia/emulator.cc | 58 +++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index 73d1abe4a9..17e6e4400b 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -83,10 +83,9 @@ DEFINE_bool(ge_remove_blur, false, DEFINE_bool(ge_debug_menu, false, "(GoldenEye) Enables the debug menu, accessible with LB/1", "MouseHook"); -DEFINE_bool(sr_better_drive_cam, true, - "(Saints Row 1&2) unties X rotation from vehicles when " - "auto-centering is disabled, this makes the camera similar to the " - "GTA series vehicle camera.", +DEFINE_bool(sr2_better_drive_cam, true, + "(Saints Row 2) unties X rotation from vehicles when " + "auto-centering is disabled akin to GTA IV.", "MouseHook"); DEFINE_bool(sr2_better_handbrake_cam, true, @@ -116,12 +115,6 @@ DECLARE_int32(user_language); DECLARE_bool(allow_plugins); DECLARE_bool(disable_autoaim); -DEFINE_int32(priority_class, 0, - "Forces Xenia to use different process priority than default one. " - "It might affect performance and cause unexpected bugs. Possible " - "values: 0 - Normal, 1 - Above normal, 2 - High", - "General"); - namespace xe { using namespace xe::literals; @@ -150,7 +143,6 @@ Emulator::Emulator(const std::filesystem::path& command_line, display_window_(nullptr), memory_(), audio_system_(), - audio_media_player_(), graphics_system_(), input_system_(), export_resolver_(), @@ -162,13 +154,6 @@ Emulator::Emulator(const std::filesystem::path& command_line, paused_(false), restoring_(false), restore_fence_() { - if (cvars::priority_class != 0) { - if (SetProcessPriorityClass(cvars::priority_class)) { - XELOGI("Higher priority class request: Successful. New priority: {}", - cvars::priority_class); - } - } - #if XE_PLATFORM_WIN32 == 1 // Show a disclaimer that links to the quickstart // guide the first time they ever open the emulator @@ -207,7 +192,6 @@ Emulator::~Emulator() { input_system_.reset(); graphics_system_.reset(); audio_system_.reset(); - audio_media_player_.reset(); kernel_state_.reset(); file_system_.reset(); @@ -343,9 +327,6 @@ X_STATUS Emulator::Setup( if (result) { return result; } - audio_media_player_ = std::make_unique( - audio_system_.get(), kernel_state_.get()); - audio_media_player_->Setup(); } // Initialize emulator fallback exception handling last. @@ -1582,10 +1563,8 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, 0xD19F16A4, // stfs f12, 0x16A4(r31) 0xD19F1690, // stfs f12, 0x1690(r31) 0xD15F1694, // stfs f10, 0x1694(r31) - 0xD0FF0CFC, // stfs f7, 0xCFC(r31) // Right gun x - 0xD0BF0D00, // stfs f5, 0xD00(r31) // Right gun y - 0xD07F14A0, // stfs f3, 0x14A0(r31) // Left gun x - 0xD05F14A4 // stfs f2, 0x14A4(r31) // Left gun y + 0xD0FF0CFC, // stfs f7, 0xCFC(r31) + 0xD0BF0D00 // stfs f5, 0xD00(r31) }; int patched = 0; @@ -1851,7 +1830,7 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, patch_addr(build.multiplierread_addr5, build.zero_patch1); patch_addr(build.sensYvalue_addr1, build.zero_patch1); patch_addr(build.sensXvalue_addr2, build.zero_patch1); - if (cvars::sr_better_drive_cam && build.Vehicle_RotationXWrite_addr1) { + if (cvars::sr2_better_drive_cam && build.Vehicle_RotationXWrite_addr1) { patch_addr(build.Vehicle_RotationXWrite_addr1, build.beNOP); } @@ -2071,14 +2050,27 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, } } - if (module->title_id() == 0x584111F7) { // Minecraft - Prevent game from - // writing to inventory cursor - std::map supported_builds = {{"1.0.80", 0x827594EC}}; + if (module->title_id() == 0x4D5307D3) { + struct PDZPatchOffsets { + const char* build_string; + uint32_t build_string_addr; + uint32_t gun_y_read_camera_address; + uint32_t gun_x_read_camera_address; + }; + + std::vector supported_builds{ + {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BD7A4, 0x8253EDA0, 0x8253EDA8}, + }; for (auto& build : supported_builds) { - if (build.first == title_version_) { - patch_addr(build.second, 0x60000000); - break; + const char* build_ptr = reinterpret_cast( + module->memory()->TranslateVirtual(build.build_string_addr)); + if (strcmp(build_ptr, build.build_string) != 0) { + continue; } + // Gun sway is read from RS camera movement, we decouple it by moving it's + // pointer to +0xF9C for Y and + 0xFA10 for X. + patch_addr(build.gun_y_read_camera_address, 0xC0230F9C); + patch_addr(build.gun_x_read_camera_address, 0xC0230FA0); } } From 04be4f11c4847bb50589bfc8f6e9499cd1d6aac5 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Sat, 19 Oct 2024 11:49:31 +0300 Subject: [PATCH 08/29] TU3 support --- src/xenia/emulator.cc | 4 ++-- src/xenia/hid/winkey/hookables/PerfectDarkZero.cc | 5 ++++- src/xenia/hid/winkey/hookables/PerfectDarkZero.h | 5 +---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index 17e6e4400b..f93a76250f 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -2060,7 +2060,7 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, std::vector supported_builds{ {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BD7A4, 0x8253EDA0, 0x8253EDA8}, - }; + {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BBF64, 0x8254E4D8, 0x8254E4E0}}; for (auto& build : supported_builds) { const char* build_ptr = reinterpret_cast( module->memory()->TranslateVirtual(build.build_string_addr)); @@ -2068,7 +2068,7 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, continue; } // Gun sway is read from RS camera movement, we decouple it by moving it's - // pointer to +0xF9C for Y and + 0xFA10 for X. + // pointer to +0xF9C for Y and + 0xFA0 for X. patch_addr(build.gun_y_read_camera_address, 0xC0230F9C); patch_addr(build.gun_x_read_camera_address, 0xC0230FA0); } diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 741c12a552..baf7fbc051 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -54,7 +54,10 @@ struct GameBuildAddrs { std::map supported_builds{ {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU0, {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BD7A4, 0x82D2AD38, 0x16A7, 0x150, - 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82D68320, 0x820EC228, 0x16A3}}}; + 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82D68320, 0x820EC228, 0x16A3}}, + {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU3, + {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BBF64, 0x82D2B758, 0x16A7, 0x150, + 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82D69048, 0x820EAF40, 0x16A3}}}; PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h index 921544d672..d4a83d163d 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h @@ -18,10 +18,7 @@ namespace winkey { class PerfectDarkZeroGame : public HookableGame { public: - enum class GameBuild { - Unknown, - PerfectDarkZero_TU0, - }; + enum class GameBuild { Unknown, PerfectDarkZero_TU0, PerfectDarkZero_TU3 }; ~PerfectDarkZeroGame() override; From 581548ca01fc71fee1e96e716b0d721ff9442aa9 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Sat, 19 Oct 2024 12:57:05 +0300 Subject: [PATCH 09/29] Right Stick emulation for intro mission --- .../hid/winkey/hookables/PerfectDarkZero.cc | 345 ++++++++++-------- .../hid/winkey/hookables/PerfectDarkZero.h | 8 + 2 files changed, 209 insertions(+), 144 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index baf7fbc051..f3e67b6cd8 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -25,6 +25,7 @@ using namespace xe::kernel; DECLARE_double(sensitivity); DECLARE_double(fov_sensitivity); +DECLARE_double(right_stick_hold_time_workaround); DECLARE_bool(invert_y); DECLARE_bool(invert_x); DECLARE_bool(ge_gun_sway); @@ -47,6 +48,7 @@ struct GameBuildAddrs { // with a patch. uint32_t gun_x_offset; uint32_t fovscale_address; + uint32_t fovscale_alt_static_address; uint32_t current_set_fov; // Incase FOV is increased with a patch. uint32_t pause_offset; }; @@ -54,10 +56,12 @@ struct GameBuildAddrs { std::map supported_builds{ {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU0, {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BD7A4, 0x82D2AD38, 0x16A7, 0x150, - 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82D68320, 0x820EC228, 0x16A3}}, + 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82D68320, 0x82E1B930, 0x820EC228, + 0x16A3}}, {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU3, {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BBF64, 0x82D2B758, 0x16A7, 0x150, - 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82D69048, 0x820EAF40, 0x16A3}}}; + 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82D69048, 0x82D3EED0, 0x820EAF40, + 0x16A3}}}; PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; @@ -120,165 +124,173 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, return false; } - if (IsPaused()) return false; - xe::be x_address; - bool in_cover = InCover(); + if (!IsPaused()) { + xe::be x_address; + bool in_cover = InCover(); - if (!in_cover) { - x_address = *radians_x_base + supported_builds[game_build_].x_offset; - } else { - x_address = *base_address + supported_builds[game_build_].cover_x_offset; - } - - xe::be y_address = - *base_address + supported_builds[game_build_].y_offset; - - xe::be* cam_x = - kernel_memory()->TranslateVirtual*>(x_address); - - xe::be* cam_y = - kernel_memory()->TranslateVirtual*>(y_address); - - float degree_x, degree_y; - - if (!in_cover) { - // Normal mode: convert radians to degrees - degree_x = RadianstoDegree(*cam_x); - } else { - // Cover mode: X-axis is already in degrees - degree_x = *cam_x; - } - - degree_y = (float)*cam_y; - - float set_fov_multiplier = 1.0f; - static float fovscale_l = 1.0f; - xe::be* base_address_fov = - kernel_memory()->TranslateVirtual*>( - supported_builds[game_build_].fovscale_address); - if (!base_address_fov || base_address_fov != NULL) { - xe::be fovscale_address = *base_address_fov + 0x440; - xe::be fovscale_sanity = *base_address_fov + 0x660; + if (!in_cover) { + x_address = *radians_x_base + supported_builds[game_build_].x_offset; + } else { + x_address = *base_address + supported_builds[game_build_].cover_x_offset; + } - xe::be* set_fov = kernel_memory()->TranslateVirtual*>( - supported_builds[game_build_].current_set_fov); + xe::be y_address = + *base_address + supported_builds[game_build_].y_offset; - xe::be* fovscale = - kernel_memory()->TranslateVirtual*>(fovscale_address); + xe::be* cam_x = + kernel_memory()->TranslateVirtual*>(x_address); - const float a = (float)cvars::fov_sensitivity; - fovscale_l = *fovscale; - if (cvars::pdz_scale_base_fov_sens && *set_fov != 58.f) - set_fov_multiplier = *set_fov / 58.f; + xe::be* cam_y = + kernel_memory()->TranslateVirtual*>(y_address); - fovscale_l = (*set_fov / *fovscale); + float degree_x, degree_y; - if (fovscale_l > 1.f) { - fovscale_l = - (a * fovscale_l + (1 - a) * (fovscale_l * fovscale_l) * 1.1f); + if (!in_cover) { + // Normal mode: convert radians to degrees + degree_x = RadianstoDegree(*cam_x); + } else { + // Cover mode: X-axis is already in degrees + degree_x = *cam_x; } - } - // X-axis = 0 to 360 - if (cvars::invert_x) { - degree_x += ((input_state.mouse.x_delta / set_fov_multiplier) / - (7.5f * fovscale_l)) * - (float)cvars::sensitivity; - } else { - degree_x -= ((input_state.mouse.x_delta / set_fov_multiplier) / - (7.5f * fovscale_l)) * - (float)cvars::sensitivity; - } - - if (!in_cover) { - *cam_x = DegreetoRadians( - degree_x); // Convert degrees back to radians for normal aiming - } else { - degree_x = std::clamp(degree_x, -68.0f, 68.0f); - *cam_x = degree_x; // Directly store degrees for cover aiming - } + degree_y = (float)*cam_y; - // Y-axis = -90 to 90 - if (cvars::invert_y) { - degree_y -= ((input_state.mouse.y_delta / set_fov_multiplier) / - (7.5f * fovscale_l)) * - (float)cvars::sensitivity; - } else { - degree_y += ((input_state.mouse.y_delta / set_fov_multiplier) / - (7.5f * fovscale_l)) * - (float)cvars::sensitivity; - } - *cam_y = degree_y; - if (cvars::ge_gun_sway) { - xe::be gun_x_address = - *base_address + supported_builds[game_build_].gun_x_offset; - xe::be gun_y_address = - *base_address + supported_builds[game_build_].gun_y_offset; - - // revised gun sway from goldeneye.cc - xe::be* gun_x = - kernel_memory()->TranslateVirtual*>(gun_x_address); - xe::be* gun_y = - kernel_memory()->TranslateVirtual*>(gun_y_address); - - float gun_x_val = *gun_x; - float gun_y_val = *gun_y; - - // Apply the mouse input to the gun sway - if (input_state.mouse.x_delta || input_state.mouse.y_delta) { - if (!cvars::invert_x) { - gun_x_val += ((float)input_state.mouse.x_delta / (10.f * fovscale_l)) * - (float)cvars::sensitivity; - } else { - gun_x_val -= ((float)input_state.mouse.x_delta / (10.f * fovscale_l)) * - (float)cvars::sensitivity; + float set_fov_multiplier = 1.0f; + static float fovscale_l = 1.0f; + xe::be* base_address_fov = + kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].fovscale_address); + if (!base_address_fov || base_address_fov != NULL) { + xe::be fovscale_address = *base_address_fov + 0x440; + xe::be fovscale_sanity = *base_address_fov + 0x660; + + xe::be* set_fov = kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].current_set_fov); + + xe::be* fovscale = + kernel_memory()->TranslateVirtual*>(fovscale_address); + + const float a = (float)cvars::fov_sensitivity; + fovscale_l = *fovscale; + if (cvars::pdz_scale_base_fov_sens && *set_fov != 58.f) + set_fov_multiplier = *set_fov / 58.f; + + fovscale_l = (*set_fov / *fovscale); + + if (fovscale_l > 1.f) { + fovscale_l = + (a * fovscale_l + (1 - a) * (fovscale_l * fovscale_l) * 1.1f); } + } - if (!cvars::invert_y) { - gun_y_val += ((float)input_state.mouse.y_delta / (10.f * fovscale_l)) * - (float)cvars::sensitivity; - } else { - gun_y_val -= ((float)input_state.mouse.y_delta / (10.f * fovscale_l)) * - (float)cvars::sensitivity; - } + // X-axis = 0 to 360 + if (cvars::invert_x) { + degree_x += ((input_state.mouse.x_delta / set_fov_multiplier) / + (7.5f * fovscale_l)) * + (float)cvars::sensitivity; + } else { + degree_x -= ((input_state.mouse.x_delta / set_fov_multiplier) / + (7.5f * fovscale_l)) * + (float)cvars::sensitivity; + } - // Bound the gun sway movement within a range to prevent excessive - // movement - gun_x_val = std::min(gun_x_val, 2.5f); - gun_x_val = std::max(gun_x_val, -2.5f); - gun_y_val = std::min(gun_y_val, 2.5f); - gun_y_val = std::max(gun_y_val, -2.5f); - - // Set centering and disable sway flags - start_centering_ = true; - disable_sway_ = true; // Disable sway until centering is complete - } else if (start_centering_) { - // Apply gun centering if no input is detected - float centering_speed = 0.05f; // Adjust the speed of centering as needed - - if (gun_x_val > 0) { - gun_x_val -= std::min(centering_speed, gun_x_val); - } else if (gun_x_val < 0) { - gun_x_val += std::min(centering_speed, -gun_x_val); - } + if (!in_cover) { + *cam_x = DegreetoRadians( + degree_x); // Convert degrees back to radians for normal aiming + } else { + degree_x = std::clamp(degree_x, -68.0f, 68.0f); + *cam_x = degree_x; // Directly store degrees for cover aiming + } - if (gun_y_val > 0) { - gun_y_val -= std::min(centering_speed, gun_y_val); - } else if (gun_y_val < 0) { - gun_y_val += std::min(centering_speed, -gun_y_val); + // Y-axis = -90 to 90 + if (cvars::invert_y) { + degree_y -= ((input_state.mouse.y_delta / set_fov_multiplier) / + (7.5f * fovscale_l)) * + (float)cvars::sensitivity; + } else { + degree_y += ((input_state.mouse.y_delta / set_fov_multiplier) / + (7.5f * fovscale_l)) * + (float)cvars::sensitivity; + } + *cam_y = degree_y; + if (cvars::ge_gun_sway) { + xe::be gun_x_address = + *base_address + supported_builds[game_build_].gun_x_offset; + xe::be gun_y_address = + *base_address + supported_builds[game_build_].gun_y_offset; + + // revised gun sway from goldeneye.cc + xe::be* gun_x = + kernel_memory()->TranslateVirtual*>(gun_x_address); + xe::be* gun_y = + kernel_memory()->TranslateVirtual*>(gun_y_address); + + float gun_x_val = *gun_x; + float gun_y_val = *gun_y; + + // Apply the mouse input to the gun sway + if (input_state.mouse.x_delta || input_state.mouse.y_delta) { + if (!cvars::invert_x) { + gun_x_val += + ((float)input_state.mouse.x_delta / (10.f * fovscale_l)) * + (float)cvars::sensitivity; + } else { + gun_x_val -= + ((float)input_state.mouse.x_delta / (10.f * fovscale_l)) * + (float)cvars::sensitivity; + } + + if (!cvars::invert_y) { + gun_y_val += + ((float)input_state.mouse.y_delta / (10.f * fovscale_l)) * + (float)cvars::sensitivity; + } else { + gun_y_val -= + ((float)input_state.mouse.y_delta / (10.f * fovscale_l)) * + (float)cvars::sensitivity; + } + + // Bound the gun sway movement within a range to prevent excessive + // movement + gun_x_val = std::min(gun_x_val, 2.5f); + gun_x_val = std::max(gun_x_val, -2.5f); + gun_y_val = std::min(gun_y_val, 2.5f); + gun_y_val = std::max(gun_y_val, -2.5f); + + // Set centering and disable sway flags + start_centering_ = true; + disable_sway_ = true; // Disable sway until centering is complete + } else if (start_centering_) { + // Apply gun centering if no input is detected + float centering_speed = + 0.05f; // Adjust the speed of centering as needed + + if (gun_x_val > 0) { + gun_x_val -= std::min(centering_speed, gun_x_val); + } else if (gun_x_val < 0) { + gun_x_val += std::min(centering_speed, -gun_x_val); + } + + if (gun_y_val > 0) { + gun_y_val -= std::min(centering_speed, gun_y_val); + } else if (gun_y_val < 0) { + gun_y_val += std::min(centering_speed, -gun_y_val); + } + + // Stop centering once the gun is centered + if (gun_x_val == 0 && gun_y_val == 0) { + start_centering_ = false; + disable_sway_ = false; // Re-enable sway after centering + } } - // Stop centering once the gun is centered - if (gun_x_val == 0 && gun_y_val == 0) { - start_centering_ = false; - disable_sway_ = false; // Re-enable sway after centering - } + // Write the updated values back to the gun_x and gun_y + *gun_x = gun_x_val; + *gun_y = gun_y_val; } + } else + HandleRightStickEmulation(input_state, out_state); - // Write the updated values back to the gun_x and gun_y - *gun_x = gun_x_val; - *gun_y = gun_y_val; - } return true; } @@ -311,6 +323,51 @@ bool PerfectDarkZeroGame::InCover() { } } +void PerfectDarkZeroGame::HandleRightStickEmulation( + RawInputState& input_state, X_INPUT_STATE* out_state) { + auto now = std::chrono::steady_clock::now(); + auto elapsed_x = std::chrono::duration_cast( + now - last_movement_time_x_) + .count(); + auto elapsed_y = std::chrono::duration_cast( + now - last_movement_time_y_) + .count(); + + static float accumulated_x = 0.0f; + static float accumulated_y = 0.0f; + + const long long hold_time = + static_cast(cvars::right_stick_hold_time_workaround); + + if (input_state.mouse.x_delta != 0) { + float delta_x = + (input_state.mouse.x_delta * 50.f) * (float)cvars::sensitivity; + accumulated_x += delta_x; + accumulated_x = std::clamp(accumulated_x, (float)SHRT_MIN, (float)SHRT_MAX); + last_movement_time_x_ = now; + } else if (elapsed_x < hold_time) { // Hold the last accumulated value + accumulated_x = std::clamp(accumulated_x, (float)SHRT_MIN, (float)SHRT_MAX); + } else { + accumulated_x = 0.0f; + } + + if (input_state.mouse.y_delta != 0) { + float delta_y = + (input_state.mouse.y_delta * 50.f) * (float)cvars::sensitivity; + + accumulated_y -= delta_y; + accumulated_y = std::clamp(accumulated_y, (float)SHRT_MIN, (float)SHRT_MAX); + last_movement_time_y_ = now; + } else if (elapsed_y < hold_time) { // Hold the last accumulated value + accumulated_y = std::clamp(accumulated_y, (float)SHRT_MIN, (float)SHRT_MAX); + } else { + accumulated_y = 0.0f; + } + + out_state->gamepad.thumb_rx = static_cast(accumulated_x); + out_state->gamepad.thumb_ry = static_cast(accumulated_y); +} + std::string PerfectDarkZeroGame::ChooseBinds() { return "Default"; } bool PerfectDarkZeroGame::ModifierKeyHandler(uint32_t user_index, diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h index d4a83d163d..8426524ad0 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h @@ -11,6 +11,7 @@ #define XENIA_HID_WINKEY_PerfectDarkZero_H_ #include "xenia/hid/winkey/hookables/hookable_game.h" +#include "xenia/base/chrono.h" namespace xe { namespace hid { @@ -34,6 +35,9 @@ class PerfectDarkZeroGame : public HookableGame { bool InCover(); + void HandleRightStickEmulation(RawInputState& input_state, + X_INPUT_STATE* out_state); + std::string ChooseBinds(); bool ModifierKeyHandler(uint32_t user_index, RawInputState& input_state, @@ -45,6 +49,10 @@ class PerfectDarkZeroGame : public HookableGame { float centering_speed_ = 0.0125f; bool start_centering_ = false; bool disable_sway_ = false; // temporarily prevents sway being applied + std::chrono::steady_clock::time_point last_movement_time_x_; + std::chrono::steady_clock::time_point last_movement_time_y_; + static xe::be fovscale_address; + }; } // namespace winkey From 3ba07f54dabfc5a7e90ae8c95574d7c65fa38c46 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Sat, 19 Oct 2024 12:59:32 +0300 Subject: [PATCH 10/29] lint --- src/xenia/hid/winkey/hookables/PerfectDarkZero.cc | 9 +++++---- src/xenia/hid/winkey/hookables/PerfectDarkZero.h | 3 +-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index f3e67b6cd8..46536ff000 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -155,7 +155,7 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, degree_y = (float)*cam_y; - float set_fov_multiplier = 1.0f; + float set_fov_multiplier = 1.0f; static float fovscale_l = 1.0f; xe::be* base_address_fov = kernel_memory()->TranslateVirtual*>( @@ -164,7 +164,8 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, xe::be fovscale_address = *base_address_fov + 0x440; xe::be fovscale_sanity = *base_address_fov + 0x660; - xe::be* set_fov = kernel_memory()->TranslateVirtual*>( + xe::be* set_fov = + kernel_memory()->TranslateVirtual*>( supported_builds[game_build_].current_set_fov); xe::be* fovscale = @@ -323,8 +324,8 @@ bool PerfectDarkZeroGame::InCover() { } } -void PerfectDarkZeroGame::HandleRightStickEmulation( - RawInputState& input_state, X_INPUT_STATE* out_state) { +void PerfectDarkZeroGame::HandleRightStickEmulation(RawInputState& input_state, + X_INPUT_STATE* out_state) { auto now = std::chrono::steady_clock::now(); auto elapsed_x = std::chrono::duration_cast( now - last_movement_time_x_) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h index 8426524ad0..1ac161168f 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h @@ -10,8 +10,8 @@ #ifndef XENIA_HID_WINKEY_PerfectDarkZero_H_ #define XENIA_HID_WINKEY_PerfectDarkZero_H_ -#include "xenia/hid/winkey/hookables/hookable_game.h" #include "xenia/base/chrono.h" +#include "xenia/hid/winkey/hookables/hookable_game.h" namespace xe { namespace hid { @@ -52,7 +52,6 @@ class PerfectDarkZeroGame : public HookableGame { std::chrono::steady_clock::time_point last_movement_time_x_; std::chrono::steady_clock::time_point last_movement_time_y_; static xe::be fovscale_address; - }; } // namespace winkey From 71cc23fd54291269c3f35b6b21f4e4c3242221f0 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Sat, 19 Oct 2024 16:26:06 +0300 Subject: [PATCH 11/29] Fix pointer crash --- src/xenia/hid/winkey/hookables/PerfectDarkZero.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 46536ff000..b9e8866178 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -124,6 +124,11 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, return false; } + if (!radians_x_base || *radians_x_base == NULL) { + // Not in game + return false; + } + if (!IsPaused()) { xe::be x_address; bool in_cover = InCover(); @@ -160,7 +165,7 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, xe::be* base_address_fov = kernel_memory()->TranslateVirtual*>( supported_builds[game_build_].fovscale_address); - if (!base_address_fov || base_address_fov != NULL) { + if (!base_address_fov || *base_address_fov != NULL) { xe::be fovscale_address = *base_address_fov + 0x440; xe::be fovscale_sanity = *base_address_fov + 0x660; From 7320a8bfe5dcdea36d3b9e17e5026e6faddcae03 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Sat, 19 Oct 2024 19:28:20 +0300 Subject: [PATCH 12/29] lint --- src/xenia/hid/winkey/hookables/PerfectDarkZero.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index b9e8866178..a6e449a770 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -119,12 +119,8 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, kernel_memory()->TranslateVirtual*>(*base_address + 0xE4); - if (!base_address || *base_address == NULL) { - // Not in game - return false; - } - - if (!radians_x_base || *radians_x_base == NULL) { + if ((!base_address || *base_address == NULL) || + (!radians_x_base || *radians_x_base == NULL)) { // Not in game return false; } From 8a3c78127b63289b8d5b00d96d6fe435ff36a553 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Tue, 22 Oct 2024 13:11:46 +0300 Subject: [PATCH 13/29] Read compile date & version instead of build name --- src/xenia/emulator.cc | 6 ++++-- src/xenia/hid/winkey/hookables/PerfectDarkZero.cc | 10 ++++------ src/xenia/hid/winkey/hookables/PerfectDarkZero.h | 7 ++++++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index f93a76250f..115d49ddac 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -2059,8 +2059,10 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, }; std::vector supported_builds{ - {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BD7A4, 0x8253EDA0, 0x8253EDA8}, - {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BBF64, 0x8254E4D8, 0x8254E4E0}}; + // TU0 Base version, compiled 9 November 2005 + {"09.11.05.0052", 0x820CED70, 0x8253EDA0, 0x8253EDA8}, + // TU3 Base version, compiled 19 September 2006 + {"19.09.06.0082", 0x820CD9E0, 0x8254E4D8, 0x8254E4E0}}; for (auto& build : supported_builds) { const char* build_ptr = reinterpret_cast( module->memory()->TranslateVirtual(build.build_string_addr)); diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index a6e449a770..0e42b7f1ef 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -55,13 +55,11 @@ struct GameBuildAddrs { std::map supported_builds{ {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU0, - {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BD7A4, 0x82D2AD38, 0x16A7, 0x150, - 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82D68320, 0x82E1B930, 0x820EC228, - 0x16A3}}, + {"09.11.05.0052", 0x820CED70, 0x82D2AD38, 0x16A7, 0x150, 0x1674, 0x1670, + 0xF9C, 0xFA0, 0x82D68320, 0x82E1B930, 0x820EC228, 0x16A3}}, {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU3, - {"CLIENT.Ph.Rare-PerfectDarkZero", 0x820BBF64, 0x82D2B758, 0x16A7, 0x150, - 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82D69048, 0x82D3EED0, 0x820EAF40, - 0x16A3}}}; + {"19.09.06.0082", 0x820CD9E0, 0x82D2B758, 0x16A7, 0x150, 0x1674, 0x1670, + 0xF9C, 0xFA0, 0x82D69048, 0x82D3EED0, 0x820EAF40, 0x16A3}}}; PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h index 1ac161168f..b6aa59dd53 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h @@ -19,7 +19,12 @@ namespace winkey { class PerfectDarkZeroGame : public HookableGame { public: - enum class GameBuild { Unknown, PerfectDarkZero_TU0, PerfectDarkZero_TU3 }; + enum class GameBuild { + Unknown, + PerfectDarkZero_TU0, + PerfectDarkZero_TU3, + PerfectDarkZero_PlatinumHitsTU15 + }; ~PerfectDarkZeroGame() override; From c2c162ad442fa75954fe6beb410c6573b5cad6a4 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Tue, 22 Oct 2024 17:59:31 +0300 Subject: [PATCH 14/29] Platinum Hits verison support, modifier & initial bindings --- src/xenia/emulator.cc | 4 +- .../hid/winkey/hookables/PerfectDarkZero.cc | 41 +++++++++++++++---- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index 115d49ddac..d963fefba5 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -2062,7 +2062,9 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, // TU0 Base version, compiled 9 November 2005 {"09.11.05.0052", 0x820CED70, 0x8253EDA0, 0x8253EDA8}, // TU3 Base version, compiled 19 September 2006 - {"19.09.06.0082", 0x820CD9E0, 0x8254E4D8, 0x8254E4E0}}; + {"19.09.06.0082", 0x820CD9E0, 0x8254E4D8, 0x8254E4E0}, + // TU15 (15.0) Platinum Hits, compiled 12 September 2006 + {"12.09.06.0081", 0x820CD9C0, 0x8254E508, 0x8254E510}}; for (auto& build : supported_builds) { const char* build_ptr = reinterpret_cast( module->memory()->TranslateVirtual(build.build_string_addr)); diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 0e42b7f1ef..f1b1fc3c1c 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -48,7 +48,9 @@ struct GameBuildAddrs { // with a patch. uint32_t gun_x_offset; uint32_t fovscale_address; - uint32_t fovscale_alt_static_address; + uint32_t fovscale_alt_static_address; // TODO: Check sanity of ptr fovscale + // address, if incorrect use static + // address instead uint32_t current_set_fov; // Incase FOV is increased with a patch. uint32_t pause_offset; }; @@ -59,7 +61,10 @@ std::map supported_builds{ 0xF9C, 0xFA0, 0x82D68320, 0x82E1B930, 0x820EC228, 0x16A3}}, {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU3, {"19.09.06.0082", 0x820CD9E0, 0x82D2B758, 0x16A7, 0x150, 0x1674, 0x1670, - 0xF9C, 0xFA0, 0x82D69048, 0x82D3EED0, 0x820EAF40, 0x16A3}}}; + 0xF9C, 0xFA0, 0x82D69048, 0x82D3EED0, 0x820EAF40, 0x16A3}}, + {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_PlatinumHitsTU15, + {"12.09.06.0081", 0x820CD9C0, 0x82D2B758, 0x16A7, 0x150, 0x1674, 0x1670, + 0xF9C, 0xFA0, 0x82D69048, NULL, 0x820EAF20, 0x16A3}}}; PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; @@ -133,6 +138,11 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, x_address = *base_address + supported_builds[game_build_].cover_x_offset; } + if (!(x_address && 0x0000000000000000 < x_address && + x_address < 0x0000000000999999)) { + return false; + } + xe::be y_address = *base_address + supported_builds[game_build_].y_offset; @@ -186,11 +196,11 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, // X-axis = 0 to 360 if (cvars::invert_x) { degree_x += ((input_state.mouse.x_delta / set_fov_multiplier) / - (7.5f * fovscale_l)) * + (8.40517241378f * fovscale_l)) * (float)cvars::sensitivity; } else { degree_x -= ((input_state.mouse.x_delta / set_fov_multiplier) / - (7.5f * fovscale_l)) * + (8.40517241378f * fovscale_l)) * (float)cvars::sensitivity; } @@ -205,11 +215,11 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, // Y-axis = -90 to 90 if (cvars::invert_y) { degree_y -= ((input_state.mouse.y_delta / set_fov_multiplier) / - (7.5f * fovscale_l)) * + (8.40517241378f * fovscale_l)) * (float)cvars::sensitivity; } else { degree_y += ((input_state.mouse.y_delta / set_fov_multiplier) / - (7.5f * fovscale_l)) * + (8.40517241378f * fovscale_l)) * (float)cvars::sensitivity; } *cam_y = degree_y; @@ -373,8 +383,25 @@ std::string PerfectDarkZeroGame::ChooseBinds() { return "Default"; } bool PerfectDarkZeroGame::ModifierKeyHandler(uint32_t user_index, RawInputState& input_state, X_INPUT_STATE* out_state) { - return false; + float thumb_lx = (int16_t)out_state->gamepad.thumb_lx; + float thumb_ly = (int16_t)out_state->gamepad.thumb_ly; + + if (thumb_lx != 0 || + thumb_ly != + 0) { // Required otherwise stick is pushed to the right by default. + // Work out angle from the current stick values + float angle = atan2f(thumb_ly, thumb_lx); + + // Sticks get set to SHRT_MAX if key pressed, use half of that + float distance = (float)SHRT_MAX; + distance /= 1.55f; + + out_state->gamepad.thumb_lx = (int16_t)(distance * cosf(angle)); + out_state->gamepad.thumb_ly = (int16_t)(distance * sinf(angle)); + } + return true; } + } // namespace winkey } // namespace hid } // namespace xe \ No newline at end of file From 7190a9b2ed350bc8827d3f6deecf5975adc2c956 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 25 Oct 2024 00:14:33 +0300 Subject: [PATCH 15/29] Different pointer for Platinum Hits and remove address range check for radians X --- src/xenia/hid/winkey/hookables/PerfectDarkZero.cc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index f1b1fc3c1c..50cdf605ae 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -63,7 +63,7 @@ std::map supported_builds{ {"19.09.06.0082", 0x820CD9E0, 0x82D2B758, 0x16A7, 0x150, 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82D69048, 0x82D3EED0, 0x820EAF40, 0x16A3}}, {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_PlatinumHitsTU15, - {"12.09.06.0081", 0x820CD9C0, 0x82D2B758, 0x16A7, 0x150, 0x1674, 0x1670, + {"12.09.06.0081", 0x820CD9C0, 0x82E3C3E8, 0x16A7, 0x150, 0x1674, 0x1670, 0xF9C, 0xFA0, 0x82D69048, NULL, 0x820EAF20, 0x16A3}}}; PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; @@ -138,11 +138,6 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, x_address = *base_address + supported_builds[game_build_].cover_x_offset; } - if (!(x_address && 0x0000000000000000 < x_address && - x_address < 0x0000000000999999)) { - return false; - } - xe::be y_address = *base_address + supported_builds[game_build_].y_offset; From 69704299c62dfc589cf9b69c4b3e9e8bb4664f4a Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 25 Oct 2024 00:25:34 +0300 Subject: [PATCH 16/29] Sniper ADS fov fix --- src/xenia/hid/winkey/hookables/PerfectDarkZero.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 50cdf605ae..54342498f5 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -182,6 +182,9 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, fovscale_l = (*set_fov / *fovscale); + if (fovscale_l >= 45.f) + fovscale_l /= 2.5; // For snipers, otherwise it's too slow! + if (fovscale_l > 1.f) { fovscale_l = (a * fovscale_l + (1 - a) * (fovscale_l * fovscale_l) * 1.1f); From 4cc467ed64f21c3fec7bac45d06e5ac8c39ec08f Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Tue, 5 Nov 2024 17:58:31 +0300 Subject: [PATCH 17/29] remove pdz_scale_base_fov_sens cvar --- src/xenia/hid/winkey/hookables/PerfectDarkZero.cc | 4 +--- src/xenia/hid/winkey/winkey_input_driver.cc | 4 ---- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 54342498f5..325253ed88 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -29,7 +29,6 @@ DECLARE_double(right_stick_hold_time_workaround); DECLARE_bool(invert_y); DECLARE_bool(invert_x); DECLARE_bool(ge_gun_sway); -DECLARE_bool(pdz_scale_base_fov_sens); const uint32_t kTitleIdPerfectDarkZero = 0x4D5307D3; @@ -177,8 +176,7 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, const float a = (float)cvars::fov_sensitivity; fovscale_l = *fovscale; - if (cvars::pdz_scale_base_fov_sens && *set_fov != 58.f) - set_fov_multiplier = *set_fov / 58.f; + if (*set_fov != 58.f) set_fov_multiplier = *set_fov / 58.f; fovscale_l = (*set_fov / *fovscale); diff --git a/src/xenia/hid/winkey/winkey_input_driver.cc b/src/xenia/hid/winkey/winkey_input_driver.cc index fc9ffe88b7..1349fe6cfe 100644 --- a/src/xenia/hid/winkey/winkey_input_driver.cc +++ b/src/xenia/hid/winkey/winkey_input_driver.cc @@ -95,10 +95,6 @@ DEFINE_bool( rdr_snappy_wheel, true, "(Red Dead Redemption) Snaps the Weapon Wheel in 45 degree increments", "MouseHook"); -DEFINE_bool(pdz_scale_base_fov_sens, true, - "(Perfect Dark Zero) Scales base sentiviity if base FOV is " - "increased with a patch. ", - "MouseHook"); #define XE_HID_WINKEY_BINDING(button, description, cvar_name, \ cvar_default_value) \ From d9b803937ffeed24b1c32b2c85c1b1863d72d5ec Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Sun, 17 Nov 2024 22:37:50 +0300 Subject: [PATCH 18/29] rebase --- README.md | 1 + bindings.ini | 35 +++++++++++++++ src/xenia/emulator.cc | 44 ++++++++++++++++--- .../hid/winkey/hookables/PerfectDarkZero.cc | 5 ++- .../hid/winkey/hookables/PerfectDarkZero.h | 3 ++ 5 files changed, 81 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 020e8b45d1..0a949fc31b 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Mousehook implements mouse input into games by injecting into game memory, most | Bloody Good Time | | 584109B3 | Fair | | Postal III | | 4541080F | Fair | | GoldenEye XBLA | Nov 16th 2007, also renamed as 'Aug 25th 2007' | 584108A9 | Good | Camera X rotation might not work when using the tank in the Runway and Street level | +| Perfect Dark Zero | TU0,TU3 & Platinum Hits base | 4D5307D3 | Good | No mousehook for Spycam in first mission | | Perfect Dark XBLA | b33, b52 (TU0) & b102 | 584109C2 | Fair | Camera doesn't work with the camspy
No mousehook for HoverBike | | Halo 3 | TU0/TU3 & 08172 'delta' | 4D5307E6 | Fair | | Halo 3: ODST | | 4D530877 | Fair | diff --git a/bindings.ini b/bindings.ini index 6add482c64..a2824b1eb4 100644 --- a/bindings.ini +++ b/bindings.ini @@ -22,6 +22,41 @@ Down = Down Left = Left Right = Right +[4D5307D3 Default - Perfect Dark Zero] +; Perfect Dark Zero modifier reduces LS movement to 1/2 (ie allows for a 'walk' button) +Shift = Modifier +W = LS-Up +S = LS-Down +A = LS-Left +D = LS-Right +E = A +R = X +Q = LB +F = B +B = B +LClick = RT +RClick = LT +MClick = RB +T = RB +MWheelUp = B +MWheelDown = Y +Mouse4 = Y +Mouse5 = LB +Enter = Start +Tab = Back +1 = Y +2 = Left +3 = Right +4 = Up +5 = Down +Ctrl = LS +C = LS +V = RS +Up = RS-Up +Down = RS-Down +Left = RS-Left +Right = RS-Right + ; Configure these binds in-game. ; Sprint = D-PAD LEFT ; Pick Block = D-PAD RIGHT diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index d963fefba5..178fad43a2 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -83,9 +83,10 @@ DEFINE_bool(ge_remove_blur, false, DEFINE_bool(ge_debug_menu, false, "(GoldenEye) Enables the debug menu, accessible with LB/1", "MouseHook"); -DEFINE_bool(sr2_better_drive_cam, true, - "(Saints Row 2) unties X rotation from vehicles when " - "auto-centering is disabled akin to GTA IV.", +DEFINE_bool(sr_better_drive_cam, true, + "(Saints Row 1&2) unties X rotation from vehicles when " + "auto-centering is disabled, this makes the camera similar to the " + "GTA series vehicle camera.", "MouseHook"); DEFINE_bool(sr2_better_handbrake_cam, true, @@ -115,6 +116,12 @@ DECLARE_int32(user_language); DECLARE_bool(allow_plugins); DECLARE_bool(disable_autoaim); +DEFINE_int32(priority_class, 0, + "Forces Xenia to use different process priority than default one. " + "It might affect performance and cause unexpected bugs. Possible " + "values: 0 - Normal, 1 - Above normal, 2 - High", + "General"); + namespace xe { using namespace xe::literals; @@ -143,6 +150,7 @@ Emulator::Emulator(const std::filesystem::path& command_line, display_window_(nullptr), memory_(), audio_system_(), + audio_media_player_(), graphics_system_(), input_system_(), export_resolver_(), @@ -154,6 +162,13 @@ Emulator::Emulator(const std::filesystem::path& command_line, paused_(false), restoring_(false), restore_fence_() { + if (cvars::priority_class != 0) { + if (SetProcessPriorityClass(cvars::priority_class)) { + XELOGI("Higher priority class request: Successful. New priority: {}", + cvars::priority_class); + } + } + #if XE_PLATFORM_WIN32 == 1 // Show a disclaimer that links to the quickstart // guide the first time they ever open the emulator @@ -192,6 +207,7 @@ Emulator::~Emulator() { input_system_.reset(); graphics_system_.reset(); audio_system_.reset(); + audio_media_player_.reset(); kernel_state_.reset(); file_system_.reset(); @@ -327,6 +343,9 @@ X_STATUS Emulator::Setup( if (result) { return result; } + audio_media_player_ = std::make_unique( + audio_system_.get(), kernel_state_.get()); + audio_media_player_->Setup(); } // Initialize emulator fallback exception handling last. @@ -1563,8 +1582,10 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, 0xD19F16A4, // stfs f12, 0x16A4(r31) 0xD19F1690, // stfs f12, 0x1690(r31) 0xD15F1694, // stfs f10, 0x1694(r31) - 0xD0FF0CFC, // stfs f7, 0xCFC(r31) - 0xD0BF0D00 // stfs f5, 0xD00(r31) + 0xD0FF0CFC, // stfs f7, 0xCFC(r31) // Right gun x + 0xD0BF0D00, // stfs f5, 0xD00(r31) // Right gun y + 0xD07F14A0, // stfs f3, 0x14A0(r31) // Left gun x + 0xD05F14A4 // stfs f2, 0x14A4(r31) // Left gun y }; int patched = 0; @@ -1830,7 +1851,7 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, patch_addr(build.multiplierread_addr5, build.zero_patch1); patch_addr(build.sensYvalue_addr1, build.zero_patch1); patch_addr(build.sensXvalue_addr2, build.zero_patch1); - if (cvars::sr2_better_drive_cam && build.Vehicle_RotationXWrite_addr1) { + if (cvars::sr_better_drive_cam && build.Vehicle_RotationXWrite_addr1) { patch_addr(build.Vehicle_RotationXWrite_addr1, build.beNOP); } @@ -2050,6 +2071,17 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, } } + if (module->title_id() == 0x584111F7) { // Minecraft - Prevent game from + // writing to inventory cursor + std::map supported_builds = {{"1.0.80", 0x827594EC}}; + for (auto& build : supported_builds) { + if (build.first == title_version_) { + patch_addr(build.second, 0x60000000); + break; + } + } + } + if (module->title_id() == 0x4D5307D3) { struct PDZPatchOffsets { const char* build_string; diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 325253ed88..e9c9cfdfa5 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -397,7 +397,10 @@ bool PerfectDarkZeroGame::ModifierKeyHandler(uint32_t user_index, } return true; } - +void PerfectDarkZeroGame::WeaponSwitchHandler(uint32_t user_index, + RawInputState& input_state, + X_INPUT_STATE* out_state, + int weapon, uint16_t buttons) {} } // namespace winkey } // namespace hid } // namespace xe \ No newline at end of file diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h index b6aa59dd53..d8e3ce01b4 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h @@ -47,6 +47,9 @@ class PerfectDarkZeroGame : public HookableGame { bool ModifierKeyHandler(uint32_t user_index, RawInputState& input_state, X_INPUT_STATE* out_state); + void WeaponSwitchHandler(uint32_t user_index, RawInputState& input_state, + X_INPUT_STATE* out_state, int weapon, + uint16_t buttons); private: GameBuild game_build_ = GameBuild::Unknown; From e3ad1ed6c63cca904cfac83a9c3db2966fad59ea Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Tue, 19 Nov 2024 16:16:25 +0300 Subject: [PATCH 19/29] Gun sway edits for ADS --- .../hid/winkey/hookables/PerfectDarkZero.cc | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index e9c9cfdfa5..91384b964e 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -238,30 +238,41 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, if (input_state.mouse.x_delta || input_state.mouse.y_delta) { if (!cvars::invert_x) { gun_x_val += - ((float)input_state.mouse.x_delta / (10.f * fovscale_l)) * + ((float)input_state.mouse.x_delta / (20.f * fovscale_l)) * (float)cvars::sensitivity; } else { gun_x_val -= - ((float)input_state.mouse.x_delta / (10.f * fovscale_l)) * + ((float)input_state.mouse.x_delta / (20.f * fovscale_l)) * (float)cvars::sensitivity; } if (!cvars::invert_y) { gun_y_val += - ((float)input_state.mouse.y_delta / (10.f * fovscale_l)) * + ((float)input_state.mouse.y_delta / (20.f * fovscale_l)) * (float)cvars::sensitivity; } else { gun_y_val -= - ((float)input_state.mouse.y_delta / (10.f * fovscale_l)) * + ((float)input_state.mouse.y_delta / (20.f * fovscale_l)) * (float)cvars::sensitivity; } // Bound the gun sway movement within a range to prevent excessive // movement - gun_x_val = std::min(gun_x_val, 2.5f); - gun_x_val = std::max(gun_x_val, -2.5f); - gun_y_val = std::min(gun_y_val, 2.5f); - gun_y_val = std::max(gun_y_val, -2.5f); + float x_limit = 6.6f; + float y_limit = 1.8f; + xe::be* gun_zoom = + kernel_memory()->TranslateVirtual*>( + *base_address + + 0x1910); // unneeded but we're using this as our aim check. + if ((fovscale_l >= 1.05f) && *gun_zoom > 0.f) { + x_limit /= (fovscale_l * 2.5f); + y_limit /= (fovscale_l * 2.5f); + } + + gun_x_val = std::min(gun_x_val, x_limit); + gun_x_val = std::max(gun_x_val, -x_limit); + gun_y_val = std::min(gun_y_val, y_limit); + gun_y_val = std::max(gun_y_val, -y_limit); // Set centering and disable sway flags start_centering_ = true; From 52988a55ef8837aa2a0de359fe787e8cae4a2547 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 22 Nov 2024 16:13:31 +0300 Subject: [PATCH 20/29] Turret camera support, only tested for TU3 --- .../hid/winkey/hookables/PerfectDarkZero.cc | 80 ++++++++++++++----- .../hid/winkey/hookables/PerfectDarkZero.h | 2 +- 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 91384b964e..3914bbb0f2 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -42,6 +42,10 @@ struct GameBuildAddrs { uint32_t cover_flag_offset; uint32_t x_offset; uint32_t y_offset; + uint32_t turret_flag_offset; + uint32_t turret_base_offset; + uint32_t turret_x_offset; + uint32_t turret_y_offset; uint32_t cover_x_offset; uint32_t gun_y_offset; // These in-game are tied to camera, we decouple them // with a patch. @@ -56,14 +60,17 @@ struct GameBuildAddrs { std::map supported_builds{ {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU0, - {"09.11.05.0052", 0x820CED70, 0x82D2AD38, 0x16A7, 0x150, 0x1674, 0x1670, - 0xF9C, 0xFA0, 0x82D68320, 0x82E1B930, 0x820EC228, 0x16A3}}, + {"09.11.05.0052", 0x820CED70, 0x82D2AD38, 0x16B9, 0x150, 0x1674, 0x16AB, + 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D68320, 0x82E1B930, + 0x820EC228, 0x16A3}}, {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU3, - {"19.09.06.0082", 0x820CD9E0, 0x82D2B758, 0x16A7, 0x150, 0x1674, 0x1670, - 0xF9C, 0xFA0, 0x82D69048, 0x82D3EED0, 0x820EAF40, 0x16A3}}, + {"19.09.06.0082", 0x820CD9E0, 0x82D2B758, 0x16B9, 0x150, 0x1674, 0x16AB, + 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D69048, 0x82D3EED0, + 0x820EAF40, 0x16A3}}, {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_PlatinumHitsTU15, - {"12.09.06.0081", 0x820CD9C0, 0x82E3C3E8, 0x16A7, 0x150, 0x1674, 0x1670, - 0xF9C, 0xFA0, 0x82D69048, NULL, 0x820EAF20, 0x16A3}}}; + {"12.09.06.0081", 0x820CD9C0, 0x82E3C3E8, 0x16B9, 0x150, 0x1674, 0x16AB, + 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D69048, NULL, 0x820EAF20, + 0x16A3}}}; PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; @@ -129,16 +136,42 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, if (!IsPaused()) { xe::be x_address; - bool in_cover = InCover(); - + xe::be y_address; + bool in_cover = + isSpecialCam(supported_builds[game_build_].cover_flag_offset); + bool in_turret = false; + bool in_turret2 = false; + if (supported_builds[game_build_].turret_flag_offset) + in_turret = + isSpecialCam(supported_builds[game_build_].turret_flag_offset); if (!in_cover) { x_address = *radians_x_base + supported_builds[game_build_].x_offset; } else { x_address = *base_address + supported_builds[game_build_].cover_x_offset; } - - xe::be y_address = - *base_address + supported_builds[game_build_].y_offset; + y_address = *base_address + supported_builds[game_build_].y_offset; + xe::be* turret_base = NULL; + if (in_turret) { + xe::be* turret_base = + kernel_memory()->TranslateVirtual*>( + *base_address + supported_builds[game_build_].turret_base_offset); + + if (*turret_base != NULL) { + // MOUSEHOOK TODO: use static turret base address instead, currently I + // use one the chains from the base address we have but it's points to + // something else for a frame or two thus the address check, this makes + // it easier to just copy and paste to other versions. + + if (*turret_base && *turret_base >= 0x00100000 && + *turret_base < 0x20000000) { + in_turret2 = true; + x_address = + *turret_base + supported_builds[game_build_].turret_x_offset; + y_address = + *turret_base + supported_builds[game_build_].turret_y_offset; + } + } + } xe::be* cam_x = kernel_memory()->TranslateVirtual*>(x_address); @@ -148,15 +181,17 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, float degree_x, degree_y; - if (!in_cover) { + if (!in_cover || (in_turret2)) { // Normal mode: convert radians to degrees degree_x = RadianstoDegree(*cam_x); } else { // Cover mode: X-axis is already in degrees degree_x = *cam_x; } - - degree_y = (float)*cam_y; + if (in_turret2) + degree_y = RadianstoDegree(*cam_y); + else + degree_y = (float)*cam_y; float set_fov_multiplier = 1.0f; static float fovscale_l = 1.0f; @@ -200,10 +235,10 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, (float)cvars::sensitivity; } - if (!in_cover) { + if (!in_cover || (in_turret2)) { *cam_x = DegreetoRadians( degree_x); // Convert degrees back to radians for normal aiming - } else { + } else if (in_cover) { degree_x = std::clamp(degree_x, -68.0f, 68.0f); *cam_x = degree_x; // Directly store degrees for cover aiming } @@ -218,7 +253,10 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, (8.40517241378f * fovscale_l)) * (float)cvars::sensitivity; } - *cam_y = degree_y; + if (in_turret2) + *cam_y = DegreetoRadians(degree_y); + else + *cam_y = degree_y; if (cvars::ge_gun_sway) { xe::be gun_x_address = *base_address + supported_builds[game_build_].gun_x_offset; @@ -325,15 +363,15 @@ bool PerfectDarkZeroGame::IsPaused() { } } -bool PerfectDarkZeroGame::InCover() { +bool PerfectDarkZeroGame::isSpecialCam(uint32_t special_cam_flag_offset) { xe::be* base_address = kernel_memory()->TranslateVirtual*>( supported_builds[game_build_].base_address); - uint8_t* cover_flag = kernel_memory()->TranslateVirtual( - *base_address + supported_builds[game_build_].cover_flag_offset); + uint8_t* special_cam_flag = kernel_memory()->TranslateVirtual( + *base_address + special_cam_flag_offset); - if (*cover_flag == 1) { + if (*special_cam_flag == 1) { return true; } else { return false; diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h index d8e3ce01b4..7c471fde91 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h @@ -38,7 +38,7 @@ class PerfectDarkZeroGame : public HookableGame { bool IsPaused(); - bool InCover(); + bool isSpecialCam(uint32_t special_cam_flag_offset); void HandleRightStickEmulation(RawInputState& input_state, X_INPUT_STATE* out_state); From 674b62c926b9a431373c9f6eea3eb1c83b687d82 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Sat, 23 Nov 2024 21:09:49 +0300 Subject: [PATCH 21/29] Local player address for TU3, fixes coop thanks to @A1eNaz for helping me find it --- .../hid/winkey/hookables/PerfectDarkZero.cc | 59 +++++++++++-------- .../hid/winkey/hookables/PerfectDarkZero.h | 4 +- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 3914bbb0f2..fcb99e76a5 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -39,6 +39,7 @@ struct GameBuildAddrs { const char* build_string; uint32_t build_string_addr; uint32_t base_address; + uint32_t base_address_multi; uint32_t cover_flag_offset; uint32_t x_offset; uint32_t y_offset; @@ -60,17 +61,17 @@ struct GameBuildAddrs { std::map supported_builds{ {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU0, - {"09.11.05.0052", 0x820CED70, 0x82D2AD38, 0x16B9, 0x150, 0x1674, 0x16AB, - 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D68320, 0x82E1B930, + {"09.11.05.0052", 0x820CED70, 0x82D2AD38, NULL, 0x16B9, 0x150, 0x1674, + 0x16AB, 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D68320, 0x82E1B930, 0x820EC228, 0x16A3}}, {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU3, - {"19.09.06.0082", 0x820CD9E0, 0x82D2B758, 0x16B9, 0x150, 0x1674, 0x16AB, - 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D69048, 0x82D3EED0, - 0x820EAF40, 0x16A3}}, + {"19.09.06.0082", 0x820CD9E0, 0x82E3C3E8, 0x82E34224, 0x16B9, 0x150, + 0x1674, 0x16AB, 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D69048, + 0x82D3EED0, 0x820EAF40, 0x16A3}}, {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_PlatinumHitsTU15, - {"12.09.06.0081", 0x820CD9C0, 0x82E3C3E8, 0x16B9, 0x150, 0x1674, 0x16AB, - 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D69048, NULL, 0x820EAF20, - 0x16A3}}}; + {"12.09.06.0081", 0x820CD9C0, 0x82E3C3E8, NULL, 0x16B9, 0x150, 0x1674, + 0x16AB, 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D69048, NULL, + 0x820EAF20, 0x16A3}}}; PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; @@ -123,6 +124,21 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, xe::be* base_address = kernel_memory()->TranslateVirtual*>( supported_builds[game_build_].base_address); + if (supported_builds[game_build_].base_address_multi != NULL) { + // This multi pointer actually holds the LOCAL PLAYER rather than Joanna! + // base_address works fine in Missions / Combat Arena but will break for + // player2 on coop, player2 will attempt to control Joanna rather than their + // own player. + + // Maybe implement sanity check and if fails use our base_address? + xe::be* base_address_multi = + kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].base_address_multi); + if (*base_address_multi != NULL) { + base_address = kernel_memory()->TranslateVirtual*>( + *base_address_multi + 0x3C4); + } + } xe::be* radians_x_base = kernel_memory()->TranslateVirtual*>(*base_address + @@ -134,16 +150,16 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, return false; } - if (!IsPaused()) { + if (!IsPaused(base_address)) { xe::be x_address; xe::be y_address; - bool in_cover = - isSpecialCam(supported_builds[game_build_].cover_flag_offset); + bool in_cover = isSpecialCam( + base_address, supported_builds[game_build_].cover_flag_offset); bool in_turret = false; bool in_turret2 = false; if (supported_builds[game_build_].turret_flag_offset) - in_turret = - isSpecialCam(supported_builds[game_build_].turret_flag_offset); + in_turret = isSpecialCam( + base_address, supported_builds[game_build_].turret_flag_offset); if (!in_cover) { x_address = *radians_x_base + supported_builds[game_build_].x_offset; } else { @@ -349,13 +365,9 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, return true; } -bool PerfectDarkZeroGame::IsPaused() { - xe::be* base_address = - kernel_memory()->TranslateVirtual*>( - supported_builds[game_build_].base_address); - +bool PerfectDarkZeroGame::IsPaused(xe::be* player) { uint8_t* pause_flag = kernel_memory()->TranslateVirtual( - *base_address + supported_builds[game_build_].pause_offset); + *player + supported_builds[game_build_].pause_offset); if (*pause_flag != 0) { return true; } else { @@ -363,13 +375,10 @@ bool PerfectDarkZeroGame::IsPaused() { } } -bool PerfectDarkZeroGame::isSpecialCam(uint32_t special_cam_flag_offset) { - xe::be* base_address = - kernel_memory()->TranslateVirtual*>( - supported_builds[game_build_].base_address); - +bool PerfectDarkZeroGame::isSpecialCam(xe::be* player, + uint32_t special_cam_flag_offset) { uint8_t* special_cam_flag = kernel_memory()->TranslateVirtual( - *base_address + special_cam_flag_offset); + *player + special_cam_flag_offset); if (*special_cam_flag == 1) { return true; diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h index 7c471fde91..112392ca86 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h @@ -36,9 +36,9 @@ class PerfectDarkZeroGame : public HookableGame { bool DoHooks(uint32_t user_index, RawInputState& input_state, X_INPUT_STATE* out_state); - bool IsPaused(); + bool IsPaused(xe::be* player); - bool isSpecialCam(uint32_t special_cam_flag_offset); + bool isSpecialCam(xe::be* player, uint32_t special_cam_flag_offset); void HandleRightStickEmulation(RawInputState& input_state, X_INPUT_STATE* out_state); From d84cd788e91401ae692118eed80b11eddf4d4877 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Sat, 23 Nov 2024 22:08:10 +0300 Subject: [PATCH 22/29] Port multi base address to TU0 & Plat hits for coop fix --- .../hid/winkey/hookables/PerfectDarkZero.cc | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index fcb99e76a5..96a12cfc7e 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -40,6 +40,7 @@ struct GameBuildAddrs { uint32_t build_string_addr; uint32_t base_address; uint32_t base_address_multi; + uint32_t base_address_multi_offset; uint32_t cover_flag_offset; uint32_t x_offset; uint32_t y_offset; @@ -61,17 +62,17 @@ struct GameBuildAddrs { std::map supported_builds{ {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU0, - {"09.11.05.0052", 0x820CED70, 0x82D2AD38, NULL, 0x16B9, 0x150, 0x1674, - 0x16AB, 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D68320, 0x82E1B930, - 0x820EC228, 0x16A3}}, + {"09.11.05.0052", 0x820CED70, 0x82D2AD38, 0x82E35468, 0x3B8, 0x16B9, 0x150, + 0x1674, 0x16AB, 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D68320, + 0x82E1B930, 0x820EC228, 0x16A3}}, {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU3, - {"19.09.06.0082", 0x820CD9E0, 0x82E3C3E8, 0x82E34224, 0x16B9, 0x150, + {"19.09.06.0082", 0x820CD9E0, 0x82E3C3E8, 0x82E34224, 0x3C4, 0x16B9, 0x150, 0x1674, 0x16AB, 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D69048, 0x82D3EED0, 0x820EAF40, 0x16A3}}, {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_PlatinumHitsTU15, - {"12.09.06.0081", 0x820CD9C0, 0x82E3C3E8, NULL, 0x16B9, 0x150, 0x1674, - 0x16AB, 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D69048, NULL, - 0x820EAF20, 0x16A3}}}; + {"12.09.06.0081", 0x820CD9C0, 0x82E3C3E8, 0x82E3622C, 0x3C4, 0x16B9, 0x150, + 0x1674, 0x16AB, 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D69048, + NULL, 0x820EAF20, 0x16A3}}}; PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; @@ -125,6 +126,10 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, kernel_memory()->TranslateVirtual*>( supported_builds[game_build_].base_address); if (supported_builds[game_build_].base_address_multi != NULL) { + // Other candidates for this address on TU3 are. + // + 3C4 at 82E2F568,82E2FB30 & 82E34224( we are using this), the offset + // seems to be different in TU0? + // + 0x8 or +0x10 at 82D69048 // This multi pointer actually holds the LOCAL PLAYER rather than Joanna! // base_address works fine in Missions / Combat Arena but will break for // player2 on coop, player2 will attempt to control Joanna rather than their @@ -136,7 +141,8 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, supported_builds[game_build_].base_address_multi); if (*base_address_multi != NULL) { base_address = kernel_memory()->TranslateVirtual*>( - *base_address_multi + 0x3C4); + *base_address_multi + + supported_builds[game_build_].base_address_multi_offset); } } From a5cbfb954d03530298148d88426e1d328bc6a14e Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Thu, 5 Dec 2024 17:28:44 +0300 Subject: [PATCH 23/29] universal_address chain for isSpecialCam --- .../hid/winkey/hookables/PerfectDarkZero.cc | 53 +++++++++++++++---- .../hid/winkey/hookables/PerfectDarkZero.h | 3 +- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 96a12cfc7e..812695636f 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -159,13 +159,19 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, if (!IsPaused(base_address)) { xe::be x_address; xe::be y_address; + enum universal_addr_cam { + HOVERCRAFT = 2, + COVER = 3, + TURRET = 6, + }; bool in_cover = isSpecialCam( - base_address, supported_builds[game_build_].cover_flag_offset); + base_address, supported_builds[game_build_].cover_flag_offset, true, 3); bool in_turret = false; bool in_turret2 = false; if (supported_builds[game_build_].turret_flag_offset) - in_turret = isSpecialCam( - base_address, supported_builds[game_build_].turret_flag_offset); + in_turret = isSpecialCam(base_address, + supported_builds[game_build_].turret_flag_offset, + true, 6); if (!in_cover) { x_address = *radians_x_base + supported_builds[game_build_].x_offset; } else { @@ -382,14 +388,43 @@ bool PerfectDarkZeroGame::IsPaused(xe::be* player) { } bool PerfectDarkZeroGame::isSpecialCam(xe::be* player, - uint32_t special_cam_flag_offset) { - uint8_t* special_cam_flag = kernel_memory()->TranslateVirtual( - *player + special_cam_flag_offset); + uint32_t special_cam_flag_offset, + bool universal_addr, uint8_t cam_type) { + if (!universal_addr) { + uint8_t* special_cam_flag = kernel_memory()->TranslateVirtual( + *player + special_cam_flag_offset); - if (*special_cam_flag == 1) { - return true; + if (special_cam_flag && *special_cam_flag == 1) { + return true; + } else { + return false; + } } else { - return false; + xe::be* base_address = + kernel_memory()->TranslateVirtual*>( + supported_builds[game_build_].fovscale_address); + + if (!base_address || *base_address == 0) { + return false; + } + + xe::be* ptr1 = + kernel_memory()->TranslateVirtual*>(*base_address + + 0x53C); + if (!ptr1 || *ptr1 == 0) { + return false; + } + + uint8_t* current_cam = + kernel_memory()->TranslateVirtual(*ptr1 + 0xB); + if (!current_cam) { + return false; + } + if (*current_cam == cam_type) { + return true; + } else { + return false; + } } } diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h index 112392ca86..94a9467aa0 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h @@ -38,7 +38,8 @@ class PerfectDarkZeroGame : public HookableGame { bool IsPaused(xe::be* player); - bool isSpecialCam(xe::be* player, uint32_t special_cam_flag_offset); + bool isSpecialCam(xe::be* player, uint32_t special_cam_flag_offset, + bool universal_addr = false, uint8_t cam_type = -1); void HandleRightStickEmulation(RawInputState& input_state, X_INPUT_STATE* out_state); From 4fe426787bdfa208679616338ffed4c962b48fcc Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 6 Dec 2024 12:21:22 +0300 Subject: [PATCH 24/29] Hovercraft cam support --- .../hid/winkey/hookables/PerfectDarkZero.cc | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 812695636f..35df0d0e30 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -49,6 +49,8 @@ struct GameBuildAddrs { uint32_t turret_x_offset; uint32_t turret_y_offset; uint32_t cover_x_offset; + uint32_t hovercraft_base_offset; + uint32_t hovercraft_y_offset; uint32_t gun_y_offset; // These in-game are tied to camera, we decouple them // with a patch. uint32_t gun_x_offset; @@ -62,17 +64,21 @@ struct GameBuildAddrs { std::map supported_builds{ {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU0, - {"09.11.05.0052", 0x820CED70, 0x82D2AD38, 0x82E35468, 0x3B8, 0x16B9, 0x150, - 0x1674, 0x16AB, 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D68320, - 0x82E1B930, 0x820EC228, 0x16A3}}, + {"09.11.05.0052", 0x820CED70, 0x82D2AD38, 0x82E35468, 0x3B8, 0x16B9, + 0x150, 0x1674, 0x16AB, 0x5C, 0x3A0, 0x39C, + 0x1670, 0x5C, 0xE54, 0xF9C, 0xFA0, 0x82D68320, + 0x82E1B930, 0x820EC228, 0x16A3}}, {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_TU3, - {"19.09.06.0082", 0x820CD9E0, 0x82E3C3E8, 0x82E34224, 0x3C4, 0x16B9, 0x150, - 0x1674, 0x16AB, 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D69048, - 0x82D3EED0, 0x820EAF40, 0x16A3}}, + {"19.09.06.0082", 0x820CD9E0, 0x82E3C3E8, 0x82E34224, 0x3C4, 0x16B9, + 0x150, 0x1674, 0x16AB, 0x5C, 0x3A0, 0x39C, + 0x1670, 0x5C, 0xE54, 0xF9C, 0xFA0, 0x82D69048, + 0x82D3EED0, 0x820EAF40, 0x16A3}}, {PerfectDarkZeroGame::GameBuild::PerfectDarkZero_PlatinumHitsTU15, - {"12.09.06.0081", 0x820CD9C0, 0x82E3C3E8, 0x82E3622C, 0x3C4, 0x16B9, 0x150, - 0x1674, 0x16AB, 0x5C, 0x3A0, 0x39C, 0x1670, 0xF9C, 0xFA0, 0x82D69048, - NULL, 0x820EAF20, 0x16A3}}}; + {"12.09.06.0081", 0x820CD9C0, 0x82E3C3E8, 0x82E3622C, 0x3C4, + 0x16B9, 0x150, 0x1674, 0x16AB, 0x5C, + 0x3A0, 0x39C, 0x1670, 0x5C, 0xE54, + 0xF9C, 0xFA0, 0x82D69048, NULL, 0x820EAF20, + 0x16A3}}}; PerfectDarkZeroGame::~PerfectDarkZeroGame() = default; @@ -166,6 +172,7 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, }; bool in_cover = isSpecialCam( base_address, supported_builds[game_build_].cover_flag_offset, true, 3); + bool in_hovercraft = isSpecialCam(base_address, NULL, true, HOVERCRAFT); bool in_turret = false; bool in_turret2 = false; if (supported_builds[game_build_].turret_flag_offset) @@ -199,6 +206,15 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, *turret_base + supported_builds[game_build_].turret_y_offset; } } + } else if (in_hovercraft) { + xe::be* hovercraft_base = + kernel_memory()->TranslateVirtual*>( + *base_address + + supported_builds[game_build_].hovercraft_base_offset); + x_address = *hovercraft_base + + supported_builds[game_build_].hovercraft_y_offset + 0x4; + y_address = + *hovercraft_base + supported_builds[game_build_].hovercraft_y_offset; } xe::be* cam_x = @@ -209,14 +225,14 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, float degree_x, degree_y; - if (!in_cover || (in_turret2)) { + if (!in_cover || (in_turret2) || in_hovercraft) { // Normal mode: convert radians to degrees degree_x = RadianstoDegree(*cam_x); } else { // Cover mode: X-axis is already in degrees degree_x = *cam_x; } - if (in_turret2) + if (in_turret2 || in_hovercraft) degree_y = RadianstoDegree(*cam_y); else degree_y = (float)*cam_y; @@ -263,7 +279,7 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, (float)cvars::sensitivity; } - if (!in_cover || (in_turret2)) { + if (!in_cover || (in_turret2) || in_hovercraft) { *cam_x = DegreetoRadians( degree_x); // Convert degrees back to radians for normal aiming } else if (in_cover) { @@ -281,7 +297,7 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, (8.40517241378f * fovscale_l)) * (float)cvars::sensitivity; } - if (in_turret2) + if (in_turret2 || in_hovercraft) *cam_y = DegreetoRadians(degree_y); else *cam_y = degree_y; From fe4f930957fd3a7ee667240384862b37e1aea364 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 13 Dec 2024 15:52:51 +0300 Subject: [PATCH 25/29] Jetpac unsupported note --- README.md | 2 +- src/xenia/hid/winkey/hookables/PerfectDarkZero.cc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a949fc31b..d45b138e79 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Mousehook implements mouse input into games by injecting into game memory, most | Bloody Good Time | | 584109B3 | Fair | | Postal III | | 4541080F | Fair | | GoldenEye XBLA | Nov 16th 2007, also renamed as 'Aug 25th 2007' | 584108A9 | Good | Camera X rotation might not work when using the tank in the Runway and Street level | -| Perfect Dark Zero | TU0,TU3 & Platinum Hits base | 4D5307D3 | Good | No mousehook for Spycam in first mission | +| Perfect Dark Zero | TU0,TU3 & Platinum Hits base | 4D5307D3 | Good | No mousehook for Spycam in first mission
No mousehook for Jetpac| | Perfect Dark XBLA | b33, b52 (TU0) & b102 | 584109C2 | Fair | Camera doesn't work with the camspy
No mousehook for HoverBike | | Halo 3 | TU0/TU3 & 08172 'delta' | 4D5307E6 | Fair | | Halo 3: ODST | | 4D530877 | Fair | diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 35df0d0e30..179715fd5b 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -168,6 +168,8 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, enum universal_addr_cam { HOVERCRAFT = 2, COVER = 3, + JETPAC = + 4, // UNWRITEABLE CAMERA ADDRESS, CURRENTLY RS IS EMULATED FOR IT. TURRET = 6, }; bool in_cover = isSpecialCam( From 703071da033f6f183f7e453deaaa0a81a0721b73 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 13 Dec 2024 20:50:08 +0300 Subject: [PATCH 26/29] Emulate LS with mouse when using gadgets. --- .../hid/winkey/hookables/PerfectDarkZero.cc | 21 ++++++++++++------- .../hid/winkey/hookables/PerfectDarkZero.h | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 179715fd5b..b9b32e33ed 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -389,8 +389,10 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, *gun_x = gun_x_val; *gun_y = gun_y_val; } - } else + } else if (IsPaused(base_address) && !isSpecialCam(base_address, 0x16D1)) HandleRightStickEmulation(input_state, out_state); + else if (IsPaused(base_address) && isSpecialCam(base_address, 0x16D1)) + HandleRightStickEmulation(input_state, out_state, true); return true; } @@ -447,7 +449,8 @@ bool PerfectDarkZeroGame::isSpecialCam(xe::be* player, } void PerfectDarkZeroGame::HandleRightStickEmulation(RawInputState& input_state, - X_INPUT_STATE* out_state) { + X_INPUT_STATE* out_state, + bool LSmode) { auto now = std::chrono::steady_clock::now(); auto elapsed_x = std::chrono::duration_cast( now - last_movement_time_x_) @@ -470,7 +473,7 @@ void PerfectDarkZeroGame::HandleRightStickEmulation(RawInputState& input_state, last_movement_time_x_ = now; } else if (elapsed_x < hold_time) { // Hold the last accumulated value accumulated_x = std::clamp(accumulated_x, (float)SHRT_MIN, (float)SHRT_MAX); - } else { + } else if (!LSmode) { accumulated_x = 0.0f; } @@ -483,12 +486,16 @@ void PerfectDarkZeroGame::HandleRightStickEmulation(RawInputState& input_state, last_movement_time_y_ = now; } else if (elapsed_y < hold_time) { // Hold the last accumulated value accumulated_y = std::clamp(accumulated_y, (float)SHRT_MIN, (float)SHRT_MAX); - } else { + } else if (!LSmode) { accumulated_y = 0.0f; } - - out_state->gamepad.thumb_rx = static_cast(accumulated_x); - out_state->gamepad.thumb_ry = static_cast(accumulated_y); + if (!LSmode) { + out_state->gamepad.thumb_rx = static_cast(accumulated_x); + out_state->gamepad.thumb_ry = static_cast(accumulated_y); + } else { + out_state->gamepad.thumb_lx = static_cast(accumulated_x); + out_state->gamepad.thumb_ly = static_cast(accumulated_y); + } } std::string PerfectDarkZeroGame::ChooseBinds() { return "Default"; } diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h index 94a9467aa0..1ae4558e45 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.h +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.h @@ -42,7 +42,7 @@ class PerfectDarkZeroGame : public HookableGame { bool universal_addr = false, uint8_t cam_type = -1); void HandleRightStickEmulation(RawInputState& input_state, - X_INPUT_STATE* out_state); + X_INPUT_STATE* out_state, bool LSmode = false); std::string ChooseBinds(); From cc5da4e5ccb6e1246a712854de56a08c5ae0d26a Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 13 Dec 2024 21:04:38 +0300 Subject: [PATCH 27/29] Disable mouse LS emulation if SHIFT is held down --- src/xenia/hid/winkey/hookables/PerfectDarkZero.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index b9b32e33ed..60a5739118 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -35,6 +35,9 @@ const uint32_t kTitleIdPerfectDarkZero = 0x4D5307D3; namespace xe { namespace hid { namespace winkey { +bool __inline IsKeyDown(uint8_t key) { + return (GetAsyncKeyState(key) & 0x8000) == 0x8000; +} struct GameBuildAddrs { const char* build_string; uint32_t build_string_addr; @@ -492,7 +495,7 @@ void PerfectDarkZeroGame::HandleRightStickEmulation(RawInputState& input_state, if (!LSmode) { out_state->gamepad.thumb_rx = static_cast(accumulated_x); out_state->gamepad.thumb_ry = static_cast(accumulated_y); - } else { + } else if (LSmode && !IsKeyDown(VK_SHIFT)) { out_state->gamepad.thumb_lx = static_cast(accumulated_x); out_state->gamepad.thumb_ly = static_cast(accumulated_y); } From 3e132c621196459d5a6aa62a92148b98adaf24e3 Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 13 Dec 2024 22:55:33 +0300 Subject: [PATCH 28/29] Jetpac cam support --- README.md | 2 +- .../hid/winkey/hookables/PerfectDarkZero.cc | 29 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index d45b138e79..93a7ee8866 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Mousehook implements mouse input into games by injecting into game memory, most | Bloody Good Time | | 584109B3 | Fair | | Postal III | | 4541080F | Fair | | GoldenEye XBLA | Nov 16th 2007, also renamed as 'Aug 25th 2007' | 584108A9 | Good | Camera X rotation might not work when using the tank in the Runway and Street level | -| Perfect Dark Zero | TU0,TU3 & Platinum Hits base | 4D5307D3 | Good | No mousehook for Spycam in first mission
No mousehook for Jetpac| +| Perfect Dark Zero | TU0,TU3 & Platinum Hits base | 4D5307D3 | Good | No mousehook for Spycam in first mission
Mousehook bindings break in menus and switches to using HID.Winkey bindings.| | Perfect Dark XBLA | b33, b52 (TU0) & b102 | 584109C2 | Fair | Camera doesn't work with the camspy
No mousehook for HoverBike | | Halo 3 | TU0/TU3 & 08172 'delta' | 4D5307E6 | Fair | | Halo 3: ODST | | 4D530877 | Fair | diff --git a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc index 60a5739118..c7745739be 100644 --- a/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc +++ b/src/xenia/hid/winkey/hookables/PerfectDarkZero.cc @@ -164,17 +164,18 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, // Not in game return false; } - - if (!IsPaused(base_address)) { + enum universal_addr_cam { + HOVERCRAFT = 2, + COVER = 3, + JETPAC = 4, + TURRET = 6, + }; + + bool in_jetpac = isSpecialCam(base_address, NULL, true, JETPAC); + if (!IsPaused(base_address) || in_jetpac) { xe::be x_address; xe::be y_address; - enum universal_addr_cam { - HOVERCRAFT = 2, - COVER = 3, - JETPAC = - 4, // UNWRITEABLE CAMERA ADDRESS, CURRENTLY RS IS EMULATED FOR IT. - TURRET = 6, - }; + bool in_cover = isSpecialCam( base_address, supported_builds[game_build_].cover_flag_offset, true, 3); bool in_hovercraft = isSpecialCam(base_address, NULL, true, HOVERCRAFT); @@ -211,7 +212,7 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, *turret_base + supported_builds[game_build_].turret_y_offset; } } - } else if (in_hovercraft) { + } else if (in_hovercraft || in_jetpac) { xe::be* hovercraft_base = kernel_memory()->TranslateVirtual*>( *base_address + @@ -230,14 +231,14 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, float degree_x, degree_y; - if (!in_cover || (in_turret2) || in_hovercraft) { + if (!in_cover || (in_turret2) || in_hovercraft || in_jetpac) { // Normal mode: convert radians to degrees degree_x = RadianstoDegree(*cam_x); } else { // Cover mode: X-axis is already in degrees degree_x = *cam_x; } - if (in_turret2 || in_hovercraft) + if (in_turret2 || in_hovercraft || in_jetpac) degree_y = RadianstoDegree(*cam_y); else degree_y = (float)*cam_y; @@ -284,7 +285,7 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, (float)cvars::sensitivity; } - if (!in_cover || (in_turret2) || in_hovercraft) { + if (!in_cover || (in_turret2) || in_hovercraft || in_jetpac) { *cam_x = DegreetoRadians( degree_x); // Convert degrees back to radians for normal aiming } else if (in_cover) { @@ -302,7 +303,7 @@ bool PerfectDarkZeroGame::DoHooks(uint32_t user_index, (8.40517241378f * fovscale_l)) * (float)cvars::sensitivity; } - if (in_turret2 || in_hovercraft) + if (in_turret2 || in_hovercraft || in_jetpac) *cam_y = DegreetoRadians(degree_y); else *cam_y = degree_y; From e40bb16bb49777958e34e0e8ea713768762abc7f Mon Sep 17 00:00:00 2001 From: Clippy95 Date: Fri, 13 Dec 2024 23:06:34 +0300 Subject: [PATCH 29/29] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 93a7ee8866..eb4afacbcf 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Mousehook implements mouse input into games by injecting into game memory, most | Bloody Good Time | | 584109B3 | Fair | | Postal III | | 4541080F | Fair | | GoldenEye XBLA | Nov 16th 2007, also renamed as 'Aug 25th 2007' | 584108A9 | Good | Camera X rotation might not work when using the tank in the Runway and Street level | -| Perfect Dark Zero | TU0,TU3 & Platinum Hits base | 4D5307D3 | Good | No mousehook for Spycam in first mission
Mousehook bindings break in menus and switches to using HID.Winkey bindings.| +| Perfect Dark Zero | TU0,TU3 & Platinum Hits base | 4D5307D3 | Good | No mousehook for Spycam in
Mousehook bindings break in menus and switches to using HID.Winkey bindings.| | Perfect Dark XBLA | b33, b52 (TU0) & b102 | 584109C2 | Fair | Camera doesn't work with the camspy
No mousehook for HoverBike | | Halo 3 | TU0/TU3 & 08172 'delta' | 4D5307E6 | Fair | | Halo 3: ODST | | 4D530877 | Fair |