diff --git a/README.md b/README.md index 8e18a7b4ae..b0bf3dac45 100644 --- a/README.md +++ b/README.md @@ -40,10 +40,11 @@ This is a fork of [emoose's Xenia build](https://github.com/emoose/xenia) as ori | Call Of Duty Ghosts Alpha | 2-iw6mp.exe / 1-iw6sp.exe / default.xex "May 08 2013 build" | | Call Of Duty Advanced Warfare | Singleplayer & Multiplayer TU17 | | Wolfenstein | Singleplayer TU0 | -| Gears Of Wars 1 | TU0/TU5 | -| Gears Of Wars 2 | TU0/TU6 | -| Gears Of Wars 3 | TU0/TU6 | -| Gears Of Wars Judgement | TU0/TU4| +| Gears Of War 1 | TU0/TU5 | +| Gears Of War 2 | TU0/TU6 | +| Gears Of War 3 | TU0/TU6 | +| Gears Of War Judgement | TU0/TU4| +| Minecraft | TU75 (1.0.80) | ### [Netplay Mousehook](https://github.com/marinesciencedude/xenia-canary-mousehook/tree/netplay_canary_experimental) diff --git a/bindings.ini b/bindings.ini index d76797643d..902f623748 100644 --- a/bindings.ini +++ b/bindings.ini @@ -22,6 +22,59 @@ Down = Down Left = Left Right = Right +; Configure these binds in-game. +; Sprint = D-PAD LEFT +; Pick Block = D-PAD RIGHT +[584111F7 Default - Minecraft] +W = LS-Up +S = LS-Down +A = LS-Left +D = LS-Right +Ctrl = Left +LClick = RT +RClick = LT +MClick = Right +MWheelUp = LB +MWheelDown = RB +Space = A +Q = B +E = Y +R = X +Up = Up +Down = Down +Left = Left +Right = Right +LShift = RS +Tab = Back +Enter = Start +1 = weapon1 +2 = weapon2 +3 = weapon3 +4 = weapon4 +5 = weapon5 +6 = weapon6 +7 = weapon7 +8 = weapon8 +9 = weapon9 + +[584111F7 Inventory - Minecraft] +W = LS-Up +S = LS-Down +A = LS-Left +D = LS-Right +LClick = A +RClick = X +Q = B +R = LT +F = RT +Up = Up +Down = Down +Left = Left +Right = Right +LShift = Y +Tab = Back +Enter = Start + [545107D1 Default - Saints Row 1] W = LS-Up S = LS-Down diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index 12e9eac18f..ec90d983f4 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -2075,6 +2075,16 @@ 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; + } + } + } + // Initializing the shader storage in a blocking way so the user doesn't // miss the initial seconds - for instance, sound from an intro video may // start playing before the video can be seen if doing this in parallel with diff --git a/src/xenia/hid/winkey/hookables/CallOfDuty.cc b/src/xenia/hid/winkey/hookables/CallOfDuty.cc index f291e1ec7e..b0bc61fb0c 100644 --- a/src/xenia/hid/winkey/hookables/CallOfDuty.cc +++ b/src/xenia/hid/winkey/hookables/CallOfDuty.cc @@ -319,6 +319,11 @@ bool CallOfDutyGame::ModifierKeyHandler(uint32_t user_index, } else return false; } + +void CallOfDutyGame::WeaponSwitchHandler(uint32_t user_index, RawInputState& input_state, + X_INPUT_STATE* out_state, int weapon, + uint16_t buttons) {} + bool CallOfDutyGame::Dvar_GetBool(std::string dvar, uint32_t dvar_address) { XThread* current_thread = XThread::GetCurrentThread(); diff --git a/src/xenia/hid/winkey/hookables/CallOfDuty.h b/src/xenia/hid/winkey/hookables/CallOfDuty.h index aab39d1870..3904568942 100644 --- a/src/xenia/hid/winkey/hookables/CallOfDuty.h +++ b/src/xenia/hid/winkey/hookables/CallOfDuty.h @@ -76,6 +76,10 @@ class CallOfDutyGame : 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); + bool Dvar_GetBool(std::string dvar, uint32_t dvar_address); private: diff --git a/src/xenia/hid/winkey/hookables/Crackdown2.cc b/src/xenia/hid/winkey/hookables/Crackdown2.cc index d0098fedb6..e1b5de1e1c 100644 --- a/src/xenia/hid/winkey/hookables/Crackdown2.cc +++ b/src/xenia/hid/winkey/hookables/Crackdown2.cc @@ -136,6 +136,11 @@ bool Crackdown2Game::ModifierKeyHandler(uint32_t user_index, X_INPUT_STATE* out_state) { return false; } + +void Crackdown2Game::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/Crackdown2.h b/src/xenia/hid/winkey/hookables/Crackdown2.h index 1390ed346f..9ca17ffd03 100644 --- a/src/xenia/hid/winkey/hookables/Crackdown2.h +++ b/src/xenia/hid/winkey/hookables/Crackdown2.h @@ -35,6 +35,10 @@ class Crackdown2Game : 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; }; diff --git a/src/xenia/hid/winkey/hookables/DeadRising.cc b/src/xenia/hid/winkey/hookables/DeadRising.cc index 01b94e4a68..58f9496bda 100644 --- a/src/xenia/hid/winkey/hookables/DeadRising.cc +++ b/src/xenia/hid/winkey/hookables/DeadRising.cc @@ -157,6 +157,11 @@ bool DeadRisingGame::ModifierKeyHandler(uint32_t user_index, // won't be used return true; } + +void DeadRisingGame::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/DeadRising.h b/src/xenia/hid/winkey/hookables/DeadRising.h index dd4abc1596..47aa6dd004 100644 --- a/src/xenia/hid/winkey/hookables/DeadRising.h +++ b/src/xenia/hid/winkey/hookables/DeadRising.h @@ -35,6 +35,10 @@ class DeadRisingGame : 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; }; diff --git a/src/xenia/hid/winkey/hookables/Farcry.cc b/src/xenia/hid/winkey/hookables/Farcry.cc index 4450ae3043..be514db246 100644 --- a/src/xenia/hid/winkey/hookables/Farcry.cc +++ b/src/xenia/hid/winkey/hookables/Farcry.cc @@ -127,6 +127,11 @@ bool FarCryGame::ModifierKeyHandler(uint32_t user_index, X_INPUT_STATE* out_state) { return false; } + +void FarCryGame::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/Farcry.h b/src/xenia/hid/winkey/hookables/Farcry.h index 4ccafdd439..b53e3a5e87 100644 --- a/src/xenia/hid/winkey/hookables/Farcry.h +++ b/src/xenia/hid/winkey/hookables/Farcry.h @@ -32,6 +32,10 @@ class FarCryGame : 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; }; diff --git a/src/xenia/hid/winkey/hookables/GearsOfWars.cc b/src/xenia/hid/winkey/hookables/GearsOfWars.cc index 2bba0e0607..63bb7924fa 100644 --- a/src/xenia/hid/winkey/hookables/GearsOfWars.cc +++ b/src/xenia/hid/winkey/hookables/GearsOfWars.cc @@ -439,6 +439,11 @@ bool GearsOfWarsGame::ModifierKeyHandler(uint32_t user_index, } return true; } + +void GearsOfWarsGame::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/GearsOfWars.h b/src/xenia/hid/winkey/hookables/GearsOfWars.h index b0eeaeab1b..f6d5c34e53 100644 --- a/src/xenia/hid/winkey/hookables/GearsOfWars.h +++ b/src/xenia/hid/winkey/hookables/GearsOfWars.h @@ -51,6 +51,10 @@ class GearsOfWarsGame : 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; // Timer variables to hold the state for a while // this is probably not ideal diff --git a/src/xenia/hid/winkey/hookables/JustCause.cc b/src/xenia/hid/winkey/hookables/JustCause.cc index cce784de42..df7bc7240c 100644 --- a/src/xenia/hid/winkey/hookables/JustCause.cc +++ b/src/xenia/hid/winkey/hookables/JustCause.cc @@ -147,6 +147,11 @@ bool JustCauseGame::ModifierKeyHandler(uint32_t user_index, X_INPUT_STATE* out_state) { return false; } + +void JustCauseGame::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/JustCause.h b/src/xenia/hid/winkey/hookables/JustCause.h index d476d05dcb..1b28b40348 100644 --- a/src/xenia/hid/winkey/hookables/JustCause.h +++ b/src/xenia/hid/winkey/hookables/JustCause.h @@ -35,6 +35,10 @@ class JustCauseGame : 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; }; diff --git a/src/xenia/hid/winkey/hookables/Minecraft.cc b/src/xenia/hid/winkey/hookables/Minecraft.cc new file mode 100644 index 0000000000..eabe371b02 --- /dev/null +++ b/src/xenia/hid/winkey/hookables/Minecraft.cc @@ -0,0 +1,313 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/hid/winkey/hookables/Minecraft.h" + +#include "xenia/emulator.h" +#include "xenia/kernel/util/shim_utils.h" +#include "xenia/kernel/xmodule.h" +#include "xenia/kernel/xthread.h" + +using namespace xe::kernel; + +DECLARE_double(sensitivity); +DECLARE_bool(invert_y); +DECLARE_bool(invert_x); + +namespace xe { +namespace hid { +namespace winkey { + +MinecraftGame::~MinecraftGame() = default; + +struct GameBuildAddrs { + const char* title_version; + uint32_t camera_base_addr; + std::vector camera_offsets; + uint32_t camera_x_offset; + uint32_t camera_y_offset; + + uint32_t pause_flag; + + uint32_t inventory_flag_base; + std::vector inventory_flag_offsets; + + uint32_t inventory_base_addr; + std::vector inventory_base_offsets; + + uint32_t inventory_x_offset; + uint32_t inventory_y_offset; + uint32_t workbench_x_offset; + uint32_t workbench_y_offset; + uint32_t furnace_x_offset; + uint32_t furnace_y_offset; + uint32_t chest_x_offset; // chest (normal/trapped/ender), dispenser, dropper, + // hopper, minecart variants + uint32_t chest_y_offset; + uint32_t anvil_x_offset; + uint32_t anvil_y_offset; + uint32_t enchanting_x_offset; + uint32_t enchanting_y_offset; + uint32_t brewing_x_offset; + uint32_t brewing_y_offset; + uint32_t beacon_x_offset; + uint32_t beacon_y_offset; + uint32_t creative_x_offset; + uint32_t creative_y_offset; + + uint32_t hotbar_base_addr; + std::vector hotbar_offsets; +}; + +std::map supported_builds{ + {MinecraftGame::GameBuild::Unknown, + {"", NULL, {}, NULL, NULL, NULL, NULL, {}, NULL, {}, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, {}}}, + {MinecraftGame::GameBuild::TU75, {"1.0.80", 0x82C8518C, + {0x38}, 0x148, + 0x14C, 0x82C84986, + 0x82C83084, {0x24, 0x114, 0x4}, + 0x82CCDB90, {0x4, 0x44, 0x6B8}, + 0x1A1C, 0x1A20, + 0x14EC, 0x14F0, + 0x2118, 0x211C, + 0x1284, 0x1288, + 0x1A2C, 0x1A30, + 0x1D5C, 0x1D60, + 0x2390, 0x2394, + 0x1A48, 0x1A4C, + 0x25FC, 0x2600, + 0x82CCDB90, {0x34, 0x5F8, 0x6C}}}}; + +bool MinecraftGame::IsGameSupported() { + auto title_id = kernel_state()->title_id(); + if (title_id != 0x584111F7) return false; + + const std::string current_version = + kernel_state()->emulator()->title_version(); + + for (auto& build : supported_builds) { + if (current_version == build.second.title_version) { + game_build_ = build.first; + return true; + } + } + + return false; +} + +bool MinecraftGame::DoHooks(uint32_t user_index, RawInputState& input_state, + X_INPUT_STATE* out_state) { + if (!IsGameSupported()) { + return false; + } + + XThread* current_thread = XThread::GetCurrentThread(); + + if (!current_thread) { + return false; + } + + if (*kernel_memory()->TranslateVirtual( + supported_builds[game_build_].pause_flag)) { + return true; + } + + auto* inventory_flag_ptr = + multi_pointer(supported_builds[game_build_].inventory_flag_base, + supported_builds[game_build_].inventory_flag_offsets); + if (inventory_flag_ptr) { + if (*inventory_flag_ptr) { + uint32_t x_offset; + uint32_t y_offset; + + switch (*inventory_flag_ptr) { + case 1: { + x_offset = supported_builds[game_build_].inventory_x_offset; + y_offset = supported_builds[game_build_].inventory_y_offset; + break; + } + case 37: { + x_offset = supported_builds[game_build_].workbench_x_offset; + y_offset = supported_builds[game_build_].workbench_y_offset; + break; + } + case 4: { + x_offset = supported_builds[game_build_].furnace_x_offset; + y_offset = supported_builds[game_build_].furnace_y_offset; + break; + } + case 10: // normal/trapped/ender chests + case 11: // dispenser/dropper + case 32: // hopper + { + x_offset = supported_builds[game_build_].chest_x_offset; + y_offset = supported_builds[game_build_].chest_y_offset; + break; + } + case 27: { + x_offset = supported_builds[game_build_].anvil_x_offset; + y_offset = supported_builds[game_build_].anvil_y_offset; + break; + } + case 20: { + x_offset = supported_builds[game_build_].enchanting_x_offset; + y_offset = supported_builds[game_build_].enchanting_y_offset; + break; + } + case 18: { + x_offset = supported_builds[game_build_].brewing_x_offset; + y_offset = supported_builds[game_build_].brewing_y_offset; + break; + } + case 34: { + x_offset = supported_builds[game_build_].beacon_x_offset; + y_offset = supported_builds[game_build_].beacon_y_offset; + break; + } + case 14: { + x_offset = supported_builds[game_build_].creative_x_offset; + y_offset = supported_builds[game_build_].creative_y_offset; + break; + } + default: // sometimes we need to check if offsets are being set at all + // to make sure it doesn't crash when re-entering games + return false; + } + + auto* inventory_ptr = + multi_pointer(supported_builds[game_build_].inventory_base_addr, + supported_builds[game_build_].inventory_base_offsets); + if (*inventory_ptr) { + auto* inventoryX_ptr = + kernel_memory()->TranslateVirtual*>(*inventory_ptr + + x_offset); + auto* inventoryY_ptr = + kernel_memory()->TranslateVirtual*>(*inventory_ptr + + y_offset); + + float inventoryX = *inventoryX_ptr; + float inventoryY = *inventoryY_ptr; + + inventoryX += + (((float)input_state.mouse.x_delta)) * (float)cvars::sensitivity; + + inventoryY += + (((float)input_state.mouse.y_delta)) * (float)cvars::sensitivity; + + *inventoryX_ptr = inventoryX; + *inventoryY_ptr = inventoryY; + + return true; + } + } + } + + auto* input_base_addr = + multi_pointer(supported_builds[game_build_].camera_base_addr, + supported_builds[game_build_].camera_offsets); + + if (*input_base_addr) { + + auto* player_cam_x = + kernel_memory()->TranslateVirtual*>( + *input_base_addr + supported_builds[game_build_].camera_x_offset); + auto* player_cam_y = + kernel_memory()->TranslateVirtual*>( + *input_base_addr + supported_builds[game_build_].camera_y_offset); + + // Have to do weird things converting it to normal float otherwise + // xe::be += treats things as int? + float camX = (float)*player_cam_x; + float camY = (float)*player_cam_y; + + if (!cvars::invert_x) { + camX += + (((float)input_state.mouse.x_delta) / 5.f) * (float)cvars::sensitivity; + } else { + camX -= + (((float)input_state.mouse.x_delta) / 5.f) * (float)cvars::sensitivity; + } + + if (!cvars::invert_y) { + camY += + (((float)input_state.mouse.y_delta) / 5.f) * (float)cvars::sensitivity; + } else { + camY -= + (((float)input_state.mouse.y_delta) / 5.f) * (float)cvars::sensitivity; + } + + // Keep in bounds because game can't catch up + if (camY > 90.0f) + camY = 90.0f; + else if (camY < -90.0f) + camY = -90.0f; + + *player_cam_x = camX; + *player_cam_y = camY; + + return true; + } + + return false; +} + +std::string MinecraftGame::ChooseBinds() { + auto* inventory_flag_ptr = + multi_pointer(supported_builds[game_build_].inventory_flag_base, + supported_builds[game_build_].inventory_flag_offsets); + if (inventory_flag_ptr) { + if (*inventory_flag_ptr) { + return "Inventory"; + } + } + + return "Default"; +} + +bool MinecraftGame::ModifierKeyHandler(uint32_t user_index, + RawInputState& input_state, + X_INPUT_STATE* out_state) { + return false; +} + +void MinecraftGame::WeaponSwitchHandler(uint32_t user_index, + RawInputState& input_state, + X_INPUT_STATE* out_state, + int weapon, uint16_t buttons) { + auto* hotbar_selection = + multi_pointer(supported_builds[game_build_].hotbar_base_addr, + supported_builds[game_build_].hotbar_offsets); + if (hotbar_selection) { + if (weapon == 1) { + *hotbar_selection = 0; + } else if (weapon == 2) { + *hotbar_selection = 1; + } else if (weapon == 3) { + *hotbar_selection = 2; + } else if (weapon == 4) { + *hotbar_selection = 3; + } else if (weapon == 5) { + *hotbar_selection = 4; + } else if (weapon == 6) { + *hotbar_selection = 5; + } else if (weapon == 7) { + *hotbar_selection = 6; + } else if (weapon == 8) { + *hotbar_selection = 7; + } else if (weapon == 9) { + *hotbar_selection = 8; + } + } +} + +} // namespace winkey +} // namespace hid +} // namespace xe \ No newline at end of file diff --git a/src/xenia/hid/winkey/hookables/Minecraft.h b/src/xenia/hid/winkey/hookables/Minecraft.h new file mode 100644 index 0000000000..455b3d4e77 --- /dev/null +++ b/src/xenia/hid/winkey/hookables/Minecraft.h @@ -0,0 +1,44 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_HID_WINKEY_MINECRAFT_H_ +#define XENIA_HID_WINKEY_MINECRAFT_H_ + +#include "xenia/hid/winkey/hookables/hookable_game.h" + +namespace xe { +namespace hid { +namespace winkey { + +class MinecraftGame : public HookableGame { + public: + enum class GameBuild { Unknown, TU75 }; + + ~MinecraftGame() override; + + bool IsGameSupported(); + 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); + 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; +}; + +} // namespace winkey +} // namespace hid +} // namespace xe + +#endif // XENIA_HID_WINKEY_MINECRAFT_H_ \ No newline at end of file diff --git a/src/xenia/hid/winkey/hookables/RDR.cc b/src/xenia/hid/winkey/hookables/RDR.cc index df6d443084..938630857e 100644 --- a/src/xenia/hid/winkey/hookables/RDR.cc +++ b/src/xenia/hid/winkey/hookables/RDR.cc @@ -845,6 +845,11 @@ bool RedDeadRedemptionGame::ModifierKeyHandler(uint32_t user_index, out_state->gamepad.buttons = buttons; return true; } + +void RedDeadRedemptionGame::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/RDR.h b/src/xenia/hid/winkey/hookables/RDR.h index 2effe2791e..5889c493d9 100644 --- a/src/xenia/hid/winkey/hookables/RDR.h +++ b/src/xenia/hid/winkey/hookables/RDR.h @@ -62,6 +62,10 @@ class RedDeadRedemptionGame : 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; std::chrono::steady_clock::time_point last_movement_time_x_; diff --git a/src/xenia/hid/winkey/hookables/SaintsRow1.cc b/src/xenia/hid/winkey/hookables/SaintsRow1.cc index 0cbbf25d7d..40c96109b4 100644 --- a/src/xenia/hid/winkey/hookables/SaintsRow1.cc +++ b/src/xenia/hid/winkey/hookables/SaintsRow1.cc @@ -426,6 +426,7 @@ std::string SaintsRow1Game::ChooseBinds() { return "Default"; } + bool SaintsRow1Game::ModifierKeyHandler(uint32_t user_index, RawInputState& input_state, X_INPUT_STATE* out_state) { @@ -450,6 +451,11 @@ bool SaintsRow1Game::ModifierKeyHandler(uint32_t user_index, // won't be used return true; } + +void SaintsRow1Game::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/SaintsRow1.h b/src/xenia/hid/winkey/hookables/SaintsRow1.h index 9e0ed36e41..485c984958 100644 --- a/src/xenia/hid/winkey/hookables/SaintsRow1.h +++ b/src/xenia/hid/winkey/hookables/SaintsRow1.h @@ -40,6 +40,9 @@ class SaintsRow1Game : public HookableGame { std::string ChooseBinds(); 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; diff --git a/src/xenia/hid/winkey/hookables/SaintsRow2.cc b/src/xenia/hid/winkey/hookables/SaintsRow2.cc index 7499f95a75..c8efe43353 100644 --- a/src/xenia/hid/winkey/hookables/SaintsRow2.cc +++ b/src/xenia/hid/winkey/hookables/SaintsRow2.cc @@ -291,6 +291,10 @@ bool SaintsRow2Game::ModifierKeyHandler(uint32_t user_index, return true; } +void SaintsRow2Game::WeaponSwitchHandler(uint32_t user_index, RawInputState& input_state, + X_INPUT_STATE* out_state, int weapon, + uint16_t buttons) {} + void SaintsRow2Game::FixHavokFrameTime() { XThread* current_thread = XThread::GetCurrentThread(); if (!current_thread) return; diff --git a/src/xenia/hid/winkey/hookables/SaintsRow2.h b/src/xenia/hid/winkey/hookables/SaintsRow2.h index 067c30a374..79b91fa6a5 100644 --- a/src/xenia/hid/winkey/hookables/SaintsRow2.h +++ b/src/xenia/hid/winkey/hookables/SaintsRow2.h @@ -36,6 +36,10 @@ class SaintsRow2Game : 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); + void FixHavokFrameTime(); uint64_t reset_fineaim(uint32_t function_address, uint32_t player_ptr, diff --git a/src/xenia/hid/winkey/hookables/SourceEngine.cc b/src/xenia/hid/winkey/hookables/SourceEngine.cc index 2aab7db216..603520a0bc 100644 --- a/src/xenia/hid/winkey/hookables/SourceEngine.cc +++ b/src/xenia/hid/winkey/hookables/SourceEngine.cc @@ -263,6 +263,11 @@ bool SourceEngine::ModifierKeyHandler(uint32_t user_index, return true; } +void SourceEngine::WeaponSwitchHandler(uint32_t user_index, + RawInputState& input_state, + X_INPUT_STATE* out_state, int weapon, + uint16_t buttons) {} + } // namespace winkey } // namespace hid } // namespace xe diff --git a/src/xenia/hid/winkey/hookables/SourceEngine.h b/src/xenia/hid/winkey/hookables/SourceEngine.h index 8a425e48b2..cf884c3d4c 100644 --- a/src/xenia/hid/winkey/hookables/SourceEngine.h +++ b/src/xenia/hid/winkey/hookables/SourceEngine.h @@ -43,6 +43,9 @@ class SourceEngine : public HookableGame { std::string ChooseBinds(); 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; diff --git a/src/xenia/hid/winkey/hookables/goldeneye.cc b/src/xenia/hid/winkey/hookables/goldeneye.cc index 396bdd66c9..439f3d7cf6 100644 --- a/src/xenia/hid/winkey/hookables/goldeneye.cc +++ b/src/xenia/hid/winkey/hookables/goldeneye.cc @@ -574,6 +574,10 @@ bool GoldeneyeGame::ModifierKeyHandler(uint32_t user_index, return true; } +void GoldeneyeGame::WeaponSwitchHandler(uint32_t user_index, RawInputState& input_state, + X_INPUT_STATE* out_state, int weapon, + uint16_t buttons) {} + } // namespace winkey } // namespace hid } // namespace xe diff --git a/src/xenia/hid/winkey/hookables/goldeneye.h b/src/xenia/hid/winkey/hookables/goldeneye.h index 0a67df5e8f..e4ac0596d2 100644 --- a/src/xenia/hid/winkey/hookables/goldeneye.h +++ b/src/xenia/hid/winkey/hookables/goldeneye.h @@ -40,6 +40,9 @@ class GoldeneyeGame : public HookableGame { std::string ChooseBinds(); 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; diff --git a/src/xenia/hid/winkey/hookables/halo3.cc b/src/xenia/hid/winkey/hookables/halo3.cc index 4c1c41b04e..45cb91fe91 100644 --- a/src/xenia/hid/winkey/hookables/halo3.cc +++ b/src/xenia/hid/winkey/hookables/halo3.cc @@ -180,6 +180,10 @@ bool Halo3Game::ModifierKeyHandler(uint32_t user_index, return false; } +void Halo3Game::WeaponSwitchHandler(uint32_t user_index, RawInputState& input_state, + X_INPUT_STATE* out_state, int weapon, + uint16_t buttons) {} + } // namespace winkey } // namespace hid } // namespace xe diff --git a/src/xenia/hid/winkey/hookables/halo3.h b/src/xenia/hid/winkey/hookables/halo3.h index 0ad8e2e95d..ea63d67c3e 100644 --- a/src/xenia/hid/winkey/hookables/halo3.h +++ b/src/xenia/hid/winkey/hookables/halo3.h @@ -55,6 +55,9 @@ class Halo3Game : public HookableGame { std::string ChooseBinds(); 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; diff --git a/src/xenia/hid/winkey/hookables/hookable_game.cc b/src/xenia/hid/winkey/hookables/hookable_game.cc new file mode 100644 index 0000000000..7053941fea --- /dev/null +++ b/src/xenia/hid/winkey/hookables/hookable_game.cc @@ -0,0 +1,36 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/hid/winkey/hookables/hookable_game.h" +#include "xenia/kernel/util/shim_utils.h" + +namespace xe { +namespace hid { +namespace winkey { + +xe::be* multi_pointer(uint32_t base_address, + std::vector offsets) { + auto* current_pointer = + xe::kernel::kernel_memory()->TranslateVirtual*>( + base_address); + for (auto& offset : offsets) { + if (*current_pointer) { + current_pointer = + xe::kernel::kernel_memory()->TranslateVirtual*>( + *current_pointer + offset); + } else { + return nullptr; + } + } + return current_pointer; +} + +} // namespace winkey +} // namespace hid +} // namespace xe \ No newline at end of file diff --git a/src/xenia/hid/winkey/hookables/hookable_game.h b/src/xenia/hid/winkey/hookables/hookable_game.h index 51e0ebebff..f3d1f546c0 100644 --- a/src/xenia/hid/winkey/hookables/hookable_game.h +++ b/src/xenia/hid/winkey/hookables/hookable_game.h @@ -12,6 +12,7 @@ #include "xenia/hid/input.h" #include "xenia/xbox.h" +#include namespace xe { namespace hid { @@ -40,8 +41,15 @@ class HookableGame { virtual bool ModifierKeyHandler(uint32_t user_index, RawInputState& input_state, X_INPUT_STATE* out_state) = 0; + virtual void WeaponSwitchHandler(uint32_t user_index, + RawInputState& input_state, + X_INPUT_STATE* out_state, int weapon, + uint16_t buttons) = 0; }; +xe::be* multi_pointer(uint32_t base_address, + std::vector offsets); + } // namespace winkey } // namespace hid } // namespace xe diff --git a/src/xenia/hid/winkey/winkey_input_driver.cc b/src/xenia/hid/winkey/winkey_input_driver.cc index 5790e0145c..8e08ede5ef 100644 --- a/src/xenia/hid/winkey/winkey_input_driver.cc +++ b/src/xenia/hid/winkey/winkey_input_driver.cc @@ -30,6 +30,7 @@ #include "xenia/hid/winkey/hookables/SourceEngine.h" #include "xenia/hid/winkey/hookables/goldeneye.h" #include "xenia/hid/winkey/hookables/halo3.h" +#include "xenia/hid/winkey/hookables/Minecraft.h" DEFINE_bool(invert_y, false, "Invert mouse Y axis", "MouseHook"); DEFINE_bool(invert_x, false, "Invert mouse X axis", "MouseHook"); @@ -123,7 +124,7 @@ bool __inline IsKeyDown(ui::VirtualKey virtual_key) { return IsKeyDown(static_cast(virtual_key)); } -static const std::unordered_map kXInputButtons = { +static const std::unordered_map kXInputButtons = { {"up", XINPUT_BIND_UP}, {"down", XINPUT_BIND_DOWN}, {"left", XINPUT_BIND_LEFT}, @@ -156,7 +157,18 @@ static const std::unordered_map kXInputButtons = { {"rs-left", XINPUT_BIND_RS_LEFT}, {"rs-right", XINPUT_BIND_RS_RIGHT}, - {"modifier", XINPUT_BIND_MODIFIER}}; + {"modifier", XINPUT_BIND_MODIFIER}, + + {"weapon1", XINPUT_BIND_WEAPON1}, + {"weapon2", XINPUT_BIND_WEAPON2}, + {"weapon3", XINPUT_BIND_WEAPON3}, + {"weapon4", XINPUT_BIND_WEAPON4}, + {"weapon5", XINPUT_BIND_WEAPON5}, + {"weapon6", XINPUT_BIND_WEAPON6}, + {"weapon7", XINPUT_BIND_WEAPON7}, + {"weapon8", XINPUT_BIND_WEAPON8}, + {"weapon9", XINPUT_BIND_WEAPON9}, + {"weapon10", XINPUT_BIND_WEAPON10}}; // Lookup the value of key string static const std::map kKeyMap = { {"lclick", ui::VirtualKey::kLButton}, @@ -305,10 +317,10 @@ void WinKeyInputDriver::ParseKeyBinding(ui::VirtualKey output_key, } } -int WinKeyInputDriver::ParseButtonCombination(const char* combo) { +uint64_t WinKeyInputDriver::ParseButtonCombination(const char* combo) { size_t len = strlen(combo); - int retval = 0; + uint64_t retval = 0; std::string cur_token; // Parse combo tokens into buttons bitfield (tokens seperated by any @@ -316,7 +328,7 @@ int WinKeyInputDriver::ParseButtonCombination(const char* combo) { for (size_t i = 0; i < len; i++) { char c = combo[i]; - if (!isalpha(c) && c != '-') { + if (!isalpha(c) && !isdigit(c) && c != '-') { if (cur_token.length() && kXInputButtons.count(cur_token)) retval |= kXInputButtons.at(cur_token); @@ -349,8 +361,8 @@ void WinKeyInputDriver::ParseCustomKeyBinding( uint32_t prev_title_id = 0; std::string cur_type = "Default"; - std::map cur_binds; - std::map> cur_title_binds; + std::map cur_binds; + std::map> cur_title_binds; std::string line; while (std::getline(binds, line)) { @@ -453,6 +465,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())); auto path = std::filesystem::current_path() / "bindings.ini"; @@ -505,6 +518,8 @@ X_RESULT WinKeyInputDriver::GetState(uint32_t user_index, int16_t thumb_rx = 0; int16_t thumb_ry = 0; bool modifier_pressed = false; + bool weapon_switch = false; + int weapon = 0; X_RESULT result = X_ERROR_SUCCESS; @@ -526,7 +541,7 @@ X_RESULT WinKeyInputDriver::GetState(uint32_t user_index, for (int i = 0; i < sizeof(key_states_); i++) { if (key_states_[i]) { - std::map binds; + std::map binds; if (key_binds_.find(title_id) == key_binds_.end()) { binds = key_binds_.at(0).at("Default"); @@ -590,6 +605,47 @@ X_RESULT WinKeyInputDriver::GetState(uint32_t user_index, if (binding & XINPUT_BIND_MODIFIER) { modifier_pressed = true; } + + if (binding & XINPUT_BIND_WEAPON1) { + weapon_switch = true; + weapon = 1; + } + if (binding & XINPUT_BIND_WEAPON2) { + weapon_switch = true; + weapon = 2; + } + if (binding & XINPUT_BIND_WEAPON3) { + weapon_switch = true; + weapon = 3; + } + if (binding & XINPUT_BIND_WEAPON4) { + weapon_switch = true; + weapon = 4; + } + if (binding & XINPUT_BIND_WEAPON5) { + weapon_switch = true; + weapon = 5; + } + if (binding & XINPUT_BIND_WEAPON6) { + weapon_switch = true; + weapon = 6; + } + if (binding & XINPUT_BIND_WEAPON7) { + weapon_switch = true; + weapon = 7; + } + if (binding & XINPUT_BIND_WEAPON8) { + weapon_switch = true; + weapon = 8; + } + if (binding & XINPUT_BIND_WEAPON9) { + weapon_switch = true; + weapon = 9; + } + if (binding & XINPUT_BIND_WEAPON10) { + weapon_switch = true; + weapon = 10; + } } } } @@ -613,6 +669,10 @@ X_RESULT WinKeyInputDriver::GetState(uint32_t user_index, game_modifier_handled = game->ModifierKeyHandler(user_index, state, out_state); } + if (weapon_switch) { + game->WeaponSwitchHandler(user_index, state, out_state, weapon, + buttons); + } break; } } diff --git a/src/xenia/hid/winkey/winkey_input_driver.h b/src/xenia/hid/winkey/winkey_input_driver.h index 565946122f..9b89b52341 100644 --- a/src/xenia/hid/winkey/winkey_input_driver.h +++ b/src/xenia/hid/winkey/winkey_input_driver.h @@ -57,6 +57,17 @@ #define XINPUT_BIND_MODIFIER (1 << 26) +#define XINPUT_BIND_WEAPON1 ((uint64_t)1 << 54) +#define XINPUT_BIND_WEAPON2 ((uint64_t)1 << 55) +#define XINPUT_BIND_WEAPON3 ((uint64_t)1 << 56) +#define XINPUT_BIND_WEAPON4 ((uint64_t)1 << 57) +#define XINPUT_BIND_WEAPON5 ((uint64_t)1 << 58) +#define XINPUT_BIND_WEAPON6 ((uint64_t)1 << 59) +#define XINPUT_BIND_WEAPON7 ((uint64_t)1 << 60) +#define XINPUT_BIND_WEAPON8 ((uint64_t)1 << 61) +#define XINPUT_BIND_WEAPON9 ((uint64_t)1 << 62) +#define XINPUT_BIND_WEAPON10 ((uint64_t)1 << 63) + namespace xe { namespace hid { namespace winkey { @@ -108,7 +119,7 @@ class WinKeyInputDriver final : public InputDriver { const std::string_view description, const std::string_view binding); - int ParseButtonCombination(const char* combo); + uint64_t ParseButtonCombination(const char* combo); void ParseCustomKeyBinding(const std::string_view bindings_file); @@ -127,7 +138,7 @@ class WinKeyInputDriver final : public InputDriver { std::queue mouse_events_; uint8_t key_states_[256] = {}; - std::map>> + std::map>> key_binds_; uint32_t packet_number_ = 1; diff --git a/third_party/FFmpeg b/third_party/FFmpeg index 83a50c70b8..cc89fa079f 160000 --- a/third_party/FFmpeg +++ b/third_party/FFmpeg @@ -1 +1 @@ -Subproject commit 83a50c70b8a66b987d76b5baddf54586d26b4add +Subproject commit cc89fa079fe27365fc5fe953ae2c39cd39ca808b diff --git a/third_party/SDL2 b/third_party/SDL2 index 79ec168f3c..859844eae3 160000 --- a/third_party/SDL2 +++ b/third_party/SDL2 @@ -1 +1 @@ -Subproject commit 79ec168f3c1e2fe27335cb8886439f7ef676fb49 +Subproject commit 859844eae358447be8d66e6da59b6fb3df0ed778 diff --git a/third_party/imgui b/third_party/imgui index b81bd7ed98..1ebb913827 160000 --- a/third_party/imgui +++ b/third_party/imgui @@ -1 +1 @@ -Subproject commit b81bd7ed984ce095c20a059dd0f4d527e006998f +Subproject commit 1ebb91382757777382b3629ced2a573996e46453 diff --git a/third_party/xbyak b/third_party/xbyak index cf209c915b..ccdf68421b 160000 --- a/third_party/xbyak +++ b/third_party/xbyak @@ -1 +1 @@ -Subproject commit cf209c915b849141ed9821fea883fd04bcc34859 +Subproject commit ccdf68421bc8eb85693f573080fc0a5faad862db