From bcdbe485238d790e5776353d3963a45e1ba4b727 Mon Sep 17 00:00:00 2001 From: Jack Back Date: Wed, 24 Jan 2024 10:45:25 +0100 Subject: [PATCH] init --- .gitattributes | 1 + .gitignore | 150 + .gitmodules | 36 + LICENSE | 674 ++ README.md | 38 + deps/GSL | 1 + deps/WinToast | 1 + deps/asmjit | 1 + deps/discord-rpc | 1 + deps/extra/udis86/libudis86/itab.c | 5946 +++++++++++++++++ deps/extra/udis86/libudis86/itab.h | 939 +++ deps/gsc-tool | 1 + deps/libtomcrypt | 1 + deps/libtommath | 1 + deps/minhook | 1 + deps/premake/asmjit.lua | 34 + deps/premake/discord-rpc.lua | 39 + deps/premake/gsc-tool.lua | 62 + deps/premake/gsl.lua | 19 + deps/premake/libtomcrypt.lua | 64 + deps/premake/libtommath.lua | 52 + deps/premake/minhook.lua | 31 + deps/premake/minizip.lua | 43 + deps/premake/protobuf.lua | 60 + deps/premake/rapidjson.lua | 23 + deps/premake/udis86.lua | 37 + deps/premake/wintoast.lua | 32 + deps/premake/zlib.lua | 39 + deps/protobuf | 1 + deps/rapidjson | 1 + deps/udis86 | 1 + deps/zlib | 1 + premake5.lua | 356 + src/client/component/arxan.cpp | 165 + src/client/component/auth.cpp | 228 + src/client/component/auth.hpp | 6 + src/client/component/binding.cpp | 133 + src/client/component/bots.cpp | 204 + src/client/component/branding.cpp | 66 + src/client/component/bullet.cpp | 44 + src/client/component/colors.cpp | 173 + src/client/component/command.cpp | 701 ++ src/client/component/command.hpp | 50 + src/client/component/console.cpp | 260 + src/client/component/console.hpp | 35 + src/client/component/cursor.cpp | 75 + src/client/component/dedicated.cpp | 400 ++ src/client/component/dedicated_info.cpp | 70 + src/client/component/demonware.cpp | 467 ++ src/client/component/demonware.hpp | 9 + src/client/component/discord.cpp | 151 + src/client/component/dvar_cheats.cpp | 188 + src/client/component/dvars.cpp | 86 + src/client/component/dvars.hpp | 11 + src/client/component/fastfiles.cpp | 152 + src/client/component/fastfiles.hpp | 6 + src/client/component/filesystem.cpp | 288 + src/client/component/filesystem.hpp | 30 + src/client/component/fps.cpp | 183 + src/client/component/game_console.cpp | 781 +++ src/client/component/game_console.hpp | 12 + src/client/component/game_log.cpp | 116 + src/client/component/game_log.hpp | 6 + src/client/component/game_module.cpp | 122 + src/client/component/game_module.hpp | 9 + src/client/component/gameplay.cpp | 403 ++ src/client/component/gsc/script_error.cpp | 319 + src/client/component/gsc/script_error.hpp | 16 + src/client/component/gsc/script_extension.cpp | 324 + src/client/component/gsc/script_extension.hpp | 12 + src/client/component/gsc/script_loading.cpp | 369 + src/client/component/gsc/script_loading.hpp | 9 + src/client/component/input.cpp | 59 + src/client/component/localized_strings.cpp | 66 + src/client/component/localized_strings.hpp | 6 + src/client/component/logger.cpp | 159 + src/client/component/map_rotation.cpp | 292 + src/client/component/map_rotation.hpp | 34 + src/client/component/musical_talent.cpp | 49 + src/client/component/network.cpp | 291 + src/client/component/network.hpp | 47 + src/client/component/notifies.cpp | 197 + src/client/component/notifies.hpp | 15 + src/client/component/party.cpp | 494 ++ src/client/component/party.hpp | 19 + src/client/component/patches.cpp | 412 ++ src/client/component/ranked.cpp | 109 + src/client/component/raw_mouse.cpp | 198 + src/client/component/rcon.cpp | 202 + src/client/component/rcon.hpp | 6 + src/client/component/redirect.cpp | 74 + src/client/component/renderer.cpp | 59 + src/client/component/resources.cpp | 70 + src/client/component/scheduler.cpp | 197 + src/client/component/scheduler.hpp | 33 + src/client/component/scripting.cpp | 215 + src/client/component/scripting.hpp | 16 + src/client/component/security.cpp | 51 + src/client/component/server_list.cpp | 486 ++ src/client/component/server_list.hpp | 10 + src/client/component/slowmotion.cpp | 74 + src/client/component/splash.cpp | 141 + src/client/component/stats.cpp | 404 ++ src/client/component/steam_proxy.cpp | 210 + src/client/component/system_check.cpp | 99 + src/client/component/system_check.hpp | 6 + src/client/component/thread_names.cpp | 59 + src/client/component/ui_scripting.cpp | 391 ++ src/client/component/ui_scripting.hpp | 47 + src/client/component/ultrawide.cpp | 238 + src/client/game/demonware/bit_buffer.cpp | 182 + src/client/game/demonware/bit_buffer.hpp | 40 + src/client/game/demonware/byte_buffer.cpp | 313 + src/client/game/demonware/byte_buffer.hpp | 69 + src/client/game/demonware/data_types.hpp | 449 ++ src/client/game/demonware/i_server.hpp | 201 + src/client/game/demonware/i_service.hpp | 82 + src/client/game/demonware/service_server.cpp | 206 + src/client/game/demonware/service_server.hpp | 43 + .../game/demonware/services/bdAnticheat.cpp | 18 + .../game/demonware/services/bdAnticheat.hpp | 14 + .../demonware/services/bdBandwidthTest.cpp | 24 + .../demonware/services/bdBandwidthTest.hpp | 11 + src/client/game/demonware/services/bdDML.cpp | 29 + src/client/game/demonware/services/bdDML.hpp | 14 + .../game/demonware/services/bdDediAuth.cpp | 63 + .../game/demonware/services/bdDediAuth.hpp | 11 + .../game/demonware/services/bdDediRSAAuth.cpp | 73 + .../game/demonware/services/bdDediRSAAuth.hpp | 11 + .../game/demonware/services/bdGroup.cpp | 49 + .../game/demonware/services/bdGroup.hpp | 17 + .../game/demonware/services/bdLSGHello.cpp | 26 + .../game/demonware/services/bdLSGHello.hpp | 11 + .../game/demonware/services/bdMatchMaking.cpp | 107 + .../game/demonware/services/bdMatchMaking.hpp | 18 + .../demonware/services/bdRelayService.cpp | 136 + .../demonware/services/bdRelayService.hpp | 15 + .../game/demonware/services/bdSteamAuth.cpp | 63 + .../game/demonware/services/bdSteamAuth.hpp | 11 + .../game/demonware/services/bdStorage.cpp | 365 + .../game/demonware/services/bdStorage.hpp | 33 + .../demonware/services/bdTitleUtilities.cpp | 21 + .../demonware/services/bdTitleUtilities.hpp | 14 + src/client/game/demonware/stun_server.cpp | 78 + src/client/game/demonware/stun_server.hpp | 21 + src/client/game/dvars.cpp | 149 + src/client/game/dvars.hpp | 49 + src/client/game/game.cpp | 102 + src/client/game/game.hpp | 75 + src/client/game/scripting/functions.cpp | 90 + src/client/game/scripting/functions.hpp | 14 + src/client/game/structs.hpp | 3009 +++++++++ src/client/game/symbols.hpp | 350 + src/client/game/ui_scripting/execution.cpp | 172 + src/client/game/ui_scripting/execution.hpp | 23 + src/client/game/ui_scripting/script_value.cpp | 402 ++ src/client/game/ui_scripting/script_value.hpp | 251 + src/client/game/ui_scripting/types.cpp | 351 + src/client/game/ui_scripting/types.hpp | 141 + .../launcher/html/doc_host_ui_handler.cpp | 115 + .../launcher/html/doc_host_ui_handler.hpp | 47 + src/client/launcher/html/html_argument.cpp | 48 + src/client/launcher/html/html_argument.hpp | 20 + src/client/launcher/html/html_dispatch.cpp | 61 + src/client/launcher/html/html_dispatch.hpp | 24 + src/client/launcher/html/html_frame.cpp | 320 + src/client/launcher/html/html_frame.hpp | 67 + src/client/launcher/html/html_window.cpp | 29 + src/client/launcher/html/html_window.hpp | 15 + src/client/launcher/html/ole_client_site.cpp | 77 + src/client/launcher/html/ole_client_site.hpp | 24 + .../launcher/html/ole_in_place_frame.cpp | 82 + .../launcher/html/ole_in_place_frame.hpp | 30 + .../launcher/html/ole_in_place_site.cpp | 105 + .../launcher/html/ole_in_place_site.hpp | 32 + src/client/launcher/launcher.cpp | 69 + src/client/launcher/launcher.hpp | 29 + src/client/launcher/window.cpp | 208 + src/client/launcher/window.hpp | 44 + src/client/loader/component_interface.hpp | 35 + src/client/loader/component_loader.cpp | 127 + src/client/loader/component_loader.hpp | 61 + src/client/loader/loader.cpp | 209 + src/client/loader/loader.hpp | 23 + src/client/loader/seh.cpp | 151 + src/client/loader/seh.hpp | 38 + src/client/loader/tls.cpp | 34 + src/client/loader/tls.hpp | 6 + src/client/main.cpp | 297 + src/client/proto/auth.proto | 10 + src/client/resource.hpp | 20 + src/client/resource.rc | 138 + .../resources/dw/entitlement_config_tu14.info | 228 + src/client/resources/dw/mm.cfg | 2 + src/client/resources/dw/motd.txt | 1 + src/client/resources/dw/newsfeed.txt | 162 + src/client/resources/dw/playlists_tu14.aggr | Bin 0 -> 32016 bytes src/client/resources/dw/social_tu14.cfg | 139 + src/client/resources/icon.ico | Bin 0 -> 188686 bytes src/client/resources/icon.png | Bin 0 -> 135766 bytes src/client/resources/logo.bmp | Bin 0 -> 109976 bytes src/client/resources/main.html | 555 ++ src/client/resources/splash.bmp | Bin 0 -> 1105976 bytes src/client/std_include.cpp | 48 + src/client/std_include.hpp | 97 + src/client/steam/interface.cpp | 98 + src/client/steam/interface.hpp | 84 + src/client/steam/interfaces/apps.cpp | 104 + src/client/steam/interfaces/apps.hpp | 32 + src/client/steam/interfaces/friends.cpp | 312 + src/client/steam/interfaces/friends.hpp | 74 + src/client/steam/interfaces/game_server.cpp | 204 + src/client/steam/interfaces/game_server.hpp | 55 + src/client/steam/interfaces/matchmaking.cpp | 227 + src/client/steam/interfaces/matchmaking.hpp | 79 + src/client/steam/interfaces/networking.cpp | 121 + src/client/steam/interfaces/networking.hpp | 39 + .../steam/interfaces/remote_storage.cpp | 283 + .../steam/interfaces/remote_storage.hpp | 63 + src/client/steam/interfaces/user.cpp | 163 + src/client/steam/interfaces/user.hpp | 55 + src/client/steam/interfaces/user_stats.cpp | 230 + src/client/steam/interfaces/user_stats.hpp | 65 + src/client/steam/interfaces/utils.cpp | 118 + src/client/steam/interfaces/utils.hpp | 36 + src/client/steam/steam.cpp | 237 + src/client/steam/steam.hpp | 123 + src/common/utils/binary_resource.cpp | 67 + src/common/utils/binary_resource.hpp | 19 + src/common/utils/com.cpp | 126 + src/common/utils/com.hpp | 8 + src/common/utils/compression.cpp | 169 + src/common/utils/compression.hpp | 28 + src/common/utils/concurrency.hpp | 46 + src/common/utils/cryptography.cpp | 640 ++ src/common/utils/cryptography.hpp | 118 + src/common/utils/flags.cpp | 46 + src/common/utils/flags.hpp | 8 + src/common/utils/hook.cpp | 310 + src/common/utils/hook.hpp | 156 + src/common/utils/http.cpp | 48 + src/common/utils/http.hpp | 11 + src/common/utils/info_string.cpp | 65 + src/common/utils/info_string.hpp | 24 + src/common/utils/io.cpp | 123 + src/common/utils/io.hpp | 21 + src/common/utils/memory.cpp | 164 + src/common/utils/memory.hpp | 75 + src/common/utils/nt.cpp | 275 + src/common/utils/nt.hpp | 120 + src/common/utils/signature.cpp | 210 + src/common/utils/signature.hpp | 74 + src/common/utils/smbios.cpp | 94 + src/common/utils/smbios.hpp | 8 + src/common/utils/string.cpp | 185 + src/common/utils/string.hpp | 99 + src/common/utils/thread.cpp | 128 + src/common/utils/thread.hpp | 25 + src/common/utils/toast.cpp | 109 + src/common/utils/toast.hpp | 19 + src/runner/debugger.cpp | 95 + src/runner/debugger.hpp | 15 + src/runner/resource.rc | 100 + src/runner/runner.cpp | 26 + src/tlsdll/dllmain.cpp | 7 + src/tlsdll/resource.rc | 100 + tools/protoc.exe | 3 + 267 files changed, 39510 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 LICENSE create mode 100644 README.md create mode 160000 deps/GSL create mode 160000 deps/WinToast create mode 160000 deps/asmjit create mode 160000 deps/discord-rpc create mode 100644 deps/extra/udis86/libudis86/itab.c create mode 100644 deps/extra/udis86/libudis86/itab.h create mode 160000 deps/gsc-tool create mode 160000 deps/libtomcrypt create mode 160000 deps/libtommath create mode 160000 deps/minhook create mode 100644 deps/premake/asmjit.lua create mode 100644 deps/premake/discord-rpc.lua create mode 100644 deps/premake/gsc-tool.lua create mode 100644 deps/premake/gsl.lua create mode 100644 deps/premake/libtomcrypt.lua create mode 100644 deps/premake/libtommath.lua create mode 100644 deps/premake/minhook.lua create mode 100644 deps/premake/minizip.lua create mode 100644 deps/premake/protobuf.lua create mode 100644 deps/premake/rapidjson.lua create mode 100644 deps/premake/udis86.lua create mode 100644 deps/premake/wintoast.lua create mode 100644 deps/premake/zlib.lua create mode 160000 deps/protobuf create mode 160000 deps/rapidjson create mode 160000 deps/udis86 create mode 160000 deps/zlib create mode 100644 premake5.lua create mode 100644 src/client/component/arxan.cpp create mode 100644 src/client/component/auth.cpp create mode 100644 src/client/component/auth.hpp create mode 100644 src/client/component/binding.cpp create mode 100644 src/client/component/bots.cpp create mode 100644 src/client/component/branding.cpp create mode 100644 src/client/component/bullet.cpp create mode 100644 src/client/component/colors.cpp create mode 100644 src/client/component/command.cpp create mode 100644 src/client/component/command.hpp create mode 100644 src/client/component/console.cpp create mode 100644 src/client/component/console.hpp create mode 100644 src/client/component/cursor.cpp create mode 100644 src/client/component/dedicated.cpp create mode 100644 src/client/component/dedicated_info.cpp create mode 100644 src/client/component/demonware.cpp create mode 100644 src/client/component/demonware.hpp create mode 100644 src/client/component/discord.cpp create mode 100644 src/client/component/dvar_cheats.cpp create mode 100644 src/client/component/dvars.cpp create mode 100644 src/client/component/dvars.hpp create mode 100644 src/client/component/fastfiles.cpp create mode 100644 src/client/component/fastfiles.hpp create mode 100644 src/client/component/filesystem.cpp create mode 100644 src/client/component/filesystem.hpp create mode 100644 src/client/component/fps.cpp create mode 100644 src/client/component/game_console.cpp create mode 100644 src/client/component/game_console.hpp create mode 100644 src/client/component/game_log.cpp create mode 100644 src/client/component/game_log.hpp create mode 100644 src/client/component/game_module.cpp create mode 100644 src/client/component/game_module.hpp create mode 100644 src/client/component/gameplay.cpp create mode 100644 src/client/component/gsc/script_error.cpp create mode 100644 src/client/component/gsc/script_error.hpp create mode 100644 src/client/component/gsc/script_extension.cpp create mode 100644 src/client/component/gsc/script_extension.hpp create mode 100644 src/client/component/gsc/script_loading.cpp create mode 100644 src/client/component/gsc/script_loading.hpp create mode 100644 src/client/component/input.cpp create mode 100644 src/client/component/localized_strings.cpp create mode 100644 src/client/component/localized_strings.hpp create mode 100644 src/client/component/logger.cpp create mode 100644 src/client/component/map_rotation.cpp create mode 100644 src/client/component/map_rotation.hpp create mode 100644 src/client/component/musical_talent.cpp create mode 100644 src/client/component/network.cpp create mode 100644 src/client/component/network.hpp create mode 100644 src/client/component/notifies.cpp create mode 100644 src/client/component/notifies.hpp create mode 100644 src/client/component/party.cpp create mode 100644 src/client/component/party.hpp create mode 100644 src/client/component/patches.cpp create mode 100644 src/client/component/ranked.cpp create mode 100644 src/client/component/raw_mouse.cpp create mode 100644 src/client/component/rcon.cpp create mode 100644 src/client/component/rcon.hpp create mode 100644 src/client/component/redirect.cpp create mode 100644 src/client/component/renderer.cpp create mode 100644 src/client/component/resources.cpp create mode 100644 src/client/component/scheduler.cpp create mode 100644 src/client/component/scheduler.hpp create mode 100644 src/client/component/scripting.cpp create mode 100644 src/client/component/scripting.hpp create mode 100644 src/client/component/security.cpp create mode 100644 src/client/component/server_list.cpp create mode 100644 src/client/component/server_list.hpp create mode 100644 src/client/component/slowmotion.cpp create mode 100644 src/client/component/splash.cpp create mode 100644 src/client/component/stats.cpp create mode 100644 src/client/component/steam_proxy.cpp create mode 100644 src/client/component/system_check.cpp create mode 100644 src/client/component/system_check.hpp create mode 100644 src/client/component/thread_names.cpp create mode 100644 src/client/component/ui_scripting.cpp create mode 100644 src/client/component/ui_scripting.hpp create mode 100644 src/client/component/ultrawide.cpp create mode 100644 src/client/game/demonware/bit_buffer.cpp create mode 100644 src/client/game/demonware/bit_buffer.hpp create mode 100644 src/client/game/demonware/byte_buffer.cpp create mode 100644 src/client/game/demonware/byte_buffer.hpp create mode 100644 src/client/game/demonware/data_types.hpp create mode 100644 src/client/game/demonware/i_server.hpp create mode 100644 src/client/game/demonware/i_service.hpp create mode 100644 src/client/game/demonware/service_server.cpp create mode 100644 src/client/game/demonware/service_server.hpp create mode 100644 src/client/game/demonware/services/bdAnticheat.cpp create mode 100644 src/client/game/demonware/services/bdAnticheat.hpp create mode 100644 src/client/game/demonware/services/bdBandwidthTest.cpp create mode 100644 src/client/game/demonware/services/bdBandwidthTest.hpp create mode 100644 src/client/game/demonware/services/bdDML.cpp create mode 100644 src/client/game/demonware/services/bdDML.hpp create mode 100644 src/client/game/demonware/services/bdDediAuth.cpp create mode 100644 src/client/game/demonware/services/bdDediAuth.hpp create mode 100644 src/client/game/demonware/services/bdDediRSAAuth.cpp create mode 100644 src/client/game/demonware/services/bdDediRSAAuth.hpp create mode 100644 src/client/game/demonware/services/bdGroup.cpp create mode 100644 src/client/game/demonware/services/bdGroup.hpp create mode 100644 src/client/game/demonware/services/bdLSGHello.cpp create mode 100644 src/client/game/demonware/services/bdLSGHello.hpp create mode 100644 src/client/game/demonware/services/bdMatchMaking.cpp create mode 100644 src/client/game/demonware/services/bdMatchMaking.hpp create mode 100644 src/client/game/demonware/services/bdRelayService.cpp create mode 100644 src/client/game/demonware/services/bdRelayService.hpp create mode 100644 src/client/game/demonware/services/bdSteamAuth.cpp create mode 100644 src/client/game/demonware/services/bdSteamAuth.hpp create mode 100644 src/client/game/demonware/services/bdStorage.cpp create mode 100644 src/client/game/demonware/services/bdStorage.hpp create mode 100644 src/client/game/demonware/services/bdTitleUtilities.cpp create mode 100644 src/client/game/demonware/services/bdTitleUtilities.hpp create mode 100644 src/client/game/demonware/stun_server.cpp create mode 100644 src/client/game/demonware/stun_server.hpp create mode 100644 src/client/game/dvars.cpp create mode 100644 src/client/game/dvars.hpp create mode 100644 src/client/game/game.cpp create mode 100644 src/client/game/game.hpp create mode 100644 src/client/game/scripting/functions.cpp create mode 100644 src/client/game/scripting/functions.hpp create mode 100644 src/client/game/structs.hpp create mode 100644 src/client/game/symbols.hpp create mode 100644 src/client/game/ui_scripting/execution.cpp create mode 100644 src/client/game/ui_scripting/execution.hpp create mode 100644 src/client/game/ui_scripting/script_value.cpp create mode 100644 src/client/game/ui_scripting/script_value.hpp create mode 100644 src/client/game/ui_scripting/types.cpp create mode 100644 src/client/game/ui_scripting/types.hpp create mode 100644 src/client/launcher/html/doc_host_ui_handler.cpp create mode 100644 src/client/launcher/html/doc_host_ui_handler.hpp create mode 100644 src/client/launcher/html/html_argument.cpp create mode 100644 src/client/launcher/html/html_argument.hpp create mode 100644 src/client/launcher/html/html_dispatch.cpp create mode 100644 src/client/launcher/html/html_dispatch.hpp create mode 100644 src/client/launcher/html/html_frame.cpp create mode 100644 src/client/launcher/html/html_frame.hpp create mode 100644 src/client/launcher/html/html_window.cpp create mode 100644 src/client/launcher/html/html_window.hpp create mode 100644 src/client/launcher/html/ole_client_site.cpp create mode 100644 src/client/launcher/html/ole_client_site.hpp create mode 100644 src/client/launcher/html/ole_in_place_frame.cpp create mode 100644 src/client/launcher/html/ole_in_place_frame.hpp create mode 100644 src/client/launcher/html/ole_in_place_site.cpp create mode 100644 src/client/launcher/html/ole_in_place_site.hpp create mode 100644 src/client/launcher/launcher.cpp create mode 100644 src/client/launcher/launcher.hpp create mode 100644 src/client/launcher/window.cpp create mode 100644 src/client/launcher/window.hpp create mode 100644 src/client/loader/component_interface.hpp create mode 100644 src/client/loader/component_loader.cpp create mode 100644 src/client/loader/component_loader.hpp create mode 100644 src/client/loader/loader.cpp create mode 100644 src/client/loader/loader.hpp create mode 100644 src/client/loader/seh.cpp create mode 100644 src/client/loader/seh.hpp create mode 100644 src/client/loader/tls.cpp create mode 100644 src/client/loader/tls.hpp create mode 100644 src/client/main.cpp create mode 100644 src/client/proto/auth.proto create mode 100644 src/client/resource.hpp create mode 100644 src/client/resource.rc create mode 100644 src/client/resources/dw/entitlement_config_tu14.info create mode 100644 src/client/resources/dw/mm.cfg create mode 100644 src/client/resources/dw/motd.txt create mode 100644 src/client/resources/dw/newsfeed.txt create mode 100644 src/client/resources/dw/playlists_tu14.aggr create mode 100644 src/client/resources/dw/social_tu14.cfg create mode 100644 src/client/resources/icon.ico create mode 100644 src/client/resources/icon.png create mode 100644 src/client/resources/logo.bmp create mode 100644 src/client/resources/main.html create mode 100644 src/client/resources/splash.bmp create mode 100644 src/client/std_include.cpp create mode 100644 src/client/std_include.hpp create mode 100644 src/client/steam/interface.cpp create mode 100644 src/client/steam/interface.hpp create mode 100644 src/client/steam/interfaces/apps.cpp create mode 100644 src/client/steam/interfaces/apps.hpp create mode 100644 src/client/steam/interfaces/friends.cpp create mode 100644 src/client/steam/interfaces/friends.hpp create mode 100644 src/client/steam/interfaces/game_server.cpp create mode 100644 src/client/steam/interfaces/game_server.hpp create mode 100644 src/client/steam/interfaces/matchmaking.cpp create mode 100644 src/client/steam/interfaces/matchmaking.hpp create mode 100644 src/client/steam/interfaces/networking.cpp create mode 100644 src/client/steam/interfaces/networking.hpp create mode 100644 src/client/steam/interfaces/remote_storage.cpp create mode 100644 src/client/steam/interfaces/remote_storage.hpp create mode 100644 src/client/steam/interfaces/user.cpp create mode 100644 src/client/steam/interfaces/user.hpp create mode 100644 src/client/steam/interfaces/user_stats.cpp create mode 100644 src/client/steam/interfaces/user_stats.hpp create mode 100644 src/client/steam/interfaces/utils.cpp create mode 100644 src/client/steam/interfaces/utils.hpp create mode 100644 src/client/steam/steam.cpp create mode 100644 src/client/steam/steam.hpp create mode 100644 src/common/utils/binary_resource.cpp create mode 100644 src/common/utils/binary_resource.hpp create mode 100644 src/common/utils/com.cpp create mode 100644 src/common/utils/com.hpp create mode 100644 src/common/utils/compression.cpp create mode 100644 src/common/utils/compression.hpp create mode 100644 src/common/utils/concurrency.hpp create mode 100644 src/common/utils/cryptography.cpp create mode 100644 src/common/utils/cryptography.hpp create mode 100644 src/common/utils/flags.cpp create mode 100644 src/common/utils/flags.hpp create mode 100644 src/common/utils/hook.cpp create mode 100644 src/common/utils/hook.hpp create mode 100644 src/common/utils/http.cpp create mode 100644 src/common/utils/http.hpp create mode 100644 src/common/utils/info_string.cpp create mode 100644 src/common/utils/info_string.hpp create mode 100644 src/common/utils/io.cpp create mode 100644 src/common/utils/io.hpp create mode 100644 src/common/utils/memory.cpp create mode 100644 src/common/utils/memory.hpp create mode 100644 src/common/utils/nt.cpp create mode 100644 src/common/utils/nt.hpp create mode 100644 src/common/utils/signature.cpp create mode 100644 src/common/utils/signature.hpp create mode 100644 src/common/utils/smbios.cpp create mode 100644 src/common/utils/smbios.hpp create mode 100644 src/common/utils/string.cpp create mode 100644 src/common/utils/string.hpp create mode 100644 src/common/utils/thread.cpp create mode 100644 src/common/utils/thread.hpp create mode 100644 src/common/utils/toast.cpp create mode 100644 src/common/utils/toast.hpp create mode 100644 src/runner/debugger.cpp create mode 100644 src/runner/debugger.hpp create mode 100644 src/runner/resource.rc create mode 100644 src/runner/runner.cpp create mode 100644 src/tlsdll/dllmain.cpp create mode 100644 src/tlsdll/resource.rc create mode 100644 tools/protoc.exe diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5135af0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.exe filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..130a33a --- /dev/null +++ b/.gitignore @@ -0,0 +1,150 @@ +### Windows + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Shortcuts +*.lnk + +### OSX + +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear on external disk +.Spotlight-V100 +.Trashes + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Visual Studio + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +build + +# Visual Studio 2015 cache/options directory +.vs/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +### IDA +*.id0 +*.id1 +*.id2 +*.nam +*.til + +### Custom user files +# User scripts +user*.bat + +# Premake binary +#premake5.exe \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1b3eca1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,36 @@ +[submodule "deps/asmjit"] + path = deps/asmjit + url = https://github.com/asmjit/asmjit.git +[submodule "deps/discord-rpc"] + path = deps/discord-rpc + url = https://git.alterware.dev/AlterWare/discord-rpc.git +[submodule "deps/gsc-tool"] + path = deps/gsc-tool + url = https://github.com/xensik/gsc-tool.git +[submodule "deps/GSL"] + path = deps/GSL + url = https://github.com/microsoft/GSL.git +[submodule "deps/libtomcrypt"] + path = deps/libtomcrypt + url = https://github.com/libtom/libtomcrypt.git +[submodule "deps/libtommath"] + path = deps/libtommath + url = https://github.com/libtom/libtommath.git +[submodule "deps/minhook"] + path = deps/minhook + url = https://github.com/TsudaKageyu/minhook.git +[submodule "deps/protobuf"] + path = deps/protobuf + url = https://github.com/protocolbuffers/protobuf.git +[submodule "deps/rapidjson"] + path = deps/rapidjson + url = https://github.com/Tencent/rapidjson.git +[submodule "deps/udis86"] + path = deps/udis86 + url = https://github.com/vmt/udis86.git +[submodule "deps/WinToast"] + path = deps/WinToast + url = https://github.com/mohabouje/WinToast.git +[submodule "deps/zlib"] + path = deps/zlib + url = https://github.com/madler/zlib.git diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e72bfdd --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0d51235 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# IW6: A Modded Client + +This is a client modification for IW6! +**NOTE**: You must legally own Call of Duty®: Ghosts® to run this mod. Cracked/Pirated versions of the game are **NOT** supported. + +## Build +- Install [Visual Studio 2022][vs-link] and enable `Desktop development with C++` +- Install [Premake5][premake5-link] and add it to your system PATH +- Clone this repository using [Git][git-link] +- Update the submodules using ``git submodule update --init --recursive`` +- Run Premake with this options ``premake5 vs2022`` (Visual Studio 2022). No other build systems are supported. +- Build project via solution file in `build\s1-mod.sln`. + +Only x64 is supported. Do not attempt to build for Windows ARM 64. + +### Premake arguments + +| Argument | Description | +|:----------------------------|:-----------------------------------------------| +| `--copy-to=PATH` | Optional, copy the EXE to a custom folder after build, define the path here if wanted. | +| `--dev-build` | Enable development builds of the client. | + +Contributions are welcome! Please follow the guidelines below: + +- Sign [AlterWare CLA][cla-link] and send a pull request or email your patch at patches@alterware.dev +- Make sure that PRs have only one commit, and deal with one issue only + +## Disclaimer + +This software has been created purely for the purposes of +academic research. It is not intended to be used to attack +other systems. Project maintainers are not responsible or +liable for misuse of the software. Use responsibly. + +[premake5-link]: https://premake.github.io +[git-link]: https://git-scm.com +[vs-link]: https://visualstudio.microsoft.com/vs +[cla-link]: https://alterware.dev/cla diff --git a/deps/GSL b/deps/GSL new file mode 160000 index 0000000..f1a494c --- /dev/null +++ b/deps/GSL @@ -0,0 +1 @@ +Subproject commit f1a494cfd2ce55fe88b5134eab985f5852667b8d diff --git a/deps/WinToast b/deps/WinToast new file mode 160000 index 0000000..821c481 --- /dev/null +++ b/deps/WinToast @@ -0,0 +1 @@ +Subproject commit 821c4818ade1aa4da56ac753285c159ce26fd597 diff --git a/deps/asmjit b/deps/asmjit new file mode 160000 index 0000000..bfa0bf6 --- /dev/null +++ b/deps/asmjit @@ -0,0 +1 @@ +Subproject commit bfa0bf690c2e90cc0844f2f012efa41b916bde7e diff --git a/deps/discord-rpc b/deps/discord-rpc new file mode 160000 index 0000000..963aa9f --- /dev/null +++ b/deps/discord-rpc @@ -0,0 +1 @@ +Subproject commit 963aa9f3e5ce81a4682c6ca3d136cddda614db33 diff --git a/deps/extra/udis86/libudis86/itab.c b/deps/extra/udis86/libudis86/itab.c new file mode 100644 index 0000000..953f3e5 --- /dev/null +++ b/deps/extra/udis86/libudis86/itab.c @@ -0,0 +1,5946 @@ +/* itab.c -- generated by udis86:scripts/ud_itab.py, do no edit */ +#include "decode.h" + +#define GROUP(n) (0x8000 | (n)) +#define INVALID 0 + + +const uint16_t ud_itab__0[] = { + /* 0 */ 15, 16, 17, 18, + /* 4 */ 19, 20, GROUP(1), GROUP(2), + /* 8 */ 964, 965, 966, 967, + /* c */ 968, 969, GROUP(3), GROUP(4), + /* 10 */ 5, 6, 7, 8, + /* 14 */ 9, 10, GROUP(284), GROUP(285), + /* 18 */ 1336, 1337, 1338, 1339, + /* 1c */ 1340, 1341, GROUP(286), GROUP(287), + /* 20 */ 49, 50, 51, 52, + /* 24 */ 53, 54, INVALID, GROUP(288), + /* 28 */ 1407, 1408, 1409, 1410, + /* 2c */ 1411, 1412, INVALID, GROUP(289), + /* 30 */ 1487, 1488, 1489, 1490, + /* 34 */ 1491, 1492, INVALID, GROUP(290), + /* 38 */ 100, 101, 102, 103, + /* 3c */ 104, 105, INVALID, GROUP(291), + /* 40 */ 699, 700, 701, 702, + /* 44 */ 703, 704, 705, 706, + /* 48 */ 175, 176, 177, 178, + /* 4c */ 179, 180, 181, 182, + /* 50 */ 1246, 1247, 1248, 1249, + /* 54 */ 1250, 1251, 1252, 1253, + /* 58 */ 1101, 1102, 1103, 1104, + /* 5c */ 1105, 1106, 1107, 1108, + /* 60 */ GROUP(292), GROUP(295), GROUP(298), GROUP(299), + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ 1254, 697, 1256, 698, + /* 6c */ 709, GROUP(300), 982, GROUP(301), + /* 70 */ 726, 728, 730, 732, + /* 74 */ 734, 736, 738, 740, + /* 78 */ 742, 744, 746, 748, + /* 7c */ 750, 752, 754, 756, + /* 80 */ GROUP(302), GROUP(303), GROUP(304), GROUP(313), + /* 84 */ 1433, 1434, 1475, 1476, + /* 88 */ 828, 829, 830, 831, + /* 8c */ 832, 770, 833, GROUP(314), + /* 90 */ 1477, 1478, 1479, 1480, + /* 94 */ 1481, 1482, 1483, 1484, + /* 98 */ GROUP(315), GROUP(316), GROUP(317), 1470, + /* 9c */ GROUP(318), GROUP(322), 1310, 766, + /* a0 */ 834, 835, 836, 837, + /* a4 */ 922, GROUP(326), 114, GROUP(327), + /* a8 */ 1435, 1436, 1402, GROUP(328), + /* ac */ 790, GROUP(329), 1346, GROUP(330), + /* b0 */ 838, 839, 840, 841, + /* b4 */ 842, 843, 844, 845, + /* b8 */ 846, 847, 848, 849, + /* bc */ 850, 851, 852, 853, + /* c0 */ GROUP(331), GROUP(332), 1301, 1302, + /* c4 */ GROUP(333), GROUP(403), GROUP(405), GROUP(406), + /* c8 */ 200, 776, 1303, 1304, + /* cc */ 713, 714, GROUP(407), GROUP(408), + /* d0 */ GROUP(409), GROUP(410), GROUP(411), GROUP(412), + /* d4 */ GROUP(413), GROUP(414), GROUP(415), 1486, + /* d8 */ GROUP(416), GROUP(419), GROUP(422), GROUP(425), + /* dc */ GROUP(428), GROUP(431), GROUP(434), GROUP(437), + /* e0 */ 794, 795, 796, GROUP(440), + /* e4 */ 690, 691, 978, 979, + /* e8 */ 72, 763, GROUP(441), 765, + /* ec */ 692, 693, 980, 981, + /* f0 */ 789, 712, 1299, 1300, + /* f4 */ 687, 83, GROUP(442), GROUP(443), + /* f8 */ 77, 1395, 81, 1398, + /* fc */ 78, 1396, GROUP(444), GROUP(445), +}; + +static const uint16_t ud_itab__1[] = { + /* 0 */ 1240, INVALID, +}; + +static const uint16_t ud_itab__2[] = { + /* 0 */ 1096, INVALID, +}; + +static const uint16_t ud_itab__3[] = { + /* 0 */ 1241, INVALID, +}; + +static const uint16_t ud_itab__4[] = { + /* 0 */ GROUP(5), GROUP(6), 767, 797, + /* 4 */ INVALID, 1426, 82, 1431, + /* 8 */ 716, 1471, INVALID, 1444, + /* c */ INVALID, GROUP(27), 430, GROUP(28), + /* 10 */ GROUP(29), GROUP(30), GROUP(31), GROUP(34), + /* 14 */ GROUP(35), GROUP(36), GROUP(37), GROUP(40), + /* 18 */ GROUP(41), 955, 956, 957, + /* 1c */ 958, 959, 960, 961, + /* 20 */ 854, 855, 856, 857, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ GROUP(42), GROUP(43), GROUP(44), GROUP(45), + /* 2c */ GROUP(46), GROUP(47), GROUP(48), GROUP(49), + /* 30 */ 1472, 1297, 1295, 1296, + /* 34 */ GROUP(50), GROUP(52), INVALID, 1514, + /* 38 */ GROUP(54), INVALID, GROUP(116), INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ 84, 85, 86, 87, + /* 44 */ 88, 89, 90, 91, + /* 48 */ 92, 93, 94, 95, + /* 4c */ 96, 97, 98, 99, + /* 50 */ GROUP(143), GROUP(144), GROUP(145), GROUP(146), + /* 54 */ GROUP(147), GROUP(148), GROUP(149), GROUP(150), + /* 58 */ GROUP(151), GROUP(152), GROUP(153), GROUP(154), + /* 5c */ GROUP(155), GROUP(156), GROUP(157), GROUP(158), + /* 60 */ GROUP(159), GROUP(160), GROUP(161), GROUP(162), + /* 64 */ GROUP(163), GROUP(164), GROUP(165), GROUP(166), + /* 68 */ GROUP(167), GROUP(168), GROUP(169), GROUP(170), + /* 6c */ GROUP(171), GROUP(172), GROUP(173), GROUP(176), + /* 70 */ GROUP(177), GROUP(178), GROUP(182), GROUP(186), + /* 74 */ GROUP(191), GROUP(192), GROUP(193), 199, + /* 78 */ GROUP(194), GROUP(195), INVALID, INVALID, + /* 7c */ GROUP(196), GROUP(197), GROUP(198), GROUP(201), + /* 80 */ 727, 729, 731, 733, + /* 84 */ 735, 737, 739, 741, + /* 88 */ 743, 745, 747, 749, + /* 8c */ 751, 753, 755, 757, + /* 90 */ 1350, 1351, 1352, 1353, + /* 94 */ 1354, 1355, 1356, 1357, + /* 98 */ 1358, 1359, 1360, 1361, + /* 9c */ 1362, 1363, 1364, 1365, + /* a0 */ 1245, 1100, 131, 1670, + /* a4 */ 1375, 1376, GROUP(202), GROUP(207), + /* a8 */ 1244, 1099, 1305, 1675, + /* ac */ 1377, 1378, GROUP(215), 694, + /* b0 */ 122, 123, 775, 1673, + /* b4 */ 772, 773, 940, 941, + /* b8 */ GROUP(221), INVALID, GROUP(222), 1671, + /* bc */ 1659, 1660, 930, 931, + /* c0 */ 1473, 1474, GROUP(223), 904, + /* c4 */ GROUP(224), GROUP(225), GROUP(226), GROUP(227), + /* c8 */ 1661, 1662, 1663, 1664, + /* cc */ 1665, 1666, 1667, 1668, + /* d0 */ GROUP(236), GROUP(237), GROUP(238), GROUP(239), + /* d4 */ GROUP(240), GROUP(241), GROUP(242), GROUP(243), + /* d8 */ GROUP(244), GROUP(245), GROUP(246), GROUP(247), + /* dc */ GROUP(248), GROUP(249), GROUP(250), GROUP(251), + /* e0 */ GROUP(252), GROUP(253), GROUP(254), GROUP(255), + /* e4 */ GROUP(256), GROUP(257), GROUP(258), GROUP(259), + /* e8 */ GROUP(260), GROUP(261), GROUP(262), GROUP(263), + /* ec */ GROUP(264), GROUP(265), GROUP(266), GROUP(267), + /* f0 */ GROUP(268), GROUP(269), GROUP(270), GROUP(271), + /* f4 */ GROUP(272), GROUP(273), GROUP(274), GROUP(275), + /* f8 */ GROUP(277), GROUP(278), GROUP(279), GROUP(280), + /* fc */ GROUP(281), GROUP(282), GROUP(283), INVALID, +}; + +static const uint16_t ud_itab__5[] = { + /* 0 */ 1384, 1406, 786, 798, + /* 4 */ 1453, 1454, INVALID, INVALID, +}; + +static const uint16_t ud_itab__6[] = { + /* 0 */ GROUP(7), GROUP(8), +}; + +static const uint16_t ud_itab__7[] = { + /* 0 */ 1374, 1383, 785, 774, + /* 4 */ 1385, INVALID, 787, 719, +}; + +static const uint16_t ud_itab__8[] = { + /* 0 */ GROUP(9), GROUP(14), GROUP(15), GROUP(16), + /* 4 */ 1386, INVALID, 788, GROUP(25), +}; + +static const uint16_t ud_itab__9[] = { + /* 0 */ INVALID, GROUP(10), GROUP(11), GROUP(12), + /* 4 */ GROUP(13), INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__10[] = { + /* 0 */ INVALID, 1455, INVALID, +}; + +static const uint16_t ud_itab__11[] = { + /* 0 */ INVALID, 1461, INVALID, +}; + +static const uint16_t ud_itab__12[] = { + /* 0 */ INVALID, 1462, INVALID, +}; + +static const uint16_t ud_itab__13[] = { + /* 0 */ INVALID, 1463, INVALID, +}; + +static const uint16_t ud_itab__14[] = { + /* 0 */ 824, 952, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__15[] = { + /* 0 */ 1485, 1508, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__16[] = { + /* 0 */ GROUP(17), GROUP(18), GROUP(19), GROUP(20), + /* 4 */ GROUP(21), GROUP(22), GROUP(23), GROUP(24), +}; + +static const uint16_t ud_itab__17[] = { + /* 0 */ 1466, INVALID, INVALID, +}; + +static const uint16_t ud_itab__18[] = { + /* 0 */ 1467, INVALID, INVALID, +}; + +static const uint16_t ud_itab__19[] = { + /* 0 */ 1468, INVALID, INVALID, +}; + +static const uint16_t ud_itab__20[] = { + /* 0 */ 1469, INVALID, INVALID, +}; + +static const uint16_t ud_itab__21[] = { + /* 0 */ 1397, INVALID, INVALID, +}; + +static const uint16_t ud_itab__22[] = { + /* 0 */ 80, INVALID, INVALID, +}; + +static const uint16_t ud_itab__23[] = { + /* 0 */ 1399, INVALID, INVALID, +}; + +static const uint16_t ud_itab__24[] = { + /* 0 */ 720, INVALID, INVALID, +}; + +static const uint16_t ud_itab__25[] = { + /* 0 */ 1425, GROUP(26), INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__26[] = { + /* 0 */ 1298, INVALID, INVALID, +}; + +static const uint16_t ud_itab__27[] = { + /* 0 */ 1119, 1120, 1121, 1122, + /* 4 */ 1123, 1124, 1125, 1126, +}; + +static const uint16_t ud_itab__28[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ 1216, 1217, INVALID, INVALID, + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ INVALID, INVALID, INVALID, INVALID, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ 1218, 1219, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, 1220, INVALID, + /* 8c */ INVALID, INVALID, 1221, INVALID, + /* 90 */ 1222, INVALID, INVALID, INVALID, + /* 94 */ 1223, INVALID, 1224, 1225, + /* 98 */ INVALID, INVALID, 1226, INVALID, + /* 9c */ INVALID, INVALID, 1227, INVALID, + /* a0 */ 1228, INVALID, INVALID, INVALID, + /* a4 */ 1229, INVALID, 1230, 1231, + /* a8 */ INVALID, INVALID, 1232, INVALID, + /* ac */ INVALID, INVALID, 1233, INVALID, + /* b0 */ 1234, INVALID, INVALID, INVALID, + /* b4 */ 1235, INVALID, 1236, 1237, + /* b8 */ INVALID, INVALID, INVALID, 1238, + /* bc */ INVALID, INVALID, INVALID, 1239, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__29[] = { + /* 0 */ 936, 925, 928, 932, +}; + +static const uint16_t ud_itab__30[] = { + /* 0 */ 938, 926, 929, 934, +}; + +static const uint16_t ud_itab__31[] = { + /* 0 */ GROUP(32), GROUP(33), +}; + +static const uint16_t ud_itab__32[] = { + /* 0 */ 892, 1563, 1571, 888, +}; + +static const uint16_t ud_itab__33[] = { + /* 0 */ 896, 1561, 1569, INVALID, +}; + +static const uint16_t ud_itab__34[] = { + /* 0 */ 894, INVALID, INVALID, 890, +}; + +static const uint16_t ud_itab__35[] = { + /* 0 */ 1449, INVALID, INVALID, 1451, +}; + +static const uint16_t ud_itab__36[] = { + /* 0 */ 1447, INVALID, INVALID, 1445, +}; + +static const uint16_t ud_itab__37[] = { + /* 0 */ GROUP(38), GROUP(39), +}; + +static const uint16_t ud_itab__38[] = { + /* 0 */ 882, INVALID, 1567, 878, +}; + +static const uint16_t ud_itab__39[] = { + /* 0 */ 886, INVALID, 1565, INVALID, +}; + +static const uint16_t ud_itab__40[] = { + /* 0 */ 884, INVALID, INVALID, 880, +}; + +static const uint16_t ud_itab__41[] = { + /* 0 */ 1127, 1128, 1129, 1130, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__42[] = { + /* 0 */ 862, INVALID, INVALID, 858, +}; + +static const uint16_t ud_itab__43[] = { + /* 0 */ 864, INVALID, INVALID, 860, +}; + +static const uint16_t ud_itab__44[] = { + /* 0 */ 141, 152, 154, 142, +}; + +static const uint16_t ud_itab__45[] = { + /* 0 */ 907, INVALID, INVALID, 905, +}; + +static const uint16_t ud_itab__46[] = { + /* 0 */ 165, 166, 168, 162, +}; + +static const uint16_t ud_itab__47[] = { + /* 0 */ 147, 148, 158, 138, +}; + +static const uint16_t ud_itab__48[] = { + /* 0 */ 1442, INVALID, INVALID, 1440, +}; + +static const uint16_t ud_itab__49[] = { + /* 0 */ 129, INVALID, INVALID, 127, +}; + +static const uint16_t ud_itab__50[] = { + /* 0 */ 1427, GROUP(51), +}; + +static const uint16_t ud_itab__51[] = { + /* 0 */ INVALID, 1428, INVALID, +}; + +static const uint16_t ud_itab__52[] = { + /* 0 */ 1429, GROUP(53), +}; + +static const uint16_t ud_itab__53[] = { + /* 0 */ INVALID, 1430, INVALID, +}; + +static const uint16_t ud_itab__54[] = { + /* 0 */ GROUP(67), GROUP(68), GROUP(63), GROUP(64), + /* 4 */ GROUP(65), GROUP(66), GROUP(86), GROUP(90), + /* 8 */ GROUP(69), GROUP(70), GROUP(71), GROUP(72), + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ GROUP(73), INVALID, INVALID, INVALID, + /* 14 */ GROUP(75), GROUP(76), INVALID, GROUP(77), + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ GROUP(78), GROUP(79), GROUP(80), INVALID, + /* 20 */ GROUP(81), GROUP(82), GROUP(83), GROUP(84), + /* 24 */ GROUP(85), GROUP(108), INVALID, INVALID, + /* 28 */ GROUP(87), GROUP(88), GROUP(89), GROUP(74), + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ GROUP(91), GROUP(92), GROUP(93), GROUP(94), + /* 34 */ GROUP(95), GROUP(96), INVALID, GROUP(97), + /* 38 */ GROUP(98), GROUP(99), GROUP(100), GROUP(101), + /* 3c */ GROUP(102), GROUP(103), GROUP(104), GROUP(105), + /* 40 */ GROUP(106), GROUP(107), INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ GROUP(55), GROUP(59), INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, GROUP(109), + /* dc */ GROUP(110), GROUP(111), GROUP(112), GROUP(113), + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ GROUP(114), GROUP(115), INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__55[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(56), +}; + +static const uint16_t ud_itab__56[] = { + /* 0 */ GROUP(57), GROUP(58), +}; + +static const uint16_t ud_itab__57[] = { + /* 0 */ INVALID, 717, INVALID, +}; + +static const uint16_t ud_itab__58[] = { + /* 0 */ INVALID, 718, INVALID, +}; + +static const uint16_t ud_itab__59[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(60), +}; + +static const uint16_t ud_itab__60[] = { + /* 0 */ GROUP(61), GROUP(62), +}; + +static const uint16_t ud_itab__61[] = { + /* 0 */ INVALID, 721, INVALID, +}; + +static const uint16_t ud_itab__62[] = { + /* 0 */ INVALID, 722, INVALID, +}; + +static const uint16_t ud_itab__63[] = { + /* 0 */ 1588, INVALID, INVALID, 1589, +}; + +static const uint16_t ud_itab__64[] = { + /* 0 */ 1591, INVALID, INVALID, 1592, +}; + +static const uint16_t ud_itab__65[] = { + /* 0 */ 1594, INVALID, INVALID, 1595, +}; + +static const uint16_t ud_itab__66[] = { + /* 0 */ 1597, INVALID, INVALID, 1598, +}; + +static const uint16_t ud_itab__67[] = { + /* 0 */ 1582, INVALID, INVALID, 1583, +}; + +static const uint16_t ud_itab__68[] = { + /* 0 */ 1585, INVALID, INVALID, 1586, +}; + +static const uint16_t ud_itab__69[] = { + /* 0 */ 1606, INVALID, INVALID, 1607, +}; + +static const uint16_t ud_itab__70[] = { + /* 0 */ 1612, INVALID, INVALID, 1613, +}; + +static const uint16_t ud_itab__71[] = { + /* 0 */ 1609, INVALID, INVALID, 1610, +}; + +static const uint16_t ud_itab__72[] = { + /* 0 */ 1615, INVALID, INVALID, 1616, +}; + +static const uint16_t ud_itab__73[] = { + /* 0 */ INVALID, INVALID, INVALID, 1621, +}; + +static const uint16_t ud_itab__74[] = { + /* 0 */ INVALID, INVALID, INVALID, 1683, +}; + +static const uint16_t ud_itab__75[] = { + /* 0 */ INVALID, INVALID, INVALID, 1657, +}; + +static const uint16_t ud_itab__76[] = { + /* 0 */ INVALID, INVALID, INVALID, 1656, +}; + +static const uint16_t ud_itab__77[] = { + /* 0 */ INVALID, INVALID, INVALID, 1711, +}; + +static const uint16_t ud_itab__78[] = { + /* 0 */ 1573, INVALID, INVALID, 1574, +}; + +static const uint16_t ud_itab__79[] = { + /* 0 */ 1576, INVALID, INVALID, 1577, +}; + +static const uint16_t ud_itab__80[] = { + /* 0 */ 1579, INVALID, INVALID, 1580, +}; + +static const uint16_t ud_itab__81[] = { + /* 0 */ INVALID, INVALID, INVALID, 1685, +}; + +static const uint16_t ud_itab__82[] = { + /* 0 */ INVALID, INVALID, INVALID, 1687, +}; + +static const uint16_t ud_itab__83[] = { + /* 0 */ INVALID, INVALID, INVALID, 1689, +}; + +static const uint16_t ud_itab__84[] = { + /* 0 */ INVALID, INVALID, INVALID, 1691, +}; + +static const uint16_t ud_itab__85[] = { + /* 0 */ INVALID, INVALID, INVALID, 1693, +}; + +static const uint16_t ud_itab__86[] = { + /* 0 */ 1600, INVALID, INVALID, 1601, +}; + +static const uint16_t ud_itab__87[] = { + /* 0 */ INVALID, INVALID, INVALID, 1622, +}; + +static const uint16_t ud_itab__88[] = { + /* 0 */ INVALID, INVALID, INVALID, 1708, +}; + +static const uint16_t ud_itab__89[] = { + /* 0 */ INVALID, INVALID, INVALID, 1681, +}; + +static const uint16_t ud_itab__90[] = { + /* 0 */ 1603, INVALID, INVALID, 1604, +}; + +static const uint16_t ud_itab__91[] = { + /* 0 */ INVALID, INVALID, INVALID, 1696, +}; + +static const uint16_t ud_itab__92[] = { + /* 0 */ INVALID, INVALID, INVALID, 1698, +}; + +static const uint16_t ud_itab__93[] = { + /* 0 */ INVALID, INVALID, INVALID, 1700, +}; + +static const uint16_t ud_itab__94[] = { + /* 0 */ INVALID, INVALID, INVALID, 1702, +}; + +static const uint16_t ud_itab__95[] = { + /* 0 */ INVALID, INVALID, INVALID, 1704, +}; + +static const uint16_t ud_itab__96[] = { + /* 0 */ INVALID, INVALID, INVALID, 1706, +}; + +static const uint16_t ud_itab__97[] = { + /* 0 */ INVALID, INVALID, INVALID, 1717, +}; + +static const uint16_t ud_itab__98[] = { + /* 0 */ INVALID, INVALID, INVALID, 1624, +}; + +static const uint16_t ud_itab__99[] = { + /* 0 */ INVALID, INVALID, INVALID, 1626, +}; + +static const uint16_t ud_itab__100[] = { + /* 0 */ INVALID, INVALID, INVALID, 1628, +}; + +static const uint16_t ud_itab__101[] = { + /* 0 */ INVALID, INVALID, INVALID, 1630, +}; + +static const uint16_t ud_itab__102[] = { + /* 0 */ INVALID, INVALID, INVALID, 1632, +}; + +static const uint16_t ud_itab__103[] = { + /* 0 */ INVALID, INVALID, INVALID, 1634, +}; + +static const uint16_t ud_itab__104[] = { + /* 0 */ INVALID, INVALID, INVALID, 1638, +}; + +static const uint16_t ud_itab__105[] = { + /* 0 */ INVALID, INVALID, INVALID, 1636, +}; + +static const uint16_t ud_itab__106[] = { + /* 0 */ INVALID, INVALID, INVALID, 1640, +}; + +static const uint16_t ud_itab__107[] = { + /* 0 */ INVALID, INVALID, INVALID, 1642, +}; + +static const uint16_t ud_itab__108[] = { + /* 0 */ INVALID, INVALID, INVALID, 1695, +}; + +static const uint16_t ud_itab__109[] = { + /* 0 */ INVALID, INVALID, INVALID, 45, +}; + +static const uint16_t ud_itab__110[] = { + /* 0 */ INVALID, INVALID, INVALID, 41, +}; + +static const uint16_t ud_itab__111[] = { + /* 0 */ INVALID, INVALID, INVALID, 43, +}; + +static const uint16_t ud_itab__112[] = { + /* 0 */ INVALID, INVALID, INVALID, 37, +}; + +static const uint16_t ud_itab__113[] = { + /* 0 */ INVALID, INVALID, INVALID, 39, +}; + +static const uint16_t ud_itab__114[] = { + /* 0 */ 1723, 1725, INVALID, INVALID, +}; + +static const uint16_t ud_itab__115[] = { + /* 0 */ 1724, 1726, INVALID, INVALID, +}; + +static const uint16_t ud_itab__116[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ GROUP(117), GROUP(118), GROUP(119), GROUP(120), + /* c */ GROUP(121), GROUP(122), GROUP(123), GROUP(124), + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ GROUP(125), GROUP(126), GROUP(127), GROUP(129), + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ GROUP(130), GROUP(131), GROUP(132), INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ GROUP(134), GROUP(135), GROUP(136), INVALID, + /* 44 */ GROUP(137), INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ GROUP(139), GROUP(140), GROUP(141), GROUP(142), + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, GROUP(138), + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__117[] = { + /* 0 */ INVALID, INVALID, INVALID, 1644, +}; + +static const uint16_t ud_itab__118[] = { + /* 0 */ INVALID, INVALID, INVALID, 1646, +}; + +static const uint16_t ud_itab__119[] = { + /* 0 */ INVALID, INVALID, INVALID, 1648, +}; + +static const uint16_t ud_itab__120[] = { + /* 0 */ INVALID, INVALID, INVALID, 1650, +}; + +static const uint16_t ud_itab__121[] = { + /* 0 */ INVALID, INVALID, INVALID, 1654, +}; + +static const uint16_t ud_itab__122[] = { + /* 0 */ INVALID, INVALID, INVALID, 1652, +}; + +static const uint16_t ud_itab__123[] = { + /* 0 */ INVALID, INVALID, INVALID, 1677, +}; + +static const uint16_t ud_itab__124[] = { + /* 0 */ 1618, INVALID, INVALID, 1619, +}; + +static const uint16_t ud_itab__125[] = { + /* 0 */ INVALID, INVALID, INVALID, 1045, +}; + +static const uint16_t ud_itab__126[] = { + /* 0 */ INVALID, INVALID, INVALID, 1056, +}; + +static const uint16_t ud_itab__127[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(128), +}; + +static const uint16_t ud_itab__128[] = { + /* 0 */ 1047, 1049, 1051, +}; + +static const uint16_t ud_itab__129[] = { + /* 0 */ INVALID, INVALID, INVALID, 201, +}; + +static const uint16_t ud_itab__130[] = { + /* 0 */ INVALID, INVALID, INVALID, 1058, +}; + +static const uint16_t ud_itab__131[] = { + /* 0 */ INVALID, INVALID, INVALID, 1557, +}; + +static const uint16_t ud_itab__132[] = { + /* 0 */ INVALID, INVALID, INVALID, GROUP(133), +}; + +static const uint16_t ud_itab__133[] = { + /* 0 */ 1062, 1063, 1064, +}; + +static const uint16_t ud_itab__134[] = { + /* 0 */ INVALID, INVALID, INVALID, 197, +}; + +static const uint16_t ud_itab__135[] = { + /* 0 */ INVALID, INVALID, INVALID, 195, +}; + +static const uint16_t ud_itab__136[] = { + /* 0 */ INVALID, INVALID, INVALID, 1679, +}; + +static const uint16_t ud_itab__137[] = { + /* 0 */ INVALID, INVALID, INVALID, 1512, +}; + +static const uint16_t ud_itab__138[] = { + /* 0 */ INVALID, INVALID, INVALID, 47, +}; + +static const uint16_t ud_itab__139[] = { + /* 0 */ INVALID, INVALID, INVALID, 1715, +}; + +static const uint16_t ud_itab__140[] = { + /* 0 */ INVALID, INVALID, INVALID, 1713, +}; + +static const uint16_t ud_itab__141[] = { + /* 0 */ INVALID, INVALID, INVALID, 1721, +}; + +static const uint16_t ud_itab__142[] = { + /* 0 */ INVALID, INVALID, INVALID, 1719, +}; + +static const uint16_t ud_itab__143[] = { + /* 0 */ 900, INVALID, INVALID, 898, +}; + +static const uint16_t ud_itab__144[] = { + /* 0 */ 1387, 1391, 1393, 1389, +}; + +static const uint16_t ud_itab__145[] = { + /* 0 */ 1306, INVALID, 1308, INVALID, +}; + +static const uint16_t ud_itab__146[] = { + /* 0 */ 1291, INVALID, 1293, INVALID, +}; + +static const uint16_t ud_itab__147[] = { + /* 0 */ 61, INVALID, INVALID, 59, +}; + +static const uint16_t ud_itab__148[] = { + /* 0 */ 65, INVALID, INVALID, 63, +}; + +static const uint16_t ud_itab__149[] = { + /* 0 */ 976, INVALID, INVALID, 974, +}; + +static const uint16_t ud_itab__150[] = { + /* 0 */ 1499, INVALID, INVALID, 1497, +}; + +static const uint16_t ud_itab__151[] = { + /* 0 */ 27, 29, 31, 25, +}; + +static const uint16_t ud_itab__152[] = { + /* 0 */ 946, 948, 950, 944, +}; + +static const uint16_t ud_itab__153[] = { + /* 0 */ 145, 150, 156, 139, +}; + +static const uint16_t ud_itab__154[] = { + /* 0 */ 134, INVALID, 163, 143, +}; + +static const uint16_t ud_itab__155[] = { + /* 0 */ 1419, 1421, 1423, 1417, +}; + +static const uint16_t ud_itab__156[] = { + /* 0 */ 818, 820, 822, 816, +}; + +static const uint16_t ud_itab__157[] = { + /* 0 */ 189, 191, 193, 187, +}; + +static const uint16_t ud_itab__158[] = { + /* 0 */ 802, 804, 806, 800, +}; + +static const uint16_t ud_itab__159[] = { + /* 0 */ 1209, INVALID, INVALID, 1207, +}; + +static const uint16_t ud_itab__160[] = { + /* 0 */ 1212, INVALID, INVALID, 1210, +}; + +static const uint16_t ud_itab__161[] = { + /* 0 */ 1215, INVALID, INVALID, 1213, +}; + +static const uint16_t ud_itab__162[] = { + /* 0 */ 987, INVALID, INVALID, 985, +}; + +static const uint16_t ud_itab__163[] = { + /* 0 */ 1038, INVALID, INVALID, 1036, +}; + +static const uint16_t ud_itab__164[] = { + /* 0 */ 1041, INVALID, INVALID, 1039, +}; + +static const uint16_t ud_itab__165[] = { + /* 0 */ 1044, INVALID, INVALID, 1042, +}; + +static const uint16_t ud_itab__166[] = { + /* 0 */ 993, INVALID, INVALID, 991, +}; + +static const uint16_t ud_itab__167[] = { + /* 0 */ 1200, INVALID, INVALID, 1198, +}; + +static const uint16_t ud_itab__168[] = { + /* 0 */ 1203, INVALID, INVALID, 1201, +}; + +static const uint16_t ud_itab__169[] = { + /* 0 */ 1206, INVALID, INVALID, 1204, +}; + +static const uint16_t ud_itab__170[] = { + /* 0 */ 990, INVALID, INVALID, 988, +}; + +static const uint16_t ud_itab__171[] = { + /* 0 */ INVALID, INVALID, INVALID, 1547, +}; + +static const uint16_t ud_itab__172[] = { + /* 0 */ INVALID, INVALID, INVALID, 1545, +}; + +static const uint16_t ud_itab__173[] = { + /* 0 */ GROUP(174), INVALID, INVALID, GROUP(175), +}; + +static const uint16_t ud_itab__174[] = { + /* 0 */ 866, 867, 910, +}; + +static const uint16_t ud_itab__175[] = { + /* 0 */ 868, 870, 911, +}; + +static const uint16_t ud_itab__176[] = { + /* 0 */ 920, INVALID, 1522, 1517, +}; + +static const uint16_t ud_itab__177[] = { + /* 0 */ 1134, 1537, 1535, 1539, +}; + +static const uint16_t ud_itab__178[] = { + /* 0 */ INVALID, INVALID, GROUP(179), INVALID, + /* 4 */ GROUP(180), INVALID, GROUP(181), INVALID, +}; + +static const uint16_t ud_itab__179[] = { + /* 0 */ 1159, INVALID, INVALID, 1163, +}; + +static const uint16_t ud_itab__180[] = { + /* 0 */ 1152, INVALID, INVALID, 1150, +}; + +static const uint16_t ud_itab__181[] = { + /* 0 */ 1138, INVALID, INVALID, 1137, +}; + +static const uint16_t ud_itab__182[] = { + /* 0 */ INVALID, INVALID, GROUP(183), INVALID, + /* 4 */ GROUP(184), INVALID, GROUP(185), INVALID, +}; + +static const uint16_t ud_itab__183[] = { + /* 0 */ 1165, INVALID, INVALID, 1169, +}; + +static const uint16_t ud_itab__184[] = { + /* 0 */ 1153, INVALID, INVALID, 1157, +}; + +static const uint16_t ud_itab__185[] = { + /* 0 */ 1142, INVALID, INVALID, 1141, +}; + +static const uint16_t ud_itab__186[] = { + /* 0 */ INVALID, INVALID, GROUP(187), GROUP(188), + /* 4 */ INVALID, INVALID, GROUP(189), GROUP(190), +}; + +static const uint16_t ud_itab__187[] = { + /* 0 */ 1171, INVALID, INVALID, 1175, +}; + +static const uint16_t ud_itab__188[] = { + /* 0 */ INVALID, INVALID, INVALID, 1543, +}; + +static const uint16_t ud_itab__189[] = { + /* 0 */ 1146, INVALID, INVALID, 1145, +}; + +static const uint16_t ud_itab__190[] = { + /* 0 */ INVALID, INVALID, INVALID, 1541, +}; + +static const uint16_t ud_itab__191[] = { + /* 0 */ 1027, INVALID, INVALID, 1028, +}; + +static const uint16_t ud_itab__192[] = { + /* 0 */ 1030, INVALID, INVALID, 1031, +}; + +static const uint16_t ud_itab__193[] = { + /* 0 */ 1033, INVALID, INVALID, 1034, +}; + +static const uint16_t ud_itab__194[] = { + /* 0 */ INVALID, 1464, INVALID, +}; + +static const uint16_t ud_itab__195[] = { + /* 0 */ INVALID, 1465, INVALID, +}; + +static const uint16_t ud_itab__196[] = { + /* 0 */ INVALID, 1551, INVALID, 1549, +}; + +static const uint16_t ud_itab__197[] = { + /* 0 */ INVALID, 1555, INVALID, 1553, +}; + +static const uint16_t ud_itab__198[] = { + /* 0 */ GROUP(199), INVALID, 916, GROUP(200), +}; + +static const uint16_t ud_itab__199[] = { + /* 0 */ 872, 873, 913, +}; + +static const uint16_t ud_itab__200[] = { + /* 0 */ 874, 876, 914, +}; + +static const uint16_t ud_itab__201[] = { + /* 0 */ 921, INVALID, 1524, 1515, +}; + +static const uint16_t ud_itab__202[] = { + /* 0 */ INVALID, GROUP(203), +}; + +static const uint16_t ud_itab__203[] = { + /* 0 */ GROUP(204), GROUP(205), GROUP(206), INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__204[] = { + /* 0 */ 825, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__205[] = { + /* 0 */ 1509, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__206[] = { + /* 0 */ 1510, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__207[] = { + /* 0 */ INVALID, GROUP(208), +}; + +static const uint16_t ud_itab__208[] = { + /* 0 */ GROUP(209), GROUP(210), GROUP(211), GROUP(212), + /* 4 */ GROUP(213), GROUP(214), INVALID, INVALID, +}; + +static const uint16_t ud_itab__209[] = { + /* 0 */ 1511, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__210[] = { + /* 0 */ 1501, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__211[] = { + /* 0 */ 1502, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__212[] = { + /* 0 */ 1503, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__213[] = { + /* 0 */ 1504, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__214[] = { + /* 0 */ 1505, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__215[] = { + /* 0 */ GROUP(216), GROUP(217), +}; + +static const uint16_t ud_itab__216[] = { + /* 0 */ 683, 682, 768, 1400, + /* 4 */ 1507, 1506, INVALID, 79, +}; + +static const uint16_t ud_itab__217[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, GROUP(218), GROUP(219), GROUP(220), +}; + +static const uint16_t ud_itab__218[] = { + /* 0 */ 777, 778, 779, 780, + /* 4 */ 781, 782, 783, 784, +}; + +static const uint16_t ud_itab__219[] = { + /* 0 */ 808, 809, 810, 811, + /* 4 */ 812, 813, 814, 815, +}; + +static const uint16_t ud_itab__220[] = { + /* 0 */ 1366, 1367, 1368, 1369, + /* 4 */ 1370, 1371, 1372, 1373, +}; + +static const uint16_t ud_itab__221[] = { + /* 0 */ INVALID, INVALID, 1710, INVALID, +}; + +static const uint16_t ud_itab__222[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ 1669, 1676, 1674, 1672, +}; + +static const uint16_t ud_itab__223[] = { + /* 0 */ 112, 117, 120, 110, +}; + +static const uint16_t ud_itab__224[] = { + /* 0 */ 1059, INVALID, INVALID, 1060, +}; + +static const uint16_t ud_itab__225[] = { + /* 0 */ 1055, INVALID, INVALID, 1053, +}; + +static const uint16_t ud_itab__226[] = { + /* 0 */ 1381, INVALID, INVALID, 1379, +}; + +static const uint16_t ud_itab__227[] = { + /* 0 */ GROUP(228), GROUP(235), +}; + +static const uint16_t ud_itab__228[] = { + /* 0 */ INVALID, GROUP(229), INVALID, INVALID, + /* 4 */ INVALID, INVALID, GROUP(230), GROUP(234), +}; + +static const uint16_t ud_itab__229[] = { + /* 0 */ 124, 125, 126, +}; + +static const uint16_t ud_itab__230[] = { + /* 0 */ GROUP(231), INVALID, GROUP(232), GROUP(233), +}; + +static const uint16_t ud_itab__231[] = { + /* 0 */ INVALID, 1459, INVALID, +}; + +static const uint16_t ud_itab__232[] = { + /* 0 */ INVALID, 1458, INVALID, +}; + +static const uint16_t ud_itab__233[] = { + /* 0 */ INVALID, 1457, INVALID, +}; + +static const uint16_t ud_itab__234[] = { + /* 0 */ INVALID, 1460, INVALID, +}; + +static const uint16_t ud_itab__235[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, 1456, INVALID, +}; + +static const uint16_t ud_itab__236[] = { + /* 0 */ INVALID, 35, INVALID, 33, +}; + +static const uint16_t ud_itab__237[] = { + /* 0 */ 1160, INVALID, INVALID, 1161, +}; + +static const uint16_t ud_itab__238[] = { + /* 0 */ 1166, INVALID, INVALID, 1167, +}; + +static const uint16_t ud_itab__239[] = { + /* 0 */ 1172, INVALID, INVALID, 1173, +}; + +static const uint16_t ud_itab__240[] = { + /* 0 */ 1527, INVALID, INVALID, 1528, +}; + +static const uint16_t ud_itab__241[] = { + /* 0 */ 1093, INVALID, INVALID, 1094, +}; + +static const uint16_t ud_itab__242[] = { + /* 0 */ INVALID, 1521, 1526, 918, +}; + +static const uint16_t ud_itab__243[] = { + /* 0 */ 1086, INVALID, INVALID, 1084, +}; + +static const uint16_t ud_itab__244[] = { + /* 0 */ 1192, INVALID, INVALID, 1193, +}; + +static const uint16_t ud_itab__245[] = { + /* 0 */ 1195, INVALID, INVALID, 1196, +}; + +static const uint16_t ud_itab__246[] = { + /* 0 */ 1083, INVALID, INVALID, 1081, +}; + +static const uint16_t ud_itab__247[] = { + /* 0 */ 1017, INVALID, INVALID, 1015, +}; + +static const uint16_t ud_itab__248[] = { + /* 0 */ 1009, INVALID, INVALID, 1010, +}; + +static const uint16_t ud_itab__249[] = { + /* 0 */ 1012, INVALID, INVALID, 1013, +}; + +static const uint16_t ud_itab__250[] = { + /* 0 */ 1075, INVALID, INVALID, 1076, +}; + +static const uint16_t ud_itab__251[] = { + /* 0 */ 1020, INVALID, INVALID, 1018, +}; + +static const uint16_t ud_itab__252[] = { + /* 0 */ 1023, INVALID, INVALID, 1021, +}; + +static const uint16_t ud_itab__253[] = { + /* 0 */ 1147, INVALID, INVALID, 1148, +}; + +static const uint16_t ud_itab__254[] = { + /* 0 */ 1156, INVALID, INVALID, 1154, +}; + +static const uint16_t ud_itab__255[] = { + /* 0 */ 1026, INVALID, INVALID, 1024, +}; + +static const uint16_t ud_itab__256[] = { + /* 0 */ 1087, INVALID, INVALID, 1088, +}; + +static const uint16_t ud_itab__257[] = { + /* 0 */ 1092, INVALID, INVALID, 1090, +}; + +static const uint16_t ud_itab__258[] = { + /* 0 */ INVALID, 136, 132, 160, +}; + +static const uint16_t ud_itab__259[] = { + /* 0 */ 909, INVALID, INVALID, 902, +}; + +static const uint16_t ud_itab__260[] = { + /* 0 */ 1186, INVALID, INVALID, 1187, +}; + +static const uint16_t ud_itab__261[] = { + /* 0 */ 1189, INVALID, INVALID, 1190, +}; + +static const uint16_t ud_itab__262[] = { + /* 0 */ 1080, INVALID, INVALID, 1078, +}; + +static const uint16_t ud_itab__263[] = { + /* 0 */ 1118, INVALID, INVALID, 1116, +}; + +static const uint16_t ud_itab__264[] = { + /* 0 */ 1003, INVALID, INVALID, 1004, +}; + +static const uint16_t ud_itab__265[] = { + /* 0 */ 1006, INVALID, INVALID, 1007, +}; + +static const uint16_t ud_itab__266[] = { + /* 0 */ 1074, INVALID, INVALID, 1072, +}; + +static const uint16_t ud_itab__267[] = { + /* 0 */ 1266, INVALID, INVALID, 1264, +}; + +static const uint16_t ud_itab__268[] = { + /* 0 */ INVALID, 1559, INVALID, INVALID, +}; + +static const uint16_t ud_itab__269[] = { + /* 0 */ 1136, INVALID, INVALID, 1135, +}; + +static const uint16_t ud_itab__270[] = { + /* 0 */ 1140, INVALID, INVALID, 1139, +}; + +static const uint16_t ud_itab__271[] = { + /* 0 */ 1144, INVALID, INVALID, 1143, +}; + +static const uint16_t ud_itab__272[] = { + /* 0 */ 1533, INVALID, INVALID, 1534, +}; + +static const uint16_t ud_itab__273[] = { + /* 0 */ 1069, INVALID, INVALID, 1070, +}; + +static const uint16_t ud_itab__274[] = { + /* 0 */ 1133, INVALID, INVALID, 1131, +}; + +static const uint16_t ud_itab__275[] = { + /* 0 */ INVALID, GROUP(276), +}; + +static const uint16_t ud_itab__276[] = { + /* 0 */ 799, INVALID, INVALID, 1519, +}; + +static const uint16_t ud_itab__277[] = { + /* 0 */ 1179, INVALID, INVALID, 1177, +}; + +static const uint16_t ud_itab__278[] = { + /* 0 */ 1182, INVALID, INVALID, 1180, +}; + +static const uint16_t ud_itab__279[] = { + /* 0 */ 1183, INVALID, INVALID, 1184, +}; + +static const uint16_t ud_itab__280[] = { + /* 0 */ 1532, INVALID, INVALID, 1530, +}; + +static const uint16_t ud_itab__281[] = { + /* 0 */ 996, INVALID, INVALID, 994, +}; + +static const uint16_t ud_itab__282[] = { + /* 0 */ 997, INVALID, INVALID, 998, +}; + +static const uint16_t ud_itab__283[] = { + /* 0 */ 1000, INVALID, INVALID, 1001, +}; + +static const uint16_t ud_itab__284[] = { + /* 0 */ 1242, INVALID, +}; + +static const uint16_t ud_itab__285[] = { + /* 0 */ 1097, INVALID, +}; + +static const uint16_t ud_itab__286[] = { + /* 0 */ 1243, INVALID, +}; + +static const uint16_t ud_itab__287[] = { + /* 0 */ 1098, INVALID, +}; + +static const uint16_t ud_itab__288[] = { + /* 0 */ 173, INVALID, +}; + +static const uint16_t ud_itab__289[] = { + /* 0 */ 174, INVALID, +}; + +static const uint16_t ud_itab__290[] = { + /* 0 */ 1, INVALID, +}; + +static const uint16_t ud_itab__291[] = { + /* 0 */ 4, INVALID, +}; + +static const uint16_t ud_itab__292[] = { + /* 0 */ GROUP(293), GROUP(294), INVALID, +}; + +static const uint16_t ud_itab__293[] = { + /* 0 */ 1257, INVALID, +}; + +static const uint16_t ud_itab__294[] = { + /* 0 */ 1258, INVALID, +}; + +static const uint16_t ud_itab__295[] = { + /* 0 */ GROUP(296), GROUP(297), INVALID, +}; + +static const uint16_t ud_itab__296[] = { + /* 0 */ 1110, INVALID, +}; + +static const uint16_t ud_itab__297[] = { + /* 0 */ 1111, INVALID, +}; + +static const uint16_t ud_itab__298[] = { + /* 0 */ 1658, INVALID, +}; + +static const uint16_t ud_itab__299[] = { + /* 0 */ 67, 68, +}; + +static const uint16_t ud_itab__300[] = { + /* 0 */ 710, 711, INVALID, +}; + +static const uint16_t ud_itab__301[] = { + /* 0 */ 983, 984, INVALID, +}; + +static const uint16_t ud_itab__302[] = { + /* 0 */ 21, 970, 11, 1342, + /* 4 */ 55, 1413, 1493, 106, +}; + +static const uint16_t ud_itab__303[] = { + /* 0 */ 23, 971, 13, 1343, + /* 4 */ 57, 1414, 1494, 108, +}; + +static const uint16_t ud_itab__304[] = { + /* 0 */ GROUP(305), GROUP(306), GROUP(307), GROUP(308), + /* 4 */ GROUP(309), GROUP(310), GROUP(311), GROUP(312), +}; + +static const uint16_t ud_itab__305[] = { + /* 0 */ 22, INVALID, +}; + +static const uint16_t ud_itab__306[] = { + /* 0 */ 972, INVALID, +}; + +static const uint16_t ud_itab__307[] = { + /* 0 */ 12, INVALID, +}; + +static const uint16_t ud_itab__308[] = { + /* 0 */ 1344, INVALID, +}; + +static const uint16_t ud_itab__309[] = { + /* 0 */ 56, INVALID, +}; + +static const uint16_t ud_itab__310[] = { + /* 0 */ 1415, INVALID, +}; + +static const uint16_t ud_itab__311[] = { + /* 0 */ 1495, INVALID, +}; + +static const uint16_t ud_itab__312[] = { + /* 0 */ 107, INVALID, +}; + +static const uint16_t ud_itab__313[] = { + /* 0 */ 24, 973, 14, 1345, + /* 4 */ 58, 1416, 1496, 109, +}; + +static const uint16_t ud_itab__314[] = { + /* 0 */ 1109, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__315[] = { + /* 0 */ 74, 75, 76, +}; + +static const uint16_t ud_itab__316[] = { + /* 0 */ 170, 171, 172, +}; + +static const uint16_t ud_itab__317[] = { + /* 0 */ 73, INVALID, +}; + +static const uint16_t ud_itab__318[] = { + /* 0 */ GROUP(319), GROUP(320), GROUP(321), +}; + +static const uint16_t ud_itab__319[] = { + /* 0 */ 1259, 1260, +}; + +static const uint16_t ud_itab__320[] = { + /* 0 */ 1261, 1262, +}; + +static const uint16_t ud_itab__321[] = { + /* 0 */ INVALID, 1263, +}; + +static const uint16_t ud_itab__322[] = { + /* 0 */ GROUP(323), GROUP(324), GROUP(325), +}; + +static const uint16_t ud_itab__323[] = { + /* 0 */ 1112, INVALID, +}; + +static const uint16_t ud_itab__324[] = { + /* 0 */ 1113, 1114, +}; + +static const uint16_t ud_itab__325[] = { + /* 0 */ INVALID, 1115, +}; + +static const uint16_t ud_itab__326[] = { + /* 0 */ 923, 924, 927, +}; + +static const uint16_t ud_itab__327[] = { + /* 0 */ 115, 116, 119, +}; + +static const uint16_t ud_itab__328[] = { + /* 0 */ 1403, 1404, 1405, +}; + +static const uint16_t ud_itab__329[] = { + /* 0 */ 791, 792, 793, +}; + +static const uint16_t ud_itab__330[] = { + /* 0 */ 1347, 1348, 1349, +}; + +static const uint16_t ud_itab__331[] = { + /* 0 */ 1279, 1286, 1267, 1275, + /* 4 */ 1327, 1334, 1318, 1313, +}; + +static const uint16_t ud_itab__332[] = { + /* 0 */ 1284, 1287, 1268, 1274, + /* 4 */ 1323, 1330, 1319, 1315, +}; + +static const uint16_t ud_itab__333[] = { + /* 0 */ GROUP(334), GROUP(335), INVALID, INVALID, + /* 4 */ INVALID, GROUP(341), GROUP(357), GROUP(369), + /* 8 */ INVALID, GROUP(394), INVALID, INVALID, + /* c */ INVALID, GROUP(399), INVALID, INVALID, +}; + +static const uint16_t ud_itab__334[] = { + /* 0 */ 771, INVALID, +}; + +static const uint16_t ud_itab__335[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ 937, 939, GROUP(336), 895, + /* 14 */ 1450, 1448, GROUP(337), 885, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ 863, 865, INVALID, 908, + /* 2c */ INVALID, INVALID, 1443, 130, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ 901, 1388, 1307, 1292, + /* 54 */ 62, 66, 977, 1500, + /* 58 */ 28, 947, 146, 135, + /* 5c */ 1420, 819, 190, 803, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, GROUP(340), + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, GROUP(338), INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 113, INVALID, + /* c4 */ INVALID, INVALID, 1382, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__336[] = { + /* 0 */ 893, 897, +}; + +static const uint16_t ud_itab__337[] = { + /* 0 */ 883, 887, +}; + +static const uint16_t ud_itab__338[] = { + /* 0 */ GROUP(339), INVALID, +}; + +static const uint16_t ud_itab__339[] = { + /* 0 */ INVALID, INVALID, INVALID, 1401, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__340[] = { + /* 0 */ 1742, 1743, +}; + +static const uint16_t ud_itab__341[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ 933, 935, GROUP(342), 891, + /* 14 */ 1452, 1446, GROUP(343), 881, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ 859, 861, INVALID, 906, + /* 2c */ INVALID, INVALID, 1441, 128, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ 899, 1390, INVALID, INVALID, + /* 54 */ 60, 64, 975, 1498, + /* 58 */ 26, 945, 140, 144, + /* 5c */ 1418, 817, 188, 801, + /* 60 */ 1208, 1211, 1214, 986, + /* 64 */ 1037, 1040, 1043, 992, + /* 68 */ 1199, 1202, 1205, 989, + /* 6c */ 1548, 1546, GROUP(344), 1518, + /* 70 */ 1540, GROUP(345), GROUP(347), GROUP(349), + /* 74 */ 1029, 1032, 1035, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ 1550, 1554, GROUP(351), 1516, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 111, INVALID, + /* c4 */ 1061, 1054, 1380, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ 34, 1162, 1168, 1174, + /* d4 */ 1529, 1095, 919, GROUP(352), + /* d8 */ 1194, 1197, 1082, 1016, + /* dc */ 1011, 1014, 1077, 1019, + /* e0 */ 1022, 1149, 1155, 1025, + /* e4 */ 1089, 1091, 161, 903, + /* e8 */ 1188, 1191, 1079, 1117, + /* ec */ 1005, 1008, 1073, 1265, + /* f0 */ INVALID, GROUP(353), GROUP(354), GROUP(355), + /* f4 */ INVALID, 1071, 1132, GROUP(356), + /* f8 */ 1178, 1181, 1185, 1531, + /* fc */ 995, 999, 1002, INVALID, +}; + +static const uint16_t ud_itab__342[] = { + /* 0 */ 889, INVALID, +}; + +static const uint16_t ud_itab__343[] = { + /* 0 */ 879, INVALID, +}; + +static const uint16_t ud_itab__344[] = { + /* 0 */ 869, 871, 912, +}; + +static const uint16_t ud_itab__345[] = { + /* 0 */ INVALID, INVALID, 1164, INVALID, + /* 4 */ 1151, INVALID, GROUP(346), INVALID, +}; + +static const uint16_t ud_itab__346[] = { + /* 0 */ 1756, INVALID, +}; + +static const uint16_t ud_itab__347[] = { + /* 0 */ INVALID, INVALID, 1170, INVALID, + /* 4 */ 1158, INVALID, GROUP(348), INVALID, +}; + +static const uint16_t ud_itab__348[] = { + /* 0 */ 1758, INVALID, +}; + +static const uint16_t ud_itab__349[] = { + /* 0 */ INVALID, INVALID, 1176, 1544, + /* 4 */ INVALID, INVALID, GROUP(350), 1542, +}; + +static const uint16_t ud_itab__350[] = { + /* 0 */ 1760, INVALID, +}; + +static const uint16_t ud_itab__351[] = { + /* 0 */ 875, 877, 915, +}; + +static const uint16_t ud_itab__352[] = { + /* 0 */ 1085, INVALID, +}; + +static const uint16_t ud_itab__353[] = { + /* 0 */ 1755, INVALID, +}; + +static const uint16_t ud_itab__354[] = { + /* 0 */ 1757, INVALID, +}; + +static const uint16_t ud_itab__355[] = { + /* 0 */ 1759, INVALID, +}; + +static const uint16_t ud_itab__356[] = { + /* 0 */ INVALID, 1520, +}; + +static const uint16_t ud_itab__357[] = { + /* 0 */ 1584, 1587, 1590, 1593, + /* 4 */ 1596, 1599, 1602, 1605, + /* 8 */ 1608, 1614, 1611, 1617, + /* c */ GROUP(358), GROUP(359), GROUP(360), GROUP(361), + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ INVALID, INVALID, INVALID, 1712, + /* 18 */ GROUP(362), GROUP(363), INVALID, INVALID, + /* 1c */ 1575, 1578, 1581, INVALID, + /* 20 */ 1686, 1688, 1690, 1692, + /* 24 */ 1694, INVALID, INVALID, INVALID, + /* 28 */ 1623, 1709, 1682, 1684, + /* 2c */ GROUP(365), GROUP(366), GROUP(367), GROUP(368), + /* 30 */ 1697, 1699, 1701, 1703, + /* 34 */ 1705, 1707, INVALID, 1718, + /* 38 */ 1625, 1627, 1629, 1631, + /* 3c */ 1633, 1635, 1639, 1637, + /* 40 */ 1641, 1643, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, 46, + /* dc */ 42, 44, 38, 40, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__358[] = { + /* 0 */ 1737, INVALID, +}; + +static const uint16_t ud_itab__359[] = { + /* 0 */ 1735, INVALID, +}; + +static const uint16_t ud_itab__360[] = { + /* 0 */ 1740, INVALID, +}; + +static const uint16_t ud_itab__361[] = { + /* 0 */ 1741, INVALID, +}; + +static const uint16_t ud_itab__362[] = { + /* 0 */ 1727, INVALID, +}; + +static const uint16_t ud_itab__363[] = { + /* 0 */ GROUP(364), INVALID, +}; + +static const uint16_t ud_itab__364[] = { + /* 0 */ INVALID, 1728, +}; + +static const uint16_t ud_itab__365[] = { + /* 0 */ 1731, INVALID, +}; + +static const uint16_t ud_itab__366[] = { + /* 0 */ 1733, INVALID, +}; + +static const uint16_t ud_itab__367[] = { + /* 0 */ 1732, INVALID, +}; + +static const uint16_t ud_itab__368[] = { + /* 0 */ 1734, INVALID, +}; + +static const uint16_t ud_itab__369[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ GROUP(370), GROUP(371), GROUP(372), INVALID, + /* 8 */ 1645, 1647, 1649, 1651, + /* c */ 1655, 1653, 1678, 1620, + /* 10 */ INVALID, INVALID, INVALID, INVALID, + /* 14 */ GROUP(374), 1057, GROUP(375), 202, + /* 18 */ GROUP(379), GROUP(381), INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ GROUP(383), 1558, GROUP(385), INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ 198, 196, 1680, INVALID, + /* 44 */ 1513, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, GROUP(391), GROUP(392), + /* 4c */ GROUP(393), INVALID, INVALID, INVALID, + /* 50 */ INVALID, INVALID, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ INVALID, INVALID, INVALID, INVALID, + /* 5c */ INVALID, INVALID, INVALID, INVALID, + /* 60 */ 1716, 1714, 1722, 1720, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ INVALID, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, INVALID, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, 48, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, INVALID, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__370[] = { + /* 0 */ 1738, INVALID, +}; + +static const uint16_t ud_itab__371[] = { + /* 0 */ 1736, INVALID, +}; + +static const uint16_t ud_itab__372[] = { + /* 0 */ GROUP(373), INVALID, +}; + +static const uint16_t ud_itab__373[] = { + /* 0 */ INVALID, 1739, +}; + +static const uint16_t ud_itab__374[] = { + /* 0 */ 1046, INVALID, +}; + +static const uint16_t ud_itab__375[] = { + /* 0 */ GROUP(376), GROUP(377), GROUP(378), +}; + +static const uint16_t ud_itab__376[] = { + /* 0 */ 1048, INVALID, +}; + +static const uint16_t ud_itab__377[] = { + /* 0 */ 1050, INVALID, +}; + +static const uint16_t ud_itab__378[] = { + /* 0 */ INVALID, 1052, +}; + +static const uint16_t ud_itab__379[] = { + /* 0 */ GROUP(380), INVALID, +}; + +static const uint16_t ud_itab__380[] = { + /* 0 */ INVALID, 1730, +}; + +static const uint16_t ud_itab__381[] = { + /* 0 */ GROUP(382), INVALID, +}; + +static const uint16_t ud_itab__382[] = { + /* 0 */ INVALID, 1729, +}; + +static const uint16_t ud_itab__383[] = { + /* 0 */ GROUP(384), INVALID, +}; + +static const uint16_t ud_itab__384[] = { + /* 0 */ 1065, INVALID, +}; + +static const uint16_t ud_itab__385[] = { + /* 0 */ GROUP(386), GROUP(388), +}; + +static const uint16_t ud_itab__386[] = { + /* 0 */ GROUP(387), INVALID, +}; + +static const uint16_t ud_itab__387[] = { + /* 0 */ 1066, INVALID, +}; + +static const uint16_t ud_itab__388[] = { + /* 0 */ GROUP(389), GROUP(390), +}; + +static const uint16_t ud_itab__389[] = { + /* 0 */ 1067, INVALID, +}; + +static const uint16_t ud_itab__390[] = { + /* 0 */ 1068, INVALID, +}; + +static const uint16_t ud_itab__391[] = { + /* 0 */ 1745, INVALID, +}; + +static const uint16_t ud_itab__392[] = { + /* 0 */ 1744, INVALID, +}; + +static const uint16_t ud_itab__393[] = { + /* 0 */ 1754, INVALID, +}; + +static const uint16_t ud_itab__394[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ GROUP(395), GROUP(396), GROUP(397), INVALID, + /* 14 */ INVALID, INVALID, GROUP(398), INVALID, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, 155, INVALID, + /* 2c */ 169, 159, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, 1394, 1309, 1294, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ 32, 951, 157, 164, + /* 5c */ 1424, 823, 194, 807, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, 1523, + /* 70 */ 1536, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ INVALID, INVALID, 917, 1525, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 121, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ INVALID, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, 133, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ INVALID, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__395[] = { + /* 0 */ 1751, 1750, +}; + +static const uint16_t ud_itab__396[] = { + /* 0 */ 1753, 1752, +}; + +static const uint16_t ud_itab__397[] = { + /* 0 */ 1572, 1570, +}; + +static const uint16_t ud_itab__398[] = { + /* 0 */ 1568, 1566, +}; + +static const uint16_t ud_itab__399[] = { + /* 0 */ INVALID, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, + /* 8 */ INVALID, INVALID, INVALID, INVALID, + /* c */ INVALID, INVALID, INVALID, INVALID, + /* 10 */ GROUP(402), GROUP(400), GROUP(401), INVALID, + /* 14 */ INVALID, INVALID, INVALID, INVALID, + /* 18 */ INVALID, INVALID, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, INVALID, 153, INVALID, + /* 2c */ 167, 149, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, + /* 40 */ INVALID, INVALID, INVALID, INVALID, + /* 44 */ INVALID, INVALID, INVALID, INVALID, + /* 48 */ INVALID, INVALID, INVALID, INVALID, + /* 4c */ INVALID, INVALID, INVALID, INVALID, + /* 50 */ INVALID, 1392, INVALID, INVALID, + /* 54 */ INVALID, INVALID, INVALID, INVALID, + /* 58 */ 30, 949, 151, INVALID, + /* 5c */ 1422, 821, 192, 805, + /* 60 */ INVALID, INVALID, INVALID, INVALID, + /* 64 */ INVALID, INVALID, INVALID, INVALID, + /* 68 */ INVALID, INVALID, INVALID, INVALID, + /* 6c */ INVALID, INVALID, INVALID, INVALID, + /* 70 */ 1538, INVALID, INVALID, INVALID, + /* 74 */ INVALID, INVALID, INVALID, INVALID, + /* 78 */ INVALID, INVALID, INVALID, INVALID, + /* 7c */ 1552, 1556, INVALID, INVALID, + /* 80 */ INVALID, INVALID, INVALID, INVALID, + /* 84 */ INVALID, INVALID, INVALID, INVALID, + /* 88 */ INVALID, INVALID, INVALID, INVALID, + /* 8c */ INVALID, INVALID, INVALID, INVALID, + /* 90 */ INVALID, INVALID, INVALID, INVALID, + /* 94 */ INVALID, INVALID, INVALID, INVALID, + /* 98 */ INVALID, INVALID, INVALID, INVALID, + /* 9c */ INVALID, INVALID, INVALID, INVALID, + /* a0 */ INVALID, INVALID, INVALID, INVALID, + /* a4 */ INVALID, INVALID, INVALID, INVALID, + /* a8 */ INVALID, INVALID, INVALID, INVALID, + /* ac */ INVALID, INVALID, INVALID, INVALID, + /* b0 */ INVALID, INVALID, INVALID, INVALID, + /* b4 */ INVALID, INVALID, INVALID, INVALID, + /* b8 */ INVALID, INVALID, INVALID, INVALID, + /* bc */ INVALID, INVALID, INVALID, INVALID, + /* c0 */ INVALID, INVALID, 118, INVALID, + /* c4 */ INVALID, INVALID, INVALID, INVALID, + /* c8 */ INVALID, INVALID, INVALID, INVALID, + /* cc */ INVALID, INVALID, INVALID, INVALID, + /* d0 */ 36, INVALID, INVALID, INVALID, + /* d4 */ INVALID, INVALID, INVALID, INVALID, + /* d8 */ INVALID, INVALID, INVALID, INVALID, + /* dc */ INVALID, INVALID, INVALID, INVALID, + /* e0 */ INVALID, INVALID, INVALID, INVALID, + /* e4 */ INVALID, INVALID, 137, INVALID, + /* e8 */ INVALID, INVALID, INVALID, INVALID, + /* ec */ INVALID, INVALID, INVALID, INVALID, + /* f0 */ 1560, INVALID, INVALID, INVALID, + /* f4 */ INVALID, INVALID, INVALID, INVALID, + /* f8 */ INVALID, INVALID, INVALID, INVALID, + /* fc */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__400[] = { + /* 0 */ 1749, 1748, +}; + +static const uint16_t ud_itab__401[] = { + /* 0 */ 1564, 1562, +}; + +static const uint16_t ud_itab__402[] = { + /* 0 */ 1747, 1746, +}; + +static const uint16_t ud_itab__403[] = { + /* 0 */ GROUP(404), GROUP(335), INVALID, INVALID, + /* 4 */ INVALID, GROUP(341), GROUP(357), GROUP(369), + /* 8 */ INVALID, GROUP(394), INVALID, INVALID, + /* c */ INVALID, GROUP(399), INVALID, INVALID, +}; + +static const uint16_t ud_itab__404[] = { + /* 0 */ 769, INVALID, +}; + +static const uint16_t ud_itab__405[] = { + /* 0 */ 826, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__406[] = { + /* 0 */ 827, INVALID, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__407[] = { + /* 0 */ 715, INVALID, +}; + +static const uint16_t ud_itab__408[] = { + /* 0 */ 723, 724, 725, +}; + +static const uint16_t ud_itab__409[] = { + /* 0 */ 1280, 1285, 1269, 1273, + /* 4 */ 1326, 1333, 1320, 1314, +}; + +static const uint16_t ud_itab__410[] = { + /* 0 */ 1281, 1288, 1272, 1276, + /* 4 */ 1325, 1332, 1329, 1312, +}; + +static const uint16_t ud_itab__411[] = { + /* 0 */ 1282, 1289, 1270, 1277, + /* 4 */ 1324, 1331, 1321, 1316, +}; + +static const uint16_t ud_itab__412[] = { + /* 0 */ 1283, 1290, 1271, 1278, + /* 4 */ 1328, 1335, 1322, 1317, +}; + +static const uint16_t ud_itab__413[] = { + /* 0 */ 3, INVALID, +}; + +static const uint16_t ud_itab__414[] = { + /* 0 */ 2, INVALID, +}; + +static const uint16_t ud_itab__415[] = { + /* 0 */ 1311, INVALID, +}; + +static const uint16_t ud_itab__416[] = { + /* 0 */ GROUP(417), GROUP(418), +}; + +static const uint16_t ud_itab__417[] = { + /* 0 */ 206, 503, 307, 357, + /* 4 */ 587, 630, 387, 413, +}; + +static const uint16_t ud_itab__418[] = { + /* 0 */ 215, 216, 217, 218, + /* 4 */ 219, 220, 221, 222, + /* 8 */ 504, 505, 506, 507, + /* c */ 508, 509, 510, 511, + /* 10 */ 309, 310, 311, 312, + /* 14 */ 313, 314, 315, 316, + /* 18 */ 359, 360, 361, 362, + /* 1c */ 363, 364, 365, 366, + /* 20 */ 589, 590, 591, 592, + /* 24 */ 593, 594, 595, 596, + /* 28 */ 614, 615, 616, 617, + /* 2c */ 618, 619, 620, 621, + /* 30 */ 388, 389, 390, 391, + /* 34 */ 392, 393, 394, 395, + /* 38 */ 414, 415, 416, 417, + /* 3c */ 418, 419, 420, 421, +}; + +static const uint16_t ud_itab__419[] = { + /* 0 */ GROUP(420), GROUP(421), +}; + +static const uint16_t ud_itab__420[] = { + /* 0 */ 476, INVALID, 573, 540, + /* 4 */ 493, 492, 584, 583, +}; + +static const uint16_t ud_itab__421[] = { + /* 0 */ 477, 478, 479, 480, + /* 4 */ 481, 482, 483, 484, + /* 8 */ 658, 659, 660, 661, + /* c */ 662, 663, 664, 665, + /* 10 */ 522, INVALID, INVALID, INVALID, + /* 14 */ INVALID, INVALID, INVALID, INVALID, + /* 18 */ 549, 550, 551, 552, + /* 1c */ 553, 554, 555, 556, + /* 20 */ 233, 204, INVALID, INVALID, + /* 24 */ 639, 657, INVALID, INVALID, + /* 28 */ 485, 486, 487, 488, + /* 2c */ 489, 490, 491, INVALID, + /* 30 */ 203, 685, 529, 526, + /* 34 */ 684, 528, 377, 454, + /* 38 */ 527, 686, 537, 536, + /* 3c */ 530, 534, 535, 376, +}; + +static const uint16_t ud_itab__422[] = { + /* 0 */ GROUP(423), GROUP(424), +}; + +static const uint16_t ud_itab__423[] = { + /* 0 */ 456, 520, 448, 450, + /* 4 */ 462, 464, 460, 458, +}; + +static const uint16_t ud_itab__424[] = { + /* 0 */ 235, 236, 237, 238, + /* 4 */ 239, 240, 241, 242, + /* 8 */ 243, 244, 245, 246, + /* c */ 247, 248, 249, 250, + /* 10 */ 251, 252, 253, 254, + /* 14 */ 255, 256, 257, 258, + /* 18 */ 259, 260, 261, 262, + /* 1c */ 263, 264, 265, 266, + /* 20 */ INVALID, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ INVALID, 656, INVALID, INVALID, + /* 2c */ INVALID, INVALID, INVALID, INVALID, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__425[] = { + /* 0 */ GROUP(426), GROUP(427), +}; + +static const uint16_t ud_itab__426[] = { + /* 0 */ 453, 471, 467, 470, + /* 4 */ INVALID, 474, INVALID, 538, +}; + +static const uint16_t ud_itab__427[] = { + /* 0 */ 267, 268, 269, 270, + /* 4 */ 271, 272, 273, 274, + /* 8 */ 275, 276, 277, 278, + /* c */ 279, 280, 281, 282, + /* 10 */ 283, 284, 285, 286, + /* 14 */ 287, 288, 289, 290, + /* 18 */ 291, 292, 293, 294, + /* 1c */ 295, 296, 297, 298, + /* 20 */ 524, 523, 234, 455, + /* 24 */ 525, 532, INVALID, INVALID, + /* 28 */ 299, 300, 301, 302, + /* 2c */ 303, 304, 305, 306, + /* 30 */ 333, 334, 335, 336, + /* 34 */ 337, 338, 339, 340, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__428[] = { + /* 0 */ GROUP(429), GROUP(430), +}; + +static const uint16_t ud_itab__429[] = { + /* 0 */ 205, 494, 308, 358, + /* 4 */ 588, 613, 378, 404, +}; + +static const uint16_t ud_itab__430[] = { + /* 0 */ 207, 208, 209, 210, + /* 4 */ 211, 212, 213, 214, + /* 8 */ 495, 496, 497, 498, + /* c */ 499, 500, 501, 502, + /* 10 */ 317, 318, 319, 320, + /* 14 */ 321, 322, 323, 324, + /* 18 */ 325, 326, 327, 328, + /* 1c */ 329, 330, 331, 332, + /* 20 */ 622, 623, 624, 625, + /* 24 */ 626, 627, 628, 629, + /* 28 */ 597, 598, 599, 600, + /* 2c */ 601, 602, 603, 604, + /* 30 */ 405, 406, 407, 408, + /* 34 */ 409, 410, 411, 412, + /* 38 */ 379, 380, 381, 382, + /* 3c */ 383, 384, 385, 386, +}; + +static const uint16_t ud_itab__431[] = { + /* 0 */ GROUP(432), GROUP(433), +}; + +static const uint16_t ud_itab__432[] = { + /* 0 */ 475, 472, 574, 539, + /* 4 */ 531, INVALID, 533, 585, +}; + +static const uint16_t ud_itab__433[] = { + /* 0 */ 431, 432, 433, 434, + /* 4 */ 435, 436, 437, 438, + /* 8 */ 666, 667, 668, 669, + /* c */ 670, 671, 672, 673, + /* 10 */ 575, 576, 577, 578, + /* 14 */ 579, 580, 581, 582, + /* 18 */ 541, 542, 543, 544, + /* 1c */ 545, 546, 547, 548, + /* 20 */ 640, 641, 642, 643, + /* 24 */ 644, 645, 646, 647, + /* 28 */ 648, 649, 650, 651, + /* 2c */ 652, 653, 654, 655, + /* 30 */ INVALID, INVALID, INVALID, INVALID, + /* 34 */ INVALID, INVALID, INVALID, INVALID, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__434[] = { + /* 0 */ GROUP(435), GROUP(436), +}; + +static const uint16_t ud_itab__435[] = { + /* 0 */ 457, 521, 447, 449, + /* 4 */ 463, 465, 461, 459, +}; + +static const uint16_t ud_itab__436[] = { + /* 0 */ 223, 224, 225, 226, + /* 4 */ 227, 228, 229, 230, + /* 8 */ 512, 513, 514, 515, + /* c */ 516, 517, 518, 519, + /* 10 */ 367, 368, 369, 370, + /* 14 */ 371, 372, 373, 374, + /* 18 */ INVALID, 375, INVALID, INVALID, + /* 1c */ INVALID, INVALID, INVALID, INVALID, + /* 20 */ 631, 632, 633, 634, + /* 24 */ 635, 636, 637, 638, + /* 28 */ 605, 606, 607, 608, + /* 2c */ 609, 610, 611, 612, + /* 30 */ 422, 423, 424, 425, + /* 34 */ 426, 427, 428, 429, + /* 38 */ 396, 397, 398, 399, + /* 3c */ 400, 401, 402, 403, +}; + +static const uint16_t ud_itab__437[] = { + /* 0 */ GROUP(438), GROUP(439), +}; + +static const uint16_t ud_itab__438[] = { + /* 0 */ 451, 473, 466, 468, + /* 4 */ 231, 452, 232, 469, +}; + +static const uint16_t ud_itab__439[] = { + /* 0 */ 439, 440, 441, 442, + /* 4 */ 443, 444, 445, 446, + /* 8 */ 674, 675, 676, 677, + /* c */ 678, 679, 680, 681, + /* 10 */ 557, 558, 559, 560, + /* 14 */ 561, 562, 563, 564, + /* 18 */ 565, 566, 567, 568, + /* 1c */ 569, 570, 571, 572, + /* 20 */ 586, INVALID, INVALID, INVALID, + /* 24 */ INVALID, INVALID, INVALID, INVALID, + /* 28 */ 341, 342, 343, 344, + /* 2c */ 345, 346, 347, 348, + /* 30 */ 349, 350, 351, 352, + /* 34 */ 353, 354, 355, 356, + /* 38 */ INVALID, INVALID, INVALID, INVALID, + /* 3c */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__440[] = { + /* 0 */ 758, 759, 760, +}; + +static const uint16_t ud_itab__441[] = { + /* 0 */ 764, INVALID, +}; + +static const uint16_t ud_itab__442[] = { + /* 0 */ 1432, 1437, 962, 953, + /* 4 */ 942, 695, 186, 689, +}; + +static const uint16_t ud_itab__443[] = { + /* 0 */ 1438, 1439, 963, 954, + /* 4 */ 943, 696, 185, 688, +}; + +static const uint16_t ud_itab__444[] = { + /* 0 */ 708, 183, INVALID, INVALID, + /* 4 */ INVALID, INVALID, INVALID, INVALID, +}; + +static const uint16_t ud_itab__445[] = { + /* 0 */ 707, 184, GROUP(446), 71, + /* 4 */ 761, 762, 1255, INVALID, +}; + +static const uint16_t ud_itab__446[] = { + /* 0 */ 69, 70, +}; + + +struct ud_lookup_table_list_entry ud_lookup_table_list[] = { + /* 000 */ { ud_itab__0, UD_TAB__OPC_TABLE, "opctbl" }, + /* 001 */ { ud_itab__1, UD_TAB__OPC_MODE, "/m" }, + /* 002 */ { ud_itab__2, UD_TAB__OPC_MODE, "/m" }, + /* 003 */ { ud_itab__3, UD_TAB__OPC_MODE, "/m" }, + /* 004 */ { ud_itab__4, UD_TAB__OPC_TABLE, "opctbl" }, + /* 005 */ { ud_itab__5, UD_TAB__OPC_REG, "/reg" }, + /* 006 */ { ud_itab__6, UD_TAB__OPC_MOD, "/mod" }, + /* 007 */ { ud_itab__7, UD_TAB__OPC_REG, "/reg" }, + /* 008 */ { ud_itab__8, UD_TAB__OPC_REG, "/reg" }, + /* 009 */ { ud_itab__9, UD_TAB__OPC_RM, "/rm" }, + /* 010 */ { ud_itab__10, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 011 */ { ud_itab__11, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 012 */ { ud_itab__12, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 013 */ { ud_itab__13, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 014 */ { ud_itab__14, UD_TAB__OPC_RM, "/rm" }, + /* 015 */ { ud_itab__15, UD_TAB__OPC_RM, "/rm" }, + /* 016 */ { ud_itab__16, UD_TAB__OPC_RM, "/rm" }, + /* 017 */ { ud_itab__17, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 018 */ { ud_itab__18, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 019 */ { ud_itab__19, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 020 */ { ud_itab__20, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 021 */ { ud_itab__21, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 022 */ { ud_itab__22, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 023 */ { ud_itab__23, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 024 */ { ud_itab__24, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 025 */ { ud_itab__25, UD_TAB__OPC_RM, "/rm" }, + /* 026 */ { ud_itab__26, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 027 */ { ud_itab__27, UD_TAB__OPC_REG, "/reg" }, + /* 028 */ { ud_itab__28, UD_TAB__OPC_3DNOW, "/3dnow" }, + /* 029 */ { ud_itab__29, UD_TAB__OPC_SSE, "/sse" }, + /* 030 */ { ud_itab__30, UD_TAB__OPC_SSE, "/sse" }, + /* 031 */ { ud_itab__31, UD_TAB__OPC_MOD, "/mod" }, + /* 032 */ { ud_itab__32, UD_TAB__OPC_SSE, "/sse" }, + /* 033 */ { ud_itab__33, UD_TAB__OPC_SSE, "/sse" }, + /* 034 */ { ud_itab__34, UD_TAB__OPC_SSE, "/sse" }, + /* 035 */ { ud_itab__35, UD_TAB__OPC_SSE, "/sse" }, + /* 036 */ { ud_itab__36, UD_TAB__OPC_SSE, "/sse" }, + /* 037 */ { ud_itab__37, UD_TAB__OPC_MOD, "/mod" }, + /* 038 */ { ud_itab__38, UD_TAB__OPC_SSE, "/sse" }, + /* 039 */ { ud_itab__39, UD_TAB__OPC_SSE, "/sse" }, + /* 040 */ { ud_itab__40, UD_TAB__OPC_SSE, "/sse" }, + /* 041 */ { ud_itab__41, UD_TAB__OPC_REG, "/reg" }, + /* 042 */ { ud_itab__42, UD_TAB__OPC_SSE, "/sse" }, + /* 043 */ { ud_itab__43, UD_TAB__OPC_SSE, "/sse" }, + /* 044 */ { ud_itab__44, UD_TAB__OPC_SSE, "/sse" }, + /* 045 */ { ud_itab__45, UD_TAB__OPC_SSE, "/sse" }, + /* 046 */ { ud_itab__46, UD_TAB__OPC_SSE, "/sse" }, + /* 047 */ { ud_itab__47, UD_TAB__OPC_SSE, "/sse" }, + /* 048 */ { ud_itab__48, UD_TAB__OPC_SSE, "/sse" }, + /* 049 */ { ud_itab__49, UD_TAB__OPC_SSE, "/sse" }, + /* 050 */ { ud_itab__50, UD_TAB__OPC_MODE, "/m" }, + /* 051 */ { ud_itab__51, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 052 */ { ud_itab__52, UD_TAB__OPC_MODE, "/m" }, + /* 053 */ { ud_itab__53, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 054 */ { ud_itab__54, UD_TAB__OPC_TABLE, "opctbl" }, + /* 055 */ { ud_itab__55, UD_TAB__OPC_SSE, "/sse" }, + /* 056 */ { ud_itab__56, UD_TAB__OPC_MODE, "/m" }, + /* 057 */ { ud_itab__57, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 058 */ { ud_itab__58, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 059 */ { ud_itab__59, UD_TAB__OPC_SSE, "/sse" }, + /* 060 */ { ud_itab__60, UD_TAB__OPC_MODE, "/m" }, + /* 061 */ { ud_itab__61, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 062 */ { ud_itab__62, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 063 */ { ud_itab__63, UD_TAB__OPC_SSE, "/sse" }, + /* 064 */ { ud_itab__64, UD_TAB__OPC_SSE, "/sse" }, + /* 065 */ { ud_itab__65, UD_TAB__OPC_SSE, "/sse" }, + /* 066 */ { ud_itab__66, UD_TAB__OPC_SSE, "/sse" }, + /* 067 */ { ud_itab__67, UD_TAB__OPC_SSE, "/sse" }, + /* 068 */ { ud_itab__68, UD_TAB__OPC_SSE, "/sse" }, + /* 069 */ { ud_itab__69, UD_TAB__OPC_SSE, "/sse" }, + /* 070 */ { ud_itab__70, UD_TAB__OPC_SSE, "/sse" }, + /* 071 */ { ud_itab__71, UD_TAB__OPC_SSE, "/sse" }, + /* 072 */ { ud_itab__72, UD_TAB__OPC_SSE, "/sse" }, + /* 073 */ { ud_itab__73, UD_TAB__OPC_SSE, "/sse" }, + /* 074 */ { ud_itab__74, UD_TAB__OPC_SSE, "/sse" }, + /* 075 */ { ud_itab__75, UD_TAB__OPC_SSE, "/sse" }, + /* 076 */ { ud_itab__76, UD_TAB__OPC_SSE, "/sse" }, + /* 077 */ { ud_itab__77, UD_TAB__OPC_SSE, "/sse" }, + /* 078 */ { ud_itab__78, UD_TAB__OPC_SSE, "/sse" }, + /* 079 */ { ud_itab__79, UD_TAB__OPC_SSE, "/sse" }, + /* 080 */ { ud_itab__80, UD_TAB__OPC_SSE, "/sse" }, + /* 081 */ { ud_itab__81, UD_TAB__OPC_SSE, "/sse" }, + /* 082 */ { ud_itab__82, UD_TAB__OPC_SSE, "/sse" }, + /* 083 */ { ud_itab__83, UD_TAB__OPC_SSE, "/sse" }, + /* 084 */ { ud_itab__84, UD_TAB__OPC_SSE, "/sse" }, + /* 085 */ { ud_itab__85, UD_TAB__OPC_SSE, "/sse" }, + /* 086 */ { ud_itab__86, UD_TAB__OPC_SSE, "/sse" }, + /* 087 */ { ud_itab__87, UD_TAB__OPC_SSE, "/sse" }, + /* 088 */ { ud_itab__88, UD_TAB__OPC_SSE, "/sse" }, + /* 089 */ { ud_itab__89, UD_TAB__OPC_SSE, "/sse" }, + /* 090 */ { ud_itab__90, UD_TAB__OPC_SSE, "/sse" }, + /* 091 */ { ud_itab__91, UD_TAB__OPC_SSE, "/sse" }, + /* 092 */ { ud_itab__92, UD_TAB__OPC_SSE, "/sse" }, + /* 093 */ { ud_itab__93, UD_TAB__OPC_SSE, "/sse" }, + /* 094 */ { ud_itab__94, UD_TAB__OPC_SSE, "/sse" }, + /* 095 */ { ud_itab__95, UD_TAB__OPC_SSE, "/sse" }, + /* 096 */ { ud_itab__96, UD_TAB__OPC_SSE, "/sse" }, + /* 097 */ { ud_itab__97, UD_TAB__OPC_SSE, "/sse" }, + /* 098 */ { ud_itab__98, UD_TAB__OPC_SSE, "/sse" }, + /* 099 */ { ud_itab__99, UD_TAB__OPC_SSE, "/sse" }, + /* 100 */ { ud_itab__100, UD_TAB__OPC_SSE, "/sse" }, + /* 101 */ { ud_itab__101, UD_TAB__OPC_SSE, "/sse" }, + /* 102 */ { ud_itab__102, UD_TAB__OPC_SSE, "/sse" }, + /* 103 */ { ud_itab__103, UD_TAB__OPC_SSE, "/sse" }, + /* 104 */ { ud_itab__104, UD_TAB__OPC_SSE, "/sse" }, + /* 105 */ { ud_itab__105, UD_TAB__OPC_SSE, "/sse" }, + /* 106 */ { ud_itab__106, UD_TAB__OPC_SSE, "/sse" }, + /* 107 */ { ud_itab__107, UD_TAB__OPC_SSE, "/sse" }, + /* 108 */ { ud_itab__108, UD_TAB__OPC_SSE, "/sse" }, + /* 109 */ { ud_itab__109, UD_TAB__OPC_SSE, "/sse" }, + /* 110 */ { ud_itab__110, UD_TAB__OPC_SSE, "/sse" }, + /* 111 */ { ud_itab__111, UD_TAB__OPC_SSE, "/sse" }, + /* 112 */ { ud_itab__112, UD_TAB__OPC_SSE, "/sse" }, + /* 113 */ { ud_itab__113, UD_TAB__OPC_SSE, "/sse" }, + /* 114 */ { ud_itab__114, UD_TAB__OPC_SSE, "/sse" }, + /* 115 */ { ud_itab__115, UD_TAB__OPC_SSE, "/sse" }, + /* 116 */ { ud_itab__116, UD_TAB__OPC_TABLE, "opctbl" }, + /* 117 */ { ud_itab__117, UD_TAB__OPC_SSE, "/sse" }, + /* 118 */ { ud_itab__118, UD_TAB__OPC_SSE, "/sse" }, + /* 119 */ { ud_itab__119, UD_TAB__OPC_SSE, "/sse" }, + /* 120 */ { ud_itab__120, UD_TAB__OPC_SSE, "/sse" }, + /* 121 */ { ud_itab__121, UD_TAB__OPC_SSE, "/sse" }, + /* 122 */ { ud_itab__122, UD_TAB__OPC_SSE, "/sse" }, + /* 123 */ { ud_itab__123, UD_TAB__OPC_SSE, "/sse" }, + /* 124 */ { ud_itab__124, UD_TAB__OPC_SSE, "/sse" }, + /* 125 */ { ud_itab__125, UD_TAB__OPC_SSE, "/sse" }, + /* 126 */ { ud_itab__126, UD_TAB__OPC_SSE, "/sse" }, + /* 127 */ { ud_itab__127, UD_TAB__OPC_SSE, "/sse" }, + /* 128 */ { ud_itab__128, UD_TAB__OPC_OSIZE, "/o" }, + /* 129 */ { ud_itab__129, UD_TAB__OPC_SSE, "/sse" }, + /* 130 */ { ud_itab__130, UD_TAB__OPC_SSE, "/sse" }, + /* 131 */ { ud_itab__131, UD_TAB__OPC_SSE, "/sse" }, + /* 132 */ { ud_itab__132, UD_TAB__OPC_SSE, "/sse" }, + /* 133 */ { ud_itab__133, UD_TAB__OPC_OSIZE, "/o" }, + /* 134 */ { ud_itab__134, UD_TAB__OPC_SSE, "/sse" }, + /* 135 */ { ud_itab__135, UD_TAB__OPC_SSE, "/sse" }, + /* 136 */ { ud_itab__136, UD_TAB__OPC_SSE, "/sse" }, + /* 137 */ { ud_itab__137, UD_TAB__OPC_SSE, "/sse" }, + /* 138 */ { ud_itab__138, UD_TAB__OPC_SSE, "/sse" }, + /* 139 */ { ud_itab__139, UD_TAB__OPC_SSE, "/sse" }, + /* 140 */ { ud_itab__140, UD_TAB__OPC_SSE, "/sse" }, + /* 141 */ { ud_itab__141, UD_TAB__OPC_SSE, "/sse" }, + /* 142 */ { ud_itab__142, UD_TAB__OPC_SSE, "/sse" }, + /* 143 */ { ud_itab__143, UD_TAB__OPC_SSE, "/sse" }, + /* 144 */ { ud_itab__144, UD_TAB__OPC_SSE, "/sse" }, + /* 145 */ { ud_itab__145, UD_TAB__OPC_SSE, "/sse" }, + /* 146 */ { ud_itab__146, UD_TAB__OPC_SSE, "/sse" }, + /* 147 */ { ud_itab__147, UD_TAB__OPC_SSE, "/sse" }, + /* 148 */ { ud_itab__148, UD_TAB__OPC_SSE, "/sse" }, + /* 149 */ { ud_itab__149, UD_TAB__OPC_SSE, "/sse" }, + /* 150 */ { ud_itab__150, UD_TAB__OPC_SSE, "/sse" }, + /* 151 */ { ud_itab__151, UD_TAB__OPC_SSE, "/sse" }, + /* 152 */ { ud_itab__152, UD_TAB__OPC_SSE, "/sse" }, + /* 153 */ { ud_itab__153, UD_TAB__OPC_SSE, "/sse" }, + /* 154 */ { ud_itab__154, UD_TAB__OPC_SSE, "/sse" }, + /* 155 */ { ud_itab__155, UD_TAB__OPC_SSE, "/sse" }, + /* 156 */ { ud_itab__156, UD_TAB__OPC_SSE, "/sse" }, + /* 157 */ { ud_itab__157, UD_TAB__OPC_SSE, "/sse" }, + /* 158 */ { ud_itab__158, UD_TAB__OPC_SSE, "/sse" }, + /* 159 */ { ud_itab__159, UD_TAB__OPC_SSE, "/sse" }, + /* 160 */ { ud_itab__160, UD_TAB__OPC_SSE, "/sse" }, + /* 161 */ { ud_itab__161, UD_TAB__OPC_SSE, "/sse" }, + /* 162 */ { ud_itab__162, UD_TAB__OPC_SSE, "/sse" }, + /* 163 */ { ud_itab__163, UD_TAB__OPC_SSE, "/sse" }, + /* 164 */ { ud_itab__164, UD_TAB__OPC_SSE, "/sse" }, + /* 165 */ { ud_itab__165, UD_TAB__OPC_SSE, "/sse" }, + /* 166 */ { ud_itab__166, UD_TAB__OPC_SSE, "/sse" }, + /* 167 */ { ud_itab__167, UD_TAB__OPC_SSE, "/sse" }, + /* 168 */ { ud_itab__168, UD_TAB__OPC_SSE, "/sse" }, + /* 169 */ { ud_itab__169, UD_TAB__OPC_SSE, "/sse" }, + /* 170 */ { ud_itab__170, UD_TAB__OPC_SSE, "/sse" }, + /* 171 */ { ud_itab__171, UD_TAB__OPC_SSE, "/sse" }, + /* 172 */ { ud_itab__172, UD_TAB__OPC_SSE, "/sse" }, + /* 173 */ { ud_itab__173, UD_TAB__OPC_SSE, "/sse" }, + /* 174 */ { ud_itab__174, UD_TAB__OPC_OSIZE, "/o" }, + /* 175 */ { ud_itab__175, UD_TAB__OPC_OSIZE, "/o" }, + /* 176 */ { ud_itab__176, UD_TAB__OPC_SSE, "/sse" }, + /* 177 */ { ud_itab__177, UD_TAB__OPC_SSE, "/sse" }, + /* 178 */ { ud_itab__178, UD_TAB__OPC_REG, "/reg" }, + /* 179 */ { ud_itab__179, UD_TAB__OPC_SSE, "/sse" }, + /* 180 */ { ud_itab__180, UD_TAB__OPC_SSE, "/sse" }, + /* 181 */ { ud_itab__181, UD_TAB__OPC_SSE, "/sse" }, + /* 182 */ { ud_itab__182, UD_TAB__OPC_REG, "/reg" }, + /* 183 */ { ud_itab__183, UD_TAB__OPC_SSE, "/sse" }, + /* 184 */ { ud_itab__184, UD_TAB__OPC_SSE, "/sse" }, + /* 185 */ { ud_itab__185, UD_TAB__OPC_SSE, "/sse" }, + /* 186 */ { ud_itab__186, UD_TAB__OPC_REG, "/reg" }, + /* 187 */ { ud_itab__187, UD_TAB__OPC_SSE, "/sse" }, + /* 188 */ { ud_itab__188, UD_TAB__OPC_SSE, "/sse" }, + /* 189 */ { ud_itab__189, UD_TAB__OPC_SSE, "/sse" }, + /* 190 */ { ud_itab__190, UD_TAB__OPC_SSE, "/sse" }, + /* 191 */ { ud_itab__191, UD_TAB__OPC_SSE, "/sse" }, + /* 192 */ { ud_itab__192, UD_TAB__OPC_SSE, "/sse" }, + /* 193 */ { ud_itab__193, UD_TAB__OPC_SSE, "/sse" }, + /* 194 */ { ud_itab__194, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 195 */ { ud_itab__195, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 196 */ { ud_itab__196, UD_TAB__OPC_SSE, "/sse" }, + /* 197 */ { ud_itab__197, UD_TAB__OPC_SSE, "/sse" }, + /* 198 */ { ud_itab__198, UD_TAB__OPC_SSE, "/sse" }, + /* 199 */ { ud_itab__199, UD_TAB__OPC_OSIZE, "/o" }, + /* 200 */ { ud_itab__200, UD_TAB__OPC_OSIZE, "/o" }, + /* 201 */ { ud_itab__201, UD_TAB__OPC_SSE, "/sse" }, + /* 202 */ { ud_itab__202, UD_TAB__OPC_MOD, "/mod" }, + /* 203 */ { ud_itab__203, UD_TAB__OPC_REG, "/reg" }, + /* 204 */ { ud_itab__204, UD_TAB__OPC_RM, "/rm" }, + /* 205 */ { ud_itab__205, UD_TAB__OPC_RM, "/rm" }, + /* 206 */ { ud_itab__206, UD_TAB__OPC_RM, "/rm" }, + /* 207 */ { ud_itab__207, UD_TAB__OPC_MOD, "/mod" }, + /* 208 */ { ud_itab__208, UD_TAB__OPC_REG, "/reg" }, + /* 209 */ { ud_itab__209, UD_TAB__OPC_RM, "/rm" }, + /* 210 */ { ud_itab__210, UD_TAB__OPC_RM, "/rm" }, + /* 211 */ { ud_itab__211, UD_TAB__OPC_RM, "/rm" }, + /* 212 */ { ud_itab__212, UD_TAB__OPC_RM, "/rm" }, + /* 213 */ { ud_itab__213, UD_TAB__OPC_RM, "/rm" }, + /* 214 */ { ud_itab__214, UD_TAB__OPC_RM, "/rm" }, + /* 215 */ { ud_itab__215, UD_TAB__OPC_MOD, "/mod" }, + /* 216 */ { ud_itab__216, UD_TAB__OPC_REG, "/reg" }, + /* 217 */ { ud_itab__217, UD_TAB__OPC_REG, "/reg" }, + /* 218 */ { ud_itab__218, UD_TAB__OPC_RM, "/rm" }, + /* 219 */ { ud_itab__219, UD_TAB__OPC_RM, "/rm" }, + /* 220 */ { ud_itab__220, UD_TAB__OPC_RM, "/rm" }, + /* 221 */ { ud_itab__221, UD_TAB__OPC_SSE, "/sse" }, + /* 222 */ { ud_itab__222, UD_TAB__OPC_REG, "/reg" }, + /* 223 */ { ud_itab__223, UD_TAB__OPC_SSE, "/sse" }, + /* 224 */ { ud_itab__224, UD_TAB__OPC_SSE, "/sse" }, + /* 225 */ { ud_itab__225, UD_TAB__OPC_SSE, "/sse" }, + /* 226 */ { ud_itab__226, UD_TAB__OPC_SSE, "/sse" }, + /* 227 */ { ud_itab__227, UD_TAB__OPC_MOD, "/mod" }, + /* 228 */ { ud_itab__228, UD_TAB__OPC_REG, "/reg" }, + /* 229 */ { ud_itab__229, UD_TAB__OPC_OSIZE, "/o" }, + /* 230 */ { ud_itab__230, UD_TAB__OPC_SSE, "/sse" }, + /* 231 */ { ud_itab__231, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 232 */ { ud_itab__232, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 233 */ { ud_itab__233, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 234 */ { ud_itab__234, UD_TAB__OPC_VENDOR, "/vendor" }, + /* 235 */ { ud_itab__235, UD_TAB__OPC_REG, "/reg" }, + /* 236 */ { ud_itab__236, UD_TAB__OPC_SSE, "/sse" }, + /* 237 */ { ud_itab__237, UD_TAB__OPC_SSE, "/sse" }, + /* 238 */ { ud_itab__238, UD_TAB__OPC_SSE, "/sse" }, + /* 239 */ { ud_itab__239, UD_TAB__OPC_SSE, "/sse" }, + /* 240 */ { ud_itab__240, UD_TAB__OPC_SSE, "/sse" }, + /* 241 */ { ud_itab__241, UD_TAB__OPC_SSE, "/sse" }, + /* 242 */ { ud_itab__242, UD_TAB__OPC_SSE, "/sse" }, + /* 243 */ { ud_itab__243, UD_TAB__OPC_SSE, "/sse" }, + /* 244 */ { ud_itab__244, UD_TAB__OPC_SSE, "/sse" }, + /* 245 */ { ud_itab__245, UD_TAB__OPC_SSE, "/sse" }, + /* 246 */ { ud_itab__246, UD_TAB__OPC_SSE, "/sse" }, + /* 247 */ { ud_itab__247, UD_TAB__OPC_SSE, "/sse" }, + /* 248 */ { ud_itab__248, UD_TAB__OPC_SSE, "/sse" }, + /* 249 */ { ud_itab__249, UD_TAB__OPC_SSE, "/sse" }, + /* 250 */ { ud_itab__250, UD_TAB__OPC_SSE, "/sse" }, + /* 251 */ { ud_itab__251, UD_TAB__OPC_SSE, "/sse" }, + /* 252 */ { ud_itab__252, UD_TAB__OPC_SSE, "/sse" }, + /* 253 */ { ud_itab__253, UD_TAB__OPC_SSE, "/sse" }, + /* 254 */ { ud_itab__254, UD_TAB__OPC_SSE, "/sse" }, + /* 255 */ { ud_itab__255, UD_TAB__OPC_SSE, "/sse" }, + /* 256 */ { ud_itab__256, UD_TAB__OPC_SSE, "/sse" }, + /* 257 */ { ud_itab__257, UD_TAB__OPC_SSE, "/sse" }, + /* 258 */ { ud_itab__258, UD_TAB__OPC_SSE, "/sse" }, + /* 259 */ { ud_itab__259, UD_TAB__OPC_SSE, "/sse" }, + /* 260 */ { ud_itab__260, UD_TAB__OPC_SSE, "/sse" }, + /* 261 */ { ud_itab__261, UD_TAB__OPC_SSE, "/sse" }, + /* 262 */ { ud_itab__262, UD_TAB__OPC_SSE, "/sse" }, + /* 263 */ { ud_itab__263, UD_TAB__OPC_SSE, "/sse" }, + /* 264 */ { ud_itab__264, UD_TAB__OPC_SSE, "/sse" }, + /* 265 */ { ud_itab__265, UD_TAB__OPC_SSE, "/sse" }, + /* 266 */ { ud_itab__266, UD_TAB__OPC_SSE, "/sse" }, + /* 267 */ { ud_itab__267, UD_TAB__OPC_SSE, "/sse" }, + /* 268 */ { ud_itab__268, UD_TAB__OPC_SSE, "/sse" }, + /* 269 */ { ud_itab__269, UD_TAB__OPC_SSE, "/sse" }, + /* 270 */ { ud_itab__270, UD_TAB__OPC_SSE, "/sse" }, + /* 271 */ { ud_itab__271, UD_TAB__OPC_SSE, "/sse" }, + /* 272 */ { ud_itab__272, UD_TAB__OPC_SSE, "/sse" }, + /* 273 */ { ud_itab__273, UD_TAB__OPC_SSE, "/sse" }, + /* 274 */ { ud_itab__274, UD_TAB__OPC_SSE, "/sse" }, + /* 275 */ { ud_itab__275, UD_TAB__OPC_MOD, "/mod" }, + /* 276 */ { ud_itab__276, UD_TAB__OPC_SSE, "/sse" }, + /* 277 */ { ud_itab__277, UD_TAB__OPC_SSE, "/sse" }, + /* 278 */ { ud_itab__278, UD_TAB__OPC_SSE, "/sse" }, + /* 279 */ { ud_itab__279, UD_TAB__OPC_SSE, "/sse" }, + /* 280 */ { ud_itab__280, UD_TAB__OPC_SSE, "/sse" }, + /* 281 */ { ud_itab__281, UD_TAB__OPC_SSE, "/sse" }, + /* 282 */ { ud_itab__282, UD_TAB__OPC_SSE, "/sse" }, + /* 283 */ { ud_itab__283, UD_TAB__OPC_SSE, "/sse" }, + /* 284 */ { ud_itab__284, UD_TAB__OPC_MODE, "/m" }, + /* 285 */ { ud_itab__285, UD_TAB__OPC_MODE, "/m" }, + /* 286 */ { ud_itab__286, UD_TAB__OPC_MODE, "/m" }, + /* 287 */ { ud_itab__287, UD_TAB__OPC_MODE, "/m" }, + /* 288 */ { ud_itab__288, UD_TAB__OPC_MODE, "/m" }, + /* 289 */ { ud_itab__289, UD_TAB__OPC_MODE, "/m" }, + /* 290 */ { ud_itab__290, UD_TAB__OPC_MODE, "/m" }, + /* 291 */ { ud_itab__291, UD_TAB__OPC_MODE, "/m" }, + /* 292 */ { ud_itab__292, UD_TAB__OPC_OSIZE, "/o" }, + /* 293 */ { ud_itab__293, UD_TAB__OPC_MODE, "/m" }, + /* 294 */ { ud_itab__294, UD_TAB__OPC_MODE, "/m" }, + /* 295 */ { ud_itab__295, UD_TAB__OPC_OSIZE, "/o" }, + /* 296 */ { ud_itab__296, UD_TAB__OPC_MODE, "/m" }, + /* 297 */ { ud_itab__297, UD_TAB__OPC_MODE, "/m" }, + /* 298 */ { ud_itab__298, UD_TAB__OPC_MODE, "/m" }, + /* 299 */ { ud_itab__299, UD_TAB__OPC_MODE, "/m" }, + /* 300 */ { ud_itab__300, UD_TAB__OPC_OSIZE, "/o" }, + /* 301 */ { ud_itab__301, UD_TAB__OPC_OSIZE, "/o" }, + /* 302 */ { ud_itab__302, UD_TAB__OPC_REG, "/reg" }, + /* 303 */ { ud_itab__303, UD_TAB__OPC_REG, "/reg" }, + /* 304 */ { ud_itab__304, UD_TAB__OPC_REG, "/reg" }, + /* 305 */ { ud_itab__305, UD_TAB__OPC_MODE, "/m" }, + /* 306 */ { ud_itab__306, UD_TAB__OPC_MODE, "/m" }, + /* 307 */ { ud_itab__307, UD_TAB__OPC_MODE, "/m" }, + /* 308 */ { ud_itab__308, UD_TAB__OPC_MODE, "/m" }, + /* 309 */ { ud_itab__309, UD_TAB__OPC_MODE, "/m" }, + /* 310 */ { ud_itab__310, UD_TAB__OPC_MODE, "/m" }, + /* 311 */ { ud_itab__311, UD_TAB__OPC_MODE, "/m" }, + /* 312 */ { ud_itab__312, UD_TAB__OPC_MODE, "/m" }, + /* 313 */ { ud_itab__313, UD_TAB__OPC_REG, "/reg" }, + /* 314 */ { ud_itab__314, UD_TAB__OPC_REG, "/reg" }, + /* 315 */ { ud_itab__315, UD_TAB__OPC_OSIZE, "/o" }, + /* 316 */ { ud_itab__316, UD_TAB__OPC_OSIZE, "/o" }, + /* 317 */ { ud_itab__317, UD_TAB__OPC_MODE, "/m" }, + /* 318 */ { ud_itab__318, UD_TAB__OPC_OSIZE, "/o" }, + /* 319 */ { ud_itab__319, UD_TAB__OPC_MODE, "/m" }, + /* 320 */ { ud_itab__320, UD_TAB__OPC_MODE, "/m" }, + /* 321 */ { ud_itab__321, UD_TAB__OPC_MODE, "/m" }, + /* 322 */ { ud_itab__322, UD_TAB__OPC_OSIZE, "/o" }, + /* 323 */ { ud_itab__323, UD_TAB__OPC_MODE, "/m" }, + /* 324 */ { ud_itab__324, UD_TAB__OPC_MODE, "/m" }, + /* 325 */ { ud_itab__325, UD_TAB__OPC_MODE, "/m" }, + /* 326 */ { ud_itab__326, UD_TAB__OPC_OSIZE, "/o" }, + /* 327 */ { ud_itab__327, UD_TAB__OPC_OSIZE, "/o" }, + /* 328 */ { ud_itab__328, UD_TAB__OPC_OSIZE, "/o" }, + /* 329 */ { ud_itab__329, UD_TAB__OPC_OSIZE, "/o" }, + /* 330 */ { ud_itab__330, UD_TAB__OPC_OSIZE, "/o" }, + /* 331 */ { ud_itab__331, UD_TAB__OPC_REG, "/reg" }, + /* 332 */ { ud_itab__332, UD_TAB__OPC_REG, "/reg" }, + /* 333 */ { ud_itab__333, UD_TAB__OPC_VEX, "/vex" }, + /* 334 */ { ud_itab__334, UD_TAB__OPC_MODE, "/m" }, + /* 335 */ { ud_itab__335, UD_TAB__OPC_TABLE, "opctbl" }, + /* 336 */ { ud_itab__336, UD_TAB__OPC_MOD, "/mod" }, + /* 337 */ { ud_itab__337, UD_TAB__OPC_MOD, "/mod" }, + /* 338 */ { ud_itab__338, UD_TAB__OPC_MOD, "/mod" }, + /* 339 */ { ud_itab__339, UD_TAB__OPC_REG, "/reg" }, + /* 340 */ { ud_itab__340, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 341 */ { ud_itab__341, UD_TAB__OPC_TABLE, "opctbl" }, + /* 342 */ { ud_itab__342, UD_TAB__OPC_MOD, "/mod" }, + /* 343 */ { ud_itab__343, UD_TAB__OPC_MOD, "/mod" }, + /* 344 */ { ud_itab__344, UD_TAB__OPC_OSIZE, "/o" }, + /* 345 */ { ud_itab__345, UD_TAB__OPC_REG, "/reg" }, + /* 346 */ { ud_itab__346, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 347 */ { ud_itab__347, UD_TAB__OPC_REG, "/reg" }, + /* 348 */ { ud_itab__348, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 349 */ { ud_itab__349, UD_TAB__OPC_REG, "/reg" }, + /* 350 */ { ud_itab__350, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 351 */ { ud_itab__351, UD_TAB__OPC_OSIZE, "/o" }, + /* 352 */ { ud_itab__352, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 353 */ { ud_itab__353, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 354 */ { ud_itab__354, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 355 */ { ud_itab__355, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 356 */ { ud_itab__356, UD_TAB__OPC_MOD, "/mod" }, + /* 357 */ { ud_itab__357, UD_TAB__OPC_TABLE, "opctbl" }, + /* 358 */ { ud_itab__358, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 359 */ { ud_itab__359, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 360 */ { ud_itab__360, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 361 */ { ud_itab__361, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 362 */ { ud_itab__362, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 363 */ { ud_itab__363, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 364 */ { ud_itab__364, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 365 */ { ud_itab__365, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 366 */ { ud_itab__366, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 367 */ { ud_itab__367, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 368 */ { ud_itab__368, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 369 */ { ud_itab__369, UD_TAB__OPC_TABLE, "opctbl" }, + /* 370 */ { ud_itab__370, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 371 */ { ud_itab__371, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 372 */ { ud_itab__372, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 373 */ { ud_itab__373, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 374 */ { ud_itab__374, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 375 */ { ud_itab__375, UD_TAB__OPC_OSIZE, "/o" }, + /* 376 */ { ud_itab__376, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 377 */ { ud_itab__377, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 378 */ { ud_itab__378, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 379 */ { ud_itab__379, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 380 */ { ud_itab__380, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 381 */ { ud_itab__381, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 382 */ { ud_itab__382, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 383 */ { ud_itab__383, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 384 */ { ud_itab__384, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 385 */ { ud_itab__385, UD_TAB__OPC_MODE, "/m" }, + /* 386 */ { ud_itab__386, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 387 */ { ud_itab__387, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 388 */ { ud_itab__388, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 389 */ { ud_itab__389, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 390 */ { ud_itab__390, UD_TAB__OPC_VEX_L, "/vexl" }, + /* 391 */ { ud_itab__391, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 392 */ { ud_itab__392, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 393 */ { ud_itab__393, UD_TAB__OPC_VEX_W, "/vexw" }, + /* 394 */ { ud_itab__394, UD_TAB__OPC_TABLE, "opctbl" }, + /* 395 */ { ud_itab__395, UD_TAB__OPC_MOD, "/mod" }, + /* 396 */ { ud_itab__396, UD_TAB__OPC_MOD, "/mod" }, + /* 397 */ { ud_itab__397, UD_TAB__OPC_MOD, "/mod" }, + /* 398 */ { ud_itab__398, UD_TAB__OPC_MOD, "/mod" }, + /* 399 */ { ud_itab__399, UD_TAB__OPC_TABLE, "opctbl" }, + /* 400 */ { ud_itab__400, UD_TAB__OPC_MOD, "/mod" }, + /* 401 */ { ud_itab__401, UD_TAB__OPC_MOD, "/mod" }, + /* 402 */ { ud_itab__402, UD_TAB__OPC_MOD, "/mod" }, + /* 403 */ { ud_itab__403, UD_TAB__OPC_VEX, "/vex" }, + /* 404 */ { ud_itab__404, UD_TAB__OPC_MODE, "/m" }, + /* 405 */ { ud_itab__405, UD_TAB__OPC_REG, "/reg" }, + /* 406 */ { ud_itab__406, UD_TAB__OPC_REG, "/reg" }, + /* 407 */ { ud_itab__407, UD_TAB__OPC_MODE, "/m" }, + /* 408 */ { ud_itab__408, UD_TAB__OPC_OSIZE, "/o" }, + /* 409 */ { ud_itab__409, UD_TAB__OPC_REG, "/reg" }, + /* 410 */ { ud_itab__410, UD_TAB__OPC_REG, "/reg" }, + /* 411 */ { ud_itab__411, UD_TAB__OPC_REG, "/reg" }, + /* 412 */ { ud_itab__412, UD_TAB__OPC_REG, "/reg" }, + /* 413 */ { ud_itab__413, UD_TAB__OPC_MODE, "/m" }, + /* 414 */ { ud_itab__414, UD_TAB__OPC_MODE, "/m" }, + /* 415 */ { ud_itab__415, UD_TAB__OPC_MODE, "/m" }, + /* 416 */ { ud_itab__416, UD_TAB__OPC_MOD, "/mod" }, + /* 417 */ { ud_itab__417, UD_TAB__OPC_REG, "/reg" }, + /* 418 */ { ud_itab__418, UD_TAB__OPC_X87, "/x87" }, + /* 419 */ { ud_itab__419, UD_TAB__OPC_MOD, "/mod" }, + /* 420 */ { ud_itab__420, UD_TAB__OPC_REG, "/reg" }, + /* 421 */ { ud_itab__421, UD_TAB__OPC_X87, "/x87" }, + /* 422 */ { ud_itab__422, UD_TAB__OPC_MOD, "/mod" }, + /* 423 */ { ud_itab__423, UD_TAB__OPC_REG, "/reg" }, + /* 424 */ { ud_itab__424, UD_TAB__OPC_X87, "/x87" }, + /* 425 */ { ud_itab__425, UD_TAB__OPC_MOD, "/mod" }, + /* 426 */ { ud_itab__426, UD_TAB__OPC_REG, "/reg" }, + /* 427 */ { ud_itab__427, UD_TAB__OPC_X87, "/x87" }, + /* 428 */ { ud_itab__428, UD_TAB__OPC_MOD, "/mod" }, + /* 429 */ { ud_itab__429, UD_TAB__OPC_REG, "/reg" }, + /* 430 */ { ud_itab__430, UD_TAB__OPC_X87, "/x87" }, + /* 431 */ { ud_itab__431, UD_TAB__OPC_MOD, "/mod" }, + /* 432 */ { ud_itab__432, UD_TAB__OPC_REG, "/reg" }, + /* 433 */ { ud_itab__433, UD_TAB__OPC_X87, "/x87" }, + /* 434 */ { ud_itab__434, UD_TAB__OPC_MOD, "/mod" }, + /* 435 */ { ud_itab__435, UD_TAB__OPC_REG, "/reg" }, + /* 436 */ { ud_itab__436, UD_TAB__OPC_X87, "/x87" }, + /* 437 */ { ud_itab__437, UD_TAB__OPC_MOD, "/mod" }, + /* 438 */ { ud_itab__438, UD_TAB__OPC_REG, "/reg" }, + /* 439 */ { ud_itab__439, UD_TAB__OPC_X87, "/x87" }, + /* 440 */ { ud_itab__440, UD_TAB__OPC_ASIZE, "/a" }, + /* 441 */ { ud_itab__441, UD_TAB__OPC_MODE, "/m" }, + /* 442 */ { ud_itab__442, UD_TAB__OPC_REG, "/reg" }, + /* 443 */ { ud_itab__443, UD_TAB__OPC_REG, "/reg" }, + /* 444 */ { ud_itab__444, UD_TAB__OPC_REG, "/reg" }, + /* 445 */ { ud_itab__445, UD_TAB__OPC_REG, "/reg" }, + /* 446 */ { ud_itab__446, UD_TAB__OPC_MODE, "/m" }, +}; + +/* itab entry operand definitions (for readability) */ +#define O_AL { OP_AL, SZ_B } +#define O_AX { OP_AX, SZ_W } +#define O_Av { OP_A, SZ_V } +#define O_C { OP_C, SZ_NA } +#define O_CL { OP_CL, SZ_B } +#define O_CS { OP_CS, SZ_NA } +#define O_CX { OP_CX, SZ_W } +#define O_D { OP_D, SZ_NA } +#define O_DL { OP_DL, SZ_B } +#define O_DS { OP_DS, SZ_NA } +#define O_DX { OP_DX, SZ_W } +#define O_E { OP_E, SZ_NA } +#define O_ES { OP_ES, SZ_NA } +#define O_Eb { OP_E, SZ_B } +#define O_Ed { OP_E, SZ_D } +#define O_Eq { OP_E, SZ_Q } +#define O_Ev { OP_E, SZ_V } +#define O_Ew { OP_E, SZ_W } +#define O_Ey { OP_E, SZ_Y } +#define O_Ez { OP_E, SZ_Z } +#define O_FS { OP_FS, SZ_NA } +#define O_Fv { OP_F, SZ_V } +#define O_G { OP_G, SZ_NA } +#define O_GS { OP_GS, SZ_NA } +#define O_Gb { OP_G, SZ_B } +#define O_Gd { OP_G, SZ_D } +#define O_Gq { OP_G, SZ_Q } +#define O_Gv { OP_G, SZ_V } +#define O_Gw { OP_G, SZ_W } +#define O_Gy { OP_G, SZ_Y } +#define O_Gz { OP_G, SZ_Z } +#define O_H { OP_H, SZ_X } +#define O_Hqq { OP_H, SZ_QQ } +#define O_Hx { OP_H, SZ_X } +#define O_I1 { OP_I1, SZ_NA } +#define O_I3 { OP_I3, SZ_NA } +#define O_Ib { OP_I, SZ_B } +#define O_Iv { OP_I, SZ_V } +#define O_Iw { OP_I, SZ_W } +#define O_Iz { OP_I, SZ_Z } +#define O_Jb { OP_J, SZ_B } +#define O_Jv { OP_J, SZ_V } +#define O_Jz { OP_J, SZ_Z } +#define O_L { OP_L, SZ_O } +#define O_Lx { OP_L, SZ_X } +#define O_M { OP_M, SZ_NA } +#define O_Mb { OP_M, SZ_B } +#define O_MbRd { OP_MR, SZ_BD } +#define O_MbRv { OP_MR, SZ_BV } +#define O_Md { OP_M, SZ_D } +#define O_MdRy { OP_MR, SZ_DY } +#define O_MdU { OP_MU, SZ_DO } +#define O_Mdq { OP_M, SZ_DQ } +#define O_Mo { OP_M, SZ_O } +#define O_Mq { OP_M, SZ_Q } +#define O_MqU { OP_MU, SZ_QO } +#define O_Ms { OP_M, SZ_W } +#define O_Mt { OP_M, SZ_T } +#define O_Mv { OP_M, SZ_V } +#define O_Mw { OP_M, SZ_W } +#define O_MwRd { OP_MR, SZ_WD } +#define O_MwRv { OP_MR, SZ_WV } +#define O_MwRy { OP_MR, SZ_WY } +#define O_MwU { OP_MU, SZ_WO } +#define O_N { OP_N, SZ_Q } +#define O_NONE { OP_NONE, SZ_NA } +#define O_Ob { OP_O, SZ_B } +#define O_Ov { OP_O, SZ_V } +#define O_Ow { OP_O, SZ_W } +#define O_P { OP_P, SZ_Q } +#define O_Q { OP_Q, SZ_Q } +#define O_R { OP_R, SZ_RDQ } +#define O_R0b { OP_R0, SZ_B } +#define O_R0v { OP_R0, SZ_V } +#define O_R0w { OP_R0, SZ_W } +#define O_R0y { OP_R0, SZ_Y } +#define O_R0z { OP_R0, SZ_Z } +#define O_R1b { OP_R1, SZ_B } +#define O_R1v { OP_R1, SZ_V } +#define O_R1w { OP_R1, SZ_W } +#define O_R1y { OP_R1, SZ_Y } +#define O_R1z { OP_R1, SZ_Z } +#define O_R2b { OP_R2, SZ_B } +#define O_R2v { OP_R2, SZ_V } +#define O_R2w { OP_R2, SZ_W } +#define O_R2y { OP_R2, SZ_Y } +#define O_R2z { OP_R2, SZ_Z } +#define O_R3b { OP_R3, SZ_B } +#define O_R3v { OP_R3, SZ_V } +#define O_R3w { OP_R3, SZ_W } +#define O_R3y { OP_R3, SZ_Y } +#define O_R3z { OP_R3, SZ_Z } +#define O_R4b { OP_R4, SZ_B } +#define O_R4v { OP_R4, SZ_V } +#define O_R4w { OP_R4, SZ_W } +#define O_R4y { OP_R4, SZ_Y } +#define O_R4z { OP_R4, SZ_Z } +#define O_R5b { OP_R5, SZ_B } +#define O_R5v { OP_R5, SZ_V } +#define O_R5w { OP_R5, SZ_W } +#define O_R5y { OP_R5, SZ_Y } +#define O_R5z { OP_R5, SZ_Z } +#define O_R6b { OP_R6, SZ_B } +#define O_R6v { OP_R6, SZ_V } +#define O_R6w { OP_R6, SZ_W } +#define O_R6y { OP_R6, SZ_Y } +#define O_R6z { OP_R6, SZ_Z } +#define O_R7b { OP_R7, SZ_B } +#define O_R7v { OP_R7, SZ_V } +#define O_R7w { OP_R7, SZ_W } +#define O_R7y { OP_R7, SZ_Y } +#define O_R7z { OP_R7, SZ_Z } +#define O_S { OP_S, SZ_W } +#define O_SS { OP_SS, SZ_NA } +#define O_ST0 { OP_ST0, SZ_NA } +#define O_ST1 { OP_ST1, SZ_NA } +#define O_ST2 { OP_ST2, SZ_NA } +#define O_ST3 { OP_ST3, SZ_NA } +#define O_ST4 { OP_ST4, SZ_NA } +#define O_ST5 { OP_ST5, SZ_NA } +#define O_ST6 { OP_ST6, SZ_NA } +#define O_ST7 { OP_ST7, SZ_NA } +#define O_U { OP_U, SZ_O } +#define O_Ux { OP_U, SZ_X } +#define O_V { OP_V, SZ_DQ } +#define O_Vdq { OP_V, SZ_DQ } +#define O_Vqq { OP_V, SZ_QQ } +#define O_Vsd { OP_V, SZ_Q } +#define O_Vx { OP_V, SZ_X } +#define O_W { OP_W, SZ_DQ } +#define O_Wdq { OP_W, SZ_DQ } +#define O_Wqq { OP_W, SZ_QQ } +#define O_Wsd { OP_W, SZ_Q } +#define O_Wx { OP_W, SZ_X } +#define O_eAX { OP_eAX, SZ_Z } +#define O_eCX { OP_eCX, SZ_Z } +#define O_eDX { OP_eDX, SZ_Z } +#define O_rAX { OP_rAX, SZ_V } +#define O_rCX { OP_rCX, SZ_V } +#define O_rDX { OP_rDX, SZ_V } +#define O_sIb { OP_sI, SZ_B } +#define O_sIv { OP_sI, SZ_V } +#define O_sIz { OP_sI, SZ_Z } + +struct ud_itab_entry ud_itab[] = { + /* 0000 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0001 */ { UD_Iaaa, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0002 */ { UD_Iaad, O_Ib, O_NONE, O_NONE, O_NONE, P_none }, + /* 0003 */ { UD_Iaam, O_Ib, O_NONE, O_NONE, O_NONE, P_none }, + /* 0004 */ { UD_Iaas, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0005 */ { UD_Iadc, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0006 */ { UD_Iadc, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0007 */ { UD_Iadc, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0008 */ { UD_Iadc, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0009 */ { UD_Iadc, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0010 */ { UD_Iadc, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0011 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0012 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0013 */ { UD_Iadc, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0014 */ { UD_Iadc, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0015 */ { UD_Iadd, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0016 */ { UD_Iadd, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0017 */ { UD_Iadd, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0018 */ { UD_Iadd, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0019 */ { UD_Iadd, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0020 */ { UD_Iadd, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0021 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0022 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0023 */ { UD_Iadd, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0024 */ { UD_Iadd, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0025 */ { UD_Iaddpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0026 */ { UD_Ivaddpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0027 */ { UD_Iaddps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0028 */ { UD_Ivaddps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0029 */ { UD_Iaddsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0030 */ { UD_Ivaddsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0031 */ { UD_Iaddss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0032 */ { UD_Ivaddss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0033 */ { UD_Iaddsubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0034 */ { UD_Ivaddsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0035 */ { UD_Iaddsubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0036 */ { UD_Ivaddsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0037 */ { UD_Iaesdec, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0038 */ { UD_Ivaesdec, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0039 */ { UD_Iaesdeclast, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0040 */ { UD_Ivaesdeclast, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0041 */ { UD_Iaesenc, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0042 */ { UD_Ivaesenc, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0043 */ { UD_Iaesenclast, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0044 */ { UD_Ivaesenclast, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0045 */ { UD_Iaesimc, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0046 */ { UD_Ivaesimc, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0047 */ { UD_Iaeskeygenassist, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0048 */ { UD_Ivaeskeygenassist, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0049 */ { UD_Iand, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0050 */ { UD_Iand, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0051 */ { UD_Iand, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0052 */ { UD_Iand, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0053 */ { UD_Iand, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0054 */ { UD_Iand, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0055 */ { UD_Iand, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0056 */ { UD_Iand, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0057 */ { UD_Iand, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0058 */ { UD_Iand, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0059 */ { UD_Iandpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0060 */ { UD_Ivandpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0061 */ { UD_Iandps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0062 */ { UD_Ivandps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0063 */ { UD_Iandnpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0064 */ { UD_Ivandnpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0065 */ { UD_Iandnps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0066 */ { UD_Ivandnps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0067 */ { UD_Iarpl, O_Ew, O_Gw, O_NONE, O_NONE, P_aso }, + /* 0068 */ { UD_Imovsxd, O_Gq, O_Ed, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexx|P_rexr|P_rexb }, + /* 0069 */ { UD_Icall, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0070 */ { UD_Icall, O_Eq, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 0071 */ { UD_Icall, O_Fv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0072 */ { UD_Icall, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0073 */ { UD_Icall, O_Av, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0074 */ { UD_Icbw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0075 */ { UD_Icwde, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0076 */ { UD_Icdqe, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0077 */ { UD_Iclc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0078 */ { UD_Icld, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0079 */ { UD_Iclflush, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0080 */ { UD_Iclgi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0081 */ { UD_Icli, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0082 */ { UD_Iclts, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0083 */ { UD_Icmc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0084 */ { UD_Icmovo, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0085 */ { UD_Icmovno, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0086 */ { UD_Icmovb, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0087 */ { UD_Icmovae, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0088 */ { UD_Icmovz, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0089 */ { UD_Icmovnz, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0090 */ { UD_Icmovbe, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0091 */ { UD_Icmova, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0092 */ { UD_Icmovs, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0093 */ { UD_Icmovns, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0094 */ { UD_Icmovp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0095 */ { UD_Icmovnp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0096 */ { UD_Icmovl, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0097 */ { UD_Icmovge, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0098 */ { UD_Icmovle, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0099 */ { UD_Icmovg, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0100 */ { UD_Icmp, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0101 */ { UD_Icmp, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0102 */ { UD_Icmp, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0103 */ { UD_Icmp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0104 */ { UD_Icmp, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0105 */ { UD_Icmp, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0106 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0107 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 0108 */ { UD_Icmp, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0109 */ { UD_Icmp, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0110 */ { UD_Icmppd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0111 */ { UD_Ivcmppd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0112 */ { UD_Icmpps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0113 */ { UD_Ivcmpps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0114 */ { UD_Icmpsb, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_seg }, + /* 0115 */ { UD_Icmpsw, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg }, + /* 0116 */ { UD_Icmpsd, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg }, + /* 0117 */ { UD_Icmpsd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0118 */ { UD_Ivcmpsd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0119 */ { UD_Icmpsq, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg }, + /* 0120 */ { UD_Icmpss, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0121 */ { UD_Ivcmpss, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0122 */ { UD_Icmpxchg, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0123 */ { UD_Icmpxchg, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0124 */ { UD_Icmpxchg8b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0125 */ { UD_Icmpxchg8b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0126 */ { UD_Icmpxchg16b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0127 */ { UD_Icomisd, O_Vsd, O_Wsd, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0128 */ { UD_Ivcomisd, O_Vsd, O_Wsd, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0129 */ { UD_Icomiss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0130 */ { UD_Ivcomiss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0131 */ { UD_Icpuid, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0132 */ { UD_Icvtdq2pd, O_V, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0133 */ { UD_Ivcvtdq2pd, O_Vx, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0134 */ { UD_Icvtdq2ps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0135 */ { UD_Ivcvtdq2ps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0136 */ { UD_Icvtpd2dq, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0137 */ { UD_Ivcvtpd2dq, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0138 */ { UD_Icvtpd2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0139 */ { UD_Icvtpd2ps, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0140 */ { UD_Ivcvtpd2ps, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0141 */ { UD_Icvtpi2ps, O_V, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0142 */ { UD_Icvtpi2pd, O_V, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0143 */ { UD_Icvtps2dq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0144 */ { UD_Ivcvtps2dq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0145 */ { UD_Icvtps2pd, O_V, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0146 */ { UD_Ivcvtps2pd, O_Vx, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0147 */ { UD_Icvtps2pi, O_P, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0148 */ { UD_Icvtsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0149 */ { UD_Ivcvtsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0150 */ { UD_Icvtsd2ss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0151 */ { UD_Ivcvtsd2ss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0152 */ { UD_Icvtsi2sd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0153 */ { UD_Ivcvtsi2sd, O_Vx, O_Hx, O_Ey, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0154 */ { UD_Icvtsi2ss, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0155 */ { UD_Ivcvtsi2ss, O_Vx, O_Hx, O_Ey, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0156 */ { UD_Icvtss2sd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0157 */ { UD_Ivcvtss2sd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0158 */ { UD_Icvtss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0159 */ { UD_Ivcvtss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0160 */ { UD_Icvttpd2dq, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0161 */ { UD_Ivcvttpd2dq, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0162 */ { UD_Icvttpd2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0163 */ { UD_Icvttps2dq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0164 */ { UD_Ivcvttps2dq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0165 */ { UD_Icvttps2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0166 */ { UD_Icvttsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0167 */ { UD_Ivcvttsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0168 */ { UD_Icvttss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0169 */ { UD_Ivcvttss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0170 */ { UD_Icwd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0171 */ { UD_Icdq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0172 */ { UD_Icqo, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0173 */ { UD_Idaa, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 0174 */ { UD_Idas, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 0175 */ { UD_Idec, O_R0z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0176 */ { UD_Idec, O_R1z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0177 */ { UD_Idec, O_R2z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0178 */ { UD_Idec, O_R3z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0179 */ { UD_Idec, O_R4z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0180 */ { UD_Idec, O_R5z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0181 */ { UD_Idec, O_R6z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0182 */ { UD_Idec, O_R7z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0183 */ { UD_Idec, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0184 */ { UD_Idec, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0185 */ { UD_Idiv, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0186 */ { UD_Idiv, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0187 */ { UD_Idivpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0188 */ { UD_Ivdivpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0189 */ { UD_Idivps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0190 */ { UD_Ivdivps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0191 */ { UD_Idivsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0192 */ { UD_Ivdivsd, O_Vx, O_Hx, O_MqU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0193 */ { UD_Idivss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0194 */ { UD_Ivdivss, O_Vx, O_Hx, O_MdU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0195 */ { UD_Idppd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0196 */ { UD_Ivdppd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0197 */ { UD_Idpps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0198 */ { UD_Ivdpps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0199 */ { UD_Iemms, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0200 */ { UD_Ienter, O_Iw, O_Ib, O_NONE, O_NONE, P_def64 }, + /* 0201 */ { UD_Iextractps, O_MdRy, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 0202 */ { UD_Ivextractps, O_MdRy, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 0203 */ { UD_If2xm1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0204 */ { UD_Ifabs, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0205 */ { UD_Ifadd, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0206 */ { UD_Ifadd, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0207 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0208 */ { UD_Ifadd, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0209 */ { UD_Ifadd, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0210 */ { UD_Ifadd, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0211 */ { UD_Ifadd, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0212 */ { UD_Ifadd, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0213 */ { UD_Ifadd, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0214 */ { UD_Ifadd, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0215 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0216 */ { UD_Ifadd, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0217 */ { UD_Ifadd, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0218 */ { UD_Ifadd, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0219 */ { UD_Ifadd, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0220 */ { UD_Ifadd, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0221 */ { UD_Ifadd, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0222 */ { UD_Ifadd, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0223 */ { UD_Ifaddp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0224 */ { UD_Ifaddp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0225 */ { UD_Ifaddp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0226 */ { UD_Ifaddp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0227 */ { UD_Ifaddp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0228 */ { UD_Ifaddp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0229 */ { UD_Ifaddp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0230 */ { UD_Ifaddp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0231 */ { UD_Ifbld, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0232 */ { UD_Ifbstp, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0233 */ { UD_Ifchs, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0234 */ { UD_Ifclex, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0235 */ { UD_Ifcmovb, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0236 */ { UD_Ifcmovb, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0237 */ { UD_Ifcmovb, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0238 */ { UD_Ifcmovb, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0239 */ { UD_Ifcmovb, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0240 */ { UD_Ifcmovb, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0241 */ { UD_Ifcmovb, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0242 */ { UD_Ifcmovb, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0243 */ { UD_Ifcmove, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0244 */ { UD_Ifcmove, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0245 */ { UD_Ifcmove, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0246 */ { UD_Ifcmove, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0247 */ { UD_Ifcmove, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0248 */ { UD_Ifcmove, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0249 */ { UD_Ifcmove, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0250 */ { UD_Ifcmove, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0251 */ { UD_Ifcmovbe, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0252 */ { UD_Ifcmovbe, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0253 */ { UD_Ifcmovbe, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0254 */ { UD_Ifcmovbe, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0255 */ { UD_Ifcmovbe, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0256 */ { UD_Ifcmovbe, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0257 */ { UD_Ifcmovbe, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0258 */ { UD_Ifcmovbe, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0259 */ { UD_Ifcmovu, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0260 */ { UD_Ifcmovu, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0261 */ { UD_Ifcmovu, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0262 */ { UD_Ifcmovu, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0263 */ { UD_Ifcmovu, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0264 */ { UD_Ifcmovu, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0265 */ { UD_Ifcmovu, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0266 */ { UD_Ifcmovu, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0267 */ { UD_Ifcmovnb, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0268 */ { UD_Ifcmovnb, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0269 */ { UD_Ifcmovnb, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0270 */ { UD_Ifcmovnb, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0271 */ { UD_Ifcmovnb, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0272 */ { UD_Ifcmovnb, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0273 */ { UD_Ifcmovnb, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0274 */ { UD_Ifcmovnb, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0275 */ { UD_Ifcmovne, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0276 */ { UD_Ifcmovne, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0277 */ { UD_Ifcmovne, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0278 */ { UD_Ifcmovne, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0279 */ { UD_Ifcmovne, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0280 */ { UD_Ifcmovne, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0281 */ { UD_Ifcmovne, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0282 */ { UD_Ifcmovne, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0283 */ { UD_Ifcmovnbe, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0284 */ { UD_Ifcmovnbe, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0285 */ { UD_Ifcmovnbe, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0286 */ { UD_Ifcmovnbe, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0287 */ { UD_Ifcmovnbe, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0288 */ { UD_Ifcmovnbe, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0289 */ { UD_Ifcmovnbe, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0290 */ { UD_Ifcmovnbe, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0291 */ { UD_Ifcmovnu, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0292 */ { UD_Ifcmovnu, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0293 */ { UD_Ifcmovnu, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0294 */ { UD_Ifcmovnu, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0295 */ { UD_Ifcmovnu, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0296 */ { UD_Ifcmovnu, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0297 */ { UD_Ifcmovnu, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0298 */ { UD_Ifcmovnu, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0299 */ { UD_Ifucomi, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0300 */ { UD_Ifucomi, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0301 */ { UD_Ifucomi, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0302 */ { UD_Ifucomi, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0303 */ { UD_Ifucomi, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0304 */ { UD_Ifucomi, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0305 */ { UD_Ifucomi, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0306 */ { UD_Ifucomi, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0307 */ { UD_Ifcom, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0308 */ { UD_Ifcom, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0309 */ { UD_Ifcom, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0310 */ { UD_Ifcom, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0311 */ { UD_Ifcom, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0312 */ { UD_Ifcom, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0313 */ { UD_Ifcom, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0314 */ { UD_Ifcom, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0315 */ { UD_Ifcom, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0316 */ { UD_Ifcom, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0317 */ { UD_Ifcom2, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0318 */ { UD_Ifcom2, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0319 */ { UD_Ifcom2, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0320 */ { UD_Ifcom2, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0321 */ { UD_Ifcom2, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0322 */ { UD_Ifcom2, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0323 */ { UD_Ifcom2, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0324 */ { UD_Ifcom2, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0325 */ { UD_Ifcomp3, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0326 */ { UD_Ifcomp3, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0327 */ { UD_Ifcomp3, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0328 */ { UD_Ifcomp3, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0329 */ { UD_Ifcomp3, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0330 */ { UD_Ifcomp3, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0331 */ { UD_Ifcomp3, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0332 */ { UD_Ifcomp3, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0333 */ { UD_Ifcomi, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0334 */ { UD_Ifcomi, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0335 */ { UD_Ifcomi, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0336 */ { UD_Ifcomi, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0337 */ { UD_Ifcomi, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0338 */ { UD_Ifcomi, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0339 */ { UD_Ifcomi, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0340 */ { UD_Ifcomi, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0341 */ { UD_Ifucomip, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0342 */ { UD_Ifucomip, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0343 */ { UD_Ifucomip, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0344 */ { UD_Ifucomip, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0345 */ { UD_Ifucomip, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0346 */ { UD_Ifucomip, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0347 */ { UD_Ifucomip, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0348 */ { UD_Ifucomip, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0349 */ { UD_Ifcomip, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0350 */ { UD_Ifcomip, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0351 */ { UD_Ifcomip, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0352 */ { UD_Ifcomip, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0353 */ { UD_Ifcomip, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0354 */ { UD_Ifcomip, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0355 */ { UD_Ifcomip, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0356 */ { UD_Ifcomip, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0357 */ { UD_Ifcomp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0358 */ { UD_Ifcomp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0359 */ { UD_Ifcomp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0360 */ { UD_Ifcomp, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0361 */ { UD_Ifcomp, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0362 */ { UD_Ifcomp, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0363 */ { UD_Ifcomp, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0364 */ { UD_Ifcomp, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0365 */ { UD_Ifcomp, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0366 */ { UD_Ifcomp, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0367 */ { UD_Ifcomp5, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0368 */ { UD_Ifcomp5, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0369 */ { UD_Ifcomp5, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0370 */ { UD_Ifcomp5, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0371 */ { UD_Ifcomp5, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0372 */ { UD_Ifcomp5, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0373 */ { UD_Ifcomp5, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0374 */ { UD_Ifcomp5, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0375 */ { UD_Ifcompp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0376 */ { UD_Ifcos, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0377 */ { UD_Ifdecstp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0378 */ { UD_Ifdiv, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0379 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0380 */ { UD_Ifdiv, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0381 */ { UD_Ifdiv, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0382 */ { UD_Ifdiv, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0383 */ { UD_Ifdiv, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0384 */ { UD_Ifdiv, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0385 */ { UD_Ifdiv, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0386 */ { UD_Ifdiv, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0387 */ { UD_Ifdiv, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0388 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0389 */ { UD_Ifdiv, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0390 */ { UD_Ifdiv, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0391 */ { UD_Ifdiv, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0392 */ { UD_Ifdiv, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0393 */ { UD_Ifdiv, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0394 */ { UD_Ifdiv, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0395 */ { UD_Ifdiv, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0396 */ { UD_Ifdivp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0397 */ { UD_Ifdivp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0398 */ { UD_Ifdivp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0399 */ { UD_Ifdivp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0400 */ { UD_Ifdivp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0401 */ { UD_Ifdivp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0402 */ { UD_Ifdivp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0403 */ { UD_Ifdivp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0404 */ { UD_Ifdivr, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0405 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0406 */ { UD_Ifdivr, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0407 */ { UD_Ifdivr, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0408 */ { UD_Ifdivr, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0409 */ { UD_Ifdivr, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0410 */ { UD_Ifdivr, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0411 */ { UD_Ifdivr, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0412 */ { UD_Ifdivr, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0413 */ { UD_Ifdivr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0414 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0415 */ { UD_Ifdivr, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0416 */ { UD_Ifdivr, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0417 */ { UD_Ifdivr, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0418 */ { UD_Ifdivr, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0419 */ { UD_Ifdivr, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0420 */ { UD_Ifdivr, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0421 */ { UD_Ifdivr, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0422 */ { UD_Ifdivrp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0423 */ { UD_Ifdivrp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0424 */ { UD_Ifdivrp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0425 */ { UD_Ifdivrp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0426 */ { UD_Ifdivrp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0427 */ { UD_Ifdivrp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0428 */ { UD_Ifdivrp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0429 */ { UD_Ifdivrp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0430 */ { UD_Ifemms, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0431 */ { UD_Iffree, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0432 */ { UD_Iffree, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0433 */ { UD_Iffree, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0434 */ { UD_Iffree, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0435 */ { UD_Iffree, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0436 */ { UD_Iffree, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0437 */ { UD_Iffree, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0438 */ { UD_Iffree, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0439 */ { UD_Iffreep, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0440 */ { UD_Iffreep, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0441 */ { UD_Iffreep, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0442 */ { UD_Iffreep, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0443 */ { UD_Iffreep, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0444 */ { UD_Iffreep, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0445 */ { UD_Iffreep, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0446 */ { UD_Iffreep, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0447 */ { UD_Ificom, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0448 */ { UD_Ificom, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0449 */ { UD_Ificomp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0450 */ { UD_Ificomp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0451 */ { UD_Ifild, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0452 */ { UD_Ifild, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0453 */ { UD_Ifild, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0454 */ { UD_Ifincstp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0455 */ { UD_Ifninit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0456 */ { UD_Ifiadd, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0457 */ { UD_Ifiadd, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0458 */ { UD_Ifidivr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0459 */ { UD_Ifidivr, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0460 */ { UD_Ifidiv, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0461 */ { UD_Ifidiv, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0462 */ { UD_Ifisub, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0463 */ { UD_Ifisub, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0464 */ { UD_Ifisubr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0465 */ { UD_Ifisubr, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0466 */ { UD_Ifist, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0467 */ { UD_Ifist, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0468 */ { UD_Ifistp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0469 */ { UD_Ifistp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0470 */ { UD_Ifistp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0471 */ { UD_Ifisttp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0472 */ { UD_Ifisttp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0473 */ { UD_Ifisttp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0474 */ { UD_Ifld, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0475 */ { UD_Ifld, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0476 */ { UD_Ifld, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0477 */ { UD_Ifld, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0478 */ { UD_Ifld, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0479 */ { UD_Ifld, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0480 */ { UD_Ifld, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0481 */ { UD_Ifld, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0482 */ { UD_Ifld, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0483 */ { UD_Ifld, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0484 */ { UD_Ifld, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0485 */ { UD_Ifld1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0486 */ { UD_Ifldl2t, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0487 */ { UD_Ifldl2e, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0488 */ { UD_Ifldpi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0489 */ { UD_Ifldlg2, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0490 */ { UD_Ifldln2, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0491 */ { UD_Ifldz, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0492 */ { UD_Ifldcw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0493 */ { UD_Ifldenv, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0494 */ { UD_Ifmul, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0495 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0496 */ { UD_Ifmul, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0497 */ { UD_Ifmul, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0498 */ { UD_Ifmul, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0499 */ { UD_Ifmul, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0500 */ { UD_Ifmul, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0501 */ { UD_Ifmul, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0502 */ { UD_Ifmul, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0503 */ { UD_Ifmul, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0504 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0505 */ { UD_Ifmul, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0506 */ { UD_Ifmul, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0507 */ { UD_Ifmul, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0508 */ { UD_Ifmul, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0509 */ { UD_Ifmul, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0510 */ { UD_Ifmul, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0511 */ { UD_Ifmul, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0512 */ { UD_Ifmulp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0513 */ { UD_Ifmulp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0514 */ { UD_Ifmulp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0515 */ { UD_Ifmulp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0516 */ { UD_Ifmulp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0517 */ { UD_Ifmulp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0518 */ { UD_Ifmulp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0519 */ { UD_Ifmulp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0520 */ { UD_Ifimul, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0521 */ { UD_Ifimul, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0522 */ { UD_Ifnop, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0523 */ { UD_Ifndisi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0524 */ { UD_Ifneni, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0525 */ { UD_Ifnsetpm, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0526 */ { UD_Ifpatan, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0527 */ { UD_Ifprem, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0528 */ { UD_Ifprem1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0529 */ { UD_Ifptan, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0530 */ { UD_Ifrndint, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0531 */ { UD_Ifrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0532 */ { UD_Ifrstpm, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0533 */ { UD_Ifnsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0534 */ { UD_Ifscale, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0535 */ { UD_Ifsin, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0536 */ { UD_Ifsincos, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0537 */ { UD_Ifsqrt, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0538 */ { UD_Ifstp, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0539 */ { UD_Ifstp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0540 */ { UD_Ifstp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0541 */ { UD_Ifstp, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0542 */ { UD_Ifstp, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0543 */ { UD_Ifstp, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0544 */ { UD_Ifstp, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0545 */ { UD_Ifstp, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0546 */ { UD_Ifstp, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0547 */ { UD_Ifstp, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0548 */ { UD_Ifstp, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0549 */ { UD_Ifstp1, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0550 */ { UD_Ifstp1, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0551 */ { UD_Ifstp1, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0552 */ { UD_Ifstp1, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0553 */ { UD_Ifstp1, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0554 */ { UD_Ifstp1, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0555 */ { UD_Ifstp1, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0556 */ { UD_Ifstp1, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0557 */ { UD_Ifstp8, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0558 */ { UD_Ifstp8, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0559 */ { UD_Ifstp8, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0560 */ { UD_Ifstp8, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0561 */ { UD_Ifstp8, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0562 */ { UD_Ifstp8, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0563 */ { UD_Ifstp8, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0564 */ { UD_Ifstp8, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0565 */ { UD_Ifstp9, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0566 */ { UD_Ifstp9, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0567 */ { UD_Ifstp9, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0568 */ { UD_Ifstp9, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0569 */ { UD_Ifstp9, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0570 */ { UD_Ifstp9, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0571 */ { UD_Ifstp9, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0572 */ { UD_Ifstp9, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0573 */ { UD_Ifst, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0574 */ { UD_Ifst, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0575 */ { UD_Ifst, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0576 */ { UD_Ifst, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0577 */ { UD_Ifst, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0578 */ { UD_Ifst, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0579 */ { UD_Ifst, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0580 */ { UD_Ifst, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0581 */ { UD_Ifst, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0582 */ { UD_Ifst, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0583 */ { UD_Ifnstcw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0584 */ { UD_Ifnstenv, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0585 */ { UD_Ifnstsw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0586 */ { UD_Ifnstsw, O_AX, O_NONE, O_NONE, O_NONE, P_none }, + /* 0587 */ { UD_Ifsub, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0588 */ { UD_Ifsub, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0589 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0590 */ { UD_Ifsub, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0591 */ { UD_Ifsub, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0592 */ { UD_Ifsub, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0593 */ { UD_Ifsub, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0594 */ { UD_Ifsub, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0595 */ { UD_Ifsub, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0596 */ { UD_Ifsub, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0597 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0598 */ { UD_Ifsub, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0599 */ { UD_Ifsub, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0600 */ { UD_Ifsub, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0601 */ { UD_Ifsub, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0602 */ { UD_Ifsub, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0603 */ { UD_Ifsub, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0604 */ { UD_Ifsub, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0605 */ { UD_Ifsubp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0606 */ { UD_Ifsubp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0607 */ { UD_Ifsubp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0608 */ { UD_Ifsubp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0609 */ { UD_Ifsubp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0610 */ { UD_Ifsubp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0611 */ { UD_Ifsubp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0612 */ { UD_Ifsubp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0613 */ { UD_Ifsubr, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0614 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0615 */ { UD_Ifsubr, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0616 */ { UD_Ifsubr, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0617 */ { UD_Ifsubr, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0618 */ { UD_Ifsubr, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0619 */ { UD_Ifsubr, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0620 */ { UD_Ifsubr, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0621 */ { UD_Ifsubr, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0622 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0623 */ { UD_Ifsubr, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0624 */ { UD_Ifsubr, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0625 */ { UD_Ifsubr, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0626 */ { UD_Ifsubr, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0627 */ { UD_Ifsubr, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0628 */ { UD_Ifsubr, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0629 */ { UD_Ifsubr, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0630 */ { UD_Ifsubr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0631 */ { UD_Ifsubrp, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0632 */ { UD_Ifsubrp, O_ST1, O_ST0, O_NONE, O_NONE, P_none }, + /* 0633 */ { UD_Ifsubrp, O_ST2, O_ST0, O_NONE, O_NONE, P_none }, + /* 0634 */ { UD_Ifsubrp, O_ST3, O_ST0, O_NONE, O_NONE, P_none }, + /* 0635 */ { UD_Ifsubrp, O_ST4, O_ST0, O_NONE, O_NONE, P_none }, + /* 0636 */ { UD_Ifsubrp, O_ST5, O_ST0, O_NONE, O_NONE, P_none }, + /* 0637 */ { UD_Ifsubrp, O_ST6, O_ST0, O_NONE, O_NONE, P_none }, + /* 0638 */ { UD_Ifsubrp, O_ST7, O_ST0, O_NONE, O_NONE, P_none }, + /* 0639 */ { UD_Iftst, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0640 */ { UD_Ifucom, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0641 */ { UD_Ifucom, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0642 */ { UD_Ifucom, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0643 */ { UD_Ifucom, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0644 */ { UD_Ifucom, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0645 */ { UD_Ifucom, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0646 */ { UD_Ifucom, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0647 */ { UD_Ifucom, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0648 */ { UD_Ifucomp, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0649 */ { UD_Ifucomp, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0650 */ { UD_Ifucomp, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0651 */ { UD_Ifucomp, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0652 */ { UD_Ifucomp, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0653 */ { UD_Ifucomp, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0654 */ { UD_Ifucomp, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0655 */ { UD_Ifucomp, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0656 */ { UD_Ifucompp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0657 */ { UD_Ifxam, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0658 */ { UD_Ifxch, O_ST0, O_ST0, O_NONE, O_NONE, P_none }, + /* 0659 */ { UD_Ifxch, O_ST0, O_ST1, O_NONE, O_NONE, P_none }, + /* 0660 */ { UD_Ifxch, O_ST0, O_ST2, O_NONE, O_NONE, P_none }, + /* 0661 */ { UD_Ifxch, O_ST0, O_ST3, O_NONE, O_NONE, P_none }, + /* 0662 */ { UD_Ifxch, O_ST0, O_ST4, O_NONE, O_NONE, P_none }, + /* 0663 */ { UD_Ifxch, O_ST0, O_ST5, O_NONE, O_NONE, P_none }, + /* 0664 */ { UD_Ifxch, O_ST0, O_ST6, O_NONE, O_NONE, P_none }, + /* 0665 */ { UD_Ifxch, O_ST0, O_ST7, O_NONE, O_NONE, P_none }, + /* 0666 */ { UD_Ifxch4, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0667 */ { UD_Ifxch4, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0668 */ { UD_Ifxch4, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0669 */ { UD_Ifxch4, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0670 */ { UD_Ifxch4, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0671 */ { UD_Ifxch4, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0672 */ { UD_Ifxch4, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0673 */ { UD_Ifxch4, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0674 */ { UD_Ifxch7, O_ST0, O_NONE, O_NONE, O_NONE, P_none }, + /* 0675 */ { UD_Ifxch7, O_ST1, O_NONE, O_NONE, O_NONE, P_none }, + /* 0676 */ { UD_Ifxch7, O_ST2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0677 */ { UD_Ifxch7, O_ST3, O_NONE, O_NONE, O_NONE, P_none }, + /* 0678 */ { UD_Ifxch7, O_ST4, O_NONE, O_NONE, O_NONE, P_none }, + /* 0679 */ { UD_Ifxch7, O_ST5, O_NONE, O_NONE, O_NONE, P_none }, + /* 0680 */ { UD_Ifxch7, O_ST6, O_NONE, O_NONE, O_NONE, P_none }, + /* 0681 */ { UD_Ifxch7, O_ST7, O_NONE, O_NONE, O_NONE, P_none }, + /* 0682 */ { UD_Ifxrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0683 */ { UD_Ifxsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0684 */ { UD_Ifxtract, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0685 */ { UD_Ifyl2x, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0686 */ { UD_Ifyl2xp1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0687 */ { UD_Ihlt, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0688 */ { UD_Iidiv, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0689 */ { UD_Iidiv, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0690 */ { UD_Iin, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0691 */ { UD_Iin, O_eAX, O_Ib, O_NONE, O_NONE, P_oso }, + /* 0692 */ { UD_Iin, O_AL, O_DX, O_NONE, O_NONE, P_none }, + /* 0693 */ { UD_Iin, O_eAX, O_DX, O_NONE, O_NONE, P_oso }, + /* 0694 */ { UD_Iimul, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0695 */ { UD_Iimul, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0696 */ { UD_Iimul, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0697 */ { UD_Iimul, O_Gv, O_Ev, O_Iz, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0698 */ { UD_Iimul, O_Gv, O_Ev, O_sIb, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0699 */ { UD_Iinc, O_R0z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0700 */ { UD_Iinc, O_R1z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0701 */ { UD_Iinc, O_R2z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0702 */ { UD_Iinc, O_R3z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0703 */ { UD_Iinc, O_R4z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0704 */ { UD_Iinc, O_R5z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0705 */ { UD_Iinc, O_R6z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0706 */ { UD_Iinc, O_R7z, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0707 */ { UD_Iinc, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0708 */ { UD_Iinc, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0709 */ { UD_Iinsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0710 */ { UD_Iinsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0711 */ { UD_Iinsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0712 */ { UD_Iint1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0713 */ { UD_Iint3, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0714 */ { UD_Iint, O_Ib, O_NONE, O_NONE, O_NONE, P_none }, + /* 0715 */ { UD_Iinto, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 0716 */ { UD_Iinvd, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0717 */ { UD_Iinvept, O_Gd, O_Mo, O_NONE, O_NONE, P_none }, + /* 0718 */ { UD_Iinvept, O_Gq, O_Mo, O_NONE, O_NONE, P_none }, + /* 0719 */ { UD_Iinvlpg, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0720 */ { UD_Iinvlpga, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0721 */ { UD_Iinvvpid, O_Gd, O_Mo, O_NONE, O_NONE, P_none }, + /* 0722 */ { UD_Iinvvpid, O_Gq, O_Mo, O_NONE, O_NONE, P_none }, + /* 0723 */ { UD_Iiretw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0724 */ { UD_Iiretd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0725 */ { UD_Iiretq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0726 */ { UD_Ijo, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0727 */ { UD_Ijo, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0728 */ { UD_Ijno, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0729 */ { UD_Ijno, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0730 */ { UD_Ijb, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0731 */ { UD_Ijb, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0732 */ { UD_Ijae, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0733 */ { UD_Ijae, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0734 */ { UD_Ijz, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0735 */ { UD_Ijz, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0736 */ { UD_Ijnz, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0737 */ { UD_Ijnz, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0738 */ { UD_Ijbe, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0739 */ { UD_Ijbe, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0740 */ { UD_Ija, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0741 */ { UD_Ija, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0742 */ { UD_Ijs, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0743 */ { UD_Ijs, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0744 */ { UD_Ijns, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0745 */ { UD_Ijns, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0746 */ { UD_Ijp, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0747 */ { UD_Ijp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0748 */ { UD_Ijnp, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0749 */ { UD_Ijnp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0750 */ { UD_Ijl, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0751 */ { UD_Ijl, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0752 */ { UD_Ijge, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0753 */ { UD_Ijge, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0754 */ { UD_Ijle, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0755 */ { UD_Ijle, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0756 */ { UD_Ijg, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0757 */ { UD_Ijg, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0758 */ { UD_Ijcxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso }, + /* 0759 */ { UD_Ijecxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso }, + /* 0760 */ { UD_Ijrcxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso }, + /* 0761 */ { UD_Ijmp, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 0762 */ { UD_Ijmp, O_Fv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0763 */ { UD_Ijmp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 0764 */ { UD_Ijmp, O_Av, O_NONE, O_NONE, O_NONE, P_oso }, + /* 0765 */ { UD_Ijmp, O_Jb, O_NONE, O_NONE, O_NONE, P_def64 }, + /* 0766 */ { UD_Ilahf, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0767 */ { UD_Ilar, O_Gv, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0768 */ { UD_Ildmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0769 */ { UD_Ilds, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso }, + /* 0770 */ { UD_Ilea, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0771 */ { UD_Iles, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso }, + /* 0772 */ { UD_Ilfs, O_Gz, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0773 */ { UD_Ilgs, O_Gz, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0774 */ { UD_Ilidt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0775 */ { UD_Ilss, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0776 */ { UD_Ileave, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0777 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0778 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0779 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0780 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0781 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0782 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0783 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0784 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0785 */ { UD_Ilgdt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0786 */ { UD_Illdt, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0787 */ { UD_Ilmsw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0788 */ { UD_Ilmsw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0789 */ { UD_Ilock, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0790 */ { UD_Ilodsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0791 */ { UD_Ilodsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0792 */ { UD_Ilodsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0793 */ { UD_Ilodsq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0794 */ { UD_Iloopne, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0795 */ { UD_Iloope, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0796 */ { UD_Iloop, O_Jb, O_NONE, O_NONE, O_NONE, P_none }, + /* 0797 */ { UD_Ilsl, O_Gv, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0798 */ { UD_Iltr, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0799 */ { UD_Imaskmovq, O_P, O_N, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0800 */ { UD_Imaxpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0801 */ { UD_Ivmaxpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0802 */ { UD_Imaxps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0803 */ { UD_Ivmaxps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0804 */ { UD_Imaxsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0805 */ { UD_Ivmaxsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0806 */ { UD_Imaxss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0807 */ { UD_Ivmaxss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0808 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0809 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0810 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0811 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0812 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0813 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0814 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0815 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0816 */ { UD_Iminpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0817 */ { UD_Ivminpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0818 */ { UD_Iminps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0819 */ { UD_Ivminps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0820 */ { UD_Iminsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0821 */ { UD_Ivminsd, O_Vx, O_Hx, O_MqU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0822 */ { UD_Iminss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0823 */ { UD_Ivminss, O_Vx, O_Hx, O_MdU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0824 */ { UD_Imonitor, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0825 */ { UD_Imontmul, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0826 */ { UD_Imov, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0827 */ { UD_Imov, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0828 */ { UD_Imov, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0829 */ { UD_Imov, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0830 */ { UD_Imov, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0831 */ { UD_Imov, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0832 */ { UD_Imov, O_MwRv, O_S, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0833 */ { UD_Imov, O_S, O_MwRv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0834 */ { UD_Imov, O_AL, O_Ob, O_NONE, O_NONE, P_none }, + /* 0835 */ { UD_Imov, O_rAX, O_Ov, O_NONE, O_NONE, P_aso|P_oso|P_rexw }, + /* 0836 */ { UD_Imov, O_Ob, O_AL, O_NONE, O_NONE, P_none }, + /* 0837 */ { UD_Imov, O_Ov, O_rAX, O_NONE, O_NONE, P_aso|P_oso|P_rexw }, + /* 0838 */ { UD_Imov, O_R0b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0839 */ { UD_Imov, O_R1b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0840 */ { UD_Imov, O_R2b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0841 */ { UD_Imov, O_R3b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0842 */ { UD_Imov, O_R4b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0843 */ { UD_Imov, O_R5b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0844 */ { UD_Imov, O_R6b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0845 */ { UD_Imov, O_R7b, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 0846 */ { UD_Imov, O_R0v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0847 */ { UD_Imov, O_R1v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0848 */ { UD_Imov, O_R2v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0849 */ { UD_Imov, O_R3v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0850 */ { UD_Imov, O_R4v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0851 */ { UD_Imov, O_R5v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0852 */ { UD_Imov, O_R6v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0853 */ { UD_Imov, O_R7v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 0854 */ { UD_Imov, O_R, O_C, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0855 */ { UD_Imov, O_R, O_D, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0856 */ { UD_Imov, O_C, O_R, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0857 */ { UD_Imov, O_D, O_R, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb }, + /* 0858 */ { UD_Imovapd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0859 */ { UD_Ivmovapd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0860 */ { UD_Imovapd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0861 */ { UD_Ivmovapd, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0862 */ { UD_Imovaps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0863 */ { UD_Ivmovaps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0864 */ { UD_Imovaps, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0865 */ { UD_Ivmovaps, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0866 */ { UD_Imovd, O_P, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0867 */ { UD_Imovd, O_P, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0868 */ { UD_Imovd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0869 */ { UD_Ivmovd, O_Vx, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0870 */ { UD_Imovd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0871 */ { UD_Ivmovd, O_Vx, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0872 */ { UD_Imovd, O_Ey, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0873 */ { UD_Imovd, O_Ey, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0874 */ { UD_Imovd, O_Ey, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0875 */ { UD_Ivmovd, O_Ey, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0876 */ { UD_Imovd, O_Ey, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0877 */ { UD_Ivmovd, O_Ey, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0878 */ { UD_Imovhpd, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0879 */ { UD_Ivmovhpd, O_Vx, O_Hx, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0880 */ { UD_Imovhpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0881 */ { UD_Ivmovhpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0882 */ { UD_Imovhps, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0883 */ { UD_Ivmovhps, O_Vx, O_Hx, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0884 */ { UD_Imovhps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0885 */ { UD_Ivmovhps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0886 */ { UD_Imovlhps, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0887 */ { UD_Ivmovlhps, O_Vx, O_Hx, O_Ux, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0888 */ { UD_Imovlpd, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0889 */ { UD_Ivmovlpd, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0890 */ { UD_Imovlpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0891 */ { UD_Ivmovlpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0892 */ { UD_Imovlps, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0893 */ { UD_Ivmovlps, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0894 */ { UD_Imovlps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0895 */ { UD_Ivmovlps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0896 */ { UD_Imovhlps, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0897 */ { UD_Ivmovhlps, O_Vx, O_Ux, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0898 */ { UD_Imovmskpd, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexb }, + /* 0899 */ { UD_Ivmovmskpd, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexb|P_vexl }, + /* 0900 */ { UD_Imovmskps, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexb }, + /* 0901 */ { UD_Ivmovmskps, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexb }, + /* 0902 */ { UD_Imovntdq, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0903 */ { UD_Ivmovntdq, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0904 */ { UD_Imovnti, O_M, O_Gy, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0905 */ { UD_Imovntpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0906 */ { UD_Ivmovntpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0907 */ { UD_Imovntps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0908 */ { UD_Ivmovntps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0909 */ { UD_Imovntq, O_M, O_P, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0910 */ { UD_Imovq, O_P, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0911 */ { UD_Imovq, O_V, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0912 */ { UD_Ivmovq, O_Vx, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0913 */ { UD_Imovq, O_Eq, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0914 */ { UD_Imovq, O_Eq, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0915 */ { UD_Ivmovq, O_Eq, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0916 */ { UD_Imovq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0917 */ { UD_Ivmovq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0918 */ { UD_Imovq, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0919 */ { UD_Ivmovq, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0920 */ { UD_Imovq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0921 */ { UD_Imovq, O_Q, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0922 */ { UD_Imovsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0923 */ { UD_Imovsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0924 */ { UD_Imovsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0925 */ { UD_Imovsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0926 */ { UD_Imovsd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0927 */ { UD_Imovsq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 0928 */ { UD_Imovss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0929 */ { UD_Imovss, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0930 */ { UD_Imovsx, O_Gv, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0931 */ { UD_Imovsx, O_Gy, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0932 */ { UD_Imovupd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0933 */ { UD_Ivmovupd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0934 */ { UD_Imovupd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0935 */ { UD_Ivmovupd, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0936 */ { UD_Imovups, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0937 */ { UD_Ivmovups, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0938 */ { UD_Imovups, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0939 */ { UD_Ivmovups, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0940 */ { UD_Imovzx, O_Gv, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0941 */ { UD_Imovzx, O_Gy, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0942 */ { UD_Imul, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0943 */ { UD_Imul, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0944 */ { UD_Imulpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0945 */ { UD_Ivmulpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0946 */ { UD_Imulps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0947 */ { UD_Ivmulps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0948 */ { UD_Imulsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0949 */ { UD_Ivmulsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0950 */ { UD_Imulss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0951 */ { UD_Ivmulss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0952 */ { UD_Imwait, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 0953 */ { UD_Ineg, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0954 */ { UD_Ineg, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0955 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0956 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0957 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0958 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0959 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0960 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0961 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0962 */ { UD_Inot, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0963 */ { UD_Inot, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0964 */ { UD_Ior, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0965 */ { UD_Ior, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0966 */ { UD_Ior, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0967 */ { UD_Ior, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0968 */ { UD_Ior, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 0969 */ { UD_Ior, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 0970 */ { UD_Ior, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0971 */ { UD_Ior, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0972 */ { UD_Ior, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0973 */ { UD_Ior, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0974 */ { UD_Iorpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0975 */ { UD_Ivorpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0976 */ { UD_Iorps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0977 */ { UD_Ivorps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0978 */ { UD_Iout, O_Ib, O_AL, O_NONE, O_NONE, P_none }, + /* 0979 */ { UD_Iout, O_Ib, O_eAX, O_NONE, O_NONE, P_oso }, + /* 0980 */ { UD_Iout, O_DX, O_AL, O_NONE, O_NONE, P_none }, + /* 0981 */ { UD_Iout, O_DX, O_eAX, O_NONE, O_NONE, P_oso }, + /* 0982 */ { UD_Ioutsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 0983 */ { UD_Ioutsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0984 */ { UD_Ioutsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg }, + /* 0985 */ { UD_Ipacksswb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0986 */ { UD_Ivpacksswb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0987 */ { UD_Ipacksswb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0988 */ { UD_Ipackssdw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0989 */ { UD_Ivpackssdw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0990 */ { UD_Ipackssdw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0991 */ { UD_Ipackuswb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0992 */ { UD_Ivpackuswb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0993 */ { UD_Ipackuswb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0994 */ { UD_Ipaddb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0995 */ { UD_Ivpaddb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 0996 */ { UD_Ipaddb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0997 */ { UD_Ipaddw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0998 */ { UD_Ipaddw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0999 */ { UD_Ivpaddw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1000 */ { UD_Ipaddd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1001 */ { UD_Ipaddd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1002 */ { UD_Ivpaddd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1003 */ { UD_Ipaddsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1004 */ { UD_Ipaddsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1005 */ { UD_Ivpaddsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1006 */ { UD_Ipaddsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1007 */ { UD_Ipaddsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1008 */ { UD_Ivpaddsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1009 */ { UD_Ipaddusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1010 */ { UD_Ipaddusb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1011 */ { UD_Ivpaddusb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1012 */ { UD_Ipaddusw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1013 */ { UD_Ipaddusw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1014 */ { UD_Ivpaddusw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1015 */ { UD_Ipand, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1016 */ { UD_Ivpand, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1017 */ { UD_Ipand, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1018 */ { UD_Ipandn, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1019 */ { UD_Ivpandn, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1020 */ { UD_Ipandn, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1021 */ { UD_Ipavgb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1022 */ { UD_Ivpavgb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1023 */ { UD_Ipavgb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1024 */ { UD_Ipavgw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1025 */ { UD_Ivpavgw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1026 */ { UD_Ipavgw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1027 */ { UD_Ipcmpeqb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1028 */ { UD_Ipcmpeqb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1029 */ { UD_Ivpcmpeqb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1030 */ { UD_Ipcmpeqw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1031 */ { UD_Ipcmpeqw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1032 */ { UD_Ivpcmpeqw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1033 */ { UD_Ipcmpeqd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1034 */ { UD_Ipcmpeqd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1035 */ { UD_Ivpcmpeqd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1036 */ { UD_Ipcmpgtb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1037 */ { UD_Ivpcmpgtb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1038 */ { UD_Ipcmpgtb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1039 */ { UD_Ipcmpgtw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1040 */ { UD_Ivpcmpgtw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1041 */ { UD_Ipcmpgtw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1042 */ { UD_Ipcmpgtd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1043 */ { UD_Ivpcmpgtd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1044 */ { UD_Ipcmpgtd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1045 */ { UD_Ipextrb, O_MbRv, O_V, O_Ib, O_NONE, P_aso|P_rexx|P_rexr|P_rexb|P_def64 }, + /* 1046 */ { UD_Ivpextrb, O_MbRv, O_Vx, O_Ib, O_NONE, P_aso|P_rexx|P_rexr|P_rexb|P_def64 }, + /* 1047 */ { UD_Ipextrd, O_Ed, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1048 */ { UD_Ivpextrd, O_Ed, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1049 */ { UD_Ipextrd, O_Ed, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1050 */ { UD_Ivpextrd, O_Ed, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb }, + /* 1051 */ { UD_Ipextrq, O_Eq, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexb|P_def64 }, + /* 1052 */ { UD_Ivpextrq, O_Eq, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexb|P_def64 }, + /* 1053 */ { UD_Ipextrw, O_Gd, O_U, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexb }, + /* 1054 */ { UD_Ivpextrw, O_Gd, O_Ux, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexb }, + /* 1055 */ { UD_Ipextrw, O_Gd, O_N, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1056 */ { UD_Ipextrw, O_MwRd, O_V, O_Ib, O_NONE, P_aso|P_rexw|P_rexx|P_rexr|P_rexb }, + /* 1057 */ { UD_Ivpextrw, O_MwRd, O_Vx, O_Ib, O_NONE, P_aso|P_rexw|P_rexx|P_rexr|P_rexb }, + /* 1058 */ { UD_Ipinsrb, O_V, O_MbRd, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1059 */ { UD_Ipinsrw, O_P, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1060 */ { UD_Ipinsrw, O_V, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1061 */ { UD_Ivpinsrw, O_Vx, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1062 */ { UD_Ipinsrd, O_V, O_Ed, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1063 */ { UD_Ipinsrd, O_V, O_Ed, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1064 */ { UD_Ipinsrq, O_V, O_Eq, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1065 */ { UD_Ivpinsrb, O_V, O_H, O_MbRd, O_Ib, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1066 */ { UD_Ivpinsrd, O_V, O_H, O_Ed, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1067 */ { UD_Ivpinsrd, O_V, O_H, O_Ed, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1068 */ { UD_Ivpinsrq, O_V, O_H, O_Eq, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1069 */ { UD_Ipmaddwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1070 */ { UD_Ipmaddwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1071 */ { UD_Ivpmaddwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1072 */ { UD_Ipmaxsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1073 */ { UD_Ivpmaxsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1074 */ { UD_Ipmaxsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1075 */ { UD_Ipmaxub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1076 */ { UD_Ipmaxub, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1077 */ { UD_Ivpmaxub, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1078 */ { UD_Ipminsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1079 */ { UD_Ivpminsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1080 */ { UD_Ipminsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1081 */ { UD_Ipminub, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1082 */ { UD_Ivpminub, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1083 */ { UD_Ipminub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1084 */ { UD_Ipmovmskb, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb }, + /* 1085 */ { UD_Ivpmovmskb, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb }, + /* 1086 */ { UD_Ipmovmskb, O_Gd, O_N, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb }, + /* 1087 */ { UD_Ipmulhuw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1088 */ { UD_Ipmulhuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1089 */ { UD_Ivpmulhuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1090 */ { UD_Ipmulhw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1091 */ { UD_Ivpmulhw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1092 */ { UD_Ipmulhw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1093 */ { UD_Ipmullw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1094 */ { UD_Ipmullw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1095 */ { UD_Ivpmullw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1096 */ { UD_Ipop, O_ES, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1097 */ { UD_Ipop, O_SS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1098 */ { UD_Ipop, O_DS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1099 */ { UD_Ipop, O_GS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1100 */ { UD_Ipop, O_FS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1101 */ { UD_Ipop, O_R0v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1102 */ { UD_Ipop, O_R1v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1103 */ { UD_Ipop, O_R2v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1104 */ { UD_Ipop, O_R3v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1105 */ { UD_Ipop, O_R4v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1106 */ { UD_Ipop, O_R5v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1107 */ { UD_Ipop, O_R6v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1108 */ { UD_Ipop, O_R7v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1109 */ { UD_Ipop, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1110 */ { UD_Ipopa, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1111 */ { UD_Ipopad, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1112 */ { UD_Ipopfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1113 */ { UD_Ipopfd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1114 */ { UD_Ipopfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1115 */ { UD_Ipopfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1116 */ { UD_Ipor, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1117 */ { UD_Ivpor, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1118 */ { UD_Ipor, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1119 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1120 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1121 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1122 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1123 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1124 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1125 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1126 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1127 */ { UD_Iprefetchnta, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1128 */ { UD_Iprefetcht0, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1129 */ { UD_Iprefetcht1, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1130 */ { UD_Iprefetcht2, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1131 */ { UD_Ipsadbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1132 */ { UD_Ivpsadbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1133 */ { UD_Ipsadbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1134 */ { UD_Ipshufw, O_P, O_Q, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1135 */ { UD_Ipsllw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1136 */ { UD_Ipsllw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1137 */ { UD_Ipsllw, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1138 */ { UD_Ipsllw, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1139 */ { UD_Ipslld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1140 */ { UD_Ipslld, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1141 */ { UD_Ipslld, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1142 */ { UD_Ipslld, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1143 */ { UD_Ipsllq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1144 */ { UD_Ipsllq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1145 */ { UD_Ipsllq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1146 */ { UD_Ipsllq, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1147 */ { UD_Ipsraw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1148 */ { UD_Ipsraw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1149 */ { UD_Ivpsraw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1150 */ { UD_Ipsraw, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1151 */ { UD_Ivpsraw, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1152 */ { UD_Ipsraw, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1153 */ { UD_Ipsrad, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1154 */ { UD_Ipsrad, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1155 */ { UD_Ivpsrad, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1156 */ { UD_Ipsrad, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1157 */ { UD_Ipsrad, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1158 */ { UD_Ivpsrad, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1159 */ { UD_Ipsrlw, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1160 */ { UD_Ipsrlw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1161 */ { UD_Ipsrlw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1162 */ { UD_Ivpsrlw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1163 */ { UD_Ipsrlw, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1164 */ { UD_Ivpsrlw, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1165 */ { UD_Ipsrld, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1166 */ { UD_Ipsrld, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1167 */ { UD_Ipsrld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1168 */ { UD_Ivpsrld, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1169 */ { UD_Ipsrld, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1170 */ { UD_Ivpsrld, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1171 */ { UD_Ipsrlq, O_N, O_Ib, O_NONE, O_NONE, P_none }, + /* 1172 */ { UD_Ipsrlq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1173 */ { UD_Ipsrlq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1174 */ { UD_Ivpsrlq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1175 */ { UD_Ipsrlq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1176 */ { UD_Ivpsrlq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1177 */ { UD_Ipsubb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1178 */ { UD_Ivpsubb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1179 */ { UD_Ipsubb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1180 */ { UD_Ipsubw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1181 */ { UD_Ivpsubw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1182 */ { UD_Ipsubw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1183 */ { UD_Ipsubd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1184 */ { UD_Ipsubd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1185 */ { UD_Ivpsubd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1186 */ { UD_Ipsubsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1187 */ { UD_Ipsubsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1188 */ { UD_Ivpsubsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1189 */ { UD_Ipsubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1190 */ { UD_Ipsubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1191 */ { UD_Ivpsubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1192 */ { UD_Ipsubusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1193 */ { UD_Ipsubusb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1194 */ { UD_Ivpsubusb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1195 */ { UD_Ipsubusw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1196 */ { UD_Ipsubusw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1197 */ { UD_Ivpsubusw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1198 */ { UD_Ipunpckhbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1199 */ { UD_Ivpunpckhbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1200 */ { UD_Ipunpckhbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1201 */ { UD_Ipunpckhwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1202 */ { UD_Ivpunpckhwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1203 */ { UD_Ipunpckhwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1204 */ { UD_Ipunpckhdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1205 */ { UD_Ivpunpckhdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1206 */ { UD_Ipunpckhdq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1207 */ { UD_Ipunpcklbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1208 */ { UD_Ivpunpcklbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1209 */ { UD_Ipunpcklbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1210 */ { UD_Ipunpcklwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1211 */ { UD_Ivpunpcklwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1212 */ { UD_Ipunpcklwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1213 */ { UD_Ipunpckldq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1214 */ { UD_Ivpunpckldq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1215 */ { UD_Ipunpckldq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1216 */ { UD_Ipi2fw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1217 */ { UD_Ipi2fd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1218 */ { UD_Ipf2iw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1219 */ { UD_Ipf2id, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1220 */ { UD_Ipfnacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1221 */ { UD_Ipfpnacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1222 */ { UD_Ipfcmpge, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1223 */ { UD_Ipfmin, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1224 */ { UD_Ipfrcp, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1225 */ { UD_Ipfrsqrt, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1226 */ { UD_Ipfsub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1227 */ { UD_Ipfadd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1228 */ { UD_Ipfcmpgt, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1229 */ { UD_Ipfmax, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1230 */ { UD_Ipfrcpit1, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1231 */ { UD_Ipfrsqit1, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1232 */ { UD_Ipfsubr, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1233 */ { UD_Ipfacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1234 */ { UD_Ipfcmpeq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1235 */ { UD_Ipfmul, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1236 */ { UD_Ipfrcpit2, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1237 */ { UD_Ipmulhrw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1238 */ { UD_Ipswapd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1239 */ { UD_Ipavgusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1240 */ { UD_Ipush, O_ES, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1241 */ { UD_Ipush, O_CS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1242 */ { UD_Ipush, O_SS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1243 */ { UD_Ipush, O_DS, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1244 */ { UD_Ipush, O_GS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1245 */ { UD_Ipush, O_FS, O_NONE, O_NONE, O_NONE, P_none }, + /* 1246 */ { UD_Ipush, O_R0v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1247 */ { UD_Ipush, O_R1v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1248 */ { UD_Ipush, O_R2v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1249 */ { UD_Ipush, O_R3v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1250 */ { UD_Ipush, O_R4v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1251 */ { UD_Ipush, O_R5v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1252 */ { UD_Ipush, O_R6v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1253 */ { UD_Ipush, O_R7v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 }, + /* 1254 */ { UD_Ipush, O_sIz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1255 */ { UD_Ipush, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1256 */ { UD_Ipush, O_sIb, O_NONE, O_NONE, O_NONE, P_oso|P_def64 }, + /* 1257 */ { UD_Ipusha, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1258 */ { UD_Ipushad, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 }, + /* 1259 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1260 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 }, + /* 1261 */ { UD_Ipushfd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso }, + /* 1262 */ { UD_Ipushfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 }, + /* 1263 */ { UD_Ipushfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 }, + /* 1264 */ { UD_Ipxor, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1265 */ { UD_Ivpxor, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1266 */ { UD_Ipxor, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1267 */ { UD_Ircl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1268 */ { UD_Ircl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1269 */ { UD_Ircl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1270 */ { UD_Ircl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1271 */ { UD_Ircl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1272 */ { UD_Ircl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1273 */ { UD_Ircr, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1274 */ { UD_Ircr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1275 */ { UD_Ircr, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1276 */ { UD_Ircr, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1277 */ { UD_Ircr, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1278 */ { UD_Ircr, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1279 */ { UD_Irol, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1280 */ { UD_Irol, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1281 */ { UD_Irol, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1282 */ { UD_Irol, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1283 */ { UD_Irol, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1284 */ { UD_Irol, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1285 */ { UD_Iror, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1286 */ { UD_Iror, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1287 */ { UD_Iror, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1288 */ { UD_Iror, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1289 */ { UD_Iror, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1290 */ { UD_Iror, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1291 */ { UD_Ircpps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1292 */ { UD_Ivrcpps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1293 */ { UD_Ircpss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1294 */ { UD_Ivrcpss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1295 */ { UD_Irdmsr, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1296 */ { UD_Irdpmc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1297 */ { UD_Irdtsc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1298 */ { UD_Irdtscp, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1299 */ { UD_Irepne, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1300 */ { UD_Irep, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1301 */ { UD_Iret, O_Iw, O_NONE, O_NONE, O_NONE, P_none }, + /* 1302 */ { UD_Iret, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1303 */ { UD_Iretf, O_Iw, O_NONE, O_NONE, O_NONE, P_none }, + /* 1304 */ { UD_Iretf, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1305 */ { UD_Irsm, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1306 */ { UD_Irsqrtps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1307 */ { UD_Ivrsqrtps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1308 */ { UD_Irsqrtss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1309 */ { UD_Ivrsqrtss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1310 */ { UD_Isahf, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1311 */ { UD_Isalc, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 }, + /* 1312 */ { UD_Isar, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1313 */ { UD_Isar, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1314 */ { UD_Isar, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1315 */ { UD_Isar, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1316 */ { UD_Isar, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1317 */ { UD_Isar, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1318 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1319 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1320 */ { UD_Ishl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1321 */ { UD_Ishl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1322 */ { UD_Ishl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1323 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1324 */ { UD_Ishl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1325 */ { UD_Ishl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1326 */ { UD_Ishl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1327 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1328 */ { UD_Ishl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1329 */ { UD_Ishl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1330 */ { UD_Ishr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1331 */ { UD_Ishr, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1332 */ { UD_Ishr, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1333 */ { UD_Ishr, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1334 */ { UD_Ishr, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1335 */ { UD_Ishr, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1336 */ { UD_Isbb, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1337 */ { UD_Isbb, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1338 */ { UD_Isbb, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1339 */ { UD_Isbb, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1340 */ { UD_Isbb, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1341 */ { UD_Isbb, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1342 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1343 */ { UD_Isbb, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1344 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 1345 */ { UD_Isbb, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1346 */ { UD_Iscasb, O_NONE, O_NONE, O_NONE, O_NONE, P_strz }, + /* 1347 */ { UD_Iscasw, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw }, + /* 1348 */ { UD_Iscasd, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw }, + /* 1349 */ { UD_Iscasq, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw }, + /* 1350 */ { UD_Iseto, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1351 */ { UD_Isetno, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1352 */ { UD_Isetb, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1353 */ { UD_Isetae, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1354 */ { UD_Isetz, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1355 */ { UD_Isetnz, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1356 */ { UD_Isetbe, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1357 */ { UD_Iseta, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1358 */ { UD_Isets, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1359 */ { UD_Isetns, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1360 */ { UD_Isetp, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1361 */ { UD_Isetnp, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1362 */ { UD_Isetl, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1363 */ { UD_Isetge, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1364 */ { UD_Isetle, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1365 */ { UD_Isetg, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1366 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1367 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1368 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1369 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1370 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1371 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1372 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1373 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1374 */ { UD_Isgdt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1375 */ { UD_Ishld, O_Ev, O_Gv, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1376 */ { UD_Ishld, O_Ev, O_Gv, O_CL, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1377 */ { UD_Ishrd, O_Ev, O_Gv, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1378 */ { UD_Ishrd, O_Ev, O_Gv, O_CL, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1379 */ { UD_Ishufpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1380 */ { UD_Ivshufpd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1381 */ { UD_Ishufps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1382 */ { UD_Ivshufps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1383 */ { UD_Isidt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1384 */ { UD_Isldt, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1385 */ { UD_Ismsw, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1386 */ { UD_Ismsw, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1387 */ { UD_Isqrtps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1388 */ { UD_Ivsqrtps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1389 */ { UD_Isqrtpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1390 */ { UD_Ivsqrtpd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1391 */ { UD_Isqrtsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1392 */ { UD_Ivsqrtsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1393 */ { UD_Isqrtss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1394 */ { UD_Ivsqrtss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1395 */ { UD_Istc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1396 */ { UD_Istd, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1397 */ { UD_Istgi, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1398 */ { UD_Isti, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1399 */ { UD_Iskinit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1400 */ { UD_Istmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1401 */ { UD_Ivstmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1402 */ { UD_Istosb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg }, + /* 1403 */ { UD_Istosw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 1404 */ { UD_Istosd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 1405 */ { UD_Istosq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw }, + /* 1406 */ { UD_Istr, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1407 */ { UD_Isub, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1408 */ { UD_Isub, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1409 */ { UD_Isub, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1410 */ { UD_Isub, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1411 */ { UD_Isub, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1412 */ { UD_Isub, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1413 */ { UD_Isub, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1414 */ { UD_Isub, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1415 */ { UD_Isub, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 1416 */ { UD_Isub, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1417 */ { UD_Isubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1418 */ { UD_Ivsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1419 */ { UD_Isubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1420 */ { UD_Ivsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1421 */ { UD_Isubsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1422 */ { UD_Ivsubsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1423 */ { UD_Isubss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1424 */ { UD_Ivsubss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1425 */ { UD_Iswapgs, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1426 */ { UD_Isyscall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1427 */ { UD_Isysenter, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1428 */ { UD_Isysenter, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1429 */ { UD_Isysexit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1430 */ { UD_Isysexit, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1431 */ { UD_Isysret, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1432 */ { UD_Itest, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1433 */ { UD_Itest, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1434 */ { UD_Itest, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1435 */ { UD_Itest, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1436 */ { UD_Itest, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1437 */ { UD_Itest, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1438 */ { UD_Itest, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1439 */ { UD_Itest, O_Ev, O_Iz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1440 */ { UD_Iucomisd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1441 */ { UD_Ivucomisd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1442 */ { UD_Iucomiss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1443 */ { UD_Ivucomiss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1444 */ { UD_Iud2, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1445 */ { UD_Iunpckhpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1446 */ { UD_Ivunpckhpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1447 */ { UD_Iunpckhps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1448 */ { UD_Ivunpckhps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1449 */ { UD_Iunpcklps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1450 */ { UD_Ivunpcklps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1451 */ { UD_Iunpcklpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1452 */ { UD_Ivunpcklpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1453 */ { UD_Iverr, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1454 */ { UD_Iverw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1455 */ { UD_Ivmcall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1456 */ { UD_Irdrand, O_R, O_NONE, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1457 */ { UD_Ivmclear, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1458 */ { UD_Ivmxon, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1459 */ { UD_Ivmptrld, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1460 */ { UD_Ivmptrst, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1461 */ { UD_Ivmlaunch, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1462 */ { UD_Ivmresume, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1463 */ { UD_Ivmxoff, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1464 */ { UD_Ivmread, O_Ey, O_Gy, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1465 */ { UD_Ivmwrite, O_Gy, O_Ey, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_def64 }, + /* 1466 */ { UD_Ivmrun, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1467 */ { UD_Ivmmcall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1468 */ { UD_Ivmload, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1469 */ { UD_Ivmsave, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1470 */ { UD_Iwait, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1471 */ { UD_Iwbinvd, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1472 */ { UD_Iwrmsr, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1473 */ { UD_Ixadd, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexx|P_rexb }, + /* 1474 */ { UD_Ixadd, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1475 */ { UD_Ixchg, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1476 */ { UD_Ixchg, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1477 */ { UD_Ixchg, O_R0v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1478 */ { UD_Ixchg, O_R1v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1479 */ { UD_Ixchg, O_R2v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1480 */ { UD_Ixchg, O_R3v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1481 */ { UD_Ixchg, O_R4v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1482 */ { UD_Ixchg, O_R5v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1483 */ { UD_Ixchg, O_R6v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1484 */ { UD_Ixchg, O_R7v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1485 */ { UD_Ixgetbv, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1486 */ { UD_Ixlatb, O_NONE, O_NONE, O_NONE, O_NONE, P_rexw|P_seg }, + /* 1487 */ { UD_Ixor, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1488 */ { UD_Ixor, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1489 */ { UD_Ixor, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1490 */ { UD_Ixor, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1491 */ { UD_Ixor, O_AL, O_Ib, O_NONE, O_NONE, P_none }, + /* 1492 */ { UD_Ixor, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw }, + /* 1493 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1494 */ { UD_Ixor, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1495 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 }, + /* 1496 */ { UD_Ixor, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1497 */ { UD_Ixorpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1498 */ { UD_Ivxorpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1499 */ { UD_Ixorps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1500 */ { UD_Ivxorps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1501 */ { UD_Ixcryptecb, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1502 */ { UD_Ixcryptcbc, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1503 */ { UD_Ixcryptctr, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1504 */ { UD_Ixcryptcfb, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1505 */ { UD_Ixcryptofb, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1506 */ { UD_Ixrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1507 */ { UD_Ixsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1508 */ { UD_Ixsetbv, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1509 */ { UD_Ixsha1, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1510 */ { UD_Ixsha256, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1511 */ { UD_Ixstore, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1512 */ { UD_Ipclmulqdq, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1513 */ { UD_Ivpclmulqdq, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1514 */ { UD_Igetsec, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1515 */ { UD_Imovdqa, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1516 */ { UD_Ivmovdqa, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1517 */ { UD_Imovdqa, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1518 */ { UD_Ivmovdqa, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1519 */ { UD_Imaskmovdqu, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1520 */ { UD_Ivmaskmovdqu, O_Vx, O_Ux, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1521 */ { UD_Imovdq2q, O_P, O_U, O_NONE, O_NONE, P_aso|P_rexb }, + /* 1522 */ { UD_Imovdqu, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1523 */ { UD_Ivmovdqu, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1524 */ { UD_Imovdqu, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1525 */ { UD_Ivmovdqu, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1526 */ { UD_Imovq2dq, O_V, O_N, O_NONE, O_NONE, P_aso|P_rexr }, + /* 1527 */ { UD_Ipaddq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1528 */ { UD_Ipaddq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1529 */ { UD_Ivpaddq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1530 */ { UD_Ipsubq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1531 */ { UD_Ivpsubq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1532 */ { UD_Ipsubq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1533 */ { UD_Ipmuludq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1534 */ { UD_Ipmuludq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1535 */ { UD_Ipshufhw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1536 */ { UD_Ivpshufhw, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1537 */ { UD_Ipshuflw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1538 */ { UD_Ivpshuflw, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1539 */ { UD_Ipshufd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1540 */ { UD_Ivpshufd, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1541 */ { UD_Ipslldq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1542 */ { UD_Ivpslldq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1543 */ { UD_Ipsrldq, O_U, O_Ib, O_NONE, O_NONE, P_rexb }, + /* 1544 */ { UD_Ivpsrldq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb }, + /* 1545 */ { UD_Ipunpckhqdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1546 */ { UD_Ivpunpckhqdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1547 */ { UD_Ipunpcklqdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1548 */ { UD_Ivpunpcklqdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1549 */ { UD_Ihaddpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1550 */ { UD_Ivhaddpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1551 */ { UD_Ihaddps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1552 */ { UD_Ivhaddps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1553 */ { UD_Ihsubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1554 */ { UD_Ivhsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1555 */ { UD_Ihsubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1556 */ { UD_Ivhsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1557 */ { UD_Iinsertps, O_V, O_Md, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1558 */ { UD_Ivinsertps, O_Vx, O_Hx, O_Md, O_Ib, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1559 */ { UD_Ilddqu, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1560 */ { UD_Ivlddqu, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1561 */ { UD_Imovddup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1562 */ { UD_Ivmovddup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1563 */ { UD_Imovddup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1564 */ { UD_Ivmovddup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1565 */ { UD_Imovshdup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1566 */ { UD_Ivmovshdup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1567 */ { UD_Imovshdup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1568 */ { UD_Ivmovshdup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1569 */ { UD_Imovsldup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1570 */ { UD_Ivmovsldup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1571 */ { UD_Imovsldup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1572 */ { UD_Ivmovsldup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1573 */ { UD_Ipabsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1574 */ { UD_Ipabsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1575 */ { UD_Ivpabsb, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1576 */ { UD_Ipabsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1577 */ { UD_Ipabsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1578 */ { UD_Ivpabsw, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1579 */ { UD_Ipabsd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1580 */ { UD_Ipabsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1581 */ { UD_Ivpabsd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1582 */ { UD_Ipshufb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1583 */ { UD_Ipshufb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1584 */ { UD_Ivpshufb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1585 */ { UD_Iphaddw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1586 */ { UD_Iphaddw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1587 */ { UD_Ivphaddw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1588 */ { UD_Iphaddd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1589 */ { UD_Iphaddd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1590 */ { UD_Ivphaddd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1591 */ { UD_Iphaddsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1592 */ { UD_Iphaddsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1593 */ { UD_Ivphaddsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1594 */ { UD_Ipmaddubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1595 */ { UD_Ipmaddubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1596 */ { UD_Ivpmaddubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1597 */ { UD_Iphsubw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1598 */ { UD_Iphsubw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1599 */ { UD_Ivphsubw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1600 */ { UD_Iphsubd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1601 */ { UD_Iphsubd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1602 */ { UD_Ivphsubd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1603 */ { UD_Iphsubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1604 */ { UD_Iphsubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1605 */ { UD_Ivphsubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1606 */ { UD_Ipsignb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1607 */ { UD_Ipsignb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1608 */ { UD_Ivpsignb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1609 */ { UD_Ipsignd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1610 */ { UD_Ipsignd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1611 */ { UD_Ivpsignd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1612 */ { UD_Ipsignw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1613 */ { UD_Ipsignw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1614 */ { UD_Ivpsignw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1615 */ { UD_Ipmulhrsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1616 */ { UD_Ipmulhrsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1617 */ { UD_Ivpmulhrsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1618 */ { UD_Ipalignr, O_P, O_Q, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1619 */ { UD_Ipalignr, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1620 */ { UD_Ivpalignr, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1621 */ { UD_Ipblendvb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1622 */ { UD_Ipmuldq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1623 */ { UD_Ivpmuldq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1624 */ { UD_Ipminsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1625 */ { UD_Ivpminsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1626 */ { UD_Ipminsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1627 */ { UD_Ivpminsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1628 */ { UD_Ipminuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1629 */ { UD_Ivpminuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1630 */ { UD_Ipminud, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1631 */ { UD_Ivpminud, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1632 */ { UD_Ipmaxsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1633 */ { UD_Ivpmaxsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1634 */ { UD_Ipmaxsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1635 */ { UD_Ivpmaxsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1636 */ { UD_Ipmaxud, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1637 */ { UD_Ivpmaxud, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1638 */ { UD_Ipmaxuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1639 */ { UD_Ivpmaxuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1640 */ { UD_Ipmulld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1641 */ { UD_Ivpmulld, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1642 */ { UD_Iphminposuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1643 */ { UD_Ivphminposuw, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1644 */ { UD_Iroundps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1645 */ { UD_Ivroundps, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1646 */ { UD_Iroundpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1647 */ { UD_Ivroundpd, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1648 */ { UD_Iroundss, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1649 */ { UD_Ivroundss, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1650 */ { UD_Iroundsd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1651 */ { UD_Ivroundsd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1652 */ { UD_Iblendpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1653 */ { UD_Ivblendpd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1654 */ { UD_Iblendps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1655 */ { UD_Ivblendps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1656 */ { UD_Iblendvpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1657 */ { UD_Iblendvps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1658 */ { UD_Ibound, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso }, + /* 1659 */ { UD_Ibsf, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1660 */ { UD_Ibsr, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1661 */ { UD_Ibswap, O_R0y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1662 */ { UD_Ibswap, O_R1y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1663 */ { UD_Ibswap, O_R2y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1664 */ { UD_Ibswap, O_R3y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1665 */ { UD_Ibswap, O_R4y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1666 */ { UD_Ibswap, O_R5y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1667 */ { UD_Ibswap, O_R6y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1668 */ { UD_Ibswap, O_R7y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* 1669 */ { UD_Ibt, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1670 */ { UD_Ibt, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1671 */ { UD_Ibtc, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1672 */ { UD_Ibtc, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1673 */ { UD_Ibtr, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1674 */ { UD_Ibtr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1675 */ { UD_Ibts, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1676 */ { UD_Ibts, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1677 */ { UD_Ipblendw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1678 */ { UD_Ivpblendw, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1679 */ { UD_Impsadbw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1680 */ { UD_Ivmpsadbw, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1681 */ { UD_Imovntdqa, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1682 */ { UD_Ivmovntdqa, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl }, + /* 1683 */ { UD_Ipackusdw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1684 */ { UD_Ivpackusdw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl }, + /* 1685 */ { UD_Ipmovsxbw, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1686 */ { UD_Ivpmovsxbw, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1687 */ { UD_Ipmovsxbd, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1688 */ { UD_Ivpmovsxbd, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1689 */ { UD_Ipmovsxbq, O_V, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1690 */ { UD_Ivpmovsxbq, O_Vx, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1691 */ { UD_Ipmovsxwd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1692 */ { UD_Ivpmovsxwd, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1693 */ { UD_Ipmovsxwq, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1694 */ { UD_Ivpmovsxwq, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1695 */ { UD_Ipmovsxdq, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1696 */ { UD_Ipmovzxbw, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1697 */ { UD_Ivpmovzxbw, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1698 */ { UD_Ipmovzxbd, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1699 */ { UD_Ivpmovzxbd, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1700 */ { UD_Ipmovzxbq, O_V, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1701 */ { UD_Ivpmovzxbq, O_Vx, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1702 */ { UD_Ipmovzxwd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1703 */ { UD_Ivpmovzxwd, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1704 */ { UD_Ipmovzxwq, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1705 */ { UD_Ivpmovzxwq, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1706 */ { UD_Ipmovzxdq, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1707 */ { UD_Ivpmovzxdq, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1708 */ { UD_Ipcmpeqq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1709 */ { UD_Ivpcmpeqq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1710 */ { UD_Ipopcnt, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1711 */ { UD_Iptest, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1712 */ { UD_Ivptest, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl }, + /* 1713 */ { UD_Ipcmpestri, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1714 */ { UD_Ivpcmpestri, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1715 */ { UD_Ipcmpestrm, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1716 */ { UD_Ivpcmpestrm, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1717 */ { UD_Ipcmpgtq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1718 */ { UD_Ivpcmpgtq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1719 */ { UD_Ipcmpistri, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1720 */ { UD_Ivpcmpistri, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1721 */ { UD_Ipcmpistrm, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1722 */ { UD_Ivpcmpistrm, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1723 */ { UD_Imovbe, O_Gv, O_Mv, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1724 */ { UD_Imovbe, O_Mv, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1725 */ { UD_Icrc32, O_Gy, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1726 */ { UD_Icrc32, O_Gy, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb }, + /* 1727 */ { UD_Ivbroadcastss, O_V, O_Md, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1728 */ { UD_Ivbroadcastsd, O_Vqq, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1729 */ { UD_Ivextractf128, O_Wdq, O_Vqq, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1730 */ { UD_Ivinsertf128, O_Vqq, O_Hqq, O_Wdq, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1731 */ { UD_Ivmaskmovps, O_V, O_H, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1732 */ { UD_Ivmaskmovps, O_M, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1733 */ { UD_Ivmaskmovpd, O_V, O_H, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1734 */ { UD_Ivmaskmovpd, O_M, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1735 */ { UD_Ivpermilpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1736 */ { UD_Ivpermilpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1737 */ { UD_Ivpermilps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1738 */ { UD_Ivpermilps, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1739 */ { UD_Ivperm2f128, O_Vqq, O_Hqq, O_Wqq, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1740 */ { UD_Ivtestps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1741 */ { UD_Ivtestpd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1742 */ { UD_Ivzeroupper, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1743 */ { UD_Ivzeroall, O_NONE, O_NONE, O_NONE, O_NONE, P_none }, + /* 1744 */ { UD_Ivblendvpd, O_Vx, O_Hx, O_Wx, O_Lx, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1745 */ { UD_Ivblendvps, O_Vx, O_Hx, O_Wx, O_Lx, P_aso|P_rexr|P_rexx|P_rexb|P_vexl }, + /* 1746 */ { UD_Ivmovsd, O_V, O_H, O_U, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1747 */ { UD_Ivmovsd, O_V, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1748 */ { UD_Ivmovsd, O_U, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1749 */ { UD_Ivmovsd, O_Mq, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1750 */ { UD_Ivmovss, O_V, O_H, O_U, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1751 */ { UD_Ivmovss, O_V, O_Md, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1752 */ { UD_Ivmovss, O_U, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1753 */ { UD_Ivmovss, O_Md, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1754 */ { UD_Ivpblendvb, O_V, O_H, O_W, O_L, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1755 */ { UD_Ivpsllw, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1756 */ { UD_Ivpsllw, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1757 */ { UD_Ivpslld, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1758 */ { UD_Ivpslld, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1759 */ { UD_Ivpsllq, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1760 */ { UD_Ivpsllq, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, +}; + + +const char* ud_mnemonics_str[] = { + "aaa", + "aad", + "aam", + "aas", + "adc", + "add", + "addpd", + "addps", + "addsd", + "addss", + "addsubpd", + "addsubps", + "aesdec", + "aesdeclast", + "aesenc", + "aesenclast", + "aesimc", + "aeskeygenassist", + "and", + "andnpd", + "andnps", + "andpd", + "andps", + "arpl", + "blendpd", + "blendps", + "blendvpd", + "blendvps", + "bound", + "bsf", + "bsr", + "bswap", + "bt", + "btc", + "btr", + "bts", + "call", + "cbw", + "cdq", + "cdqe", + "clc", + "cld", + "clflush", + "clgi", + "cli", + "clts", + "cmc", + "cmova", + "cmovae", + "cmovb", + "cmovbe", + "cmovg", + "cmovge", + "cmovl", + "cmovle", + "cmovno", + "cmovnp", + "cmovns", + "cmovnz", + "cmovo", + "cmovp", + "cmovs", + "cmovz", + "cmp", + "cmppd", + "cmpps", + "cmpsb", + "cmpsd", + "cmpsq", + "cmpss", + "cmpsw", + "cmpxchg", + "cmpxchg16b", + "cmpxchg8b", + "comisd", + "comiss", + "cpuid", + "cqo", + "crc32", + "cvtdq2pd", + "cvtdq2ps", + "cvtpd2dq", + "cvtpd2pi", + "cvtpd2ps", + "cvtpi2pd", + "cvtpi2ps", + "cvtps2dq", + "cvtps2pd", + "cvtps2pi", + "cvtsd2si", + "cvtsd2ss", + "cvtsi2sd", + "cvtsi2ss", + "cvtss2sd", + "cvtss2si", + "cvttpd2dq", + "cvttpd2pi", + "cvttps2dq", + "cvttps2pi", + "cvttsd2si", + "cvttss2si", + "cwd", + "cwde", + "daa", + "das", + "dec", + "div", + "divpd", + "divps", + "divsd", + "divss", + "dppd", + "dpps", + "emms", + "enter", + "extractps", + "f2xm1", + "fabs", + "fadd", + "faddp", + "fbld", + "fbstp", + "fchs", + "fclex", + "fcmovb", + "fcmovbe", + "fcmove", + "fcmovnb", + "fcmovnbe", + "fcmovne", + "fcmovnu", + "fcmovu", + "fcom", + "fcom2", + "fcomi", + "fcomip", + "fcomp", + "fcomp3", + "fcomp5", + "fcompp", + "fcos", + "fdecstp", + "fdiv", + "fdivp", + "fdivr", + "fdivrp", + "femms", + "ffree", + "ffreep", + "fiadd", + "ficom", + "ficomp", + "fidiv", + "fidivr", + "fild", + "fimul", + "fincstp", + "fist", + "fistp", + "fisttp", + "fisub", + "fisubr", + "fld", + "fld1", + "fldcw", + "fldenv", + "fldl2e", + "fldl2t", + "fldlg2", + "fldln2", + "fldpi", + "fldz", + "fmul", + "fmulp", + "fndisi", + "fneni", + "fninit", + "fnop", + "fnsave", + "fnsetpm", + "fnstcw", + "fnstenv", + "fnstsw", + "fpatan", + "fprem", + "fprem1", + "fptan", + "frndint", + "frstor", + "frstpm", + "fscale", + "fsin", + "fsincos", + "fsqrt", + "fst", + "fstp", + "fstp1", + "fstp8", + "fstp9", + "fsub", + "fsubp", + "fsubr", + "fsubrp", + "ftst", + "fucom", + "fucomi", + "fucomip", + "fucomp", + "fucompp", + "fxam", + "fxch", + "fxch4", + "fxch7", + "fxrstor", + "fxsave", + "fxtract", + "fyl2x", + "fyl2xp1", + "getsec", + "haddpd", + "haddps", + "hlt", + "hsubpd", + "hsubps", + "idiv", + "imul", + "in", + "inc", + "insb", + "insd", + "insertps", + "insw", + "int", + "int1", + "int3", + "into", + "invd", + "invept", + "invlpg", + "invlpga", + "invvpid", + "iretd", + "iretq", + "iretw", + "ja", + "jae", + "jb", + "jbe", + "jcxz", + "jecxz", + "jg", + "jge", + "jl", + "jle", + "jmp", + "jno", + "jnp", + "jns", + "jnz", + "jo", + "jp", + "jrcxz", + "js", + "jz", + "lahf", + "lar", + "lddqu", + "ldmxcsr", + "lds", + "lea", + "leave", + "les", + "lfence", + "lfs", + "lgdt", + "lgs", + "lidt", + "lldt", + "lmsw", + "lock", + "lodsb", + "lodsd", + "lodsq", + "lodsw", + "loop", + "loope", + "loopne", + "lsl", + "lss", + "ltr", + "maskmovdqu", + "maskmovq", + "maxpd", + "maxps", + "maxsd", + "maxss", + "mfence", + "minpd", + "minps", + "minsd", + "minss", + "monitor", + "montmul", + "mov", + "movapd", + "movaps", + "movbe", + "movd", + "movddup", + "movdq2q", + "movdqa", + "movdqu", + "movhlps", + "movhpd", + "movhps", + "movlhps", + "movlpd", + "movlps", + "movmskpd", + "movmskps", + "movntdq", + "movntdqa", + "movnti", + "movntpd", + "movntps", + "movntq", + "movq", + "movq2dq", + "movsb", + "movsd", + "movshdup", + "movsldup", + "movsq", + "movss", + "movsw", + "movsx", + "movsxd", + "movupd", + "movups", + "movzx", + "mpsadbw", + "mul", + "mulpd", + "mulps", + "mulsd", + "mulss", + "mwait", + "neg", + "nop", + "not", + "or", + "orpd", + "orps", + "out", + "outsb", + "outsd", + "outsw", + "pabsb", + "pabsd", + "pabsw", + "packssdw", + "packsswb", + "packusdw", + "packuswb", + "paddb", + "paddd", + "paddq", + "paddsb", + "paddsw", + "paddusb", + "paddusw", + "paddw", + "palignr", + "pand", + "pandn", + "pavgb", + "pavgusb", + "pavgw", + "pblendvb", + "pblendw", + "pclmulqdq", + "pcmpeqb", + "pcmpeqd", + "pcmpeqq", + "pcmpeqw", + "pcmpestri", + "pcmpestrm", + "pcmpgtb", + "pcmpgtd", + "pcmpgtq", + "pcmpgtw", + "pcmpistri", + "pcmpistrm", + "pextrb", + "pextrd", + "pextrq", + "pextrw", + "pf2id", + "pf2iw", + "pfacc", + "pfadd", + "pfcmpeq", + "pfcmpge", + "pfcmpgt", + "pfmax", + "pfmin", + "pfmul", + "pfnacc", + "pfpnacc", + "pfrcp", + "pfrcpit1", + "pfrcpit2", + "pfrsqit1", + "pfrsqrt", + "pfsub", + "pfsubr", + "phaddd", + "phaddsw", + "phaddw", + "phminposuw", + "phsubd", + "phsubsw", + "phsubw", + "pi2fd", + "pi2fw", + "pinsrb", + "pinsrd", + "pinsrq", + "pinsrw", + "pmaddubsw", + "pmaddwd", + "pmaxsb", + "pmaxsd", + "pmaxsw", + "pmaxub", + "pmaxud", + "pmaxuw", + "pminsb", + "pminsd", + "pminsw", + "pminub", + "pminud", + "pminuw", + "pmovmskb", + "pmovsxbd", + "pmovsxbq", + "pmovsxbw", + "pmovsxdq", + "pmovsxwd", + "pmovsxwq", + "pmovzxbd", + "pmovzxbq", + "pmovzxbw", + "pmovzxdq", + "pmovzxwd", + "pmovzxwq", + "pmuldq", + "pmulhrsw", + "pmulhrw", + "pmulhuw", + "pmulhw", + "pmulld", + "pmullw", + "pmuludq", + "pop", + "popa", + "popad", + "popcnt", + "popfd", + "popfq", + "popfw", + "por", + "prefetch", + "prefetchnta", + "prefetcht0", + "prefetcht1", + "prefetcht2", + "psadbw", + "pshufb", + "pshufd", + "pshufhw", + "pshuflw", + "pshufw", + "psignb", + "psignd", + "psignw", + "pslld", + "pslldq", + "psllq", + "psllw", + "psrad", + "psraw", + "psrld", + "psrldq", + "psrlq", + "psrlw", + "psubb", + "psubd", + "psubq", + "psubsb", + "psubsw", + "psubusb", + "psubusw", + "psubw", + "pswapd", + "ptest", + "punpckhbw", + "punpckhdq", + "punpckhqdq", + "punpckhwd", + "punpcklbw", + "punpckldq", + "punpcklqdq", + "punpcklwd", + "push", + "pusha", + "pushad", + "pushfd", + "pushfq", + "pushfw", + "pxor", + "rcl", + "rcpps", + "rcpss", + "rcr", + "rdmsr", + "rdpmc", + "rdrand", + "rdtsc", + "rdtscp", + "rep", + "repne", + "ret", + "retf", + "rol", + "ror", + "roundpd", + "roundps", + "roundsd", + "roundss", + "rsm", + "rsqrtps", + "rsqrtss", + "sahf", + "salc", + "sar", + "sbb", + "scasb", + "scasd", + "scasq", + "scasw", + "seta", + "setae", + "setb", + "setbe", + "setg", + "setge", + "setl", + "setle", + "setno", + "setnp", + "setns", + "setnz", + "seto", + "setp", + "sets", + "setz", + "sfence", + "sgdt", + "shl", + "shld", + "shr", + "shrd", + "shufpd", + "shufps", + "sidt", + "skinit", + "sldt", + "smsw", + "sqrtpd", + "sqrtps", + "sqrtsd", + "sqrtss", + "stc", + "std", + "stgi", + "sti", + "stmxcsr", + "stosb", + "stosd", + "stosq", + "stosw", + "str", + "sub", + "subpd", + "subps", + "subsd", + "subss", + "swapgs", + "syscall", + "sysenter", + "sysexit", + "sysret", + "test", + "ucomisd", + "ucomiss", + "ud2", + "unpckhpd", + "unpckhps", + "unpcklpd", + "unpcklps", + "vaddpd", + "vaddps", + "vaddsd", + "vaddss", + "vaddsubpd", + "vaddsubps", + "vaesdec", + "vaesdeclast", + "vaesenc", + "vaesenclast", + "vaesimc", + "vaeskeygenassist", + "vandnpd", + "vandnps", + "vandpd", + "vandps", + "vblendpd", + "vblendps", + "vblendvpd", + "vblendvps", + "vbroadcastsd", + "vbroadcastss", + "vcmppd", + "vcmpps", + "vcmpsd", + "vcmpss", + "vcomisd", + "vcomiss", + "vcvtdq2pd", + "vcvtdq2ps", + "vcvtpd2dq", + "vcvtpd2ps", + "vcvtps2dq", + "vcvtps2pd", + "vcvtsd2si", + "vcvtsd2ss", + "vcvtsi2sd", + "vcvtsi2ss", + "vcvtss2sd", + "vcvtss2si", + "vcvttpd2dq", + "vcvttps2dq", + "vcvttsd2si", + "vcvttss2si", + "vdivpd", + "vdivps", + "vdivsd", + "vdivss", + "vdppd", + "vdpps", + "verr", + "verw", + "vextractf128", + "vextractps", + "vhaddpd", + "vhaddps", + "vhsubpd", + "vhsubps", + "vinsertf128", + "vinsertps", + "vlddqu", + "vmaskmovdqu", + "vmaskmovpd", + "vmaskmovps", + "vmaxpd", + "vmaxps", + "vmaxsd", + "vmaxss", + "vmcall", + "vmclear", + "vminpd", + "vminps", + "vminsd", + "vminss", + "vmlaunch", + "vmload", + "vmmcall", + "vmovapd", + "vmovaps", + "vmovd", + "vmovddup", + "vmovdqa", + "vmovdqu", + "vmovhlps", + "vmovhpd", + "vmovhps", + "vmovlhps", + "vmovlpd", + "vmovlps", + "vmovmskpd", + "vmovmskps", + "vmovntdq", + "vmovntdqa", + "vmovntpd", + "vmovntps", + "vmovq", + "vmovsd", + "vmovshdup", + "vmovsldup", + "vmovss", + "vmovupd", + "vmovups", + "vmpsadbw", + "vmptrld", + "vmptrst", + "vmread", + "vmresume", + "vmrun", + "vmsave", + "vmulpd", + "vmulps", + "vmulsd", + "vmulss", + "vmwrite", + "vmxoff", + "vmxon", + "vorpd", + "vorps", + "vpabsb", + "vpabsd", + "vpabsw", + "vpackssdw", + "vpacksswb", + "vpackusdw", + "vpackuswb", + "vpaddb", + "vpaddd", + "vpaddq", + "vpaddsb", + "vpaddsw", + "vpaddusb", + "vpaddusw", + "vpaddw", + "vpalignr", + "vpand", + "vpandn", + "vpavgb", + "vpavgw", + "vpblendvb", + "vpblendw", + "vpclmulqdq", + "vpcmpeqb", + "vpcmpeqd", + "vpcmpeqq", + "vpcmpeqw", + "vpcmpestri", + "vpcmpestrm", + "vpcmpgtb", + "vpcmpgtd", + "vpcmpgtq", + "vpcmpgtw", + "vpcmpistri", + "vpcmpistrm", + "vperm2f128", + "vpermilpd", + "vpermilps", + "vpextrb", + "vpextrd", + "vpextrq", + "vpextrw", + "vphaddd", + "vphaddsw", + "vphaddw", + "vphminposuw", + "vphsubd", + "vphsubsw", + "vphsubw", + "vpinsrb", + "vpinsrd", + "vpinsrq", + "vpinsrw", + "vpmaddubsw", + "vpmaddwd", + "vpmaxsb", + "vpmaxsd", + "vpmaxsw", + "vpmaxub", + "vpmaxud", + "vpmaxuw", + "vpminsb", + "vpminsd", + "vpminsw", + "vpminub", + "vpminud", + "vpminuw", + "vpmovmskb", + "vpmovsxbd", + "vpmovsxbq", + "vpmovsxbw", + "vpmovsxwd", + "vpmovsxwq", + "vpmovzxbd", + "vpmovzxbq", + "vpmovzxbw", + "vpmovzxdq", + "vpmovzxwd", + "vpmovzxwq", + "vpmuldq", + "vpmulhrsw", + "vpmulhuw", + "vpmulhw", + "vpmulld", + "vpmullw", + "vpor", + "vpsadbw", + "vpshufb", + "vpshufd", + "vpshufhw", + "vpshuflw", + "vpsignb", + "vpsignd", + "vpsignw", + "vpslld", + "vpslldq", + "vpsllq", + "vpsllw", + "vpsrad", + "vpsraw", + "vpsrld", + "vpsrldq", + "vpsrlq", + "vpsrlw", + "vpsubb", + "vpsubd", + "vpsubq", + "vpsubsb", + "vpsubsw", + "vpsubusb", + "vpsubusw", + "vpsubw", + "vptest", + "vpunpckhbw", + "vpunpckhdq", + "vpunpckhqdq", + "vpunpckhwd", + "vpunpcklbw", + "vpunpckldq", + "vpunpcklqdq", + "vpunpcklwd", + "vpxor", + "vrcpps", + "vrcpss", + "vroundpd", + "vroundps", + "vroundsd", + "vroundss", + "vrsqrtps", + "vrsqrtss", + "vshufpd", + "vshufps", + "vsqrtpd", + "vsqrtps", + "vsqrtsd", + "vsqrtss", + "vstmxcsr", + "vsubpd", + "vsubps", + "vsubsd", + "vsubss", + "vtestpd", + "vtestps", + "vucomisd", + "vucomiss", + "vunpckhpd", + "vunpckhps", + "vunpcklpd", + "vunpcklps", + "vxorpd", + "vxorps", + "vzeroall", + "vzeroupper", + "wait", + "wbinvd", + "wrmsr", + "xadd", + "xchg", + "xcryptcbc", + "xcryptcfb", + "xcryptctr", + "xcryptecb", + "xcryptofb", + "xgetbv", + "xlatb", + "xor", + "xorpd", + "xorps", + "xrstor", + "xsave", + "xsetbv", + "xsha1", + "xsha256", + "xstore", + "invalid", + "3dnow", + "none", + "db", + "pause" +}; diff --git a/deps/extra/udis86/libudis86/itab.h b/deps/extra/udis86/libudis86/itab.h new file mode 100644 index 0000000..3d54c43 --- /dev/null +++ b/deps/extra/udis86/libudis86/itab.h @@ -0,0 +1,939 @@ +#ifndef UD_ITAB_H +#define UD_ITAB_H + +/* itab.h -- generated by udis86:scripts/ud_itab.py, do no edit */ + +/* ud_table_type -- lookup table types (see decode.c) */ +enum ud_table_type { + UD_TAB__OPC_VEX, + UD_TAB__OPC_TABLE, + UD_TAB__OPC_X87, + UD_TAB__OPC_MOD, + UD_TAB__OPC_RM, + UD_TAB__OPC_OSIZE, + UD_TAB__OPC_MODE, + UD_TAB__OPC_VEX_L, + UD_TAB__OPC_3DNOW, + UD_TAB__OPC_REG, + UD_TAB__OPC_ASIZE, + UD_TAB__OPC_VEX_W, + UD_TAB__OPC_SSE, + UD_TAB__OPC_VENDOR +}; + +/* ud_mnemonic -- mnemonic constants */ +enum ud_mnemonic_code { + UD_Iaaa, + UD_Iaad, + UD_Iaam, + UD_Iaas, + UD_Iadc, + UD_Iadd, + UD_Iaddpd, + UD_Iaddps, + UD_Iaddsd, + UD_Iaddss, + UD_Iaddsubpd, + UD_Iaddsubps, + UD_Iaesdec, + UD_Iaesdeclast, + UD_Iaesenc, + UD_Iaesenclast, + UD_Iaesimc, + UD_Iaeskeygenassist, + UD_Iand, + UD_Iandnpd, + UD_Iandnps, + UD_Iandpd, + UD_Iandps, + UD_Iarpl, + UD_Iblendpd, + UD_Iblendps, + UD_Iblendvpd, + UD_Iblendvps, + UD_Ibound, + UD_Ibsf, + UD_Ibsr, + UD_Ibswap, + UD_Ibt, + UD_Ibtc, + UD_Ibtr, + UD_Ibts, + UD_Icall, + UD_Icbw, + UD_Icdq, + UD_Icdqe, + UD_Iclc, + UD_Icld, + UD_Iclflush, + UD_Iclgi, + UD_Icli, + UD_Iclts, + UD_Icmc, + UD_Icmova, + UD_Icmovae, + UD_Icmovb, + UD_Icmovbe, + UD_Icmovg, + UD_Icmovge, + UD_Icmovl, + UD_Icmovle, + UD_Icmovno, + UD_Icmovnp, + UD_Icmovns, + UD_Icmovnz, + UD_Icmovo, + UD_Icmovp, + UD_Icmovs, + UD_Icmovz, + UD_Icmp, + UD_Icmppd, + UD_Icmpps, + UD_Icmpsb, + UD_Icmpsd, + UD_Icmpsq, + UD_Icmpss, + UD_Icmpsw, + UD_Icmpxchg, + UD_Icmpxchg16b, + UD_Icmpxchg8b, + UD_Icomisd, + UD_Icomiss, + UD_Icpuid, + UD_Icqo, + UD_Icrc32, + UD_Icvtdq2pd, + UD_Icvtdq2ps, + UD_Icvtpd2dq, + UD_Icvtpd2pi, + UD_Icvtpd2ps, + UD_Icvtpi2pd, + UD_Icvtpi2ps, + UD_Icvtps2dq, + UD_Icvtps2pd, + UD_Icvtps2pi, + UD_Icvtsd2si, + UD_Icvtsd2ss, + UD_Icvtsi2sd, + UD_Icvtsi2ss, + UD_Icvtss2sd, + UD_Icvtss2si, + UD_Icvttpd2dq, + UD_Icvttpd2pi, + UD_Icvttps2dq, + UD_Icvttps2pi, + UD_Icvttsd2si, + UD_Icvttss2si, + UD_Icwd, + UD_Icwde, + UD_Idaa, + UD_Idas, + UD_Idec, + UD_Idiv, + UD_Idivpd, + UD_Idivps, + UD_Idivsd, + UD_Idivss, + UD_Idppd, + UD_Idpps, + UD_Iemms, + UD_Ienter, + UD_Iextractps, + UD_If2xm1, + UD_Ifabs, + UD_Ifadd, + UD_Ifaddp, + UD_Ifbld, + UD_Ifbstp, + UD_Ifchs, + UD_Ifclex, + UD_Ifcmovb, + UD_Ifcmovbe, + UD_Ifcmove, + UD_Ifcmovnb, + UD_Ifcmovnbe, + UD_Ifcmovne, + UD_Ifcmovnu, + UD_Ifcmovu, + UD_Ifcom, + UD_Ifcom2, + UD_Ifcomi, + UD_Ifcomip, + UD_Ifcomp, + UD_Ifcomp3, + UD_Ifcomp5, + UD_Ifcompp, + UD_Ifcos, + UD_Ifdecstp, + UD_Ifdiv, + UD_Ifdivp, + UD_Ifdivr, + UD_Ifdivrp, + UD_Ifemms, + UD_Iffree, + UD_Iffreep, + UD_Ifiadd, + UD_Ificom, + UD_Ificomp, + UD_Ifidiv, + UD_Ifidivr, + UD_Ifild, + UD_Ifimul, + UD_Ifincstp, + UD_Ifist, + UD_Ifistp, + UD_Ifisttp, + UD_Ifisub, + UD_Ifisubr, + UD_Ifld, + UD_Ifld1, + UD_Ifldcw, + UD_Ifldenv, + UD_Ifldl2e, + UD_Ifldl2t, + UD_Ifldlg2, + UD_Ifldln2, + UD_Ifldpi, + UD_Ifldz, + UD_Ifmul, + UD_Ifmulp, + UD_Ifndisi, + UD_Ifneni, + UD_Ifninit, + UD_Ifnop, + UD_Ifnsave, + UD_Ifnsetpm, + UD_Ifnstcw, + UD_Ifnstenv, + UD_Ifnstsw, + UD_Ifpatan, + UD_Ifprem, + UD_Ifprem1, + UD_Ifptan, + UD_Ifrndint, + UD_Ifrstor, + UD_Ifrstpm, + UD_Ifscale, + UD_Ifsin, + UD_Ifsincos, + UD_Ifsqrt, + UD_Ifst, + UD_Ifstp, + UD_Ifstp1, + UD_Ifstp8, + UD_Ifstp9, + UD_Ifsub, + UD_Ifsubp, + UD_Ifsubr, + UD_Ifsubrp, + UD_Iftst, + UD_Ifucom, + UD_Ifucomi, + UD_Ifucomip, + UD_Ifucomp, + UD_Ifucompp, + UD_Ifxam, + UD_Ifxch, + UD_Ifxch4, + UD_Ifxch7, + UD_Ifxrstor, + UD_Ifxsave, + UD_Ifxtract, + UD_Ifyl2x, + UD_Ifyl2xp1, + UD_Igetsec, + UD_Ihaddpd, + UD_Ihaddps, + UD_Ihlt, + UD_Ihsubpd, + UD_Ihsubps, + UD_Iidiv, + UD_Iimul, + UD_Iin, + UD_Iinc, + UD_Iinsb, + UD_Iinsd, + UD_Iinsertps, + UD_Iinsw, + UD_Iint, + UD_Iint1, + UD_Iint3, + UD_Iinto, + UD_Iinvd, + UD_Iinvept, + UD_Iinvlpg, + UD_Iinvlpga, + UD_Iinvvpid, + UD_Iiretd, + UD_Iiretq, + UD_Iiretw, + UD_Ija, + UD_Ijae, + UD_Ijb, + UD_Ijbe, + UD_Ijcxz, + UD_Ijecxz, + UD_Ijg, + UD_Ijge, + UD_Ijl, + UD_Ijle, + UD_Ijmp, + UD_Ijno, + UD_Ijnp, + UD_Ijns, + UD_Ijnz, + UD_Ijo, + UD_Ijp, + UD_Ijrcxz, + UD_Ijs, + UD_Ijz, + UD_Ilahf, + UD_Ilar, + UD_Ilddqu, + UD_Ildmxcsr, + UD_Ilds, + UD_Ilea, + UD_Ileave, + UD_Iles, + UD_Ilfence, + UD_Ilfs, + UD_Ilgdt, + UD_Ilgs, + UD_Ilidt, + UD_Illdt, + UD_Ilmsw, + UD_Ilock, + UD_Ilodsb, + UD_Ilodsd, + UD_Ilodsq, + UD_Ilodsw, + UD_Iloop, + UD_Iloope, + UD_Iloopne, + UD_Ilsl, + UD_Ilss, + UD_Iltr, + UD_Imaskmovdqu, + UD_Imaskmovq, + UD_Imaxpd, + UD_Imaxps, + UD_Imaxsd, + UD_Imaxss, + UD_Imfence, + UD_Iminpd, + UD_Iminps, + UD_Iminsd, + UD_Iminss, + UD_Imonitor, + UD_Imontmul, + UD_Imov, + UD_Imovapd, + UD_Imovaps, + UD_Imovbe, + UD_Imovd, + UD_Imovddup, + UD_Imovdq2q, + UD_Imovdqa, + UD_Imovdqu, + UD_Imovhlps, + UD_Imovhpd, + UD_Imovhps, + UD_Imovlhps, + UD_Imovlpd, + UD_Imovlps, + UD_Imovmskpd, + UD_Imovmskps, + UD_Imovntdq, + UD_Imovntdqa, + UD_Imovnti, + UD_Imovntpd, + UD_Imovntps, + UD_Imovntq, + UD_Imovq, + UD_Imovq2dq, + UD_Imovsb, + UD_Imovsd, + UD_Imovshdup, + UD_Imovsldup, + UD_Imovsq, + UD_Imovss, + UD_Imovsw, + UD_Imovsx, + UD_Imovsxd, + UD_Imovupd, + UD_Imovups, + UD_Imovzx, + UD_Impsadbw, + UD_Imul, + UD_Imulpd, + UD_Imulps, + UD_Imulsd, + UD_Imulss, + UD_Imwait, + UD_Ineg, + UD_Inop, + UD_Inot, + UD_Ior, + UD_Iorpd, + UD_Iorps, + UD_Iout, + UD_Ioutsb, + UD_Ioutsd, + UD_Ioutsw, + UD_Ipabsb, + UD_Ipabsd, + UD_Ipabsw, + UD_Ipackssdw, + UD_Ipacksswb, + UD_Ipackusdw, + UD_Ipackuswb, + UD_Ipaddb, + UD_Ipaddd, + UD_Ipaddq, + UD_Ipaddsb, + UD_Ipaddsw, + UD_Ipaddusb, + UD_Ipaddusw, + UD_Ipaddw, + UD_Ipalignr, + UD_Ipand, + UD_Ipandn, + UD_Ipavgb, + UD_Ipavgusb, + UD_Ipavgw, + UD_Ipblendvb, + UD_Ipblendw, + UD_Ipclmulqdq, + UD_Ipcmpeqb, + UD_Ipcmpeqd, + UD_Ipcmpeqq, + UD_Ipcmpeqw, + UD_Ipcmpestri, + UD_Ipcmpestrm, + UD_Ipcmpgtb, + UD_Ipcmpgtd, + UD_Ipcmpgtq, + UD_Ipcmpgtw, + UD_Ipcmpistri, + UD_Ipcmpistrm, + UD_Ipextrb, + UD_Ipextrd, + UD_Ipextrq, + UD_Ipextrw, + UD_Ipf2id, + UD_Ipf2iw, + UD_Ipfacc, + UD_Ipfadd, + UD_Ipfcmpeq, + UD_Ipfcmpge, + UD_Ipfcmpgt, + UD_Ipfmax, + UD_Ipfmin, + UD_Ipfmul, + UD_Ipfnacc, + UD_Ipfpnacc, + UD_Ipfrcp, + UD_Ipfrcpit1, + UD_Ipfrcpit2, + UD_Ipfrsqit1, + UD_Ipfrsqrt, + UD_Ipfsub, + UD_Ipfsubr, + UD_Iphaddd, + UD_Iphaddsw, + UD_Iphaddw, + UD_Iphminposuw, + UD_Iphsubd, + UD_Iphsubsw, + UD_Iphsubw, + UD_Ipi2fd, + UD_Ipi2fw, + UD_Ipinsrb, + UD_Ipinsrd, + UD_Ipinsrq, + UD_Ipinsrw, + UD_Ipmaddubsw, + UD_Ipmaddwd, + UD_Ipmaxsb, + UD_Ipmaxsd, + UD_Ipmaxsw, + UD_Ipmaxub, + UD_Ipmaxud, + UD_Ipmaxuw, + UD_Ipminsb, + UD_Ipminsd, + UD_Ipminsw, + UD_Ipminub, + UD_Ipminud, + UD_Ipminuw, + UD_Ipmovmskb, + UD_Ipmovsxbd, + UD_Ipmovsxbq, + UD_Ipmovsxbw, + UD_Ipmovsxdq, + UD_Ipmovsxwd, + UD_Ipmovsxwq, + UD_Ipmovzxbd, + UD_Ipmovzxbq, + UD_Ipmovzxbw, + UD_Ipmovzxdq, + UD_Ipmovzxwd, + UD_Ipmovzxwq, + UD_Ipmuldq, + UD_Ipmulhrsw, + UD_Ipmulhrw, + UD_Ipmulhuw, + UD_Ipmulhw, + UD_Ipmulld, + UD_Ipmullw, + UD_Ipmuludq, + UD_Ipop, + UD_Ipopa, + UD_Ipopad, + UD_Ipopcnt, + UD_Ipopfd, + UD_Ipopfq, + UD_Ipopfw, + UD_Ipor, + UD_Iprefetch, + UD_Iprefetchnta, + UD_Iprefetcht0, + UD_Iprefetcht1, + UD_Iprefetcht2, + UD_Ipsadbw, + UD_Ipshufb, + UD_Ipshufd, + UD_Ipshufhw, + UD_Ipshuflw, + UD_Ipshufw, + UD_Ipsignb, + UD_Ipsignd, + UD_Ipsignw, + UD_Ipslld, + UD_Ipslldq, + UD_Ipsllq, + UD_Ipsllw, + UD_Ipsrad, + UD_Ipsraw, + UD_Ipsrld, + UD_Ipsrldq, + UD_Ipsrlq, + UD_Ipsrlw, + UD_Ipsubb, + UD_Ipsubd, + UD_Ipsubq, + UD_Ipsubsb, + UD_Ipsubsw, + UD_Ipsubusb, + UD_Ipsubusw, + UD_Ipsubw, + UD_Ipswapd, + UD_Iptest, + UD_Ipunpckhbw, + UD_Ipunpckhdq, + UD_Ipunpckhqdq, + UD_Ipunpckhwd, + UD_Ipunpcklbw, + UD_Ipunpckldq, + UD_Ipunpcklqdq, + UD_Ipunpcklwd, + UD_Ipush, + UD_Ipusha, + UD_Ipushad, + UD_Ipushfd, + UD_Ipushfq, + UD_Ipushfw, + UD_Ipxor, + UD_Ircl, + UD_Ircpps, + UD_Ircpss, + UD_Ircr, + UD_Irdmsr, + UD_Irdpmc, + UD_Irdrand, + UD_Irdtsc, + UD_Irdtscp, + UD_Irep, + UD_Irepne, + UD_Iret, + UD_Iretf, + UD_Irol, + UD_Iror, + UD_Iroundpd, + UD_Iroundps, + UD_Iroundsd, + UD_Iroundss, + UD_Irsm, + UD_Irsqrtps, + UD_Irsqrtss, + UD_Isahf, + UD_Isalc, + UD_Isar, + UD_Isbb, + UD_Iscasb, + UD_Iscasd, + UD_Iscasq, + UD_Iscasw, + UD_Iseta, + UD_Isetae, + UD_Isetb, + UD_Isetbe, + UD_Isetg, + UD_Isetge, + UD_Isetl, + UD_Isetle, + UD_Isetno, + UD_Isetnp, + UD_Isetns, + UD_Isetnz, + UD_Iseto, + UD_Isetp, + UD_Isets, + UD_Isetz, + UD_Isfence, + UD_Isgdt, + UD_Ishl, + UD_Ishld, + UD_Ishr, + UD_Ishrd, + UD_Ishufpd, + UD_Ishufps, + UD_Isidt, + UD_Iskinit, + UD_Isldt, + UD_Ismsw, + UD_Isqrtpd, + UD_Isqrtps, + UD_Isqrtsd, + UD_Isqrtss, + UD_Istc, + UD_Istd, + UD_Istgi, + UD_Isti, + UD_Istmxcsr, + UD_Istosb, + UD_Istosd, + UD_Istosq, + UD_Istosw, + UD_Istr, + UD_Isub, + UD_Isubpd, + UD_Isubps, + UD_Isubsd, + UD_Isubss, + UD_Iswapgs, + UD_Isyscall, + UD_Isysenter, + UD_Isysexit, + UD_Isysret, + UD_Itest, + UD_Iucomisd, + UD_Iucomiss, + UD_Iud2, + UD_Iunpckhpd, + UD_Iunpckhps, + UD_Iunpcklpd, + UD_Iunpcklps, + UD_Ivaddpd, + UD_Ivaddps, + UD_Ivaddsd, + UD_Ivaddss, + UD_Ivaddsubpd, + UD_Ivaddsubps, + UD_Ivaesdec, + UD_Ivaesdeclast, + UD_Ivaesenc, + UD_Ivaesenclast, + UD_Ivaesimc, + UD_Ivaeskeygenassist, + UD_Ivandnpd, + UD_Ivandnps, + UD_Ivandpd, + UD_Ivandps, + UD_Ivblendpd, + UD_Ivblendps, + UD_Ivblendvpd, + UD_Ivblendvps, + UD_Ivbroadcastsd, + UD_Ivbroadcastss, + UD_Ivcmppd, + UD_Ivcmpps, + UD_Ivcmpsd, + UD_Ivcmpss, + UD_Ivcomisd, + UD_Ivcomiss, + UD_Ivcvtdq2pd, + UD_Ivcvtdq2ps, + UD_Ivcvtpd2dq, + UD_Ivcvtpd2ps, + UD_Ivcvtps2dq, + UD_Ivcvtps2pd, + UD_Ivcvtsd2si, + UD_Ivcvtsd2ss, + UD_Ivcvtsi2sd, + UD_Ivcvtsi2ss, + UD_Ivcvtss2sd, + UD_Ivcvtss2si, + UD_Ivcvttpd2dq, + UD_Ivcvttps2dq, + UD_Ivcvttsd2si, + UD_Ivcvttss2si, + UD_Ivdivpd, + UD_Ivdivps, + UD_Ivdivsd, + UD_Ivdivss, + UD_Ivdppd, + UD_Ivdpps, + UD_Iverr, + UD_Iverw, + UD_Ivextractf128, + UD_Ivextractps, + UD_Ivhaddpd, + UD_Ivhaddps, + UD_Ivhsubpd, + UD_Ivhsubps, + UD_Ivinsertf128, + UD_Ivinsertps, + UD_Ivlddqu, + UD_Ivmaskmovdqu, + UD_Ivmaskmovpd, + UD_Ivmaskmovps, + UD_Ivmaxpd, + UD_Ivmaxps, + UD_Ivmaxsd, + UD_Ivmaxss, + UD_Ivmcall, + UD_Ivmclear, + UD_Ivminpd, + UD_Ivminps, + UD_Ivminsd, + UD_Ivminss, + UD_Ivmlaunch, + UD_Ivmload, + UD_Ivmmcall, + UD_Ivmovapd, + UD_Ivmovaps, + UD_Ivmovd, + UD_Ivmovddup, + UD_Ivmovdqa, + UD_Ivmovdqu, + UD_Ivmovhlps, + UD_Ivmovhpd, + UD_Ivmovhps, + UD_Ivmovlhps, + UD_Ivmovlpd, + UD_Ivmovlps, + UD_Ivmovmskpd, + UD_Ivmovmskps, + UD_Ivmovntdq, + UD_Ivmovntdqa, + UD_Ivmovntpd, + UD_Ivmovntps, + UD_Ivmovq, + UD_Ivmovsd, + UD_Ivmovshdup, + UD_Ivmovsldup, + UD_Ivmovss, + UD_Ivmovupd, + UD_Ivmovups, + UD_Ivmpsadbw, + UD_Ivmptrld, + UD_Ivmptrst, + UD_Ivmread, + UD_Ivmresume, + UD_Ivmrun, + UD_Ivmsave, + UD_Ivmulpd, + UD_Ivmulps, + UD_Ivmulsd, + UD_Ivmulss, + UD_Ivmwrite, + UD_Ivmxoff, + UD_Ivmxon, + UD_Ivorpd, + UD_Ivorps, + UD_Ivpabsb, + UD_Ivpabsd, + UD_Ivpabsw, + UD_Ivpackssdw, + UD_Ivpacksswb, + UD_Ivpackusdw, + UD_Ivpackuswb, + UD_Ivpaddb, + UD_Ivpaddd, + UD_Ivpaddq, + UD_Ivpaddsb, + UD_Ivpaddsw, + UD_Ivpaddusb, + UD_Ivpaddusw, + UD_Ivpaddw, + UD_Ivpalignr, + UD_Ivpand, + UD_Ivpandn, + UD_Ivpavgb, + UD_Ivpavgw, + UD_Ivpblendvb, + UD_Ivpblendw, + UD_Ivpclmulqdq, + UD_Ivpcmpeqb, + UD_Ivpcmpeqd, + UD_Ivpcmpeqq, + UD_Ivpcmpeqw, + UD_Ivpcmpestri, + UD_Ivpcmpestrm, + UD_Ivpcmpgtb, + UD_Ivpcmpgtd, + UD_Ivpcmpgtq, + UD_Ivpcmpgtw, + UD_Ivpcmpistri, + UD_Ivpcmpistrm, + UD_Ivperm2f128, + UD_Ivpermilpd, + UD_Ivpermilps, + UD_Ivpextrb, + UD_Ivpextrd, + UD_Ivpextrq, + UD_Ivpextrw, + UD_Ivphaddd, + UD_Ivphaddsw, + UD_Ivphaddw, + UD_Ivphminposuw, + UD_Ivphsubd, + UD_Ivphsubsw, + UD_Ivphsubw, + UD_Ivpinsrb, + UD_Ivpinsrd, + UD_Ivpinsrq, + UD_Ivpinsrw, + UD_Ivpmaddubsw, + UD_Ivpmaddwd, + UD_Ivpmaxsb, + UD_Ivpmaxsd, + UD_Ivpmaxsw, + UD_Ivpmaxub, + UD_Ivpmaxud, + UD_Ivpmaxuw, + UD_Ivpminsb, + UD_Ivpminsd, + UD_Ivpminsw, + UD_Ivpminub, + UD_Ivpminud, + UD_Ivpminuw, + UD_Ivpmovmskb, + UD_Ivpmovsxbd, + UD_Ivpmovsxbq, + UD_Ivpmovsxbw, + UD_Ivpmovsxwd, + UD_Ivpmovsxwq, + UD_Ivpmovzxbd, + UD_Ivpmovzxbq, + UD_Ivpmovzxbw, + UD_Ivpmovzxdq, + UD_Ivpmovzxwd, + UD_Ivpmovzxwq, + UD_Ivpmuldq, + UD_Ivpmulhrsw, + UD_Ivpmulhuw, + UD_Ivpmulhw, + UD_Ivpmulld, + UD_Ivpmullw, + UD_Ivpor, + UD_Ivpsadbw, + UD_Ivpshufb, + UD_Ivpshufd, + UD_Ivpshufhw, + UD_Ivpshuflw, + UD_Ivpsignb, + UD_Ivpsignd, + UD_Ivpsignw, + UD_Ivpslld, + UD_Ivpslldq, + UD_Ivpsllq, + UD_Ivpsllw, + UD_Ivpsrad, + UD_Ivpsraw, + UD_Ivpsrld, + UD_Ivpsrldq, + UD_Ivpsrlq, + UD_Ivpsrlw, + UD_Ivpsubb, + UD_Ivpsubd, + UD_Ivpsubq, + UD_Ivpsubsb, + UD_Ivpsubsw, + UD_Ivpsubusb, + UD_Ivpsubusw, + UD_Ivpsubw, + UD_Ivptest, + UD_Ivpunpckhbw, + UD_Ivpunpckhdq, + UD_Ivpunpckhqdq, + UD_Ivpunpckhwd, + UD_Ivpunpcklbw, + UD_Ivpunpckldq, + UD_Ivpunpcklqdq, + UD_Ivpunpcklwd, + UD_Ivpxor, + UD_Ivrcpps, + UD_Ivrcpss, + UD_Ivroundpd, + UD_Ivroundps, + UD_Ivroundsd, + UD_Ivroundss, + UD_Ivrsqrtps, + UD_Ivrsqrtss, + UD_Ivshufpd, + UD_Ivshufps, + UD_Ivsqrtpd, + UD_Ivsqrtps, + UD_Ivsqrtsd, + UD_Ivsqrtss, + UD_Ivstmxcsr, + UD_Ivsubpd, + UD_Ivsubps, + UD_Ivsubsd, + UD_Ivsubss, + UD_Ivtestpd, + UD_Ivtestps, + UD_Ivucomisd, + UD_Ivucomiss, + UD_Ivunpckhpd, + UD_Ivunpckhps, + UD_Ivunpcklpd, + UD_Ivunpcklps, + UD_Ivxorpd, + UD_Ivxorps, + UD_Ivzeroall, + UD_Ivzeroupper, + UD_Iwait, + UD_Iwbinvd, + UD_Iwrmsr, + UD_Ixadd, + UD_Ixchg, + UD_Ixcryptcbc, + UD_Ixcryptcfb, + UD_Ixcryptctr, + UD_Ixcryptecb, + UD_Ixcryptofb, + UD_Ixgetbv, + UD_Ixlatb, + UD_Ixor, + UD_Ixorpd, + UD_Ixorps, + UD_Ixrstor, + UD_Ixsave, + UD_Ixsetbv, + UD_Ixsha1, + UD_Ixsha256, + UD_Ixstore, + UD_Iinvalid, + UD_I3dnow, + UD_Inone, + UD_Idb, + UD_Ipause, + UD_MAX_MNEMONIC_CODE +}; + +extern const char * ud_mnemonics_str[]; + +#endif /* UD_ITAB_H */ diff --git a/deps/gsc-tool b/deps/gsc-tool new file mode 160000 index 0000000..9b885e3 --- /dev/null +++ b/deps/gsc-tool @@ -0,0 +1 @@ +Subproject commit 9b885e3439d390a978a742b0dbfdd97b1ba68765 diff --git a/deps/libtomcrypt b/deps/libtomcrypt new file mode 160000 index 0000000..7e863d2 --- /dev/null +++ b/deps/libtomcrypt @@ -0,0 +1 @@ +Subproject commit 7e863d21429f94ed6a720e24499a12a3f852bb31 diff --git a/deps/libtommath b/deps/libtommath new file mode 160000 index 0000000..8314bde --- /dev/null +++ b/deps/libtommath @@ -0,0 +1 @@ +Subproject commit 8314bde5e5c8e5d9331460130a9d1066e324f091 diff --git a/deps/minhook b/deps/minhook new file mode 160000 index 0000000..f5485b8 --- /dev/null +++ b/deps/minhook @@ -0,0 +1 @@ +Subproject commit f5485b8454544c2f034c78f8f127c1d03dea3636 diff --git a/deps/premake/asmjit.lua b/deps/premake/asmjit.lua new file mode 100644 index 0000000..ee93259 --- /dev/null +++ b/deps/premake/asmjit.lua @@ -0,0 +1,34 @@ +asmjit = { + source = path.join(dependencies.basePath, "asmjit"), +} + +function asmjit.import() + links { "asmjit" } + asmjit.includes() +end + +function asmjit.includes() + includedirs { + path.join(asmjit.source, "src") + } + + defines { + "ASMJIT_STATIC" + } +end + +function asmjit.project() + project "asmjit" + language "C++" + + asmjit.includes() + + files { + path.join(asmjit.source, "src/**.cpp"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, asmjit) diff --git a/deps/premake/discord-rpc.lua b/deps/premake/discord-rpc.lua new file mode 100644 index 0000000..ef28bcb --- /dev/null +++ b/deps/premake/discord-rpc.lua @@ -0,0 +1,39 @@ +discordrpc = { + source = path.join(dependencies.basePath, "discord-rpc"), +} + +function discordrpc.import() + links { "discord-rpc" } + discordrpc.includes() +end + +function discordrpc.includes() + includedirs { + path.join(discordrpc.source, "include"), + } +end + +function discordrpc.project() + project "discord-rpc" + language "C++" + + discordrpc.includes() + rapidjson.import(); + + files { + path.join(discordrpc.source, "src/*.h"), + path.join(discordrpc.source, "src/*.cpp"), + } + + removefiles { + path.join(discordrpc.source, "src/dllmain.cpp"), + path.join(discordrpc.source, "src/*_linux.cpp"), + path.join(discordrpc.source, "src/*_unix.cpp"), + path.join(discordrpc.source, "src/*_osx.cpp"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, discordrpc) diff --git a/deps/premake/gsc-tool.lua b/deps/premake/gsc-tool.lua new file mode 100644 index 0000000..10a185f --- /dev/null +++ b/deps/premake/gsc-tool.lua @@ -0,0 +1,62 @@ +gsc_tool = { + source = path.join(dependencies.basePath, "gsc-tool"), +} + +function gsc_tool.import() + links { "xsk-gsc-iw6", "xsk-gsc-utils" } + gsc_tool.includes() +end + +function gsc_tool.includes() + includedirs { + path.join(gsc_tool.source, "include"), + } +end + +function gsc_tool.project() + project "xsk-gsc-utils" + kind "StaticLib" + language "C++" + + files { + path.join(gsc_tool.source, "include/xsk/utils/*.hpp"), + path.join(gsc_tool.source, "src/utils/*.cpp"), + } + + includedirs { + path.join(gsc_tool.source, "include"), + } + + zlib.includes() + + project "xsk-gsc-iw6" + kind "StaticLib" + language "C++" + + filter "action:vs*" + buildoptions "/Zc:__cplusplus" + filter {} + + files { + path.join(gsc_tool.source, "include/xsk/stdinc.hpp"), + + path.join(gsc_tool.source, "include/xsk/gsc/engine/iw6_pc.hpp"), + path.join(gsc_tool.source, "src/gsc/engine/iw6_pc.cpp"), + + path.join(gsc_tool.source, "src/gsc/engine/iw6_pc_code.cpp"), + path.join(gsc_tool.source, "src/gsc/engine/iw6_pc_func.cpp"), + path.join(gsc_tool.source, "src/gsc/engine/iw6_pc_meth.cpp"), + path.join(gsc_tool.source, "src/gsc/engine/iw6_pc_token.cpp"), + + path.join(gsc_tool.source, "src/gsc/*.cpp"), + + path.join(gsc_tool.source, "src/gsc/common/*.cpp"), + path.join(gsc_tool.source, "include/xsk/gsc/common/*.hpp"), + } + + includedirs { + path.join(gsc_tool.source, "include"), + } +end + +table.insert(dependencies, gsc_tool) diff --git a/deps/premake/gsl.lua b/deps/premake/gsl.lua new file mode 100644 index 0000000..7a2daf6 --- /dev/null +++ b/deps/premake/gsl.lua @@ -0,0 +1,19 @@ +gsl = { + source = path.join(dependencies.basePath, "GSL"), +} + +function gsl.import() + gsl.includes() +end + +function gsl.includes() + includedirs { + path.join(gsl.source, "include") + } +end + +function gsl.project() + +end + +table.insert(dependencies, gsl) diff --git a/deps/premake/libtomcrypt.lua b/deps/premake/libtomcrypt.lua new file mode 100644 index 0000000..7ca3570 --- /dev/null +++ b/deps/premake/libtomcrypt.lua @@ -0,0 +1,64 @@ +libtomcrypt = { + source = path.join(dependencies.basePath, "libtomcrypt"), +} + +function libtomcrypt.import() + links { + "libtomcrypt" + } + + libtomcrypt.includes() +end + +function libtomcrypt.includes() + includedirs { + path.join(libtomcrypt.source, "src/headers") + } + + defines { + "LTC_NO_FAST", + "LTC_NO_PROTOTYPES", + "LTC_NO_RSA_BLINDING", + "LTC_NO_FILE", + "ARGTYPE=4", + } +end + +function libtomcrypt.project() + project "libtomcrypt" + language "C" + + libtomcrypt.includes() + libtommath.import() + + files { + path.join(libtomcrypt.source, "src/**.c"), + } + + removefiles { + path.join(libtomcrypt.source, "src/**/*_test.c"), + path.join(libtomcrypt.source, "src/**/*tab.c"), + path.join(libtomcrypt.source, "src/encauth/ocb3/**.c"), + } + + defines { + "_CRT_SECURE_NO_WARNINGS", + "LTC_SOURCE", + "_LIB", + "USE_LTM" + } + + removedefines { + "_DLL", + "_USRDLL" + } + + linkoptions { + "-IGNORE:4221" + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, libtomcrypt) diff --git a/deps/premake/libtommath.lua b/deps/premake/libtommath.lua new file mode 100644 index 0000000..ab4cdde --- /dev/null +++ b/deps/premake/libtommath.lua @@ -0,0 +1,52 @@ +libtommath = { + source = path.join(dependencies.basePath, "libtommath"), +} + +function libtommath.import() + links { + "libtommath" + } + + libtommath.includes() +end + +function libtommath.includes() + includedirs { + libtommath.source + } + + defines { + "LTM_DESC", + "__STDC_IEC_559__", + "MP_NO_DEV_URANDOM", + } +end + +function libtommath.project() + project "libtommath" + language "C" + + libtommath.includes() + + files { + path.join(libtommath.source, "*.c"), + } + + defines { + "_LIB" + } + + removedefines { + "_DLL", + "_USRDLL" + } + + linkoptions { + "-IGNORE:4221" + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, libtommath) diff --git a/deps/premake/minhook.lua b/deps/premake/minhook.lua new file mode 100644 index 0000000..396d4d3 --- /dev/null +++ b/deps/premake/minhook.lua @@ -0,0 +1,31 @@ +minhook = { + source = path.join(dependencies.basePath, "minhook"), +} + +function minhook.import() + links { "minhook" } + minhook.includes() +end + +function minhook.includes() + includedirs { + path.join(minhook.source, "include") + } +end + +function minhook.project() + project "minhook" + language "C" + + minhook.includes() + + files { + path.join(minhook.source, "src/**.h"), + path.join(minhook.source, "src/**.c"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, minhook) diff --git a/deps/premake/minizip.lua b/deps/premake/minizip.lua new file mode 100644 index 0000000..4a5754b --- /dev/null +++ b/deps/premake/minizip.lua @@ -0,0 +1,43 @@ +minizip = { + source = path.join(dependencies.basePath, "zlib/contrib/minizip"), +} + +function minizip.import() + links { "minizip" } + zlib.import() + minizip.includes() +end + +function minizip.includes() + includedirs { + minizip.source + } + + zlib.includes() +end + +function minizip.project() + project "minizip" + language "C" + + minizip.includes() + + files { + path.join(minizip.source, "*.h"), + path.join(minizip.source, "*.c"), + } + + removefiles { + path.join(minizip.source, "miniunz.c"), + path.join(minizip.source, "minizip.c"), + } + + defines { + "_CRT_SECURE_NO_DEPRECATE", + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, minizip) diff --git a/deps/premake/protobuf.lua b/deps/premake/protobuf.lua new file mode 100644 index 0000000..1c58972 --- /dev/null +++ b/deps/premake/protobuf.lua @@ -0,0 +1,60 @@ +protobuf = { + source = path.join(dependencies.basePath, "protobuf"), +} + +function protobuf.import() + links { + "protobuf" + } + + protobuf.includes() +end + +function protobuf.includes() + includedirs { + path.join(protobuf.source, "src"), + } +end + +function protobuf.project() + project "protobuf" + language "C++" + + protobuf.includes() + + files { + path.join(protobuf.source, "src/**.cc"), + "./src/**.proto", + } + + removefiles { + path.join(protobuf.source, "src/**/*test.cc"), + path.join(protobuf.source, "src/google/protobuf/*test*.cc"), + + path.join(protobuf.source, "src/google/protobuf/testing/**.cc"), + path.join(protobuf.source, "src/google/protobuf/compiler/**.cc"), + + path.join(protobuf.source, "src/google/protobuf/arena_nc.cc"), + path.join(protobuf.source, "src/google/protobuf/util/internal/error_listener.cc"), + path.join(protobuf.source, "**/*_gcc.cc"), + } + + rules { + "ProtobufCompiler" + } + + defines { + "_SCL_SECURE_NO_WARNINGS", + "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS", + "_SILENCE_ALL_CXX20_DEPRECATION_WARNINGS", + } + + linkoptions { + "-IGNORE:4221" + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, protobuf) diff --git a/deps/premake/rapidjson.lua b/deps/premake/rapidjson.lua new file mode 100644 index 0000000..0dc3b4b --- /dev/null +++ b/deps/premake/rapidjson.lua @@ -0,0 +1,23 @@ +rapidjson = { + source = path.join(dependencies.basePath, "rapidjson"), +} + +function rapidjson.import() + defines { + "RAPIDJSON_HAS_STDSTRING" + } + + rapidjson.includes() +end + +function rapidjson.includes() + includedirs { + path.join(rapidjson.source, "include"), + } +end + +function rapidjson.project() + +end + +table.insert(dependencies, rapidjson) diff --git a/deps/premake/udis86.lua b/deps/premake/udis86.lua new file mode 100644 index 0000000..896ec8b --- /dev/null +++ b/deps/premake/udis86.lua @@ -0,0 +1,37 @@ +udis86 = { + source = path.join(dependencies.basePath, "udis86"), +} + +function udis86.import() + links { + "udis86" + } + + udis86.includes() +end + +function udis86.includes() + includedirs { + udis86.source, + path.join(udis86.source, "libudis86"), + path.join(dependencies.basePath, "extra/udis86"), + path.join(dependencies.basePath, "extra/udis86/libudis86"), + } +end + +function udis86.project() + project "udis86" + language "C" + + udis86.includes() + + files { + path.join(udis86.source, "libudis86/*.c"), + path.join(dependencies.basePath, "extra/udis86/libudis86/*.c"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, udis86) diff --git a/deps/premake/wintoast.lua b/deps/premake/wintoast.lua new file mode 100644 index 0000000..deffb7c --- /dev/null +++ b/deps/premake/wintoast.lua @@ -0,0 +1,32 @@ +wintoast = { + source = path.join(dependencies.basePath, "WinToast"), +} + +function wintoast.import() + links { "WinToast" } + wintoast.includes() +end + +function wintoast.includes() + includedirs { + path.join(wintoast.source, "include"), + } +end + +function wintoast.project() + project "WinToast" + language "C++" + + wintoast.includes() + rapidjson.import(); + + files { + path.join(wintoast.source, "include/wintoastlib.h"), + path.join(wintoast.source, "src/wintoastlib.cpp"), + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, wintoast) diff --git a/deps/premake/zlib.lua b/deps/premake/zlib.lua new file mode 100644 index 0000000..566a707 --- /dev/null +++ b/deps/premake/zlib.lua @@ -0,0 +1,39 @@ +zlib = { + source = path.join(dependencies.basePath, "zlib"), +} + +function zlib.import() + links { "zlib" } + zlib.includes() +end + +function zlib.includes() + includedirs { + zlib.source + } + + defines { + "ZLIB_CONST", + } +end + +function zlib.project() + project "zlib" + language "C" + + zlib.includes() + + files { + path.join(zlib.source, "*.h"), + path.join(zlib.source, "*.c"), + } + + defines { + "_CRT_SECURE_NO_DEPRECATE", + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, zlib) diff --git a/deps/protobuf b/deps/protobuf new file mode 160000 index 0000000..5a3dac8 --- /dev/null +++ b/deps/protobuf @@ -0,0 +1 @@ +Subproject commit 5a3dac894157bf3618b2c906a8b9073b4cad62b6 diff --git a/deps/rapidjson b/deps/rapidjson new file mode 160000 index 0000000..6089180 --- /dev/null +++ b/deps/rapidjson @@ -0,0 +1 @@ +Subproject commit 6089180ecb704cb2b136777798fa1be303618975 diff --git a/deps/udis86 b/deps/udis86 new file mode 160000 index 0000000..56ff6c8 --- /dev/null +++ b/deps/udis86 @@ -0,0 +1 @@ +Subproject commit 56ff6c87c11de0ffa725b14339004820556e343d diff --git a/deps/zlib b/deps/zlib new file mode 160000 index 0000000..9f0f2d4 --- /dev/null +++ b/deps/zlib @@ -0,0 +1 @@ +Subproject commit 9f0f2d4f9f1f28be7e16d8bf3b4e9d4ada70aa9f diff --git a/premake5.lua b/premake5.lua new file mode 100644 index 0000000..02e571c --- /dev/null +++ b/premake5.lua @@ -0,0 +1,356 @@ +gitVersioningCommand = "git describe --tags --dirty --always" +gitCurrentBranchCommand = "git symbolic-ref -q --short HEAD" + +-- Quote the given string input as a C string +function cstrquote(value) + if value == nil then + return "\"\"" + end + result = value:gsub("\\", "\\\\") + result = result:gsub("\"", "\\\"") + result = result:gsub("\n", "\\n") + result = result:gsub("\t", "\\t") + result = result:gsub("\r", "\\r") + result = result:gsub("\a", "\\a") + result = result:gsub("\b", "\\b") + result = "\"" .. result .. "\"" + return result +end + +-- Converts tags in "vX.X.X" format and given revision number Y to an array of numbers {X,X,X,Y}. +-- In the case where the format does not work fall back to padding with zeroes and just ending with the revision number. +-- partscount can be either 3 or 4. +function vertonumarr(value, vernumber, partscount) + vernum = {} + for num in string.gmatch(value or "", "%d+") do + if #vernum < 3 then + table.insert(vernum, tonumber(num)) + end + end + while #vernum < 3 do + table.insert(vernum, 0) + end + if #vernum < partscount then + table.insert(vernum, tonumber(vernumber)) + end + return vernum +end + +dependencies = { + basePath = "./deps" +} + +function dependencies.load() + dir = path.join(dependencies.basePath, "premake/*.lua") + deps = os.matchfiles(dir) + + for i, dep in pairs(deps) do + dep = dep:gsub(".lua", "") + require(dep) + end +end + +function dependencies.imports() + for i, proj in pairs(dependencies) do + if type(i) == 'number' then + proj.import() + end + end +end + +function dependencies.projects() + for i, proj in pairs(dependencies) do + if type(i) == 'number' then + proj.project() + end + end +end + +newoption { + trigger = "copy-to", + description = "Optional, copy the EXE to a custom folder after build, define the path here if wanted.", + value = "PATH" +} + +newoption { + trigger = "dev-build", + description = "Enable development builds of the client." +} + +newaction { + trigger = "version", + description = "Returns the version string for the current commit of the source code.", + onWorkspace = function(wks) + -- get current version via git + local proc = assert(io.popen(gitVersioningCommand, "r")) + local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "") + proc:close() + local version = gitDescribeOutput + + proc = assert(io.popen(gitCurrentBranchCommand, "r")) + local gitCurrentBranchOutput = assert(proc:read('*a')):gsub("%s+", "") + local gitCurrentBranchSuccess = proc:close() + if gitCurrentBranchSuccess then + -- We got a branch name, check if it is a feature branch + if gitCurrentBranchOutput ~= "develop" and gitCurrentBranchOutput ~= "master" then + version = version .. "-" .. gitCurrentBranchOutput + end + end + + print(version) + os.exit(0) + end +} + +newaction { + trigger = "generate-buildinfo", + description = "Sets up build information file like version.h.", + onWorkspace = function(wks) + -- get old version number from version.hpp if any + local oldVersion = "(none)" + local oldVersionHeader = io.open(wks.location .. "/src/version.h", "r") + if oldVersionHeader ~= nil then + local oldVersionHeaderContent = assert(oldVersionHeader:read('*l')) + while oldVersionHeaderContent do + m = string.match(oldVersionHeaderContent, "#define GIT_DESCRIBE (.+)%s*$") + if m ~= nil then + oldVersion = m + end + + oldVersionHeaderContent = oldVersionHeader:read('*l') + end + end + + -- get current version via git + local proc = assert(io.popen(gitVersioningCommand, "r")) + local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "") + proc:close() + + -- generate version.hpp with a revision number if not equal + gitDescribeOutputQuoted = cstrquote(gitDescribeOutput) + if oldVersion ~= gitDescribeOutputQuoted then + -- get current git hash and write to version.txt (used by the preliminary updater) + -- TODO - remove once proper updater and release versioning exists + local proc = assert(io.popen("git rev-parse HEAD", "r")) + local gitCommitHash = assert(proc:read('*a')):gsub("%s+", "") + proc:close() + + -- get whether this is a clean revision (no uncommitted changes) + proc = assert(io.popen("git status --porcelain", "r")) + local revDirty = (assert(proc:read('*a')) ~= "") + if revDirty then revDirty = 1 else revDirty = 0 end + proc:close() + + -- get current tag name + proc = assert(io.popen("git describe --tags --abbrev=0")) + local tagName = proc:read('*l') + + -- get current branch name + proc = assert(io.popen("git branch --show-current")) + local branchName = proc:read('*l') + + -- branch for ci + if branchName == nil or branchName == '' then + proc = assert(io.popen("git show -s --pretty=%d HEAD")) + local branchInfo = proc:read('*l') + m = string.match(branchInfo, ".+,.+, ([^)]+)") + if m ~= nil then + branchName = m + end + end + + if branchName == nil then + branchName = "develop" + end + + print("Detected branch: " .. branchName) + + -- get revision number via git + local proc = assert(io.popen("git rev-list --count HEAD", "r")) + local revNumber = assert(proc:read('*a')):gsub("%s+", "") + + print ("Update " .. oldVersion .. " -> " .. gitDescribeOutputQuoted) + + -- write to version.txt for preliminary updater + -- NOTE - remove this once we have a proper updater and proper release versioning + local versionFile = assert(io.open(wks.location .. "/version.txt", "w")) + versionFile:write(gitCommitHash) + versionFile:close() + + -- write version header + local versionHeader = assert(io.open(wks.location .. "/src/version.h", "w")) + versionHeader:write("/*\n") + versionHeader:write(" * Automatically generated by premake5.\n") + versionHeader:write(" * Do not touch!\n") + versionHeader:write(" */\n") + versionHeader:write("\n") + versionHeader:write("#define GIT_DESCRIBE " .. gitDescribeOutputQuoted .. "\n") + versionHeader:write("#define GIT_DIRTY " .. revDirty .. "\n") + versionHeader:write("#define GIT_HASH " .. cstrquote(gitCommitHash) .. "\n") + versionHeader:write("#define GIT_TAG " .. cstrquote(tagName) .. "\n") + versionHeader:write("#define GIT_BRANCH " .. cstrquote(branchName) .. "\n") + versionHeader:write("\n") + versionHeader:write("// Version transformed for RC files\n") + versionHeader:write("#define VERSION_PRODUCT_RC " .. table.concat(vertonumarr(tagName, revNumber, 3), ",") .. "\n") + versionHeader:write("#define VERSION_PRODUCT " .. cstrquote(table.concat(vertonumarr(tagName, revNumber, 3), ".")) .. "\n") + versionHeader:write("#define VERSION_FILE_RC " .. table.concat(vertonumarr(tagName, revNumber, 4), ",") .. "\n") + versionHeader:write("#define VERSION_FILE " .. cstrquote(table.concat(vertonumarr(tagName, revNumber, 4), ".")) .. "\n") + versionHeader:write("\n") + versionHeader:write("// Alias definitions\n") + versionHeader:write("#define VERSION GIT_DESCRIBE\n") + versionHeader:write("#define SHORTVERSION VERSION_PRODUCT\n") + versionHeader:close() + local versionHeader = assert(io.open(wks.location .. "/src/version.hpp", "w")) + versionHeader:write("/*\n") + versionHeader:write(" * Automatically generated by premake5.\n") + versionHeader:write(" * Do not touch!\n") + versionHeader:write(" *\n") + versionHeader:write(" * This file exists for reasons of complying with our coding standards.\n") + versionHeader:write(" *\n") + versionHeader:write(" * The Resource Compiler will ignore any content from C++ header files if they're not from STDInclude.hpp.\n") + versionHeader:write(" * That's the reason why we now place all version info in version.h instead.\n") + versionHeader:write(" */\n") + versionHeader:write("\n") + versionHeader:write("#include \".\\version.h\"\n") + versionHeader:close() + end + end +} + +dependencies.load() + +workspace "iw6-mod" +startproject "client" +location "./build" +objdir "%{wks.location}/obj" +targetdir "%{wks.location}/bin/%{cfg.platform}/%{cfg.buildcfg}" + +configurations {"Debug", "Release"} + +language "C++" +cppdialect "C++20" + +architecture "x86_64" +platforms "x64" + +systemversion "latest" +symbols "On" +staticruntime "On" +editandcontinue "Off" +warnings "Extra" +characterset "ASCII" + +if _OPTIONS["dev-build"] then + defines {"DEV_BUILD"} +end + +if os.getenv("CI") then + defines {"CI"} +end + +flags {"NoIncrementalLink", "NoMinimalRebuild", "MultiProcessorCompile", "No64BitChecks"} + +filter "platforms:x64" + defines {"_WINDOWS", "WIN32"} +filter {} + +filter "configurations:Release" + optimize "Size" + buildoptions {"/GL"} + linkoptions {"/IGNORE:4702", "/LTCG"} + defines {"NDEBUG"} + flags {"FatalCompileWarnings"} +filter {} + +filter "configurations:Debug" + optimize "Debug" + defines {"DEBUG", "_DEBUG"} +filter {} + +project "common" +kind "StaticLib" +language "C++" + +files {"./src/common/**.hpp", "./src/common/**.cpp"} + +includedirs {"./src/common", "%{prj.location}/src"} + +resincludedirs {"$(ProjectDir)src"} + +dependencies.imports() + +project "runner" +kind "WindowedApp" +language "C++" + +files {"./src/runner/**.rc", "./src/runner/**.hpp", "./src/runner/**.cpp", "./src/runner/resources/**.*"} + +includedirs {"./src/runner", "./src/common", "%{prj.location}/src"} + +resincludedirs {"$(ProjectDir)src"} + +project "client" +kind "WindowedApp" +language "C++" + +targetname "iw6-mod" + +pchheader "std_include.hpp" +pchsource "src/client/std_include.cpp" + +linkoptions {"/IGNORE:4254", "/DYNAMICBASE:NO", "/SAFESEH:NO", "/LARGEADDRESSAWARE", "/LAST:.main", "/PDBCompress"} + +files {"./src/client/**.rc", "./src/client/**.hpp", "./src/client/**.cpp", "./src/client/resources/**.*"} + +includedirs {"./src/client", "./src/common", "%{prj.location}/src"} + +resincludedirs {"$(ProjectDir)src"} + +dependson {"tlsdll", "runner"} + +links {"common"} + +prebuildcommands {"pushd %{_MAIN_SCRIPT_DIR}", "tools\\premake5 generate-buildinfo", "popd"} + +if _OPTIONS["copy-to"] then + postbuildcommands {"copy /y \"$(TargetPath)\" \"" .. _OPTIONS["copy-to"] .. "\""} +end + +dependencies.imports() + +project "tlsdll" +kind "SharedLib" +language "C++" + +files {"./src/tlsdll/**.rc", "./src/tlsdll/**.hpp", "./src/tlsdll/**.cpp", "./src/tlsdll/resources/**.*"} + +includedirs {"./src/tlsdll", "%{prj.location}/src"} + +links {"common"} + +resincludedirs {"$(ProjectDir)src"} + +project "runner" +kind "WindowedApp" +language "C++" + +files {"./src/runner/**.rc", "./src/runner/**.hpp", "./src/runner/**.cpp", "./src/runner/resources/**.*"} + +includedirs {"./src/runner", "./src/common", "%{prj.location}/src"} + +links {"common"} + +resincludedirs {"$(ProjectDir)src"} + +group "Dependencies" +dependencies.projects() + +rule "ProtobufCompiler" +display "Protobuf compiler" +location "./build" +fileExtension ".proto" +buildmessage "Compiling %(Identity) with protoc..." +buildcommands {'@echo off', 'path "$(SolutionDir)\\..\\tools"', + 'if not exist "$(ProjectDir)\\src\\proto" mkdir "$(ProjectDir)\\src\\proto"', + 'protoc --error_format=msvs -I=%(RelativeDir) --cpp_out=src\\proto %(Identity)'} +buildoutputs {'$(ProjectDir)\\src\\proto\\%(Filename).pb.cc', '$(ProjectDir)\\src\\proto\\%(Filename).pb.h'} diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp new file mode 100644 index 0000000..88085eb --- /dev/null +++ b/src/client/component/arxan.cpp @@ -0,0 +1,165 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "scheduler.hpp" + +#include + +namespace arxan +{ + namespace + { + utils::hook::detour nt_close_hook; + utils::hook::detour nt_query_information_process_hook; + + NTSTATUS WINAPI nt_query_information_process_stub(const HANDLE handle, const PROCESSINFOCLASS info_class, + const PVOID info, + const ULONG info_length, const PULONG ret_length) + { + auto* orig = static_cast(nt_query_information_process_hook. + get_original()); + const auto status = orig(handle, info_class, info, info_length, ret_length); + + if (NT_SUCCESS(status)) + { + if (info_class == ProcessBasicInformation) + { + static DWORD explorer_pid = 0; + if (!explorer_pid) + { + auto* const shell_window = GetShellWindow(); + GetWindowThreadProcessId(shell_window, &explorer_pid); + } + + static_cast(info)->Reserved3 = PVOID(DWORD64(explorer_pid)); + } + else if (info_class == 30) // ProcessDebugObjectHandle + { + *static_cast(info) = nullptr; + + return 0xC0000353; + } + else if (info_class == 7) // ProcessDebugPort + { + *static_cast(info) = nullptr; + } + else if (info_class == 31) + { + *static_cast(info) = 1; + } + } + + return status; + } + + NTSTATUS NTAPI nt_close_stub(const HANDLE handle) + { + char info[16]; + if (NtQueryObject(handle, OBJECT_INFORMATION_CLASS(4), &info, 2, nullptr) >= 0) + { + auto* orig = static_cast(nt_close_hook.get_original()); + return orig(handle); + } + + return STATUS_INVALID_HANDLE; + } + + LONG WINAPI exception_filter(const LPEXCEPTION_POINTERS info) + { + if (info->ExceptionRecord->ExceptionCode == STATUS_INVALID_HANDLE) + { + return EXCEPTION_CONTINUE_EXECUTION; + } + + return EXCEPTION_CONTINUE_SEARCH; + } + + void hide_being_debugged() + { + auto* const peb = PPEB(__readgsqword(0x60)); + peb->BeingDebugged = false; + *reinterpret_cast(LPSTR(peb) + 0xBC) &= ~0x70; + } + + void remove_hardware_breakpoints() + { + CONTEXT context; + ZeroMemory(&context, sizeof(context)); + context.ContextFlags = CONTEXT_DEBUG_REGISTERS; + + auto* const thread = GetCurrentThread(); + GetThreadContext(thread, &context); + + context.Dr0 = 0; + context.Dr1 = 0; + context.Dr2 = 0; + context.Dr3 = 0; + context.Dr6 = 0; + context.Dr7 = 0; + + SetThreadContext(thread, &context); + } + + BOOL WINAPI set_thread_context_stub(const HANDLE thread, CONTEXT* context) + { + if (!game::environment::is_sp() + && game::dwGetLogOnStatus(0) == game::DW_LIVE_CONNECTED + && context->ContextFlags == CONTEXT_DEBUG_REGISTERS) + { + return TRUE; + } + + return SetThreadContext(thread, context); + } + } + + class component final : public component_interface + { + public: + void* load_import(const std::string& library, const std::string& function) override + { + if (function == "SetThreadContext") + { + return set_thread_context_stub; + } + + return nullptr; + } + + void post_load() override + { + hide_being_debugged(); + scheduler::loop(hide_being_debugged, scheduler::pipeline::async); + + const utils::nt::library ntdll("ntdll.dll"); + nt_close_hook.create(ntdll.get_proc("NtClose"), nt_close_stub); + nt_query_information_process_hook.create(ntdll.get_proc("NtQueryInformationProcess"), + nt_query_information_process_stub); + + AddVectoredExceptionHandler(1, exception_filter); + } + + void post_unpack() override + { + if (game::environment::is_sp()) return; + + utils::hook::jump(0x1404FE1E0, 0x1404FE2D0); // idk + utils::hook::jump(0x140558C20, 0x140558CB0); // dwNetPump + utils::hook::jump(0x140591850, 0x1405918E0); // dwLobbyPump + utils::hook::jump(0x140589480, 0x140589490); // dwGetLogonStatus + + // Fix arxan crashes + // Are these opaque predicates? + utils::hook::nop(0x14AE2B384, 6); // 0000000140035EA7 + utils::hook::nop(0x14A31E98E, 4); // 000000014B1A892E + utils::hook::nop(0x14A920E10, 4); // 000000014AEF4F39 + utils::hook::nop(0x14A1A2425, 4); // 000000014A0B52A8 + utils::hook::nop(0x14AE07CEA, 4); // 000000014A143BFF + + scheduler::on_game_initialized(remove_hardware_breakpoints, scheduler::pipeline::main); + } + }; +} + +REGISTER_COMPONENT(arxan::component) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp new file mode 100644 index 0000000..74115b2 --- /dev/null +++ b/src/client/component/auth.cpp @@ -0,0 +1,228 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "steam/steam.hpp" + +#include "auth.hpp" +#include "command.hpp" +#include "console.hpp" +#include "network.hpp" + +#include +#include +#include +#include +#include + +namespace auth +{ + namespace + { + std::string get_hdd_serial() + { + DWORD serial{}; + if (!GetVolumeInformationA("C:\\", nullptr, 0, &serial, nullptr, nullptr, nullptr, 0)) + { + return {}; + } + + return utils::string::va("%08X", serial); + } + + std::string get_hw_profile_guid() + { + HW_PROFILE_INFO info; + if (!GetCurrentHwProfileA(&info)) + { + return {}; + } + + return std::string{ info.szHwProfileGuid, sizeof(info.szHwProfileGuid) }; + } + + std::string get_protected_data() + { + std::string input = "AlterWare-IW6-Auth"; + + DATA_BLOB data_in{}, data_out{}; + data_in.pbData = reinterpret_cast(input.data()); + data_in.cbData = static_cast(input.size()); + if (CryptProtectData(&data_in, nullptr, nullptr, nullptr, nullptr, CRYPTPROTECT_LOCAL_MACHINE, &data_out) != TRUE) + { + return {}; + } + + const auto size = std::min(data_out.cbData, 52ul); + std::string result{ reinterpret_cast(data_out.pbData), size }; + LocalFree(data_out.pbData); + + return result; + } + + std::string get_key_entropy() + { + std::string entropy{}; + entropy.append(utils::smbios::get_uuid()); + entropy.append(get_hw_profile_guid()); + entropy.append(get_protected_data()); + entropy.append(get_hdd_serial()); + + if (entropy.empty()) + { + entropy.resize(32); + utils::cryptography::random::get_data(entropy.data(), entropy.size()); + } + + return entropy; + } + + utils::cryptography::ecc::key& get_key() + { + static auto key = utils::cryptography::ecc::generate_key(512, get_key_entropy()); + return key; + } + + int send_connect_data_stub(game::netsrc_t sock, game::netadr_s* adr, const char* format, const int len) + { + std::string connect_string(format, len); + game::SV_Cmd_TokenizeString(connect_string.data()); + const auto _ = gsl::finally([]() + { + game::SV_Cmd_EndTokenizedString(); + }); + + const command::params_sv params; + if (params.size() < 3) + { + return false; + } + + const utils::info_string info_string{std::string{params[2]}}; + const auto challenge = info_string.get("challenge"); + + connect_string.clear(); + connect_string.append(params[0]); + connect_string.append(" "); + connect_string.append(params[1]); + connect_string.append(" "); + connect_string.append("\"" + info_string.build() + "\""); + + proto::network::connect_info info; + info.set_publickey(get_key().get_public_key()); + info.set_signature(sign_message(get_key(), challenge)); + info.set_infostring(connect_string); + + network::send(*adr, "connect", info.SerializeAsString()); + return true; + } + + void direct_connect(game::netadr_s* from, game::msg_t* msg) + { + const auto offset = sizeof("connect") + 4; + + proto::network::connect_info info; + if (msg->cursize < offset || !info.ParseFromArray(msg->data + offset, msg->cursize - offset)) + { + network::send(*from, "error", "Invalid connect data!", '\n'); + return; + } + + game::SV_Cmd_EndTokenizedString(); + game::SV_Cmd_TokenizeString(info.infostring().data()); + + const command::params_sv params; + if (params.size() < 3) + { + network::send(*from, "error", "Invalid connect string!", '\n'); + return; + } + + const utils::info_string info_string{std::string{params[2]}}; + const auto steam_id = info_string.get("xuid"); + const auto challenge = info_string.get("challenge"); + + if (steam_id.empty() || challenge.empty()) + { + network::send(*from, "error", "Invalid connect data!", '\n'); + return; + } + + utils::cryptography::ecc::key key; + key.set(info.publickey()); + + const auto xuid = strtoull(steam_id.data(), nullptr, 16); + if (xuid != key.get_hash()) + { + network::send(*from, "error", "XUID doesn't match the certificate!", '\n'); + return; + } + + if (!key.is_valid() || !verify_message(key, challenge, info.signature())) + { + network::send(*from, "error", "Challenge signature was invalid!", '\n'); + return; + } + + game::SV_DirectConnect(from); + } + + void* get_direct_connect_stub() + { + return utils::hook::assemble([](utils::hook::assembler& a) + { + a.lea(rcx, qword_ptr(rsp, 0x20)); + a.movaps(xmmword_ptr(rsp, 0x20), xmm0); + + a.pushad64(); + a.mov(rdx, rsi); + a.call_aligned(direct_connect); + a.popad64(); + + a.jmp(0x140479757); + }); + } + } + + uint64_t get_guid() + { + if (game::environment::is_dedi()) + { + return 0x110000100000000 | (::utils::cryptography::random::get_integer() & ~0x80000000); + } + + return get_key().get_hash(); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Patch steam id bit check + if (game::environment::is_sp()) + { + utils::hook::jump(0x1404BF3F0, 0x1404BF446); + utils::hook::jump(0x1404C02AF, 0x1404C02F0); + utils::hook::jump(0x1404C07F4, 0x1404C0842); + } + else + { + utils::hook::jump(0x140585410, 0x140585466); + utils::hook::jump(0x140142252, 0x140142293); + utils::hook::jump(0x140142334, 0x140142389); + utils::hook::jump(0x1405864EF, 0x140586530); + utils::hook::jump(0x140586A80, 0x140586AC6); + + utils::hook::jump(0x140479636, get_direct_connect_stub(), true); + utils::hook::call(0x1402C4F8E, send_connect_data_stub); + } + + command::add("guid", [] + { + console::info("Your guid: %llX\n", steam::SteamUser()->GetSteamID().bits); + }); + } + }; +} + +REGISTER_COMPONENT(auth::component) diff --git a/src/client/component/auth.hpp b/src/client/component/auth.hpp new file mode 100644 index 0000000..3ee0c53 --- /dev/null +++ b/src/client/component/auth.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace auth +{ + uint64_t get_guid(); +} diff --git a/src/client/component/binding.cpp b/src/client/component/binding.cpp new file mode 100644 index 0000000..44b47c0 --- /dev/null +++ b/src/client/component/binding.cpp @@ -0,0 +1,133 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include +#include + +namespace binding +{ + namespace + { + std::vector custom_binds = {}; + + utils::hook::detour cl_execute_key_hook; + + int key_write_bindings_to_buffer_stub(int /*localClientNum*/, char* buffer, const int buffer_size) + { + auto bytes_used = 0; + const auto buffer_size_align = static_cast(buffer_size) - 4; + + for (auto key_index = 0; key_index < 256; ++key_index) + { + const auto* const key_button = game::Key_KeynumToString(key_index, 0, 1); + auto value = game::playerKeys->keys[key_index].binding; + + if (value && value < 100) + { + const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used), + "bind %s \"%s\"\n", key_button, game::command_whitelist[value]); + + if (len < 0) + { + return bytes_used; + } + + bytes_used += len; + } + else if (value >= 100) + { + value -= 100; + if (static_cast(value) < custom_binds.size() && !custom_binds[value].empty()) + { + const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used), + "bind %s \"%s\"\n", key_button, custom_binds[value].data()); + + if (len < 0) + { + return bytes_used; + } + + bytes_used += len; + } + } + } + + buffer[bytes_used] = 0; + return bytes_used; + } + + int get_binding_for_custom_command(const char* command) + { + auto index = 0; + for (auto& bind : custom_binds) + { + if (bind == command) + { + return index; + } + index++; + } + + custom_binds.emplace_back(command); + index = static_cast(custom_binds.size()) - 1; + + return index; + } + + int key_get_binding_for_cmd_stub(const char* command) + { + // original binds + for (auto i = 0; i <= 100; i++) + { + if (game::command_whitelist[i] && !strcmp(command, game::command_whitelist[i])) + { + return i; + } + } + + // custom binds + return 100 + get_binding_for_custom_command(command); + } + + void cl_execute_key_stub(const int local_client_num, int key, const int down, const unsigned int time) + { + if (key >= 100) + { + key -= 100; + + if (static_cast(key) < custom_binds.size() && !custom_binds[key].empty()) + { + game::Cbuf_AddText(local_client_num, utils::string::va("%s\n", custom_binds[key].data())); + } + + return; + } + + cl_execute_key_hook.invoke(local_client_num, key, down, time); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + // write all bindings to config file + utils::hook::call(SELECT_VALUE(0x14023DF2B, 0x1402C465B), key_write_bindings_to_buffer_stub); + + // links a custom command to an index + utils::hook::jump(SELECT_VALUE(0x14023D6E0, 0x1402C3E50), key_get_binding_for_cmd_stub); + + // execute custom binds + cl_execute_key_hook.create(SELECT_VALUE(0x140239970, 0x1402BF0E0), &cl_execute_key_stub); + } + }; +} + +REGISTER_COMPONENT(binding::component) diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp new file mode 100644 index 0000000..2da44fd --- /dev/null +++ b/src/client/component/bots.cpp @@ -0,0 +1,204 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "filesystem.hpp" +#include "network.hpp" +#include "party.hpp" +#include "scheduler.hpp" +#include "server_list.hpp" + +#include +#include + +namespace bots +{ + namespace + { + constexpr std::size_t MAX_NAME_LENGTH = 16; + + bool can_add() + { + return party::get_client_count() < *game::mp::svs_clientCount; + } + + void bot_team_join(const int entity_num) + { + // schedule the select team call + scheduler::once([entity_num]() + { + game::SV_ExecuteClientCommand(&game::mp::svs_clients[entity_num], + utils::string::va("lui 68 2 %i", *game::mp::sv_serverId_value), + false); + + // scheduler the select class call + scheduler::once([entity_num]() + { + game::SV_ExecuteClientCommand(&game::mp::svs_clients[entity_num], + utils::string::va("lui 5 %i %i", (rand() % 5) + 10, + *game::mp::sv_serverId_value), false); + }, scheduler::pipeline::server, 1s); + }, scheduler::pipeline::server, 1s); + } + + void bot_team(const int entity_num) + { + if (game::SV_BotIsBot(game::mp::g_entities[entity_num].s.clientNum)) + { + if (game::mp::g_entities[entity_num].client->sess.cs.team == game::mp::team_t::TEAM_SPECTATOR) + { + bot_team_join(entity_num); + } + + scheduler::once([entity_num]() + { + bot_team(entity_num); + }, scheduler::pipeline::server, 3s); + } + } + + void spawn_bot(const int entity_num) + { + scheduler::once([entity_num]() + { + game::SV_SpawnTestClient(&game::mp::g_entities[entity_num]); + bot_team(entity_num); + }, scheduler::pipeline::server, 1s); + } + + void add_bot() + { + if (!can_add()) + { + return; + } + + auto* bot_name = game::SV_BotGetRandomName(); + auto* bot_ent = game::SV_AddBot(bot_name, 26, 62, 0); + if (bot_ent) + { + spawn_bot(bot_ent->s.number); + } + } + + utils::hook::detour get_bot_name_hook; + volatile bool bot_names_received = false; + std::vector bot_names; + + const char* get_random_bot_name() + { + if (bot_names.empty()) + { + return get_bot_name_hook.invoke(); + } + + const auto index = std::rand() % bot_names.size(); + const auto& name = bot_names.at(index); + + return utils::string::va("%.*s", static_cast(name.size()), name.data()); + } + + bool should_update_bot_names() + { + return !filesystem::exists("bots.txt"); + } + + void update_bot_names() + { + bot_names_received = false; + + game::netadr_s master{}; + if (server_list::get_master_server(master)) + { + console::info("Getting bots...\n"); + network::send(master, "getbots"); + } + } + + void parse_bot_names_from_file() + { + std::string data; + filesystem::read_file("bots.txt", &data); + if (data.empty()) + { + return; + } + + auto name_list = utils::string::split(data, '\n'); + for (auto& entry : name_list) + { + // Take into account CR line endings + entry = utils::string::replace(entry, "\r", ""); + + if (entry.empty()) + { + continue; + } + + entry = entry.substr(0, MAX_NAME_LENGTH - 1); + bot_names.emplace_back(entry); + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + get_bot_name_hook.create(game::SV_BotGetRandomName, get_random_bot_name); + + command::add("spawnBot", [](const command::params& params) + { + if (!game::SV_Loaded()) return; + + auto num_bots = 1; + if (params.size() == 2) + { + num_bots = atoi(params.get(1)); + } + + num_bots = std::min(num_bots, *game::mp::svs_clientCount); + + console::info("Spawning %i %s\n", num_bots, (num_bots == 1 ? "bot" : "bots")); + + for (auto i = 0; i < num_bots; i++) + { + scheduler::once(add_bot, scheduler::pipeline::server, 100ms * i); + } + }); + + if (should_update_bot_names()) + { + scheduler::on_game_initialized([]() + { + update_bot_names(); + scheduler::loop(update_bot_names, scheduler::main, 1h); + }, scheduler::main); + } + else + { + parse_bot_names_from_file(); + } + + network::on("getbotsResponse", [](const game::netadr_s& target, const std::string& data) + { + game::netadr_s master{}; + if (server_list::get_master_server(master) && !bot_names_received && target == master) + { + bot_names = utils::string::split(data, '\n'); + bot_names_received = true; + } + }); + } + }; +} + +REGISTER_COMPONENT(bots::component) diff --git a/src/client/component/branding.cpp b/src/client/component/branding.cpp new file mode 100644 index 0000000..3602fb4 --- /dev/null +++ b/src/client/component/branding.cpp @@ -0,0 +1,66 @@ +#include +#include "loader/component_loader.hpp" +#include "localized_strings.hpp" +#include "scheduler.hpp" +#include "game/game.hpp" + +#include +#include + +#include "version.hpp" + +namespace branding +{ + namespace + { + utils::hook::detour ui_get_formatted_build_number_hook; + + void dvar_set_string_stub(game::dvar_t* dvar, const char* string) + { + game::Dvar_SetString(dvar, utils::string::va("iw6-mod %s (game %s)", VERSION, string)); + } + + const char* ui_get_formatted_build_number_stub() + { + const auto* const build_num = ui_get_formatted_build_number_hook.invoke(); + + return utils::string::va("%s (%s)", VERSION, build_num); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + localized_strings::override("LUA_MENU_LEGAL_COPYRIGHT", "iw6-mod: " VERSION " by AlterWare.\n"); + + utils::hook::call(SELECT_VALUE(0x1403BDABA, 0x140414424), dvar_set_string_stub); + ui_get_formatted_build_number_hook.create( + SELECT_VALUE(0x140415FD0, 0x1404D7C00), ui_get_formatted_build_number_stub); + + scheduler::loop([]() + { + const auto x = 3; + const auto y = 0; + const auto scale = 0.5f; + float color[4] = {0.666f, 0.666f, 0.666f, 0.666f}; + const auto* text = "iw6-mod: " VERSION; + + auto* font = game::R_RegisterFont("fonts/normalfont"); + if (!font) return; + + game::R_AddCmdDrawText(text, std::numeric_limits::max(), font, static_cast(x), + y + static_cast(font->pixelHeight) * scale, + scale, scale, 0.0f, color, 0); + }, scheduler::pipeline::renderer); + } + }; +} // namespace branding + +REGISTER_COMPONENT(branding::component) diff --git a/src/client/component/bullet.cpp b/src/client/component/bullet.cpp new file mode 100644 index 0000000..caeadd7 --- /dev/null +++ b/src/client/component/bullet.cpp @@ -0,0 +1,44 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include + +namespace bullet +{ + namespace + { + utils::hook::detour bg_get_surface_penetration_depth_hook; + + float bg_get_surface_penetration_depth_stub(game::Weapon weapon, bool is_alternate, int surfaceType) + { + if (dvars::bg_surfacePenetration->current.value > 0.0f) + { + return dvars::bg_surfacePenetration->current.value; + } + + return bg_get_surface_penetration_depth_hook.invoke(weapon, is_alternate, surfaceType); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + dvars::bg_surfacePenetration = game::Dvar_RegisterFloat("bg_surfacePenetration", 0.0f, + 0.0f, std::numeric_limits::max(), game::DVAR_FLAG_SAVED, + "Set to a value greater than 0 to override the surface penetration depth"); + bg_get_surface_penetration_depth_hook.create(0x140238FD0, &bg_get_surface_penetration_depth_stub); + } + }; +} + +REGISTER_COMPONENT(bullet::component) diff --git a/src/client/component/colors.cpp b/src/client/component/colors.cpp new file mode 100644 index 0000000..7912ce5 --- /dev/null +++ b/src/client/component/colors.cpp @@ -0,0 +1,173 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include +#include + +namespace colors +{ + namespace + { + std::vector color_table; + + DWORD hsv_to_rgb(const game::HsvColor hsv) + { + DWORD rgb; + + if (hsv.s == 0) + { + return RGB(hsv.v, hsv.v, hsv.v); + } + + // converting to 16 bit to prevent overflow + const unsigned int h = hsv.h; + const unsigned int s = hsv.s; + const unsigned int v = hsv.v; + + const auto region = static_cast(h / 43); + const auto remainder = (h - (region * 43)) * 6; + + const auto p = static_cast((v * (255 - s)) >> 8); + const auto q = static_cast( + (v * (255 - ((s * remainder) >> 8))) >> 8); + const auto t = static_cast( + (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8); + + switch (region) + { + case 0: + rgb = RGB(v, t, p); + break; + case 1: + rgb = RGB(q, v, p); + break; + case 2: + rgb = RGB(p, v, t); + break; + case 3: + rgb = RGB(p, q, v); + break; + case 4: + rgb = RGB(t, p, v); + break; + default: + rgb = RGB(v, p, q); + break; + } + + return rgb; + } + + int color_index(const char c) + { + const auto index = c - 48; + return index >= 0xC ? 7 : index; + } + + char add(const uint8_t r, const uint8_t g, const uint8_t b) + { + const char index = '0' + static_cast(color_table.size()); + color_table.push_back(RGB(r, g, b)); + return index; + } + + void com_clean_name_stub(const char* in, char* out, const int out_size) + { + strncpy_s(out, out_size, in, _TRUNCATE); + } + + char* i_clean_str_stub(char* string) + { + utils::string::strip(string, string, std::strlen(string) + 1); + + return string; + } + + size_t get_client_name_stub(const int local_client_num, const int index, char* buf, const int size, + const size_t unk, const size_t unk2) + { + // CL_GetClientName (CL_GetClientNameAndClantag?) + const auto result = reinterpret_cast(0x1402CF790)( + local_client_num, index, buf, size, unk, unk2); + + utils::string::strip(buf, buf, size); + + return result; + } + + void rb_lookup_color_stub(const char index, DWORD* color) + { + *color = RGB(255, 255, 255); + + if (index == '8') + { + *color = *reinterpret_cast(SELECT_VALUE(0x145FFD958, 0x1480E85BC)); + } + else if (index == '9') + { + *color = *reinterpret_cast(SELECT_VALUE(0x145FFD95C, 0x1480E85C0)); + } + else if (index == ':') + { + *color = hsv_to_rgb({static_cast((game::Sys_Milliseconds() / 100) % 256), 255, 255}); + } + else if (index == ';') + { + *color = *reinterpret_cast(SELECT_VALUE(0x145FFD964, 0x1480E85C8)); + } + else + { + *color = color_table[color_index(index)]; + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + if (!game::environment::is_sp()) + { + // allows colored name in-game + utils::hook::jump(0x1404F5FC0, com_clean_name_stub); + + // don't apply colors to overhead names + utils::hook::call(0x14025CE79, get_client_name_stub); + + // patch I_CleanStr + utils::hook::jump(0x1404F63C0, i_clean_str_stub); + } + + // force new colors + utils::hook::jump(SELECT_VALUE(0x14055DCC0, 0x14062AE80), rb_lookup_color_stub); + + // add colors + add(0, 0, 0); // 0 - Black + add(255, 49, 49); // 1 - Red + add(134, 192, 0); // 2 - Green + add(255, 173, 34); // 3 - Yellow + add(0, 135, 193); // 4 - Blue + add(32, 197, 255); // 5 - Light Blue + add(151, 80, 221); // 6 - Pink + add(255, 255, 255); // 7 - White + + add(0, 0, 0); // 8 - Team color (axis?) + add(0, 0, 0); // 9 - Team color (allies?) + + add(0, 0, 0); // 10 - Rainbow (:) + add(0, 0, 0); + // 11 - Server color (;) - using that color in infostrings (e.g. your name) fails, ';' is an illegal character! + } + }; +} + +REGISTER_COMPONENT(colors::component) diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp new file mode 100644 index 0000000..32127b6 --- /dev/null +++ b/src/client/component/command.cpp @@ -0,0 +1,701 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "game_console.hpp" +#include "fastfiles.hpp" + +#include +#include +#include +#include + +namespace command +{ + namespace + { + constexpr auto CMD_MAX_NESTING = 8; + + utils::hook::detour client_command_hook; + + std::unordered_map> handlers; + std::unordered_map> handlers_sv; + + void main_handler() + { + params params = {}; + + const auto command = utils::string::to_lower(params[0]); + if (const auto itr = handlers.find(command); itr != handlers.end()) + { + itr->second(params); + } + } + + void client_command(const int client_num) + { + if (game::mp::g_entities[client_num].client == nullptr) + { + // Client is not fully connected + return; + } + + params_sv params = {}; + + const auto command = utils::string::to_lower(params[0]); + if (const auto itr = handlers_sv.find(command); itr != handlers_sv.end()) + { + itr->second(client_num, params); + } + + client_command_hook.invoke(client_num); + } + + // Shamelessly stolen from Quake3 + // https://github.com/id-Software/Quake-III-Arena/blob/dbe4ddb10315479fc00086f08e25d968b4b43c49/code/qcommon/common.c#L364 + void parse_command_line() + { + static auto parsed = false; + if (parsed) + { + return; + } + + static std::string comand_line_buffer = GetCommandLineA(); + auto* command_line = comand_line_buffer.data(); + + auto& com_num_console_lines = *reinterpret_cast(0x1445CFF98); + auto* com_console_lines = reinterpret_cast(0x1445CFFA0); + + auto inq = false; + com_console_lines[0] = command_line; + com_num_console_lines = 0; + + while (*command_line) + { + if (*command_line == '"') + { + inq = !inq; + } + // look for a + separating character + // if commandLine came from a file, we might have real line seperators + if ((*command_line == '+' && !inq) || *command_line == '\n' || *command_line == '\r') + { + if (com_num_console_lines == 0x20) // MAX_CONSOLE_LINES + { + break; + } + com_console_lines[com_num_console_lines] = command_line + 1; + com_num_console_lines++; + *command_line = '\0'; + } + command_line++; + } + parsed = true; + } + + void parse_commandline_stub() + { + parse_command_line(); + reinterpret_cast(0x140413080)(); + } + } + + void read_startup_variable(const std::string& dvar) + { + // parse the commandline if it's not parsed + parse_command_line(); + + auto com_num_console_lines = *reinterpret_cast(0x1445CFF98); + auto* com_console_lines = reinterpret_cast(0x1445CFFA0); + + for (int i = 0; i < com_num_console_lines; i++) + { + game::Com_TokenizeString(com_console_lines[i]); + + // only +set dvar value + if (game::Cmd_Argc() >= 3 && game::Cmd_Argv(0) == "set"s && game::Cmd_Argv(1) == dvar) + { + game::Dvar_SetCommand(game::Cmd_Argv(1), game::Cmd_Argv(2)); + } + + game::Com_EndTokenizeString(); + } + } + + params::params() + : nesting_(game::cmd_args->nesting) + { + assert(this->nesting_ < CMD_MAX_NESTING); + } + + int params::size() const + { + return game::cmd_args->argc[this->nesting_]; + } + + const char* params::get(const int index) const + { + if (index >= this->size()) + { + return ""; + } + + return game::cmd_args->argv[this->nesting_][index]; + } + + std::string params::join(const int index) const + { + std::string result = {}; + + for (auto i = index; i < this->size(); i++) + { + if (i > index) result.append(" "); + result.append(this->get(i)); + } + return result; + } + + params_sv::params_sv() + : nesting_(game::sv_cmd_args->nesting) + { + assert(this->nesting_ < CMD_MAX_NESTING); + } + + int params_sv::size() const + { + return game::sv_cmd_args->argc[this->nesting_]; + } + + const char* params_sv::get(const int index) const + { + if (index >= this->size()) + { + return ""; + } + + return game::sv_cmd_args->argv[this->nesting_][index]; + } + + std::string params_sv::join(const int index) const + { + std::string result = {}; + + for (auto i = index; i < this->size(); i++) + { + if (i > index) result.append(" "); + result.append(this->get(i)); + } + return result; + } + + void add_raw(const char* name, void (*callback)()) + { + game::Cmd_AddCommandInternal(name, callback, utils::memory::get_allocator()->allocate()); + } + + void add(const char* name, const std::function& callback) + { + const auto command = utils::string::to_lower(name); + + if (!handlers.contains(command)) + { + add_raw(name, main_handler); + } + + handlers[command] = callback; + } + + void add(const char* name, const std::function& callback) + { + add(name, [callback](const params&) + { + callback(); + }); + } + + void add_sv(const char* name, const std::function& callback) + { + // doing this so the sv command would show up in the console + add_raw(name, nullptr); + + const auto command = utils::string::to_lower(name); + + if (!handlers_sv.contains(command)) + { + handlers_sv[command] = callback; + } + } + + void execute(std::string command, const bool sync) + { + command += "\n"; + + if (sync) + { + game::Cmd_ExecuteSingleCommand(0, 0, command.data()); + } + else + { + game::Cbuf_AddText(0, command.data()); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + add_sp_commands(); + } + else + { + utils::hook::call(0x14041213C, &parse_commandline_stub); + + add_mp_commands(); + } + add_commands_generic(); + } + + private: + static void add_commands_generic() + { + add("quit", game::Com_Quit); + add("crash", [] + { + *reinterpret_cast(1) = 0x12345678; + }); + + add("dvarDump", [](const params& argument) + { + std::string filename; + if (argument.size() == 2) + { + filename = "iw6/"; + filename.append(argument[1]); + if (!filename.ends_with(".txt")) + { + filename.append(".txt"); + } + } + + console::info("================================ DVAR DUMP ========================================\n"); + for (auto i = 0; i < *game::dvarCount; i++) + { + auto* dvar = game::sortedDvars[i]; + if (dvar) + { + if (!filename.empty()) + { + const auto line = std::format("{} \"{}\"\r\n", dvar->name, game::Dvar_ValueToString(dvar, dvar->current)); + utils::io::write_file(filename, line, i != 0); + } + + console::info("%s \"%s\"\n", dvar->name, game::Dvar_ValueToString(dvar, dvar->current)); + } + } + + console::info("\n%i dvars\n", *game::dvarCount); + console::info("================================ END DVAR DUMP ====================================\n"); + }); + + add("commandDump", [](const params& argument) + { + std::string filename; + if (argument.size() == 2) + { + filename = "iw6/"; + filename.append(argument[1]); + if (!filename.ends_with(".txt")) + { + filename.append(".txt"); + } + } + + console::info("================================ COMMAND DUMP =====================================\n"); + game::cmd_function_s* cmd = *game::cmd_functions; + auto i = 0; + while (cmd) + { + if (cmd->name) + { + if (!filename.empty()) + { + const auto line = std::format("{}\r\n", cmd->name); + utils::io::write_file(filename, line, i != 0); + } + + console::info("%s\n", cmd->name); + i++; + } + + cmd = cmd->next; + } + console::info("\n%i commands\n", i); + console::info("================================ END COMMAND DUMP =================================\n"); + }); + + add("consoleList", [](const params& params) + { + const std::string input = params.get(1); + + std::vector matches; + game_console::find_matches(input, matches, false); + + for (auto& match : matches) + { + auto* dvar = game::Dvar_FindVar(match.c_str()); + if (!dvar) + { + console::info("[CMD]\t %s\n", match.c_str()); + } + else + { + console::info("[DVAR]\t%s \"%s\"\n", match.c_str(), game::Dvar_ValueToString(dvar, dvar->current)); + } + } + + console::info("Total %i matches\n", matches.size()); + }); + + add("listassetpool", [](const params& params) + { + if (params.size() < 2) + { + console::info("listassetpool [filter]: list all the assets in the specified pool\n"); + + for (auto i = 0; i < game::XAssetType::ASSET_TYPE_COUNT; i++) + { + console::info("%d %s\n", i, game::g_assetNames[i]); + } + } + else + { + const auto type = static_cast(atoi(params.get(1))); + + if (type < 0 || type >= game::XAssetType::ASSET_TYPE_COUNT) + { + console::error("Invalid pool passed must be between [%d, %d]\n", 0, game::XAssetType::ASSET_TYPE_COUNT - 1); + return; + } + + console::info("Listing assets in pool %s\n", game::g_assetNames[type]); + + auto total_assets = 0; + const std::string filter = params.get(2); + fastfiles::enum_assets(type, [type, &total_assets, filter](const game::XAssetHeader header) + { + const game::XAsset asset{ type, header }; + const auto* const asset_name = game::DB_GetXAssetName(&asset); + //const auto* const entry = game::DB_FindXAssetEntry(type, asset_name); + //const char* zone_name; + + total_assets++; + + if (!filter.empty() && !game_console::match_compare(filter, asset_name, false)) + { + return; + } + // TODO: in some cases returning garbage data + //if (game::environment::is_sp()) + //{ + // zone_name = game::sp::g_zones_0[entry->zoneIndex].name; + //} + //else + //{ + // zone_name = game::mp::g_zones_0[entry->zoneIndex].name; + //} + + console::info("%s\n", asset_name); + }, true); + + console::info("Total %s assets: %d/%d", game::g_assetNames[type], total_assets, game::g_poolSize[type]); + } + }); + + add("vstr", [](const params& params) + { + if (params.size() < 2) + { + console::info("vstr : execute a variable command\n"); + return; + } + + const auto* dvarName = params.get(1); + const auto* dvar = game::Dvar_FindVar(dvarName); + + if (dvar == nullptr) + { + console::info("%s doesn't exist\n", dvarName); + return; + } + + if (dvar->type != game::dvar_type::string + && dvar->type != game::dvar_type::enumeration) + { + console::info("%s is not a string-based dvar\n", dvar->name); + return; + } + + execute(dvar->current.string); + }); + } + + void add_sp_commands() + { + add("god", [] + { + if (!game::SV_Loaded()) + { + return; + } + + game::sp::g_entities[0].flags ^= game::FL_GODMODE; + game::CG_GameMessage(0, utils::string::va("godmode %s", + game::sp::g_entities[0].flags & game::FL_GODMODE + ? "^2on" + : "^1off")); + }); + + add("notarget", [] + { + if (!game::SV_Loaded()) + { + return; + } + + game::sp::g_entities[0].flags ^= game::FL_NOTARGET; + game::CG_GameMessage(0, utils::string::va("notarget %s", + game::sp::g_entities[0].flags & game::FL_NOTARGET + ? "^2on" + : "^1off")); + }); + + add("noclip", [] + { + if (!game::SV_Loaded()) + { + return; + } + + game::sp::g_entities[0].client->flags ^= 1; + game::CG_GameMessage(0, utils::string::va("noclip %s", + game::sp::g_entities[0].client->flags & 1 + ? "^2on" + : "^1off")); + }); + + add("ufo", [] + { + if (!game::SV_Loaded()) + { + return; + } + + game::sp::g_entities[0].client->flags ^= 2; + game::CG_GameMessage(0, utils::string::va("ufo %s", + game::sp::g_entities[0].client->flags & 2 + ? "^2on" + : "^1off")); + }); + + add("give", [](const params& params) + { + if (!game::SV_Loaded()) + { + return; + } + + if (params.size() < 2) + { + game::CG_GameMessage(0, "You did not specify a weapon name"); + return; + } + + auto ps = game::SV_GetPlayerstateForClientNum(0); + auto wp = game::G_GetWeaponForName(params.get(1)); + if (game::G_GivePlayerWeapon(ps, wp, 0, 0, 0)) + { + game::G_InitializeAmmo(ps, wp, 0); + game::G_SelectWeapon(0, wp); + } + }); + + add("take", [](const params& params) + { + if (!game::SV_Loaded()) + { + return; + } + + if (params.size() < 2) + { + game::CG_GameMessage(0, "You did not specify a weapon name"); + return; + } + + auto ps = game::SV_GetPlayerstateForClientNum(0); + auto wp = game::G_GetWeaponForName(params.get(1)); + game::G_TakePlayerWeapon(ps, wp); + }); + } + + static void add_mp_commands() + { + client_command_hook.create(0x1403929B0, &client_command); + + add_sv("god", [&](const int client_num, const params_sv&) + { + if (!dvars::sv_cheats->current.enabled) + { + game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\""); + return; + } + + game::mp::g_entities[client_num].flags ^= game::FL_GODMODE; + game::SV_GameSendServerCommand(client_num, 1, + utils::string::va("f \"godmode %s\"", + game::mp::g_entities[client_num].flags & game::FL_GODMODE + ? "^2on" + : "^1off")); + }); + + add_sv("notarget", [](const int client_num, const params_sv&) + { + if (!dvars::sv_cheats->current.enabled) + { + game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\""); + return; + } + + game::mp::g_entities[client_num].flags ^= game::FL_NOTARGET; + game::SV_GameSendServerCommand(client_num, 1, + utils::string::va("f \"notarget %s\"", + game::mp::g_entities[client_num].flags & game::FL_NOTARGET + ? "^2on" + : "^1off")); + }); + + add_sv("noclip", [](const int client_num, const params_sv&) + { + if (!dvars::sv_cheats->current.enabled) + { + game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\""); + return; + } + + game::mp::g_entities[client_num].client->flags ^= 1; + game::SV_GameSendServerCommand(client_num, 1, + utils::string::va("f \"noclip %s\"", + game::mp::g_entities[client_num].client->flags & 1 + ? "^2on" + : "^1off")); + }); + + add_sv("ufo", [](const int client_num, const params_sv&) + { + if (!dvars::sv_cheats->current.enabled) + { + game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\""); + return; + } + + game::mp::g_entities[client_num].client->flags ^= 2; + game::SV_GameSendServerCommand(client_num, 1, + utils::string::va("f \"ufo %s\"", + game::mp::g_entities[client_num].client->flags & 2 + ? "^2on" + : "^1off")); + }); + + add_sv("setviewpos", [](const int client_num, const params_sv& params) + { + if (!dvars::sv_cheats->current.enabled) + { + game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\""); + return; + } + + if (params.size() < 4) + { + game::SV_GameSendServerCommand(client_num, 1, + "f \"You did not specify the correct number of coordinates\""); + return; + } + + game::mp::g_entities[client_num].client->ps.origin[0] = std::strtof(params.get(1), nullptr); + game::mp::g_entities[client_num].client->ps.origin[1] = std::strtof(params.get(2), nullptr); + game::mp::g_entities[client_num].client->ps.origin[2] = std::strtof(params.get(3), nullptr); + }); + + add_sv("setviewang", [](const int client_num, const params_sv& params) + { + if (!dvars::sv_cheats->current.enabled) + { + game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\""); + return; + } + + if (params.size() < 4) + { + game::SV_GameSendServerCommand(client_num, 1, + "f \"You did not specify the correct number of coordinates\""); + return; + } + + game::mp::g_entities[client_num].client->ps.delta_angles[0] = std::strtof(params.get(1), nullptr); + game::mp::g_entities[client_num].client->ps.delta_angles[1] = std::strtof(params.get(2), nullptr); + game::mp::g_entities[client_num].client->ps.delta_angles[2] = std::strtof(params.get(3), nullptr); + }); + + add_sv("give", [](const int client_num, const params_sv& params) + { + if (!dvars::sv_cheats->current.enabled) + { + game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\""); + return; + } + + if (params.size() < 2) + { + game::SV_GameSendServerCommand(client_num, 1, "f \"You did not specify a weapon name\""); + return; + } + + auto ps = game::SV_GetPlayerstateForClientNum(client_num); + auto wp = game::G_GetWeaponForName(params.get(1)); + if (game::G_GivePlayerWeapon(ps, wp, 0, 0, 0)) + { + game::G_InitializeAmmo(ps, wp, 0); + game::G_SelectWeapon(client_num, wp); + } + }); + + add_sv("take", [](const int client_num, const params_sv& params) + { + if (!dvars::sv_cheats->current.enabled) + { + game::SV_GameSendServerCommand(client_num, 1, "f \"Cheats are not enabled on this server\""); + return; + } + + if (params.size() < 2) + { + game::SV_GameSendServerCommand(client_num, 1, "f \"You did not specify a weapon name\""); + return; + } + + auto ps = game::SV_GetPlayerstateForClientNum(client_num); + auto wp = game::G_GetWeaponForName(params.get(1)); + game::G_TakePlayerWeapon(ps, wp); + }); + } + }; +} + +REGISTER_COMPONENT(command::component) diff --git a/src/client/component/command.hpp b/src/client/component/command.hpp new file mode 100644 index 0000000..5efee79 --- /dev/null +++ b/src/client/component/command.hpp @@ -0,0 +1,50 @@ +#pragma once + +namespace command +{ + class params + { + public: + params(); + + int size() const; + const char* get(int index) const; + std::string join(int index) const; + + const char* operator[](const int index) const + { + return this->get(index); // + } + + private: + int nesting_; + }; + + class params_sv + { + public: + params_sv(); + + int size() const; + const char* get(int index) const; + std::string join(int index) const; + + const char* operator[](const int index) const + { + return this->get(index); // + } + + private: + int nesting_; + }; + + void read_startup_variable(const std::string& dvar); + + void add_raw(const char* name, void (*callback)()); + void add(const char* name, const std::function& callback); + void add(const char* name, const std::function& callback); + + void add_sv(const char* name, const std::function& callback); + + void execute(std::string command, bool sync = false); +} diff --git a/src/client/component/console.cpp b/src/client/component/console.cpp new file mode 100644 index 0000000..3e37281 --- /dev/null +++ b/src/client/component/console.cpp @@ -0,0 +1,260 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "console.hpp" +#include "command.hpp" +#include "game_console.hpp" +#include "rcon.hpp" +#include "scheduler.hpp" + +#include +#include +#include + +namespace console +{ + namespace + { + using message_queue = std::queue; + utils::concurrency::container message_queue_; + + std::atomic_bool started_{false}; + std::atomic_bool terminate_runner_{false}; + + void print_message(const char* message) + { +#ifdef _DEBUG + OutputDebugStringA(message); +#endif + + if (game::is_headless()) + { + std::fputs(message, stdout); + } + else + { + game::Conbuf_AppendText(message); + } + } + + std::string format(va_list* ap, const char* message) + { + static thread_local char buffer[0x1000]; + + const auto count = vsnprintf_s(buffer, _TRUNCATE, message, *ap); + + if (count < 0) return {}; + return {buffer, static_cast(count)}; + } + + void dispatch_message(const int type, const std::string& message) + { + if (rcon::message_redirect(message)) + { + return; + } + + game_console::print(type, message); + + if (game::is_headless()) + { + std::fputs(message.data(), stdout); + return; + } + + message_queue_.access([&message](message_queue& queue) + { + queue.emplace(message); + }); + } + + message_queue empty_message_queue() + { + message_queue current_queue{}; + + message_queue_.access([&](message_queue& queue) + { + current_queue = std::move(queue); + queue = {}; + }); + + return current_queue; + } + + void print_stub(const char* fmt, ...) + { + va_list ap; + va_start(ap, fmt); + + char buffer[4096]{}; + const auto res = vsnprintf_s(buffer, _TRUNCATE, fmt, ap); + (void)res; + print_message(buffer); + + va_end(ap); + } + + void append_text(const char* text) + { + dispatch_message(con_type_info, text); + } + } + + class component final : public component_interface + { + public: + component() + { + if (game::is_headless()) + { + if (!AttachConsole(ATTACH_PARENT_PROCESS)) + { + AllocConsole(); + AttachConsole(GetCurrentProcessId()); + } + + ShowWindow(GetConsoleWindow(), SW_SHOW); + + FILE* fp; + freopen_s(&fp, "CONIN$", "r", stdin); + freopen_s(&fp, "CONOUT$", "w", stdout); + freopen_s(&fp, "CONOUT$", "w", stderr); + } + } + + void post_unpack() override + { + // Redirect input (]command) + utils::hook::jump(SELECT_VALUE(0x14043DFA0, 0x140502A80), append_text); + + utils::hook::jump(printf, print_stub); + + if (game::is_headless()) + { + return; + } + + terminate_runner_ = false; + + this->message_runner_ = utils::thread::create_named_thread("Console IO", [] + { + while (!started_) + { + std::this_thread::sleep_for(10ms); + } + + while (!terminate_runner_) + { + std::string message_buffer{}; + auto current_queue = empty_message_queue(); + + while (!current_queue.empty()) + { + const auto& msg = current_queue.front(); + message_buffer.append(msg); + current_queue.pop(); + } + + if (!message_buffer.empty()) + { + print_message(message_buffer.data()); + } + + std::this_thread::sleep_for(5ms); + } + }); + + this->console_runner_ = utils::thread::create_named_thread("Console Window", [this] + { + game::Sys_ShowConsole(); + + MSG msg{}; + while (!terminate_runner_) + { + if (PeekMessageW(&msg, nullptr, NULL, NULL, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + command::execute("quit", false); + break; + } + + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + else + { + std::this_thread::sleep_for(5ms); + } + } + }); + + // Give the console a chance to open or we will lose some early messages + // like the ones printed from the filesystem component + scheduler::once([]() -> void + { + started_ = true; + }, scheduler::pipeline::main); + } + + void pre_destroy() override + { + terminate_runner_ = true; + + if (this->message_runner_.joinable()) + { + this->message_runner_.join(); + } + + if (this->console_runner_.joinable()) + { + this->console_runner_.join(); + } + } + + private: + std::thread console_runner_{}; + std::thread message_runner_{}; + }; + + HWND get_window() + { + return *reinterpret_cast((SELECT_VALUE(0x145A7B490, 0x147AD1DB0))); + } + + void set_title(std::string title) + { + if (game::is_headless()) + { + SetConsoleTitleA(title.data()); + } + else + { + SetWindowTextA(get_window(), title.data()); + } + } + + void set_size(const int width, const int height) + { + RECT rect; + GetWindowRect(get_window(), &rect); + + SetWindowPos(get_window(), nullptr, rect.left, rect.top, width, height, 0); + + auto* const logo_window = *reinterpret_cast(SELECT_VALUE(0x145A7B4A0, 0x147AD1DC0)); + SetWindowPos(logo_window, nullptr, 5, 5, width - 25, 60, 0); + } + + void print(const int type, const char* fmt, ...) + { + va_list ap; + va_start(ap, fmt); + const auto result = format(&ap, fmt); + va_end(ap); + + dispatch_message(type, result); + } +} + +REGISTER_COMPONENT(console::component) diff --git a/src/client/component/console.hpp b/src/client/component/console.hpp new file mode 100644 index 0000000..484266b --- /dev/null +++ b/src/client/component/console.hpp @@ -0,0 +1,35 @@ +#pragma once + +namespace console +{ + HWND get_window(); + void set_title(std::string title); + void set_size(int width, int height); + + enum console_type + { + con_type_error = 1, + con_type_warning = 3, + con_type_info = 7 + }; + + void print(int type, const char* fmt, ...); + + template + void error(const char* fmt, Args&&... args) + { + print(con_type_error, fmt, std::forward(args)...); + } + + template + void warn(const char* fmt, Args&&... args) + { + print(con_type_warning, fmt, std::forward(args)...); + } + + template + void info(const char* fmt, Args&&... args) + { + print(con_type_info, fmt, std::forward(args)...); + } +} diff --git a/src/client/component/cursor.cpp b/src/client/component/cursor.cpp new file mode 100644 index 0000000..a18f4eb --- /dev/null +++ b/src/client/component/cursor.cpp @@ -0,0 +1,75 @@ +#include +#include "loader/component_loader.hpp" +#include "scheduler.hpp" +#include "game/game.hpp" + +#include + +namespace cursor +{ + namespace + { + bool show_cursor_next_frame = false; + + int WINAPI show_cursor_stub(const BOOL show) + { + static auto counter = 0; + counter += show ? 1 : -1; + return counter; + } + + void show_cursor(const bool show) + { + static auto last_state = false; + if (last_state == show) + { + return; + } + + if (show) + { + while (ShowCursor(TRUE) < 0); + } + else + { + while (ShowCursor(FALSE) >= 0); + } + } + + void draw_cursor_stub() + { + show_cursor_next_frame = true; + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // This is the legacy cursor + // TODO: Find the new cursor drawing... + utils::hook::call(SELECT_VALUE(0x14040117E, 0x1404BB119), draw_cursor_stub); + + scheduler::loop([]() + { + show_cursor(show_cursor_next_frame); + show_cursor_next_frame = false; + }, scheduler::pipeline::renderer); + + show_cursor(true); + } + + void* load_import(const std::string& library, const std::string& function) override + { + if (function == "ShowCursor") + { + return &show_cursor_stub; + } + + return nullptr; + } + }; +} + +//REGISTER_COMPONENT(cursor::component) diff --git a/src/client/component/dedicated.cpp b/src/client/component/dedicated.cpp new file mode 100644 index 0000000..a4263cf --- /dev/null +++ b/src/client/component/dedicated.cpp @@ -0,0 +1,400 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "dvars.hpp" +#include "network.hpp" +#include "party.hpp" +#include "scheduler.hpp" +#include "server_list.hpp" + +#include +#include + +#include + +namespace dedicated +{ + namespace + { + const game::dvar_t* sv_lanOnly; + + void initialize() + { + command::execute("exec default_xboxlive.cfg", true); + command::execute("xstartprivatematch", true); // IW6 specific, doesn't work without + command::execute("onlinegame 1", true); + command::execute("xblive_privatematch 0", true); + } + + void init_dedicated_server() + { + static bool initialized = false; + if (initialized) return; + initialized = true; + + static const char* fastfiles[] = + { + "code_post_gfx_mp", + "ui_mp", + "code_nvidia_mp", + "common_mp", + nullptr, //"mp_character_room", + nullptr, //"mp_character_room_heads", + nullptr, //"mp_character_room_bodies_updated", + nullptr, //"mp_character_room_dlc_updated", + "techsets_common_core_mp", + "common_core_mp", + "common_core_dlc_updated_mp", + "techsets_common_alien_mp", + "common_alien_mp", + "common_alien_dlc_updated_mp", + nullptr + }; + + // load fastfiles + std::memcpy(reinterpret_cast(0x1480B1E40), &fastfiles, sizeof(fastfiles)); + + // R_LoadGraphicsAssets + reinterpret_cast(0x1405E6F80)(); + } + + void start_map(const std::string& map_name) + { + if (game::Live_SyncOnlineDataFlags(0) != 0) + { + scheduler::on_game_initialized([map_name] + { + command::execute(std::format("map {}", map_name), false); + }, scheduler::pipeline::main, 1s); + + return; + } + + party::switch_gamemode_if_necessary(dvars::get_string("g_gametype")); + + if (!game::environment::is_dedi()) + { + party::perform_game_initialization(); + } + + const auto* current_mapname = game::Dvar_FindVar("mapname"); + if (current_mapname && utils::string::to_lower(current_mapname->current.string) == utils::string::to_lower(map_name) && game::SV_Loaded()) + { + console::info("Restarting map: %s\n", map_name.data()); + command::execute("map_restart", false); + return; + } + + console::info("Starting map: %s\n", map_name.data()); + game::SV_StartMapForParty(0, map_name.data(), false, false); + } + + void map_restart() + { + if (!game::SV_Loaded()) + { + return; + } + + *reinterpret_cast(0x144DB8C84) = 1; // sv_map_restart + *reinterpret_cast(0x144DB8C88) = 1; // sv_loadScripts + *reinterpret_cast(0x144DB8C8C) = 0; // sv_migrate + reinterpret_cast(0x14046F3B0)(); // SV_CheckLoadGame + } + + game::dvar_t* register_maxfps_stub(const char* name, int, int, int, unsigned int flags, + const char* desc) + { + return game::Dvar_RegisterInt(name, 0, 0, 0, game::DvarFlags::DVAR_FLAG_READ, desc); + } + + void send_heartbeat() + { + if (sv_lanOnly->current.enabled) + { + return; + } + + game::netadr_s target{}; + if (server_list::get_master_server(target)) + { + network::send(target, "heartbeat", "IW6"); + } + } + + std::vector& get_startup_command_queue() + { + static std::vector startup_command_queue; + return startup_command_queue; + } + + void execute_startup_command(int /*client*/, int /*controllerIndex*/, const char* command) + { + if (game::Live_SyncOnlineDataFlags(0) == 0) + { + game::Cbuf_ExecuteBufferInternal(0, 0, command, game::Cmd_ExecuteSingleCommand); + } + else + { + get_startup_command_queue().emplace_back(command); + } + } + + void execute_startup_command_queue() + { + const auto queue = get_startup_command_queue(); + get_startup_command_queue().clear(); + + for (const auto& command : queue) + { + game::Cbuf_ExecuteBufferInternal(0, 0, command.data(), game::Cmd_ExecuteSingleCommand); + } + } + + std::vector& get_console_command_queue() + { + static std::vector console_command_queue; + return console_command_queue; + } + + void execute_console_command([[maybe_unused]] const int local_client_num, const char* command) + { + if (game::Live_SyncOnlineDataFlags(0) == 0) + { + command::execute(command); + } + else + { + get_console_command_queue().emplace_back(command); + } + } + + void execute_console_command_queue() + { + const auto queue = get_console_command_queue(); + get_console_command_queue().clear(); + + for (const auto& command : queue) + { + command::execute(command); + } + } + + void sync_gpu_stub() + { + std::this_thread::sleep_for(1ms); + } + + void gscr_is_using_match_rules_data_stub() + { + game::Scr_AddInt(0); + } + + void glass_update() + { + if (*reinterpret_cast(0x14424C068)) + { + reinterpret_cast(0x140397450)(); + } + } + + HWND WINAPI set_focus_stub(const HWND hwnd) + { + return hwnd; + } + + void sys_error_stub(const char* msg, ...) + { + char buffer[2048]{}; + + va_list ap; + va_start(ap, msg); + + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + + va_end(ap); + + scheduler::once([]() + { + command::execute("map_rotate"); + }, scheduler::pipeline::main, 3s); + + game::Com_Error(game::ERR_DROP, "%s", buffer); + } + + void add_commands() + { + command::add("map", [](const command::params& params) + { + if (params.size() != 2) + { + return; + } + + start_map(utils::string::to_lower(params[1])); + }); + + command::add("map_restart", map_restart); + + command::add("fast_restart", [] + { + if (game::SV_Loaded()) + { + game::SV_FastRestart(); + } + }); + + command::add("heartbeat", send_heartbeat); + } + } + + class component final : public component_interface + { + public: + void* load_import(const std::string& library, const std::string& function) override + { + if (!game::environment::is_dedi()) return nullptr; + + if (function == "SetFocus") + { + return set_focus_stub; + } + + return nullptr; + } + + void post_unpack() override + { + if (!game::environment::is_dedi()) + { + return; + } + + // Arxan error fix + utils::hook::call(0x1403A0AF9, glass_update); + + // Add lanonly mode + sv_lanOnly = game::Dvar_RegisterBool("sv_lanOnly", false, game::DVAR_FLAG_NONE, "Don't send heartbeat"); + + // Make GScr_IsUsingMatchRulesData return 0 so the game doesn't override the cfg + utils::hook::jump(0x1403C9660, gscr_is_using_match_rules_data_stub); + + // Patch "Server is on a different version" + utils::hook::set(0x140471474, 0xEB); + + // Patch checksum check + utils::hook::set(0x1404714D4, 0xEB); + + // Hook R_SyncGpu + utils::hook::jump(0x1405E8530, sync_gpu_stub); + + //utils::hook::set(0x1402C89A0, 0xC3); // R_Init caller + utils::hook::jump(0x1402C89A0, init_dedicated_server); + utils::hook::call(0x140413AD8, register_maxfps_stub); + + // delay startup commands until the initialization is done + utils::hook::call(0x140412183, execute_startup_command); + + // delay console commands until the initialization is done + utils::hook::call(0x140412FD3, execute_console_command); + utils::hook::nop(0x140412FE9, 5); + + utils::hook::nop(0x1404DDC2E, 5); // don't load config file + utils::hook::set(0x140416100, 0xC3); // don't save config file + utils::hook::set(0x1402E5830, 0xC3); // disable self-registration + utils::hook::set(0x1402C7935, 5); // make CL_Frame do client packets, even for game state 9 + utils::hook::set(0x140503FF0, 0xC3); // init sound system (1) + utils::hook::set(0x140602380, 0xC3); // start render thread + utils::hook::set(0x140658580, 0xC3); // init sound system (2) + //utils::hook::set(0x49BC10, 0xC3); // Com_Frame audio processor? + utils::hook::set(0x1402CF570, 0xC3); // called from Com_Frame, seems to do renderer stuff + utils::hook::set(0x1402C49B0, 0xC3); + // CL_CheckForResend, which tries to connect to the local server constantly + utils::hook::set(0x1405DAE1F, 0); // r_loadForRenderer default to 0 + utils::hook::set(0x1404FFCE2, 0xC3); // recommended settings check - TODO: Check hook + utils::hook::set(0x140503420, 0xC3); // some mixer-related function called on shutdown + utils::hook::set(0x1404BEC10, 0xC3); // dont load ui gametype stuff + //utils::hook::set(0x611690, 0xC3); // some unknown function that seems to fail + utils::hook::nop(0x14047261C, 6); // unknown check in SV_ExecuteClientMessage + //utils::hook::nop(0x5751DF, 2); // don't spawn a DemonWare session for the dedicated server + //utils::hook::set(0x5751E9, 0xEB); // ^ + utils::hook::nop(0x140471B6B, 4); // allow first slot to be occupied + utils::hook::nop(0x1402CA0F5, 2); // properly shut down dedicated servers + utils::hook::nop(0x1402CA0B9, 2); // ^ + utils::hook::nop(0x1402CA12D, 5); // don't shutdown renderer + utils::hook::set(0x1405E87DE, 0xEB); // ignore world being in use + + utils::hook::set(0x1404FFCF0, 0xC3); // cpu detection stuff + utils::hook::set(0x1405F0620, 0xC3); // gfx stuff during fastfile loading + utils::hook::set(0x1405F0530, 0xC3); // ^ + utils::hook::set(0x1405F05C0, 0xC3); // ^ + utils::hook::set(0x140324F00, 0xC3); // ^ + utils::hook::set(0x1405F0580, 0xC3); // ^ + utils::hook::set(0x1405B81A0, 0xC3); // directx stuff + utils::hook::set(0x1405E0CF0, 0xC3); // ^ + utils::hook::set(0x1405E1530, 0xC3); // ^ + utils::hook::set(0x1405E3E50, 0xC3); // ^ - mutex + utils::hook::set(0x1405E1050, 0xC3); // ^ + + // shaders + utils::hook::set(0x140167E00, 0xC3); // ^ + utils::hook::set(0x140167D80, 0xC3); // ^ + + utils::hook::set(0x1406492A0, 0xC3); // ^ - mutex + + utils::hook::set(0x1405047A0, 0xC3); // idk + utils::hook::set(0x1405B8DB0, 0xC3); // ^ + + utils::hook::set(0x1405E7D20, 0xC3); // R_Shutdown + utils::hook::set(0x1405B8BD0, 0xC3); // shutdown stuff + utils::hook::set(0x1405E7DF0, 0xC3); // ^ + utils::hook::set(0x1405E76C0, 0xC3); // ^ + + utils::hook::set(0x14065EA00, 0xC3); // sound crashes + + utils::hook::set(0x14047BE70, 0xC3); // disable host migration + + utils::hook::set(0x140423B20, 0xC3); // render synchronization lock + utils::hook::set(0x140423A60, 0xC3); // render synchronization unlock + + //utils::hook::set(0x1405E3470, 0xC3); // some rendering stuff in R_UpdateDynamicMemory + //utils::hook::set(0x1405E31A0, 0xC3); // ^ + utils::hook::jump(0x140610EB6, 0x140610F15); // ^ + + utils::hook::nop(0x1404F8BD9, 5); // Disable sound pak file loading + utils::hook::nop(0x1404F8BE1, 2); // ^ + utils::hook::set(0x140328660, 0xC3); // Disable image pak file loading + + // Stop crashing from sys_errors + utils::hook::jump(0x1404FF510, sys_error_stub); + + // Reduce min required memory + utils::hook::set(0x1404FA6BD, 0x80000000); + utils::hook::set(0x1404FA76F, 0x80000000); + + scheduler::on_game_initialized([] + { + initialize(); + + console::info("==================================\n"); + console::info("Server started!\n"); + console::info("==================================\n"); + + execute_startup_command_queue(); + execute_console_command_queue(); + + }, scheduler::pipeline::main, 1s); + + // Send heartbeat to dpmaster + scheduler::once(send_heartbeat, scheduler::pipeline::server); + scheduler::loop(send_heartbeat, scheduler::pipeline::server, 10min); + + add_commands(); + } + }; +} + +REGISTER_COMPONENT(dedicated::component) diff --git a/src/client/component/dedicated_info.cpp b/src/client/component/dedicated_info.cpp new file mode 100644 index 0000000..9f0de69 --- /dev/null +++ b/src/client/component/dedicated_info.cpp @@ -0,0 +1,70 @@ +#include +#include "console.hpp" +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "scheduler.hpp" +#include + +namespace dedicated_info +{ + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_dedi()) + { + return; + } + + scheduler::once([]() + { + console::set_title("iw6-mod Dedicated Server"); + console::set_size(800, 600); + }); + + scheduler::loop([]() + { + auto* sv_running = game::Dvar_FindVar("sv_running"); + if (!sv_running || !sv_running->current.enabled) + { + console::set_title("iw6-mod Dedicated Server"); + return; + } + + auto* const sv_hostname = game::Dvar_FindVar("sv_hostname"); + auto* const sv_maxclients = game::Dvar_FindVar("sv_maxclients"); + auto* const mapname = game::Dvar_FindVar("mapname"); + + auto client_count = 0; + auto bot_count = 0; + + for (auto i = 0; i < sv_maxclients->current.integer; i++) + { + auto* client = &game::mp::svs_clients[i]; + auto* self = &game::mp::g_entities[i]; + + if (client->header.state > game::CS_FREE && self && self->client) + { + client_count++; + if (game::SV_BotIsBot(i)) + { + ++bot_count; + } + } + } + + std::string cleaned_hostname = sv_hostname->current.string; + + utils::string::strip(sv_hostname->current.string, cleaned_hostname.data(), + cleaned_hostname.size() + 1); + + console::set_title(utils::string::va("%s on %s [%d/%d] (%d)", cleaned_hostname.data(), + mapname->current.string, client_count, + sv_maxclients->current.integer, bot_count)); + }, scheduler::pipeline::main, 1s); + } + }; +} + +REGISTER_COMPONENT(dedicated_info::component) diff --git a/src/client/component/demonware.cpp b/src/client/component/demonware.cpp new file mode 100644 index 0000000..fca1521 --- /dev/null +++ b/src/client/component/demonware.cpp @@ -0,0 +1,467 @@ +#include +#include "loader/component_loader.hpp" +#include "demonware.hpp" +#include "game_module.hpp" + +#include +#include +#include +#include + +#include "game/game.hpp" + +#include "game/demonware/stun_server.hpp" +#include "game/demonware/service_server.hpp" + +#include "game/demonware/services/bdLSGHello.hpp" // 7 +#include "game/demonware/services/bdStorage.hpp" // 10 +#include "game/demonware/services/bdDediAuth.hpp" // 12 +#include "game/demonware/services/bdTitleUtilities.hpp" // 12 +#include "game/demonware/services/bdBandwidthTest.hpp" // 18 +#include "game/demonware/services/bdMatchMaking.hpp" // 21 +#include "game/demonware/services/bdDediRSAAuth.hpp" // 26 +#include "game/demonware/services/bdDML.hpp" // 27 +#include "game/demonware/services/bdGroup.hpp" // 28 +#include "game/demonware/services/bdSteamAuth.hpp" // 28 +#include "game/demonware/services/bdAnticheat.hpp" // 38 +#include "game/demonware/services/bdRelayService.hpp" // 86 + +#define TCP_BLOCKING true +#define UDP_BLOCKING false + +namespace demonware +{ + namespace + { + volatile bool terminate; + std::thread message_thread; + std::recursive_mutex server_mutex; + std::map blocking_sockets; + std::map> socket_links; + std::map> servers; + std::map> stun_servers; + std::map>> datagram_packets; + + uint8_t encryption_key_[24]; + uint8_t decryption_key_[24]; + + std::shared_ptr find_server_by_address(const unsigned long address) + { + std::lock_guard _(server_mutex); + + const auto server = servers.find(address); + if (server != servers.end()) + { + return server->second; + } + + return std::shared_ptr(); + } + + std::shared_ptr find_server_by_name(const std::string& name) + { + std::lock_guard _(server_mutex); + return find_server_by_address(utils::cryptography::jenkins_one_at_a_time::compute(name)); + } + + std::shared_ptr find_stun_server_by_address(const unsigned long address) + { + std::lock_guard _(server_mutex); + + const auto server = stun_servers.find(address); + if (server != stun_servers.end()) + { + return server->second; + } + + return std::shared_ptr(); + } + + std::shared_ptr find_stun_server_by_name(const std::string& name) + { + std::lock_guard _(server_mutex); + return find_stun_server_by_address(utils::cryptography::jenkins_one_at_a_time::compute(name)); + } + + std::shared_ptr find_server_by_socket(const SOCKET s) + { + std::lock_guard _(server_mutex); + + const auto server = socket_links.find(s); + if (server != socket_links.end()) + { + return server->second; + } + + return std::shared_ptr(); + } + + bool link_socket(const SOCKET s, const unsigned long address) + { + std::lock_guard _(server_mutex); + + const auto server = find_server_by_address(address); + if (!server) return false; + + socket_links[s] = server; + return true; + } + + void unlink_socket(const SOCKET sock) + { + std::lock_guard _(server_mutex); + + const auto server = socket_links.find(sock); + if (server != socket_links.end()) + { + socket_links.erase(server); + } + + const auto dgram_packets = datagram_packets.find(sock); + if (dgram_packets != datagram_packets.end()) + { + datagram_packets.erase(dgram_packets); + } + } + + bool is_blocking_socket(const SOCKET s, const bool def) + { + std::lock_guard _(server_mutex); + + if (blocking_sockets.find(s) != blocking_sockets.end()) + { + return blocking_sockets[s]; + } + + return def; + } + + int recv_datagam_packet(const SOCKET s, char* buf, const int len, sockaddr* from, int* fromlen) + { + std::unique_lock lock(server_mutex); + + auto queue = datagram_packets.find(s); + if (queue != datagram_packets.end()) + { + const auto blocking = is_blocking_socket(s, UDP_BLOCKING); + + lock.unlock(); + while (blocking && queue->second.empty()) + { + std::this_thread::sleep_for(1ms); + } + lock.lock(); + + if (!queue->second.empty()) + { + auto [address, data] = queue->second.front(); + queue->second.pop(); + + *fromlen = INT(address.size()); + std::memcpy(from, address.data(), address.size()); + + const auto size = std::min(size_t(len), data.size()); + std::memcpy(buf, data.data(), size); + + return static_cast(size); + } + + WSASetLastError(WSAEWOULDBLOCK); + return -1; + } + + return 0; + } + + void remove_blocking_socket(const SOCKET s) + { + std::lock_guard _(server_mutex); + + const auto entry = blocking_sockets.find(s); + if (entry != blocking_sockets.end()) + { + blocking_sockets.erase(entry); + } + } + + void set_blocking_socket(const SOCKET s, const bool blocking) + { + std::lock_guard _(server_mutex); + blocking_sockets[s] = blocking; + } + + void server_thread() + { + terminate = false; + while (!terminate) + { + std::unique_lock lock(server_mutex); + + for (auto& server : servers) + { + server.second->run_frame(); + } + + lock.unlock(); + + std::this_thread::sleep_for(50ms); + } + } + + void bd_logger_stub(int /*type*/, const char* const /*channelName*/, const char*, const char* const /*file*/, + const char* const function, const unsigned int /*line*/, const char* const msg, ...) + { + static const auto* bd_logger_enabled = game::Dvar_RegisterBool("bd_logger_enabled", false, game::DVAR_FLAG_NONE, "Enable bdLogger"); + if (!bd_logger_enabled->current.enabled) + { + return; + } + + char buffer[2048]{}; + + va_list ap; + va_start(ap, msg); + + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + printf("%s: %s\n", function, buffer); + + va_end(ap); + } + + namespace io + { + int WINAPI send_to(const SOCKET s, const char* buf, const int len, const int flags, const sockaddr* to, + const int tolen) + { + if (tolen == sizeof(sockaddr_in)) + { + const auto* in_addr = reinterpret_cast(to); + const auto server = find_stun_server_by_address(in_addr->sin_addr.s_addr); + if (server) return server->send(s, buf, len, to, tolen); + } + + return sendto(s, buf, len, flags, to, tolen); + } + + int WINAPI recv_from(const SOCKET s, char* buf, const int len, const int flags, sockaddr* from, + int* fromlen) + { + auto res = recv_datagam_packet(s, buf, len, from, fromlen); + if (res != 0) return res; + + res = recvfrom(s, buf, len, flags, from, fromlen); + + return res; + } + + int WINAPI send(const SOCKET s, const char* buf, const int len, const int flags) + { + auto server = find_server_by_socket(s); + if (server) return server->send(buf, len); + + return ::send(s, buf, len, flags); + } + + int WINAPI recv(const SOCKET s, char* buf, const int len, const int flags) + { + auto server = find_server_by_socket(s); + if (server) + { + const auto blocking = is_blocking_socket(s, TCP_BLOCKING); + + int result; + do + { + result = server->recv(buf, len); + if (blocking && result < 0) std::this_thread::sleep_for(1ms); + } + while (blocking && result < 0); + + if (!blocking && result < 0) + { + WSASetLastError(WSAEWOULDBLOCK); + } + + return result; + } + + return ::recv(s, buf, len, flags); + } + + int WINAPI connect(const SOCKET s, const sockaddr* addr, const int len) + { + if (len == sizeof(sockaddr_in)) + { + const auto* in_addr = reinterpret_cast(addr); + if (link_socket(s, in_addr->sin_addr.s_addr)) return 0; + } + + return ::connect(s, addr, len); + } + + int WINAPI close_socket(const SOCKET s) + { + remove_blocking_socket(s); + unlink_socket(s); + return closesocket(s); + } + + int WINAPI ioctl_socket(const SOCKET s, const long cmd, u_long* argp) + { + if (static_cast(cmd) == (FIONBIO)) + { + set_blocking_socket(s, *argp == 0); + } + + return ioctlsocket(s, cmd, argp); + } + + hostent* WINAPI get_host_by_name(char* name) + { + unsigned long addr = 0; + const auto server = find_server_by_name(name); + if (server) addr = server->get_address(); + + const auto stun_server = find_stun_server_by_name(name); + if (stun_server) addr = stun_server->get_address(); + + if (server || stun_server) + { + static thread_local in_addr address; + address.s_addr = addr; + + static thread_local in_addr* addr_list[2]; + addr_list[0] = &address; + addr_list[1] = nullptr; + + static thread_local hostent host; + host.h_name = name; + host.h_aliases = nullptr; + host.h_addrtype = AF_INET; + host.h_length = sizeof(in_addr); + host.h_addr_list = reinterpret_cast(addr_list); + + return &host; + } + +#pragma warning(push) +#pragma warning(disable: 4996) + return gethostbyname(name); +#pragma warning(pop) + } + + bool register_hook(const std::string& process, void* stub) + { + const auto game_module = game_module::get_game_module(); + + auto result = false; + result = result || utils::hook::iat(game_module, "wsock32.dll", process, stub); + result = result || utils::hook::iat(game_module, "WS2_32.dll", process, stub); + return result; + } + } + + template + std::shared_ptr register_server(Args ... args) + { + std::lock_guard _(server_mutex); + auto server = std::make_shared(args...); + servers[server->get_address()] = server; + return server; + } + + std::shared_ptr register_stun_server(const std::string& name) + { + std::lock_guard _(server_mutex); + auto server = std::make_shared(name); + stun_servers[server->get_address()] = server; + return server; + } + + void startup_dw() + { + register_stun_server("ghosts-stun.us.demonware.net"); + register_stun_server("ghosts-stun.eu.demonware.net"); + register_stun_server("ghosts-stun.jp.demonware.net"); + register_stun_server("ghosts-stun.au.demonware.net"); + + auto lsg_server = register_server("ghosts-pc-lobby.prod.demonware.net"); + auto auth_server = register_server("ghosts-pc-auth.prod.demonware.net"); + + auth_server->register_service(); + auth_server->register_service(); + auth_server->register_service(); + + lsg_server->register_service(); + lsg_server->register_service(); + lsg_server->register_service(); + lsg_server->register_service(); + lsg_server->register_service(); + lsg_server->register_service(); + lsg_server->register_service(); + lsg_server->register_service(); + lsg_server->register_service(); + } + } + + void send_datagram_packet(const SOCKET s, const std::string& data, const sockaddr* to, const int tolen) + { + std::lock_guard _(server_mutex); + datagram_packets[s].push({std::string(LPSTR(to), size_t(tolen)), data}); + } + + uint8_t* get_key(const bool encrypt) + { + return encrypt ? encryption_key_ : decryption_key_; + } + + void set_key(const bool encrypt, uint8_t* key) + { + static_assert(sizeof encryption_key_ == sizeof decryption_key_); + std::memcpy(encrypt ? encryption_key_ : decryption_key_, key, sizeof encryption_key_); + } + + class component final : public component_interface + { + public: + void post_load() override + { + startup_dw(); + + message_thread = utils::thread::create_named_thread("Demonware", server_thread); + + io::register_hook("send", io::send); + io::register_hook("recv", io::recv); + io::register_hook("sendto", io::send_to); + io::register_hook("recvfrom", io::recv_from); + io::register_hook("connect", io::connect); + io::register_hook("closesocket", io::close_socket); + io::register_hook("ioctlsocket", io::ioctl_socket); + io::register_hook("gethostbyname", io::get_host_by_name); + } + + void post_unpack() override + { + utils::hook::jump(SELECT_VALUE(0x140602230, 0x1406F54D0), bd_logger_stub); + } + + void pre_destroy() override + { + std::lock_guard _(server_mutex); + + terminate = true; + if (message_thread.joinable()) + { + message_thread.join(); + } + + servers.clear(); + stun_servers.clear(); + socket_links.clear(); + blocking_sockets.clear(); + datagram_packets.clear(); + } + }; +} + +REGISTER_COMPONENT(demonware::component) diff --git a/src/client/component/demonware.hpp b/src/client/component/demonware.hpp new file mode 100644 index 0000000..1258e96 --- /dev/null +++ b/src/client/component/demonware.hpp @@ -0,0 +1,9 @@ +#pragma once + +namespace demonware +{ + void send_datagram_packet(SOCKET s, const std::string& data, const sockaddr* to, int tolen); + + uint8_t* get_key(const bool encrypt); + void set_key(bool encrypt, uint8_t* key); +} diff --git a/src/client/component/discord.cpp b/src/client/component/discord.cpp new file mode 100644 index 0000000..97960c1 --- /dev/null +++ b/src/client/component/discord.cpp @@ -0,0 +1,151 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "console.hpp" +#include "network.hpp" +#include "party.hpp" +#include "scheduler.hpp" + +#include +#include + +#include + +namespace discord +{ + namespace + { + DiscordRichPresence discord_presence; + + void join_game(const char* join_secret) + { + game::Cbuf_AddText(0, utils::string::va("connect %s\n", join_secret)); + } + + void join_request(const DiscordUser* request) + { +#ifdef _DEBUG + console::info("Discord: Join request from %s (%s)\n", request->username, request->userId); +#endif + Discord_Respond(request->userId, DISCORD_REPLY_IGNORE); + } + + void update_discord() + { + Discord_RunCallbacks(); + + if (!game::CL_IsCgameInitialized()) + { + discord_presence.details = game::environment::is_sp() ? "Singleplayer" : "Multiplayer"; + discord_presence.state = "Main Menu"; + + discord_presence.partySize = 0; + discord_presence.partyMax = 0; + + discord_presence.startTimestamp = 0; + } + else + { + if (game::environment::is_sp()) return; + + const auto* gametype = game::UI_LocalizeGametype(game::Dvar_FindVar("ui_gametype")->current.string); + const auto* map = game::UI_LocalizeMapname(game::Dvar_FindVar("ui_mapname")->current.string); + + discord_presence.details = utils::string::va("%s on %s", gametype, map); + + discord_presence.partySize = game::mp::cgArray->snap != nullptr + ? game::mp::cgArray->snap->numClients + : 1; + + if (game::Dvar_GetBool("xblive_privatematch")) + { + discord_presence.state = "Private Match"; + discord_presence.partyMax = game::Dvar_GetInt("sv_maxclients"); + } + else + { + auto* host_name = reinterpret_cast(0x14187EBC4); + utils::string::strip(host_name, host_name, std::strlen(host_name) + 1); + + discord_presence.state = host_name; + discord_presence.partyMax = party::server_client_count(); + + std::hash hash_fn; + static const auto nonce = utils::cryptography::random::get_integer(); + + const auto& address = party::get_target(); + discord_presence.partyId = utils::string::va("%zu", hash_fn(address) ^ nonce); + discord_presence.joinSecret = network::net_adr_to_string(address); + } + + if (!discord_presence.startTimestamp) + { + discord_presence.startTimestamp = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count(); + } + } + + discord_presence.largeImageKey = "main_logo"; + Discord_UpdatePresence(&discord_presence); + } + } + + class component final : public component_interface + { + public: + void post_load() override + { + if (game::environment::is_dedi()) + { + return; + } + + DiscordEventHandlers handlers; + ZeroMemory(&handlers, sizeof(handlers)); + handlers.ready = ready; + handlers.errored = errored; + handlers.disconnected = errored; + handlers.joinGame = join_game; + handlers.spectateGame = nullptr; + handlers.joinRequest = join_request; + + Discord_Initialize("1116670204148195428", &handlers, 1, nullptr); + + scheduler::loop(update_discord, scheduler::pipeline::main, 20s); + + initialized_ = true; + } + + void pre_destroy() override + { + if (!initialized_) + { + return; + } + + Discord_Shutdown(); + } + + private: + bool initialized_ = false; + + static void ready(const DiscordUser* /*request*/) + { + ZeroMemory(&discord_presence, sizeof(discord_presence)); + + discord_presence.instance = 1; + + Discord_UpdatePresence(&discord_presence); + } + + static void errored(const int error_code, const char* message) + { + console::error("Discord: (%i) %s\n", error_code, message); + } + }; +} + +#ifndef DEV_BUILD +REGISTER_COMPONENT(discord::component) +#endif diff --git a/src/client/component/dvar_cheats.cpp b/src/client/component/dvar_cheats.cpp new file mode 100644 index 0000000..19450f2 --- /dev/null +++ b/src/client/component/dvar_cheats.cpp @@ -0,0 +1,188 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "console.hpp" + +#include +#include + +namespace dvar_cheats +{ + void apply_sv_cheats(const game::dvar_t* dvar, const game::DvarSetSource source, game::dvar_value* value) + { + if (dvar && dvar->name == "sv_cheats"s) + { + // if dedi, do not allow internal to change value so servers can allow cheats if they want to + if (game::environment::is_dedi() && source == game::DvarSetSource::DVAR_SOURCE_INTERNAL) + { + value->enabled = dvar->current.enabled; + } + + // if sv_cheats was enabled and it changes to disabled, we need to reset all cheat dvars + else if (dvar->current.enabled && !value->enabled) + { + for (auto i = 0; i < *game::dvarCount; ++i) + { + const auto var = game::sortedDvars[i]; + if (var && (var->flags & game::DvarFlags::DVAR_FLAG_CHEAT)) + { + game::Dvar_Reset(var, game::DvarSetSource::DVAR_SOURCE_INTERNAL); + } + } + } + } + } + + bool dvar_flag_checks(const game::dvar_t* dvar, const game::DvarSetSource source) + { + if ((dvar->flags & game::DvarFlags::DVAR_FLAG_WRITE)) + { + console::error("%s is write protected\n", dvar->name); + return false; + } + + if ((dvar->flags & game::DvarFlags::DVAR_FLAG_READ)) + { + console::error("%s is read only\n", dvar->name); + return false; + } + + // only check cheat/replicated values when the source is external + if (source == game::DvarSetSource::DVAR_SOURCE_EXTERNAL) + { + const auto cl_ingame = game::Dvar_FindVar("cl_ingame"); + const auto sv_running = game::Dvar_FindVar("sv_running"); + + if ((dvar->flags & game::DvarFlags::DVAR_FLAG_REPLICATED) && (cl_ingame && cl_ingame->current.enabled) && ( + sv_running && !sv_running->current.enabled)) + { + console::error("%s can only be changed by the server\n", dvar->name); + return false; + } + + const auto sv_cheats = game::Dvar_FindVar("sv_cheats"); + if ((dvar->flags & game::DvarFlags::DVAR_FLAG_CHEAT) && (sv_cheats && !sv_cheats->current.enabled)) + { + console::error("%s is cheat protected\n", dvar->name); + return false; + } + } + + // pass all the flag checks, allow dvar to be changed + return true; + } + + const auto dvar_flag_checks_stub = utils::hook::assemble([](utils::hook::assembler& a) + { + const auto can_set_value = a.newLabel(); + const auto zero_source = a.newLabel(); + + a.pushad64(); + a.mov(r8, rdi); + a.mov(edx, esi); + a.mov(rcx, rbx); + a.call_aligned(apply_sv_cheats); //check if we are setting sv_cheats + a.popad64(); + a.cmp(esi, 0); + a.jz(zero_source); //if the SetSource is 0 (INTERNAL) ignore flag checks + + a.pushad64(); + a.mov(edx, esi); //source + a.mov(rcx, rbx); //dvar + a.call_aligned(dvar_flag_checks); //protect read/write/cheat/replicated dvars + a.cmp(al, 1); + a.jz(can_set_value); + + // if we get here, we are non-zero source and CANNOT set values + a.popad64(); // if I do this before the jz it won't work. for some reason the popad64 is affecting the ZR flag + a.jmp(0x1404F0FC5); + + // if we get here, we are non-zero source and CAN set values + a.bind(can_set_value); + a.popad64(); // if I do this before the jz it won't work. for some reason the popad64 is affecting the ZR flag + a.jmp(0x1404F0D2E); + + // if we get here, we are zero source and ignore flags + a.bind(zero_source); + a.jmp(0x1404F0D74); + }); + + void cg_set_client_dvar_from_server(const int local_client_num, game::mp::cg_s* cg, const char* dvar_id, const char* value) + { + if (dvar_id == "cg_fov"s || dvar_id == "com_maxfps"s) + { + return; + } + + const auto* dvar = game::Dvar_FindVar(dvar_id); + if (dvar) + { + // If we send as string, it can't be set with source SERVERCMD because the game only allows that source on real server cmd dvars. + // Just use external instead as if it was being set by the console + game::Dvar_SetFromStringByNameFromSource(dvar_id, value, game::DvarSetSource::DVAR_SOURCE_EXTERNAL); + } + else + { + // Not a dvar name, assume it is an id and the game will handle normally + game::CG_SetClientDvarFromServer(local_client_num, cg, dvar_id, value); + } + } + + void set_client_dvar_by_string(const int entity_num, const char* value) + { + const auto* dvar = game::Scr_GetString(0); // grab the original dvar again since it's never stored on stack + const auto* command = utils::string::va("q %s \"%s\"", dvar, value); + + game::SV_GameSendServerCommand(entity_num, 1, command); + } + + const auto player_cmd_set_client_dvar = utils::hook::assemble([](utils::hook::assembler& a) + { + const auto set_by_string = a.newLabel(); + + a.pushad64(); + + // check if we didn't find a network dvar index + a.mov(ecx, dword_ptr(rsp, 0x8C8)); + a.cmp(ecx, 0); + a.je(set_by_string); + + // we found an index, handle normally + a.popad64(); + a.mov(r8d, ptr(rsp, 0x848)); + a.lea(r9, ptr(rsp, 0x30)); + a.jmp(0x14038A5A7); + + // no index, let's send the dvar as a string + a.bind(set_by_string); + a.movzx(ecx, word_ptr(rsp, 0x8C0)); //entity_num + a.lea(rdx, ptr(rsp, 0xB0)); //value + a.call_aligned(set_client_dvar_by_string); + a.popad64(); + a.jmp(0x14038A5CD); + }); + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) return; + + utils::hook::nop(0x1404F0D13, 4); // let our stub handle zero-source sets + utils::hook::jump(0x1404F0D1A, dvar_flag_checks_stub, true); // check extra dvar flags when setting values + + utils::hook::nop(0x14038A553, 5); // remove error in PlayerCmd_SetClientDvar if setting a non-network dvar + utils::hook::jump(0x14038A59A, player_cmd_set_client_dvar, true); // send non-network dvars as string + utils::hook::call(0x140287AED, cg_set_client_dvar_from_server); // check for dvars being sent as string before parsing ids + utils::hook::set(0x14026B50E, 0xEB); // fov thing + + dvars::sv_cheats = game::Dvar_RegisterBool("sv_cheats", false, game::DVAR_FLAG_REPLICATED, "Allow cheat commands and dvars on this server"); + } + }; +} + +REGISTER_COMPONENT(dvar_cheats::component) diff --git a/src/client/component/dvars.cpp b/src/client/component/dvars.cpp new file mode 100644 index 0000000..51c95be --- /dev/null +++ b/src/client/component/dvars.cpp @@ -0,0 +1,86 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "dvars.hpp" + +#include + +namespace dvars +{ + struct dvar_base + { + unsigned int flags{}; + }; + + struct dvar_bool : dvar_base + { + bool value{}; + }; + + utils::hook::detour dvar_register_bool_hook; + + template + T* find_dvar(std::unordered_map& map, const std::string& name) + { + auto i = map.find(name); + if (i != map.end()) + { + return &i->second; + } + + return nullptr; + } + + namespace override + { + static std::unordered_map register_bool_overrides; + + void register_bool(const std::string& name, const bool value, const unsigned int flags) + { + dvar_bool values; + values.value = value; + values.flags = flags; + register_bool_overrides[name] = values; + } + } + + std::string get_string(const std::string& dvar) + { + const auto* dvar_value = game::Dvar_FindVar(dvar.data()); + if (dvar_value) + { + return {dvar_value->current.string}; + } + + return {}; + } + + const game::dvar_t* dvar_register_bool_stub(const char* name, bool value, unsigned int flags, const char* description) + { + const auto* var = find_dvar(override::register_bool_overrides, name); + if (var) + { + value = var->value; + flags = var->flags; + } + + return dvar_register_bool_hook.invoke(name, value, flags, description); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + dvar_register_bool_hook.create(game::Dvar_RegisterBool, &dvar_register_bool_stub); + } + + void pre_destroy() override + { + dvar_register_bool_hook.clear(); + } + }; +} + +REGISTER_COMPONENT(dvars::component) diff --git a/src/client/component/dvars.hpp b/src/client/component/dvars.hpp new file mode 100644 index 0000000..687f8b6 --- /dev/null +++ b/src/client/component/dvars.hpp @@ -0,0 +1,11 @@ +#pragma once + +namespace dvars +{ + namespace override + { + void register_bool(const std::string& name, bool value, unsigned int flags); + } + + std::string get_string(const std::string& dvar); +} diff --git a/src/client/component/fastfiles.cpp b/src/client/component/fastfiles.cpp new file mode 100644 index 0000000..16b93a0 --- /dev/null +++ b/src/client/component/fastfiles.cpp @@ -0,0 +1,152 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "fastfiles.hpp" +#include "command.hpp" +#include "console.hpp" + +#include +#include +#include + +namespace fastfiles +{ + namespace + { + utils::hook::detour db_try_load_x_file_internal_hook; + utils::hook::detour db_find_x_asset_header_hook; + + void db_try_load_x_file_internal(const char* zone_name, const int zone_flags, const int is_base_map) + { + console::info("Loading fastfile %s\n", zone_name); + return db_try_load_x_file_internal_hook.invoke(zone_name, zone_flags, is_base_map); + } + + void dump_gsc_script(const std::string& name, game::XAssetHeader header) + { + if (!dvars::g_dump_scripts->current.enabled) + { + return; + } + + std::string buffer; + buffer.append(header.scriptfile->name, std::strlen(header.scriptfile->name) + 1); + buffer.append(reinterpret_cast(&header.scriptfile->compressedLen), 4); + buffer.append(reinterpret_cast(&header.scriptfile->len), 4); + buffer.append(reinterpret_cast(&header.scriptfile->bytecodeLen), 4); + buffer.append(header.scriptfile->buffer, header.scriptfile->compressedLen); + buffer.append(reinterpret_cast(header.scriptfile->bytecode), header.scriptfile->bytecodeLen); + + const auto out_name = std::format("gsc_dump/{}.gscbin", name); + utils::io::write_file(out_name, buffer); + + console::info("Dumped %s\n", out_name.data()); + } + + + game::XAssetHeader db_find_x_asset_header_stub(game::XAssetType type, const char* name, int allow_create_default) + { + const auto start = game::Sys_Milliseconds(); + const auto result = db_find_x_asset_header_hook.invoke(type, name, allow_create_default); + const auto diff = game::Sys_Milliseconds() - start; + + if (type == game::ASSET_TYPE_SCRIPTFILE) + { + dump_gsc_script(name, result); + } + + if (diff > 100) + { + console::print( + result.data == nullptr + ? console::con_type_error + : console::con_type_warning, + "Waited %i msec for asset '%s' of type '%s'.\n", + diff, + name, + game::g_assetNames[type] + ); + } + + return result; + } + + void reallocate_asset_pool(const game::XAssetType type, const unsigned int new_size) + { + const size_t element_size = game::DB_GetXAssetTypeSize(type); + + auto* new_pool = utils::memory::get_allocator()->allocate(new_size * element_size); + std::memmove(new_pool, game::DB_XAssetPool[type], game::g_poolSize[type] * element_size); + + game::DB_XAssetPool[type] = new_pool; + game::g_poolSize[type] = new_size; + } + + void p_mem_free_stub(const char* name, game::PMem_Direction alloc_dir) + { + console::info("Unloaded fastfile %s\n", name); + game::PMem_Free(name, alloc_dir); + } + } + + void enum_assets(const game::XAssetType type, const std::function& callback, const bool include_override) + { + game::DB_EnumXAssets_Internal(type, static_cast([](game::XAssetHeader header, void* data) + { + const auto& cb = *static_cast*>(data); + cb(header); + }), &callback, include_override); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + db_try_load_x_file_internal_hook.create(SELECT_VALUE(0x140275850, 0x1403237F0), &db_try_load_x_file_internal); + + db_find_x_asset_header_hook.create(game::DB_FindXAssetHeader, db_find_x_asset_header_stub); + dvars::g_dump_scripts = game::Dvar_RegisterBool("g_dumpScripts", false, game::DVAR_FLAG_NONE, "Dump GSC scripts to binary format"); + + utils::hook::call(SELECT_VALUE(0x1402752DF, 0x140156350), p_mem_free_stub); + utils::hook::call(SELECT_VALUE(0x140276004, 0x140324259), p_mem_free_stub); + + command::add("loadzone", [](const command::params& params) + { + if (params.size() < 2) + { + console::info("usage: loadzone \n"); + return; + } + + game::XZoneInfo info; + info.name = params.get(1); + info.allocFlags = 1; + info.freeFlags = 0; + + game::DB_LoadXAssets(&info, 1, game::DBSyncMode::DB_LOAD_SYNC); + }); + + command::add("materiallist", [](const command::params& params) + { + game::DB_EnumXAssets_FastFile(game::ASSET_TYPE_MATERIAL, [](const game::XAssetHeader header, void*) + { + if(header.material && header.material->name) + { + console::info("%s\n", header.material->name); + } + }, nullptr, false); + }); + + if (!game::environment::is_sp()) + { + reallocate_asset_pool(game::ASSET_TYPE_WEAPON, 320); + } + } + }; +} + +REGISTER_COMPONENT(fastfiles::component) diff --git a/src/client/component/fastfiles.hpp b/src/client/component/fastfiles.hpp new file mode 100644 index 0000000..5bd092d --- /dev/null +++ b/src/client/component/fastfiles.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace fastfiles +{ + void enum_assets(game::XAssetType type, const std::function& callback, bool include_override); +} diff --git a/src/client/component/filesystem.cpp b/src/client/component/filesystem.cpp new file mode 100644 index 0000000..bcf2cf0 --- /dev/null +++ b/src/client/component/filesystem.cpp @@ -0,0 +1,288 @@ +#include +#include "loader/component_loader.hpp" + +#include "filesystem.hpp" +#include "game_module.hpp" +#include "console.hpp" + +#include "game/game.hpp" + +#include +#include +#include + +namespace filesystem +{ + namespace + { + bool initialized = false; + + bool custom_path_registered = false; + + std::deque& get_search_paths_internal() + { + static std::deque search_paths{}; + return search_paths; + } + + std::string get_binary_directory() + { + const auto dir = game_module::get_host_module().get_folder(); + return utils::string::replace(dir, "/", "\\"); + } + + void register_custom_path_stub(const char* path, const char* dir) + { + if (!custom_path_registered) + { + custom_path_registered = true; + + const auto launcher_dir = get_binary_directory(); + game::FS_AddLocalizedGameDirectory(launcher_dir.data(), "data"); + } + + game::FS_AddLocalizedGameDirectory(path, dir); + } + + void fs_startup_stub(const char* gamename) + { + console::info("[FS] Startup\n"); + + custom_path_registered = false; + + game::FS_Startup(gamename); + } + + std::vector get_paths(const std::filesystem::path& path) + { + std::vector paths{}; + + paths.push_back(path); + + return paths; + } + + bool can_insert_path(const std::filesystem::path& path) + { + for (const auto& path_ : get_search_paths_internal()) + { + if (path_ == path) + { + return false; + } + } + + return true; + } + + void startup() + { + register_path("iw6"); + register_path(get_binary_directory() + "\\data"); + + // game's search paths + register_path("devraw"); + register_path("devraw_shared"); + register_path("raw_shared"); + register_path("raw"); + register_path("main"); + } + + void check_for_startup() + { + if (!initialized) + { + initialized = true; + startup(); + } + } + } + + file::file(std::string name) + : name_(std::move(name)) + { + char* buffer{}; + const auto size = game::FS_ReadFile(this->name_.data(), &buffer); + + if (size >= 0 && buffer) + { + this->valid_ = true; + this->buffer_.append(buffer, size); + game::FS_FreeFile(buffer); + } + } + + bool file::exists() const + { + return this->valid_; + } + + const std::string& file::get_buffer() const + { + return this->buffer_; + } + + const std::string& file::get_name() const + { + return this->name_; + } + + std::string read_file(const std::string& path) + { + check_for_startup(); + + for (const auto& search_path : get_search_paths_internal()) + { + const auto path_ = search_path / path; + if (utils::io::file_exists(path_.generic_string())) + { + return utils::io::read_file(path_.generic_string()); + } + } + + return {}; + } + + bool read_file(const std::string& path, std::string* data, std::string* real_path) + { + check_for_startup(); + + for (const auto& search_path : get_search_paths_internal()) + { + const auto path_ = search_path / path; + if (utils::io::read_file(path_.generic_string(), data)) + { + if (real_path != nullptr) + { + *real_path = path_.generic_string(); + } + + return true; + } + } + + return false; + } + + bool find_file(const std::string& path, std::string* real_path) + { + check_for_startup(); + + for (const auto& search_path : get_search_paths_internal()) + { + const auto path_ = search_path / path; + if (utils::io::file_exists(path_.generic_string())) + { + *real_path = path_.generic_string(); + return true; + } + } + + return false; + } + + bool exists(const std::string& path) + { + check_for_startup(); + + for (const auto& search_path : get_search_paths_internal()) + { + const auto path_ = search_path / path; + if (utils::io::file_exists(path_.generic_string())) + { + return true; + } + } + + return false; + } + + void register_path(const std::filesystem::path& path) + { + const auto paths = get_paths(path); + for (const auto& path_ : paths) + { + if (can_insert_path(path_)) + { + console::info("[FS] Registering path '%s'\n", path_.generic_string().data()); + get_search_paths_internal().push_front(path_); + } + } + } + + void unregister_path(const std::filesystem::path& path) + { + const auto paths = get_paths(path); + for (const auto& path_ : paths) + { + auto& search_paths = get_search_paths_internal(); + for (auto i = search_paths.begin(); i != search_paths.end();) + { + if (*i == path_) + { + console::info("[FS] Unregistering path '%s'\n", path_.generic_string().data()); + i = search_paths.erase(i); + } + else + { + ++i; + } + } + } + } + + std::vector get_search_paths() + { + std::vector paths{}; + + for (const auto& path : get_search_paths_internal()) + { + paths.push_back(path.generic_string()); + } + + return paths; + } + + std::vector get_search_paths_rev() + { + std::vector paths{}; + const auto& search_paths = get_search_paths_internal(); + + for (auto i = search_paths.rbegin(); i != search_paths.rend(); ++i) + { + paths.push_back(i->generic_string()); + } + + return paths; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Set fs_basegame + utils::hook::inject(SELECT_VALUE(0x14041C053, 0x1404DDA13), "iw6"); + + if (game::environment::is_sp()) + { + utils::hook::call(0x14041B744, fs_startup_stub); + + utils::hook::call(0x14041CD00, register_custom_path_stub); + utils::hook::call(0x14041CD20, register_custom_path_stub); + utils::hook::call(0x14041CD5F, register_custom_path_stub); + } + else + { + utils::hook::call(0x1404DD704, fs_startup_stub); + utils::hook::call(0x1404DDB43, fs_startup_stub); + + utils::hook::call(0x1404DE550, register_custom_path_stub); + utils::hook::call(0x1404DE570, register_custom_path_stub); + utils::hook::call(0x1404DE5AF, register_custom_path_stub); + } + } + }; +} + +REGISTER_COMPONENT(filesystem::component) diff --git a/src/client/component/filesystem.hpp b/src/client/component/filesystem.hpp new file mode 100644 index 0000000..f085210 --- /dev/null +++ b/src/client/component/filesystem.hpp @@ -0,0 +1,30 @@ +#pragma once + +namespace filesystem +{ + class file + { + public: + file(std::string name); + + [[nodiscard]] bool exists() const; + [[nodiscard]] const std::string& get_buffer() const; + [[nodiscard]] const std::string& get_name() const; + + private: + bool valid_ = false; + std::string name_; + std::string buffer_; + }; + + std::string read_file(const std::string& path); + bool read_file(const std::string& path, std::string* data, std::string* real_path = nullptr); + bool find_file(const std::string& path, std::string* real_path); + bool exists(const std::string& path); + + void register_path(const std::filesystem::path& path); + void unregister_path(const std::filesystem::path& path); + + std::vector get_search_paths(); + std::vector get_search_paths_rev(); +} diff --git a/src/client/component/fps.cpp b/src/client/component/fps.cpp new file mode 100644 index 0000000..3614829 --- /dev/null +++ b/src/client/component/fps.cpp @@ -0,0 +1,183 @@ +#include +#include "loader/component_loader.hpp" +#include "scheduler.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include +#include + +namespace fps +{ + namespace + { + const game::dvar_t* cg_drawFPS; + const game::dvar_t* cg_drawPing; + + float fps_color[4] = {0.6f, 1.0f, 0.0f, 1.0f}; + float origin_color[4] = {1.0f, 0.67f, 0.13f, 1.0f}; + float ping_color[4] = {1.0f, 1.0f, 1.0f, 0.65f}; + + struct cg_perf_data + { + std::chrono::time_point perf_start; + std::int32_t current_ms{}; + std::int32_t previous_ms{}; + std::int32_t frame_ms{}; + std::int32_t history[32]{}; + std::int32_t count{}; + std::int32_t index{}; + std::int32_t instant{}; + std::int32_t total{}; + float average{}; + float variance{}; + std::int32_t min{}; + std::int32_t max{}; + }; + + cg_perf_data cg_perf = cg_perf_data(); + + void perf_calc_fps(cg_perf_data* data, const std::int32_t value) + { + data->history[data->index % 32] = value; + data->instant = value; + data->min = std::numeric_limits::max(); + data->max = 0; + data->average = 0.0f; + data->variance = 0.0f; + data->total = 0; + + for (auto i = 0; i < data->count; ++i) + { + const std::int32_t idx = (data->index - i) % 32; + + if (idx < 0) + { + break; + } + + data->total += data->history[idx]; + + if (data->min > data->history[idx]) + { + data->min = data->history[idx]; + } + + if (data->max < data->history[idx]) + { + data->max = data->history[idx]; + } + } + + data->average = static_cast(data->total) / static_cast(data->count); + ++data->index; + } + + void perf_update() + { + cg_perf.count = 32; + + cg_perf.current_ms = static_cast(std::chrono::duration_cast( + std::chrono::high_resolution_clock::now() - cg_perf.perf_start).count()); + cg_perf.frame_ms = cg_perf.current_ms - cg_perf.previous_ms; + cg_perf.previous_ms = cg_perf.current_ms; + + perf_calc_fps(&cg_perf, cg_perf.frame_ms); + + utils::hook::invoke(SELECT_VALUE(0x1405806E0, 0x140658E30)); + } + + void cg_draw_fps() + { + if (cg_drawFPS && cg_drawFPS->current.integer != 0) + { + const auto fps = static_cast(static_cast(1000.0f / + static_cast(cg_perf.average)) + 9.313225746154785e-10); + + auto* font = game::R_RegisterFont("fonts/normalfont"); + if (!font) return; + + const auto* const fps_string = utils::string::va("%i", fps); + + const auto scale = 1.0f; + + const auto x = (game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 10.0f) - game::R_TextWidth( + fps_string, std::numeric_limits::max(), font) * scale; + + const auto y = font->pixelHeight * 1.2f; + + game::R_AddCmdDrawText(fps_string, std::numeric_limits::max(), font, x, y, scale, scale, 0.0f, fps_color, 6); + + if (game::mp::g_entities && cg_drawFPS->current.integer > 1 && game::SV_Loaded()) + { + const auto* const origin_string = utils::string::va("%f, %f, %f", + game::mp::g_entities[0].client->ps.origin[0] * + 1.0, + game::mp::g_entities[0].client->ps.origin[1] * + 1.0, + game::mp::g_entities[0].client->ps.origin[2] * + 1.0); + const auto origin_x = (game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 10.0f) - + game::R_TextWidth(origin_string, std::numeric_limits::max(), font) * scale; + game::R_AddCmdDrawText(origin_string, std::numeric_limits::max(), font, origin_x, y + 50, scale, scale, 0.0f, + origin_color, 6); + } + } + } + + void cg_draw_ping() + { + if (cg_drawPing->current.integer != 0 && game::CL_IsCgameInitialized()) + { + const auto ping = *reinterpret_cast(0x1419E5100); + + auto* font = game::R_RegisterFont("fonts/normalfont"); + if (!font) return; + + auto* const ping_string = utils::string::va("Ping: %i", ping); + + const auto scale = 1.0f; + + const auto x = (game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 375.0f) - game::R_TextWidth( + ping_string, 0x7FFFFFFF, font) * scale; + + const auto y = font->pixelHeight * 1.2f; + + game::R_AddCmdDrawText(ping_string, std::numeric_limits::max(), font, x, y, scale, scale, 0.0f, ping_color, 6); + } + } + + const game::dvar_t* cg_draw_fps_register_stub(const char* dvar_name, const char** value_list, const int default_index, unsigned int /*flags*/, const char* description) + { + cg_drawFPS = game::Dvar_RegisterEnum(dvar_name, value_list, default_index, game::DVAR_FLAG_SAVED, description); + return cg_drawFPS; + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + // fps setup + cg_perf.perf_start = std::chrono::high_resolution_clock::now(); + utils::hook::call(SELECT_VALUE(0x140242C11, 0x1402CF457), &perf_update); + + // change cg_drawfps flags to saved + utils::hook::call(SELECT_VALUE(0x1401F400A, 0x140272B98), &cg_draw_fps_register_stub); + + cg_drawPing = game::Dvar_RegisterInt("cg_drawPing", 0, 0, 1, game::DVAR_FLAG_SAVED, "Draw ping"); + + scheduler::loop(cg_draw_fps, scheduler::pipeline::renderer); + scheduler::loop(cg_draw_ping, scheduler::pipeline::renderer); + } + }; +} + +REGISTER_COMPONENT(fps::component) diff --git a/src/client/component/game_console.cpp b/src/client/component/game_console.cpp new file mode 100644 index 0000000..5b8fe91 --- /dev/null +++ b/src/client/component/game_console.cpp @@ -0,0 +1,781 @@ +#include +#include "loader/component_loader.hpp" +#include "game_console.hpp" +#include "command.hpp" +#include "console.hpp" +#include "scheduler.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include +#include +#include + +#include + +#define console_font game::R_RegisterFont("fonts/consolefont") +#define material_white game::Material_RegisterHandle("white") + +namespace game_console +{ + namespace + { + struct console_globals + { + float x{}; + float y{}; + float left_x{}; + float font_height{}; + bool may_auto_complete{}; + char auto_complete_choice[64]{}; + int info_line_count{}; + }; + + using output_queue = std::deque; + + struct ingame_console + { + char buffer[256]{}; + int cursor{}; + int font_height{}; + int visible_line_count{}; + int visible_pixel_width{}; + float screen_min[2]{}; //left & top + float screen_max[2]{}; //right & bottom + console_globals globals{}; + bool output_visible{}; + int display_line_offset{}; + int line_count{}; + utils::concurrency::container output{}; + }; + + ingame_console con{}; + + std::int32_t history_index = -1; + std::deque history{}; + + std::string fixed_input{}; + std::vector matches{}; + + float color_white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + float color_iw6[4] = { 0.0f, 0.7f, 1.0f, 1.0f }; + + void clear() + { + strncpy_s(con.buffer, "", sizeof(con.buffer)); + con.cursor = 0; + + fixed_input = ""; + matches.clear(); + } + + void print_internal(const std::string& data) + { + con.output.access([&](output_queue& output) + { + if (con.visible_line_count > 0 + && con.display_line_offset == (output.size() - con.visible_line_count)) + { + con.display_line_offset++; + } + output.push_back(data); + if (output.size() > 512) + { + output.pop_front(); + } + }); + } + + void toggle_console() + { + clear(); + + con.output_visible = false; + *game::keyCatchers ^= 1; + } + + void toggle_console_output() + { + con.output_visible = con.output_visible == 0; + } + + void check_resize() + { + con.screen_min[0] = 6.0f; + con.screen_min[1] = 6.0f; + con.screen_max[0] = game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 6.0f; + con.screen_max[1] = game::ScrPlace_GetViewPlacement()->realViewportSize[1] - 6.0f; + + if (console_font) + { + con.font_height = console_font->pixelHeight; + con.visible_line_count = static_cast((con.screen_max[1] - con.screen_min[1] - (con.font_height * 2) + ) - + 24.0f) / con.font_height; + con.visible_pixel_width = static_cast(((con.screen_max[0] - con.screen_min[0]) - 10.0f) - 18.0f); + } + else + { + con.font_height = 0; + con.visible_line_count = 0; + con.visible_pixel_width = 0; + } + } + + void draw_box(const float x, const float y, const float w, const float h, float* color) + { + game::vec4_t dark_color; + + dark_color[0] = color[0] * 0.5f; + dark_color[1] = color[1] * 0.5f; + dark_color[2] = color[2] * 0.5f; + dark_color[3] = color[3]; + + game::R_AddCmdDrawStretchPic(x, y, w, h, 0.0f, 0.0f, 0.0f, 0.0f, color, material_white); + game::R_AddCmdDrawStretchPic(x, y, 2.0f, h, 0.0f, 0.0f, 0.0f, 0.0f, dark_color, material_white); + game::R_AddCmdDrawStretchPic((x + w) - 2.0f, y, 2.0f, h, 0.0f, 0.0f, 0.0f, 0.0f, dark_color, + material_white); + game::R_AddCmdDrawStretchPic(x, y, w, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, dark_color, material_white); + game::R_AddCmdDrawStretchPic(x, (y + h) - 2.0f, w, 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, dark_color, + material_white); + } + + void draw_input_box(const int lines, float* color) + { + draw_box( + con.globals.x - 6.0f, + con.globals.y - 6.0f, + (con.screen_max[0] - con.screen_min[0]) - ((con.globals.x - 6.0f) - con.screen_min[0]), + (lines * con.globals.font_height) + 12.0f, + color); + } + + void draw_input_text_and_over(const char* str, float* color) + { + game::R_AddCmdDrawText(str, 0x7FFFFFFF, console_font, con.globals.x, + con.globals.y + con.globals.font_height, 1, + 1, 0, color, 0); + con.globals.x = game::R_TextWidth(str, 0, console_font) + con.globals.x + 6.0f; + } + + void draw_hint_box(const int lines, float* color, [[maybe_unused]] float offset_x = 0.0f, + [[maybe_unused]] float offset_y = 0.0f) + { + const auto _h = lines * con.globals.font_height + 12.0f; + const auto _y = con.globals.y - 3.0f + con.globals.font_height + 12.0f; + const auto _w = (con.screen_max[0] - con.screen_min[0]) - ((con.globals.x - 6.0f) - con.screen_min[0]); + + draw_box(con.globals.x - 6.0f, _y, _w, _h, color); + } + + void draw_hint_text(const int line, const char* text, float* color, const float offset = 0.0f) + { + const auto _y = con.globals.font_height + con.globals.y + (con.globals.font_height * (line + 1)) + 15.0f; + + game::R_AddCmdDrawText(text, 0x7FFFFFFF, console_font, con.globals.x + offset, _y, 1.0f, 1.0f, 0.0f, color, + 0); + } + + void draw_input() + { + con.globals.font_height = static_cast(console_font->pixelHeight); + con.globals.x = con.screen_min[0] + 6.0f; + con.globals.y = con.screen_min[1] + 6.0f; + con.globals.left_x = con.screen_min[0] + 6.0f; + + draw_input_box(1, dvars::con_inputBoxColor->current.vector); + draw_input_text_and_over("iw6-mod: " VERSION ">", color_iw6); + + con.globals.left_x = con.globals.x; + con.globals.auto_complete_choice[0] = 0; + + game::R_AddCmdDrawTextWithCursor(con.buffer, 0x7FFFFFFF, console_font, con.globals.x, + con.globals.y + con.globals.font_height, 1.0f, 1.0f, 0.0f, color_white, 0, + con.cursor, '|'); + + // check if using a prefixed '/' or not + const auto input = con.buffer[1] && (con.buffer[0] == '/' || con.buffer[0] == '\\') + ? std::string(con.buffer).substr(1) + : std::string(con.buffer); + + if (!input.length()) + { + return; + } + + if (input != fixed_input) + { + matches.clear(); + + if (input.find(" ") != std::string::npos) + { + find_matches(input.substr(0, input.find(" ")), matches, true); + } + else + { + find_matches(input, matches, false); + } + + fixed_input = input; + } + + con.globals.may_auto_complete = false; + if (matches.size() > 24) + { + draw_hint_box(1, dvars::con_inputHintBoxColor->current.vector); + draw_hint_text(0, utils::string::va("%i matches (too many to show here)", matches.size()), + dvars::con_inputDvarMatchColor->current.vector); + } + else if (matches.size() == 1) + { + const auto dvar = game::Dvar_FindVar(matches[0].data()); + const auto line_count = dvar ? 2 : 1; + + draw_hint_box(line_count, dvars::con_inputHintBoxColor->current.vector); + draw_hint_text(0, matches[0].data(), + dvar + ? dvars::con_inputDvarMatchColor->current.vector + : dvars::con_inputCmdMatchColor->current.vector); + + if (dvar) + { + const auto offset = (con.screen_max[0] - con.globals.x) / 2.5f; + + draw_hint_text(0, game::Dvar_ValueToString(dvar, dvar->current), + dvars::con_inputDvarValueColor->current.vector, offset); + draw_hint_text(1, " default", dvars::con_inputDvarInactiveValueColor->current.vector); + draw_hint_text(1, game::Dvar_ValueToString(dvar, dvar->reset), + dvars::con_inputDvarInactiveValueColor->current.vector, offset); + } + + strncpy_s(con.globals.auto_complete_choice, matches[0].data(), sizeof(con.globals.auto_complete_choice)); + con.globals.may_auto_complete = true; + } + else if (matches.size() > 1) + { + draw_hint_box(static_cast(matches.size()), dvars::con_inputHintBoxColor->current.vector); + + const auto offset = (con.screen_max[0] - con.globals.x) / 2.5f; + + for (size_t i = 0; i < matches.size(); i++) + { + const auto dvar = game::Dvar_FindVar(matches[i].data()); + + draw_hint_text(static_cast(i), matches[i].data(), + dvar + ? dvars::con_inputDvarMatchColor->current.vector + : dvars::con_inputCmdMatchColor->current.vector); + + if (dvar) + { + draw_hint_text(static_cast(i), game::Dvar_ValueToString(dvar, dvar->current), + dvars::con_inputDvarValueColor->current.vector, offset); + } + } + + strncpy_s(con.globals.auto_complete_choice, matches[0].data(), sizeof(con.globals.auto_complete_choice)); + con.globals.may_auto_complete = true; + } + } + + void draw_output_scrollbar(const float x, float y, const float width, const float height, output_queue& output) + { + const auto _x = (x + width) - 10.0f; + draw_box(_x, y, 10.0f, height, dvars::con_outputBarColor->current.vector); + + auto _height = height; + if (output.size() > con.visible_line_count) + { + const auto percentage = static_cast(con.visible_line_count) / output.size(); + _height *= percentage; + + const auto remainingSpace = height - _height; + const auto percentageAbove = static_cast(con.display_line_offset) / (output.size() - con. + visible_line_count); + + y = y + (remainingSpace * percentageAbove); + } + + draw_box(_x, y, 10.0f, _height, dvars::con_outputSliderColor->current.vector); + } + + void draw_output_text(const float x, float y, output_queue& output) + { + const auto offset = output.size() >= con.visible_line_count + ? 0.0f + : (con.font_height * (con.visible_line_count - output.size())); + + for (auto i = 0; i < con.visible_line_count; i++) + { + y = console_font->pixelHeight + y; + + const auto index = i + con.display_line_offset; + if (index >= output.size()) + { + break; + } + + game::R_AddCmdDrawText(output.at(index).data(), 0x7FFF, console_font, x, y + offset, 1.0f, 1.0f, + 0.0f, color_white, 0); + } + } + + void draw_output_window() + { + con.output.access([](output_queue& output) + { + draw_box(con.screen_min[0], con.screen_min[1] + 32.0f, con.screen_max[0] - con.screen_min[0], + (con.screen_max[1] - con.screen_min[1]) - 32.0f, dvars::con_outputWindowColor->current.vector); + + const auto x = con.screen_min[0] + 6.0f; + const auto y = (con.screen_min[1] + 32.0f) + 6.0f; + const auto width = (con.screen_max[0] - con.screen_min[0]) - 12.0f; + const auto height = ((con.screen_max[1] - con.screen_min[1]) - 32.0f) - 12.0f; + + game::R_AddCmdDrawText(game::Dvar_FindVar("version")->current.string, 0x7FFFFFFF, console_font, x, + ((height - 12.0f) + y) + console_font->pixelHeight, 1.0f, 1.0f, 0.0f, color_iw6, 0); + + draw_output_scrollbar(x, y, width, height, output); + draw_output_text(x, y, output); + }); + } + + void draw_console() + { + check_resize(); + + if (*game::keyCatchers & 1) + { + if (!(*game::keyCatchers & 1)) + { + con.output_visible = false; + } + + if (con.output_visible) + { + draw_output_window(); + } + + draw_input(); + } + } + } + + void print_internal(const char* fmt, ...) + { + char va_buffer[0x200] = { 0 }; + + va_list ap; + va_start(ap, fmt); + vsprintf_s(va_buffer, fmt, ap); + va_end(ap); + + const auto formatted = std::string(va_buffer); + const auto lines = utils::string::split(formatted, '\n'); + + for (const auto& line : lines) + { + print_internal(line); + } + } + + void print(const int type, const std::string& data) + { + try + { + if (game::environment::is_dedi()) + { + return; + } + } + catch (std::exception&) + { + return; + } + + const auto lines = utils::string::split(data, '\n'); + for (const auto& line : lines) + { + print_internal(type == console::con_type_info ? line : "^"s.append(std::to_string(type)).append(line)); + } + } + + bool console_char_event(const int localClientNum, const int key) + { + if (key == game::keyNum_t::K_GRAVE || key == game::keyNum_t::K_TILDE) + { + return false; + } + + if (*game::keyCatchers & 1) + { + if (key == game::keyNum_t::K_TAB) // tab (auto complete) + { + if (con.globals.may_auto_complete) + { + const auto firstChar = con.buffer[0]; + + clear(); + + if (firstChar == '\\' || firstChar == '/') + { + con.buffer[0] = firstChar; + con.buffer[1] = '\0'; + } + + strncat_s(con.buffer, con.globals.auto_complete_choice, 64); + con.cursor = static_cast(std::string(con.buffer).length()); + + if (con.cursor != 254) + { + con.buffer[con.cursor++] = ' '; + con.buffer[con.cursor] = '\0'; + } + } + } + + if (key == 'v' - 'a' + 1) // paste + { + const auto clipboard = utils::string::get_clipboard_data(); + if (clipboard.empty()) + { + return false; + } + + for (auto i = 0; i < clipboard.length(); i++) + { + console_char_event(localClientNum, clipboard[i]); + } + + return false; + } + + if (key == 'c' - 'a' + 1) // clear + { + clear(); + con.line_count = 0; + con.display_line_offset = 0; + con.output.access([](output_queue& output) + { + output.clear(); + }); + history_index = -1; + history.clear(); + + return false; + } + + if (key == 'h' - 'a' + 1) // backspace + { + if (con.cursor > 0) + { + memmove(con.buffer + con.cursor - 1, con.buffer + con.cursor, + strlen(con.buffer) + 1 - con.cursor); + con.cursor--; + } + + return false; + } + + if (key < 32) + { + return false; + } + + if (con.cursor == 256 - 1) + { + return false; + } + + memmove(con.buffer + con.cursor + 1, con.buffer + con.cursor, strlen(con.buffer) + 1 - con.cursor); + con.buffer[con.cursor] = static_cast(key); + con.cursor++; + + if (con.cursor == strlen(con.buffer) + 1) + { + con.buffer[con.cursor] = 0; + } + } + + return true; + } + + bool console_key_event(const int localClientNum, const int key, const int down) + { + if (key == game::keyNum_t::K_F10) + { + if(game::mp::svs_clients[localClientNum].header.state > game::CS_FREE) + { + return false; + } + + game::Cmd_ExecuteSingleCommand(localClientNum, 0, "lui_open menu_systemlink_join\n"); + } + + if (key == game::keyNum_t::K_GRAVE || key == game::keyNum_t::K_TILDE) + { + if (!down) + { + return false; + } + + if (game::playerKeys[localClientNum].keys[game::keyNum_t::K_SHIFT].down) + { + if (!(*game::keyCatchers & 1)) + toggle_console(); + + toggle_console_output(); + return false; + } + + toggle_console(); + + return false; + } + + if (*game::keyCatchers & 1) + { + if (down) + { + if (key == game::keyNum_t::K_UPARROW) + { + if (++history_index >= history.size()) + { + history_index = static_cast(history.size()) - 1; + } + + clear(); + + if (history_index != -1) + { + strncpy_s(con.buffer, history.at(history_index).c_str(), sizeof(con.buffer)); + con.cursor = static_cast(strlen(con.buffer)); + } + } + else if (key == game::keyNum_t::K_DOWNARROW) + { + if (--history_index < -1) + { + history_index = -1; + } + + clear(); + + if (history_index != -1) + { + strncpy_s(con.buffer, history.at(history_index).c_str(), sizeof(con.buffer)); + con.cursor = static_cast(strlen(con.buffer)); + } + } + + if (key == game::keyNum_t::K_RIGHTARROW) + { + if (con.cursor < strlen(con.buffer)) + { + con.cursor++; + } + + return false; + } + + if (key == game::keyNum_t::K_LEFTARROW) + { + if (con.cursor > 0) + { + con.cursor--; + } + + return false; + } + + //scroll through output + if (key == game::keyNum_t::K_MWHEELUP || key == game::keyNum_t::K_PGUP) + { + con.output.access([](output_queue& output) + { + if (output.size() > con.visible_line_count && con.display_line_offset > 0) + { + con.display_line_offset--; + } + }); + } + else if (key == game::keyNum_t::K_MWHEELDOWN || key == game::keyNum_t::K_PGDN) + { + con.output.access([](output_queue& output) + { + if (output.size() > con.visible_line_count + && con.display_line_offset < (output.size() - con.visible_line_count)) + { + con.display_line_offset++; + } + }); + } + + if (key == game::keyNum_t::K_ENTER) + { + game::Cbuf_AddText(0, utils::string::va("%s \n", fixed_input.data())); + + if (history_index != -1) + { + const auto itr = history.begin() + history_index; + + if (*itr == con.buffer) + { + history.erase(history.begin() + history_index); + } + } + + history.push_front(con.buffer); + + console::info("]%s\n", con.buffer); + + if (history.size() > 10) + { + history.erase(history.begin() + 10); + } + + history_index = -1; + + clear(); + } + } + } + + return true; + } + + bool match_compare(const std::string& input, const std::string& text, const bool exact) + { + if (exact && text == input) return true; + if (!exact && text.find(input) != std::string::npos) return true; + return false; + } + + void find_matches(std::string input, std::vector& suggestions, const bool exact) + { + input = utils::string::to_lower(input); + + for (int i = 0; i < *game::dvarCount; i++) + { + if (game::sortedDvars[i] && game::sortedDvars[i]->name) + { + std::string name = utils::string::to_lower(game::sortedDvars[i]->name); + + if (match_compare(input, name, exact)) + { + suggestions.push_back(game::sortedDvars[i]->name); + } + + if (exact && suggestions.size() > 1) + { + return; + } + } + } + + game::cmd_function_s* cmd = (*game::cmd_functions); + while (cmd) + { + if (cmd->name) + { + std::string name = utils::string::to_lower(cmd->name); + + if (match_compare(input, name, exact)) + { + suggestions.push_back(cmd->name); + } + + if (exact && suggestions.size() > 1) + { + return; + } + } + cmd = cmd->next; + } + } + + class component final : public component_interface + { + public: + void post_load() override + { + if (game::environment::is_dedi()) + { + return; + } + + scheduler::loop(draw_console, scheduler::pipeline::renderer); + } + + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + // initialize our structs + con.cursor = 0; + con.visible_line_count = 0; + con.output_visible = false; + con.display_line_offset = 0; + con.line_count = 0; + strncpy_s(con.buffer, "", sizeof(con.buffer)); + + con.globals.x = 0.0f; + con.globals.y = 0.0f; + con.globals.left_x = 0.0f; + con.globals.font_height = 0.0f; + con.globals.may_auto_complete = false; + con.globals.info_line_count = 0; + strncpy_s(con.globals.auto_complete_choice, "", sizeof(con.globals.auto_complete_choice)); + + // add clear command + command::add("clear", [&]() + { + clear(); + con.line_count = 0; + con.display_line_offset = 0; + con.output.access([](output_queue& output) + { + output.clear(); + }); + history_index = -1; + history.clear(); + }); + + // add our dvars + dvars::con_inputBoxColor = game::Dvar_RegisterVec4("con_inputBoxColor", 0.2f, 0.2f, 0.2f, 0.9f, 0.0f, 1.0f, + game::DvarFlags::DVAR_FLAG_SAVED, + "color of console input box"); + dvars::con_inputHintBoxColor = game::Dvar_RegisterVec4("con_inputHintBoxColor", 0.3f, 0.3f, 0.3f, 1.0f, + 0.0f, 1.0f, + game::DvarFlags::DVAR_FLAG_SAVED, "color of console input hint box"); + dvars::con_outputBarColor = game::Dvar_RegisterVec4("con_outputBarColor", 0.5f, 0.5f, 0.5f, 0.6f, 0.0f, + 1.0f, game::DvarFlags::DVAR_FLAG_SAVED, + "color of console output bar"); + dvars::con_outputSliderColor = game::Dvar_RegisterVec4("con_outputSliderColor", 0.0f, 0.7f, 1.0f, 1.00f, + 0.0f, 1.0f, + game::DvarFlags::DVAR_FLAG_SAVED, "color of console output slider"); + dvars::con_outputWindowColor = game::Dvar_RegisterVec4("con_outputWindowColor", 0.25f, 0.25f, 0.25f, 0.85f, + 0.0f, + 1.0f, game::DvarFlags::DVAR_FLAG_SAVED, "color of console output window"); + dvars::con_inputDvarMatchColor = game::Dvar_RegisterVec4("con_inputDvarMatchColor", 1.0f, 1.0f, 0.8f, 1.0f, + 0.0f, + 1.0f, game::DvarFlags::DVAR_FLAG_SAVED, "color of console matched dvar"); + dvars::con_inputDvarValueColor = game::Dvar_RegisterVec4("con_inputDvarValueColor", 1.0f, 1.0f, 0.8f, 1.0f, + 0.0f, + 1.0f, game::DvarFlags::DVAR_FLAG_SAVED, "color of console matched dvar value"); + dvars::con_inputDvarInactiveValueColor = game::Dvar_RegisterVec4( + "con_inputDvarInactiveValueColor", 0.8f, 0.8f, + 0.8f, 1.0f, 0.0f, 1.0f, game::DvarFlags::DVAR_FLAG_SAVED, + "color of console inactive dvar value"); + dvars::con_inputCmdMatchColor = game::Dvar_RegisterVec4("con_inputCmdMatchColor", 0.80f, 0.80f, 1.0f, 1.0f, + 0.0f, + 1.0f, game::DvarFlags::DVAR_FLAG_SAVED, "color of console matched command"); + } + }; +} + +REGISTER_COMPONENT(game_console::component) diff --git a/src/client/component/game_console.hpp b/src/client/component/game_console.hpp new file mode 100644 index 0000000..e941917 --- /dev/null +++ b/src/client/component/game_console.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace game_console +{ + void print(int type, const std::string& data); + + bool console_char_event(int local_client_num, int key); + bool console_key_event(int local_client_num, int key, int down); + + bool match_compare(const std::string& input, const std::string& text, const bool exact); + void find_matches(std::string input, std::vector& suggestions, const bool exact); +} diff --git a/src/client/component/game_log.cpp b/src/client/component/game_log.cpp new file mode 100644 index 0000000..5c46d91 --- /dev/null +++ b/src/client/component/game_log.cpp @@ -0,0 +1,116 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "scheduler.hpp" +#include "scripting.hpp" +#include "console.hpp" +#include "game_log.hpp" + +#include "gsc/script_extension.hpp" + +#include +#include +#include + +namespace game_log +{ + namespace + { + void gscr_log_print() + { + char buf[1024]{}; + std::size_t out_chars = 0; + + for (auto i = 0u; i < game::Scr_GetNumParam(); ++i) + { + const auto* value = game::Scr_GetString(i); + const auto len = std::strlen(value); + + out_chars += len; + if (out_chars >= sizeof(buf)) + { + break; + } + + strncat_s(buf, value, _TRUNCATE); + } + + g_log_printf("%s", buf); + } + } + + void g_log_printf(const char* fmt, ...) + { + const auto* log = dvars::g_log->current.string; + if (*log == '\0') + { + return; + } + + char buffer[0x400]{}; + + va_list ap; + va_start(ap, fmt); + + vsprintf_s(buffer, fmt, ap); + + va_end(ap); + + const auto time = *game::level_time / 1000; + utils::io::write_file(log, utils::string::va("%3i:%i%i %s", + time / 60, + time % 60 / 10, + time % 60 % 10, + buffer + ), true); + } + + class component final : public component_interface + { + public: + void post_load() override + { + if (game::environment::is_sp()) + { + return; + } + + utils::hook::set(0x1409E8A20, gscr_log_print); + + scheduler::once([] + { + dvars::g_log = game::Dvar_RegisterString("g_log", "logs/games_mp.log", game::DVAR_FLAG_NONE, "Log file name"); + }, scheduler::pipeline::main); + + scripting::on_init([] + { + console::info("------- Game Initialization -------\n"); + console::info("gamename: IW6\n"); + console::info("gamedate: " __DATE__ "\n"); + + const auto* log = dvars::g_log->current.string; + if (*log == '\0') + { + console::info("Not logging to disk.\n"); + return; + } + + console::info("Logging to disk: '%s'.\n", log); + g_log_printf("------------------------------------------------------------\n"); + g_log_printf("InitGame\n"); + }); + + scripting::on_shutdown([](int free_scripts) + { + console::info("==== ShutdownGame (%d) ====\n", free_scripts); + + g_log_printf("ShutdownGame:\n"); + g_log_printf("------------------------------------------------------------\n"); + }); + } + }; +} + +REGISTER_COMPONENT(game_log::component) diff --git a/src/client/component/game_log.hpp b/src/client/component/game_log.hpp new file mode 100644 index 0000000..4135e71 --- /dev/null +++ b/src/client/component/game_log.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace game_log +{ + void g_log_printf(const char* fmt, ...); +} diff --git a/src/client/component/game_module.cpp b/src/client/component/game_module.cpp new file mode 100644 index 0000000..eb43f0f --- /dev/null +++ b/src/client/component/game_module.cpp @@ -0,0 +1,122 @@ +#include +#include "loader/component_loader.hpp" +#include "game_module.hpp" + +#include + +namespace game_module +{ + namespace + { + utils::hook::detour handle_a_hook; + utils::hook::detour handle_w_hook; + utils::hook::detour handle_ex_a_hook; + utils::hook::detour handle_ex_w_hook; + utils::hook::detour file_name_a_hook; + utils::hook::detour file_name_w_hook; + + HMODULE __stdcall get_module_handle_a(const LPCSTR module_name) + { + if (!module_name) + { + return get_game_module(); + } + + return handle_a_hook.invoke(module_name); + } + + HMODULE __stdcall get_module_handle_w(const LPWSTR module_name) + { + if (!module_name) + { + return get_game_module(); + } + + return handle_w_hook.invoke(module_name); + } + + BOOL __stdcall get_module_handle_ex_a(const DWORD flags, const LPCSTR module_name, HMODULE* hmodule) + { + if (!module_name) + { + *hmodule = get_game_module(); + return TRUE; + } + + return handle_ex_a_hook.invoke(flags, module_name, hmodule); + } + + BOOL __stdcall get_module_handle_ex_w(const DWORD flags, const LPCWSTR module_name, HMODULE* hmodule) + { + if (!module_name) + { + *hmodule = get_game_module(); + return TRUE; + } + + return handle_ex_w_hook.invoke(flags, module_name, hmodule); + } + + DWORD __stdcall get_module_file_name_a(HMODULE hmodule, const LPSTR filename, const DWORD size) + { + if (!hmodule) + { + hmodule = get_game_module(); + } + + return file_name_a_hook.invoke(hmodule, filename, size); + } + + DWORD __stdcall get_module_file_name_w(HMODULE hmodule, const LPWSTR filename, const DWORD size) + { + if (!hmodule || utils::nt::library(hmodule) == get_game_module()) + { + hmodule = get_host_module(); + } + + return file_name_w_hook.invoke(hmodule, filename, size); + } + + void hook_module_resolving() + { + handle_a_hook.create(&GetModuleHandleA, &get_module_handle_a); + handle_w_hook.create(&GetModuleHandleW, &get_module_handle_w); + handle_ex_w_hook.create(&GetModuleHandleExA, &get_module_handle_ex_a); + handle_ex_w_hook.create(&GetModuleHandleExW, &get_module_handle_ex_w); + file_name_a_hook.create(&GetModuleFileNameA, &get_module_file_name_a); + file_name_w_hook.create(&GetModuleFileNameW, &get_module_file_name_w); + } + } + + utils::nt::library get_game_module() + { + static utils::nt::library game{HMODULE(0x140000000)}; + return game; + } + + utils::nt::library get_host_module() + { + static utils::nt::library host{}; + return host; + } + + class component final : public component_interface + { + public: + void post_start() override + { + get_host_module(); + } + + void post_load() override + { +#ifdef INJECT_HOST_AS_LIB + hook_module_resolving(); +#else + assert(get_host_module() == get_game_module()); +#endif + } + }; +} + +REGISTER_COMPONENT(game_module::component) diff --git a/src/client/component/game_module.hpp b/src/client/component/game_module.hpp new file mode 100644 index 0000000..35a39f7 --- /dev/null +++ b/src/client/component/game_module.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace game_module +{ + utils::nt::library get_game_module(); + utils::nt::library get_host_module(); +} diff --git a/src/client/component/gameplay.cpp b/src/client/component/gameplay.cpp new file mode 100644 index 0000000..db4c8da --- /dev/null +++ b/src/client/component/gameplay.cpp @@ -0,0 +1,403 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include + +namespace gameplay +{ + namespace + { + template + constexpr auto VectorScale(T v, R s, T out) { out[0] = v[0] * s; out[1] = v[1] * s; out[2] = v[2] * s; } + + utils::hook::detour pm_weapon_use_ammo_hook; + + int stuck_in_client_stub(void* self) + { + if (dvars::g_playerEjection->current.enabled) + { + return utils::hook::invoke(0x140386950, self); // StuckInClient + } + + return 0; + } + + void cm_transformed_capsule_trace_stub(game::trace_t* results, const float* start, const float* end, + game::Bounds* bounds, game::Bounds* capsule, int contents, const float* origin, const float* angles) + { + if (dvars::g_playerCollision->current.enabled) + { + utils::hook::invoke(0x1403F3050, + results, start, end, bounds, capsule, contents, origin, angles); // CM_TransformedCapsuleTrace + } + } + + const auto g_gravity_stub = utils::hook::assemble([](utils::hook::assembler& a) + { + a.push(rax); + + a.mov(rax, qword_ptr(reinterpret_cast(&dvars::g_gravity))); + a.mov(eax, dword_ptr(rax, 0x10)); + a.mov(dword_ptr(rbx, 0x5C), eax); + a.mov(eax, ptr(rbx, 0x33E8)); + a.mov(ptr(rbx, 0x25C), eax); + + a.pop(rax); + + a.jmp(0x1403828D5); + }); + + const auto g_speed_stub = utils::hook::assemble([](utils::hook::assembler& a) + { + a.push(rax); + + a.mov(rax, qword_ptr(reinterpret_cast(&dvars::g_speed))); + a.mov(eax, dword_ptr(rax, 0x10)); + a.mov(dword_ptr(rdi, 0x60), eax); + + a.pop(rax); + + a.mov(eax, ptr(rdi, 0xEA4)); + a.add(eax, ptr(rdi, 0xEA0)); + + a.jmp(0x140383796); + }); + + const auto pm_bouncing_stub_sp = utils::hook::assemble([](utils::hook::assembler& a) + { + const auto no_bounce = a.newLabel(); + const auto loc_14046ED26 = a.newLabel(); + + a.push(rax); + + a.mov(rax, qword_ptr(reinterpret_cast(&dvars::pm_bouncing))); + a.mov(al, byte_ptr(rax, 0x10)); + a.cmp(ptr(rbp, -0x40), al); + + a.pop(rax); + a.jz(no_bounce); + a.jmp(0x14046EC7E); + + a.bind(no_bounce); + a.cmp(ptr(rbp, -0x80), r13d); + a.jnz(loc_14046ED26); + a.jmp(0x14046EC6C); + + a.bind(loc_14046ED26); + a.jmp(0x14046ED26); + }); + + const auto pm_bouncing_stub_mp = utils::hook::assemble([](utils::hook::assembler& a) + { + const auto no_bounce = a.newLabel(); + const auto loc_140228FB8 = a.newLabel(); + + a.push(rax); + + a.mov(rax, qword_ptr(reinterpret_cast(&dvars::pm_bouncing))); + a.mov(al, byte_ptr(rax, 0x10)); + a.cmp(byte_ptr(rbp, -0x38), al); + + a.pop(rax); + a.jz(no_bounce); + a.jmp(0x140229019); + + a.bind(no_bounce); + a.cmp(dword_ptr(rbp, -0x70), 0); + a.jnz(loc_140228FB8); + a.jmp(0x14022900B); + + a.bind(loc_140228FB8); + a.jmp(0x140228FB8); + }); + + const void pm_crashland_stub(void* ps, void* pml) + { + if (dvars::jump_enableFallDamage->current.enabled) + { + reinterpret_cast(0x140220000)(ps, pml); + } + } + + float get_jump_height_stub(void* pmove) + { + auto jump_height = reinterpret_cast(0x140213140)(pmove); + + if (jump_height == 39.f) + { + jump_height = dvars::jump_height->current.value; + } + + return jump_height; + } + + void jump_apply_slowdown_stub(game::mp::playerState_s* ps) + { + assert(ps->pm_flags & game::PMF_JUMPING); + + float scale = 1.0f; + if (ps->pm_time > 1800) + { + game::Jump_ClearState(ps); + scale = 0.65f; + } + else if (ps->pm_time == 0) + { + if (ps->jumpOriginZ + 18.0f <= ps->origin[2]) + { + ps->pm_time = 1200; + scale = 0.5f; + } + else + { + ps->pm_time = 1800; + scale = 0.65f; + } + } + + if (dvars::jump_slowdownEnable->current.enabled) + { + VectorScale(ps->velocity, scale, ps->velocity); + } + } + + float jump_get_slowdown_friction(game::mp::playerState_s* ps) + { + assert(ps->pm_flags & game::PMF_JUMPING); + assert(ps->pm_time <= game::JUMP_LAND_SLOWDOWN_TIME); + + if (!dvars::jump_slowdownEnable->current.enabled) + { + return 1.0f; + } + + if (ps->pm_time < 1700) + { + return static_cast(ps->pm_time) * 1.5f * 0.00058823527f + 1.0f; + } + + return 2.5f; + } + + float jump_reduce_friction_stub(game::mp::playerState_s* ps) + { + float control; + + assert(ps->pm_flags & game::PMF_JUMPING); + if (ps->pm_time > game::JUMP_LAND_SLOWDOWN_TIME) + { + game::Jump_ClearState(ps); + control = 1.0f; + } + else + { + control = jump_get_slowdown_friction(ps); + } + + return control; + } + + float jump_get_land_factor(game::mp::playerState_s* ps) + { + assert(ps->pm_flags & game::PMF_JUMPING); + assert(ps->pm_time <= game::JUMP_LAND_SLOWDOWN_TIME); + + if (!dvars::jump_slowdownEnable->current.enabled) + { + return 1.0f; + } + + if (ps->pm_time < 1700) + { + return static_cast(ps->pm_time) * 1.5f * 0.00058823527f + 1.0f; + } + + return 2.5f; + } + + void jump_start_stub(game::pmove_t* pm, game::pml_t* pml, float height) + { + static_assert(offsetof(game::mp::playerState_s, groundEntityNum) == 0x70); + static_assert(offsetof(game::mp::playerState_s, pm_time) == 0x8); + static_assert(offsetof(game::mp::playerState_s, sprintState.sprintButtonUpRequired) == 0x240); + static_assert(offsetof(game::pml_t, frametime) == 0x24); + static_assert(offsetof(game::pml_t, walking) == 0x2C); + static_assert(offsetof(game::pml_t, groundPlane) == 0x30); + static_assert(offsetof(game::pml_t, almostGroundPlane) == 0x34); + + float factor; + float velocity_sqrd; + game::mp::playerState_s* ps; + + ps = static_cast(pm->ps); + + assert(ps); + + velocity_sqrd = (height * 2.0f) * static_cast(ps->gravity); + + if ((ps->pm_flags & game::PMF_JUMPING) != 0 && ps->pm_time <= game::JUMP_LAND_SLOWDOWN_TIME) + { + factor = jump_get_land_factor(ps); + assert(factor); + velocity_sqrd = velocity_sqrd / factor; + } + + pml->walking = 0; + pml->groundPlane = 0; + + ps->groundEntityNum = game::ENTITYNUM_NONE; + ps->jumpTime = pm->cmd.serverTime; + ps->jumpOriginZ = ps->origin[2]; + ps->velocity[2] = std::sqrtf(velocity_sqrd); + ps->pm_flags &= ~(game::PMF_UNK1 | game::PMF_UNK2); + ps->pm_flags |= game::PMF_JUMPING; + ps->pm_time = 0; + ps->sprintState.sprintButtonUpRequired = 0; + ps->aimSpreadScale = ps->aimSpreadScale + dvars::jump_spreadAdd->current.value; + if (ps->aimSpreadScale > 255.0f) + { + ps->aimSpreadScale = 255.0f; + } + } + + const auto jump_push_off_ladder_stub = utils::hook::assemble([](utils::hook::assembler& a) + { + a.mov(rax, qword_ptr(reinterpret_cast(&dvars::jump_ladderPushVel))); + a.movaps(xmm8, dword_ptr(rax, 0x10)); + + a.mulss(xmm6, xmm8); + a.mulss(xmm7, xmm8); + + a.jmp(0x140213494); + }); + + void pm_player_trace_stub(game::pmove_t* move, game::trace_t* trace, const float* f3, + const float* f4, const game::Bounds* bounds, int a6, int a7) + { + game::PM_playerTrace(move, trace, f3, f4, bounds, a6, a7); + + if (dvars::g_enableElevators->current.enabled) + { + trace->startsolid = false; + } + } + + void pm_trace_stub(const game::pmove_t* move, game::trace_t* trace, const float* f3, + const float* f4, const game::Bounds* bounds, int a6, int a7) + { + game::PM_trace(move, trace, f3, f4, bounds, a6, a7); + + if (dvars::g_enableElevators->current.enabled) + { + trace->allsolid = false; + } + } + + void pm_weapon_use_ammo_stub(game::playerState_s* ps, game::Weapon weapon, + bool is_alternate, int amount, game::PlayerHandIndex hand) + { + if (!dvars::player_sustainAmmo->current.enabled) + { + pm_weapon_use_ammo_hook.invoke(ps, weapon, is_alternate, amount, hand); + } + } + + game::mp::gentity_s* weapon_rocket_launcher_fire_stub(game::mp::gentity_s* ent, game::Weapon weapon, float spread, game::weaponParms* wp, + const float* gun_vel, game::mp::missileFireParms* fire_parms, bool magic_bullet) + { + auto* result = utils::hook::invoke(0x1403DB8A0, ent, weapon, spread, wp, gun_vel, fire_parms, magic_bullet); + + if (ent->client != nullptr && wp->weapDef->inventoryType != game::WEAPINVENTORY_EXCLUSIVE) + { + const auto scale = dvars::g_rocketPushbackScale->current.value; + ent->client->ps.velocity[0] += (0.0f - wp->forward[0]) * scale; + ent->client->ps.velocity[1] += (0.0f - wp->forward[1]) * scale; + ent->client->ps.velocity[2] += (0.0f - wp->forward[2]) * scale; + } + + return result; + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Implement bouncing dvar + if (game::environment::is_sp()) + { + utils::hook::nop(0x14046EC5C, 16); + } + + utils::hook::jump( + SELECT_VALUE(0x14046EC5C, 0x140228FFF), SELECT_VALUE(pm_bouncing_stub_sp, pm_bouncing_stub_mp), true); + dvars::pm_bouncing = game::Dvar_RegisterBool("pm_bouncing", false, + game::DVAR_FLAG_REPLICATED, "Enable bouncing"); + + dvars::player_sustainAmmo = game::Dvar_RegisterBool("player_sustainAmmo", false, + game::DVAR_FLAG_REPLICATED, "Firing weapon will not decrease clip ammo."); + pm_weapon_use_ammo_hook.create(SELECT_VALUE(0x140479640, 0x140238A90), &pm_weapon_use_ammo_stub); + + if (game::environment::is_sp()) return; + + // Implement player ejection dvar + dvars::g_playerEjection = game::Dvar_RegisterBool("g_playerEjection", true, game::DVAR_FLAG_REPLICATED, "Flag whether player ejection is on or off"); + utils::hook::call(0x140382C13, stuck_in_client_stub); + + // Implement player collision dvar + dvars::g_playerCollision = game::Dvar_RegisterBool("g_playerCollision", true, game::DVAR_FLAG_REPLICATED, "Flag whether player collision is on or off"); + utils::hook::call(0x14048A49A, cm_transformed_capsule_trace_stub); // SV_ClipMoveToEntity + utils::hook::call(0x1402B5B88, cm_transformed_capsule_trace_stub); // CG_ClipMoveToEntity + + // Implement gravity dvar + utils::hook::nop(0x1403828C8, 13); + utils::hook::jump(0x1403828C8, g_gravity_stub, true); + dvars::g_gravity = game::Dvar_RegisterInt("g_gravity", 800, 0, 1000, game::DVAR_FLAG_NONE, + "Game gravity in inches per second squared"); + + // Implement speed dvar + utils::hook::nop(0x140383789, 13); + utils::hook::jump(0x140383789, g_speed_stub, true); + dvars::g_speed = game::Dvar_RegisterInt("g_speed", 190, 0, 999, game::DVAR_FLAG_NONE, "Maximum player speed"); + + utils::hook::call(0x140225857, jump_apply_slowdown_stub); + utils::hook::call(0x1402210A2, jump_reduce_friction_stub); + utils::hook::call(0x140213015, jump_start_stub); + dvars::jump_slowdownEnable = game::Dvar_RegisterBool("jump_slowdownEnable", true, + game::DVAR_FLAG_REPLICATED, + "Slow player movement after jumping"); + dvars::jump_spreadAdd = game::Dvar_RegisterFloat("jump_spreadAdd", 64.0f, + 0.0f, 512.0f, game::DVAR_FLAG_REPLICATED, + "The amount of spread scale to add as a side effect of jumping"); + + utils::hook::call(0x1402219A5, pm_crashland_stub); + dvars::jump_enableFallDamage = game::Dvar_RegisterBool("jump_enableFallDamage", true, + game::DVAR_FLAG_REPLICATED, + "Enable fall damage"); + + utils::hook::call(0x140213007, get_jump_height_stub); + dvars::jump_height = game::Dvar_RegisterFloat("jump_height", 39.f, 0.f, 1024.f, + game::DVAR_FLAG_REPLICATED, "Jump height"); + + utils::hook::jump(0x140213484, jump_push_off_ladder_stub, true); + dvars::jump_ladderPushVel = game::Dvar_RegisterFloat("jump_ladderPushVel", 128.f, 0.f, 1024.f, + game::DVAR_FLAG_REPLICATED, + "Ladder push velocity"); + + utils::hook::call(0x140221F92, pm_player_trace_stub); + utils::hook::call(0x140221FFA, pm_player_trace_stub); + utils::hook::call(0x14021F0E3, pm_trace_stub); + dvars::g_enableElevators = game::Dvar_RegisterBool("g_enableElevators", false, + game::DVAR_FLAG_REPLICATED, "Enable Elevators"); + + utils::hook::call(0x1403D933E, weapon_rocket_launcher_fire_stub); + dvars::g_rocketPushbackScale = game::Dvar_RegisterFloat("g_rocketPushbackScale", 1.0f, 1.0f, std::numeric_limits::max(), + game::DVAR_FLAG_REPLICATED, "The scale applied to the pushback force of a rocket"); + } + }; +} + +REGISTER_COMPONENT(gameplay::component) diff --git a/src/client/component/gsc/script_error.cpp b/src/client/component/gsc/script_error.cpp new file mode 100644 index 0000000..9585edf --- /dev/null +++ b/src/client/component/gsc/script_error.cpp @@ -0,0 +1,319 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "script_extension.hpp" +#include "script_error.hpp" + +#include "component/scripting.hpp" + +#include +#include + +using namespace utils::string; + +namespace gsc +{ + namespace + { + std::array var_typename = + { + "undefined", + "object", + "string", + "localized string", + "vector", + "float", + "int", + "codepos", + "precodepos", + "function", + "builtin function", + "builtin method", + "stack", + "animation", + "pre animation", + "thread", + "thread", + "thread", + "thread", + "struct", + "removed entity", + "entity", + "array", + "removed thread", + "", + "thread list", + "endon list", + }; + + utils::hook::detour scr_emit_function_hook; + + unsigned int current_filename = 0; + + std::string unknown_function_error; + + void scr_emit_function_stub(unsigned int filename, unsigned int thread_name, char* code_pos) + { + current_filename = filename; + scr_emit_function_hook.invoke(filename, thread_name, code_pos); + } + + std::string get_filename_name() + { + const auto filename_str = game::SL_ConvertToString(current_filename); + const auto id = std::atoi(filename_str); + if (!id) + { + return filename_str; + } + + return scripting::get_token(id); + } + + void get_unknown_function_error(const char* code_pos) + { + const auto function = find_function(code_pos); + if (function.has_value()) + { + const auto& pos = function.value(); + unknown_function_error = std::format( + "while processing function '{}' in script '{}':\nunknown script '{}'", pos.first, pos.second, scripting::current_file + ); + } + else + { + unknown_function_error = std::format("unknown script '{}'", scripting::current_file); + } + } + + void get_unknown_function_error(unsigned int thread_name) + { + const auto filename = get_filename_name(); + const auto name = scripting::get_token(thread_name); + + unknown_function_error = std::format( + "while processing script '{}':\nunknown function '{}::{}'", scripting::current_file, filename, name + ); + } + + void compile_error_stub(const char* code_pos, [[maybe_unused]] const char* msg) + { + get_unknown_function_error(code_pos); + game::Com_Error(game::ERR_DROP, "script link error\n%s", unknown_function_error.data()); + } + + unsigned int find_variable_stub(unsigned int parent_id, unsigned int thread_name) + { + const auto res = game::FindVariable(parent_id, thread_name); + if (!res) + { + get_unknown_function_error(thread_name); + game::Com_Error(game::ERR_DROP, "script link error\n%s", unknown_function_error.data()); + } + + return res; + } + + } + + unsigned int scr_get_object(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + auto* value = game::scr_VmPub->top - index; + if (value->type == game::VAR_POINTER) + { + return value->u.pointerValue; + } + + scr_error(va("Type %s is not an object", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + unsigned int scr_get_const_string(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + auto* value = game::scr_VmPub->top - index; + if (game::Scr_CastString(value)) + { + assert(value->type == game::VAR_STRING); + return value->u.stringValue; + } + + game::Scr_ErrorInternal(); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + unsigned int scr_get_const_istring(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + auto* value = game::scr_VmPub->top - index; + if (value->type == game::VAR_ISTRING) + { + return value->u.stringValue; + } + + scr_error(va("Type %s is not a localized string", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + void scr_get_vector(unsigned int index, float* vector_value) + { + if (index < game::scr_VmPub->outparamcount) + { + auto* value = game::scr_VmPub->top - index; + if (value->type == game::VAR_VECTOR) + { + std::memcpy(vector_value, value->u.vectorValue, sizeof(std::float_t[3])); + return; + } + + scr_error(va("Type %s is not a vector", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + } + + int scr_get_int(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + auto* value = game::scr_VmPub->top - index; + if (value->type == game::VAR_INTEGER) + { + return value->u.intValue; + } + + scr_error(va("Type %s is not an int", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + float scr_get_float(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + auto* value = game::scr_VmPub->top - index; + if (value->type == game::VAR_FLOAT) + { + return value->u.floatValue; + } + + if (value->type == game::VAR_INTEGER) + { + return static_cast(value->u.intValue); + } + + scr_error(va("Type %s is not a float", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0.0f; + } + + int scr_get_pointer_type(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + if ((game::scr_VmPub->top - index)->type == game::VAR_POINTER) + { + return game::GetObjectType((game::scr_VmPub->top - index)->u.intValue); + } + + scr_error(va("Type %s is not an object", var_typename[(game::scr_VmPub->top - index)->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + int scr_get_type(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + return (game::scr_VmPub->top - index)->type; + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + const char* scr_get_type_name(unsigned int index) + { + if (index < game::scr_VmPub->outparamcount) + { + return var_typename[(game::scr_VmPub->top - index)->type]; + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return nullptr; + } + + std::optional> find_function(const char* pos) + { + for (const auto& file : scripting::script_function_table_sort) + { + for (auto i = file.second.begin(); i != file.second.end() && std::next(i) != file.second.end(); ++i) + { + const auto next = std::next(i); + if (pos >= i->second && pos < next->second) + { + return {std::make_pair(i->first, file.first)}; + } + } + } + + return {}; + } + + class error final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + scr_emit_function_hook.create(0x14042E150, &scr_emit_function_stub); + + utils::hook::call(0x14042E0E4, compile_error_stub); // LinkFile + utils::hook::call(0x14042E138, compile_error_stub); // LinkFile + utils::hook::call(0x14042E22B, find_variable_stub); // Scr_EmitFunction + + // Restore basic error messages to scr functions + utils::hook::jump(0x140438ED0, scr_get_object); + utils::hook::jump(0x140438AD0, scr_get_const_string); + utils::hook::jump(0x1404388B0, scr_get_const_istring); + utils::hook::jump(0x1404393D0, scr_get_vector); + utils::hook::jump(0x140438E10, scr_get_int); + utils::hook::jump(0x140438D60, scr_get_float); + + utils::hook::jump(0x1404390B0, scr_get_pointer_type); + utils::hook::jump(0x140439280, scr_get_type); + utils::hook::jump(0x1404392F0, scr_get_type_name); + } + + void pre_destroy() override + { + scr_emit_function_hook.clear(); + } + }; +} + +REGISTER_COMPONENT(gsc::error) diff --git a/src/client/component/gsc/script_error.hpp b/src/client/component/gsc/script_error.hpp new file mode 100644 index 0000000..4056a95 --- /dev/null +++ b/src/client/component/gsc/script_error.hpp @@ -0,0 +1,16 @@ +#pragma once + +namespace gsc +{ + unsigned int scr_get_object(unsigned int index); + unsigned int scr_get_const_string(unsigned int index); + unsigned int scr_get_const_istring(unsigned int index); + void scr_get_vector(unsigned int index, float* vector_value); + int scr_get_int(unsigned int index); + float scr_get_float(unsigned int index); + int scr_get_pointer_type(unsigned int index); + int scr_get_type(unsigned int index); + const char* scr_get_type_name(unsigned int index); + + std::optional> find_function(const char* pos); +} diff --git a/src/client/component/gsc/script_extension.cpp b/src/client/component/gsc/script_extension.cpp new file mode 100644 index 0000000..dd0634e --- /dev/null +++ b/src/client/component/gsc/script_extension.cpp @@ -0,0 +1,324 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "game/scripting/functions.hpp" + +#include +#include + +#include "component/console.hpp" +#include "component/scripting.hpp" +#include "component/notifies.hpp" +#include "component/command.hpp" + +#include "script_extension.hpp" +#include "script_error.hpp" +#include "script_loading.hpp" + +namespace gsc +{ + std::uint16_t function_id_start = 0x25D; + std::uint16_t method_id_start = 0x8429; + + void* func_table[0x1000]; + + const game::dvar_t* developer_script = nullptr; + + namespace + { + #define RVA(ptr) static_cast(reinterpret_cast(ptr) - 0x140000000) + + struct gsc_error : public std::runtime_error + { + using std::runtime_error::runtime_error; + }; + + std::unordered_map functions; + + bool force_error_print = false; + std::optional gsc_error_msg; + + unsigned int scr_get_function_stub(const char** p_name, int* type) + { + const auto result = utils::hook::invoke(0x1403CD9F0, p_name, type); + + for (const auto& [name, func] : functions) + { + game::Scr_RegisterFunction(func, 0, name); + } + + return result; + } + + void execute_custom_function(game::BuiltinFunction function) + { + auto error = false; + + try + { + function(); + } + catch (const std::exception& ex) + { + error = true; + force_error_print = true; + gsc_error_msg = ex.what(); + } + + if (error) + { + game::Scr_ErrorInternal(); + } + } + + void vm_call_builtin_function(const std::uint32_t index) + { + const auto func = reinterpret_cast(scripting::get_function_by_index(index)); + + const auto custom = functions.contains(static_cast(index)); + if (!custom) + { + func(); + } + else + { + execute_custom_function(func); + } + } + + void builtin_call_error(const std::string& error) + { + const auto pos = game::scr_function_stack->pos; + const auto function_id = *reinterpret_cast(reinterpret_cast(pos - 2)); + + if (function_id > 0x1000) + { + console::warn("in call to builtin method \"%s\"%s", gsc_ctx->meth_name(function_id).data(), error.data()); + } + else + { + console::warn("in call to builtin function \"%s\"%s", gsc_ctx->func_name(function_id).data(), error.data()); + } + } + + std::optional get_opcode_name(const std::uint8_t opcode) + { + try + { + const auto index = gsc_ctx->opcode_enum(opcode); + return {gsc_ctx->opcode_name(index)}; + } + catch (...) + { + return {}; + } + } + + void print_callstack() + { + for (auto frame = game::scr_VmPub->function_frame; frame != game::scr_VmPub->function_frame_start; --frame) + { + const auto pos = frame == game::scr_VmPub->function_frame ? game::scr_function_stack->pos : frame->fs.pos; + const auto function = find_function(frame->fs.pos); + + if (function.has_value()) + { + console::warn("\tat function \"%s\" in file \"%s.gsc\"\n", function.value().first.data(), function.value().second.data()); + } + else + { + console::warn("\tat unknown location %p\n", pos); + } + } + } + + void vm_error_stub(int mark_pos) + { + if (!developer_script->current.enabled && !force_error_print) + { + utils::hook::invoke(0x1404E4D00, mark_pos); + return; + } + + console::warn("******* script runtime error ********\n"); + const auto opcode_id = *reinterpret_cast(0x144D57840); + + const std::string error = gsc_error_msg.has_value() ? std::format(": {}", gsc_error_msg.value()) : std::string(); + + if ((opcode_id >= 0x1A && opcode_id <= 0x20) || (opcode_id >= 0xA8 && opcode_id <= 0xAE)) + { + builtin_call_error(error); + } + else + { + const auto opcode = get_opcode_name(opcode_id); + if (opcode.has_value()) + { + console::warn("while processing instruction %s%s\n", opcode.value().data(), error.data()); + } + else + { + console::warn("while processing instruction 0x%X%s\n", opcode_id, error.data()); + } + } + + force_error_print = false; + gsc_error_msg = {}; + + print_callstack(); + console::warn("************************************\n"); + utils::hook::invoke(0x1404E4D00, mark_pos); + } + + void inc_in_param() + { + game::Scr_ClearOutParams(); + + if (game::scr_VmPub->top == game::scr_VmPub->maxstack) + { + game::Sys_Error("Internal script stack overflow"); + } + + ++game::scr_VmPub->top; + ++game::scr_VmPub->inparamcount; + } + + void add_code_pos(const char* pos) + { + inc_in_param(); + game::scr_VmPub->top->type = game::VAR_FUNCTION; + game::scr_VmPub->top->u.codePosValue = pos; + } + + void scr_print() + { + for (auto i = 0u; i < game::Scr_GetNumParam(); ++i) + { + console::info("%s", game::Scr_GetString(i)); + } + } + + void scr_print_ln() + { + for (auto i = 0u; i < game::Scr_GetNumParam(); ++i) + { + console::info("%s", game::Scr_GetString(i)); + } + + console::info("\n"); + } + + void assert_cmd() + { + if (!game::Scr_GetInt(0)) + { + scr_error("Assert fail"); + } + } + + void assert_ex_cmd() + { + if (!game::Scr_GetInt(0)) + { + scr_error(utils::string::va("Assert fail: %s", game::Scr_GetString(1))); + } + } + + void assert_msg_cmd() + { + scr_error(utils::string::va("Assert fail: %s", game::Scr_GetString(0))); + } + + const char* get_code_pos(const int index) + { + if (static_cast(index) >= game::scr_VmPub->outparamcount) + { + scr_error("Scr_GetCodePos: index is out of range"); + return ""; + } + + const auto* value = &game::scr_VmPub->top[-index]; + + if (value->type != game::VAR_FUNCTION) + { + scr_error("Scr_GetCodePos requires a function as parameter"); + return ""; + } + + return value->u.codePosValue; + } + } + + void add_function(const std::string& name, game::BuiltinFunction function) + { + ++function_id_start; + functions[function_id_start] = function; + gsc_ctx->func_add(name, function_id_start); + } + + void scr_error(const char* error) + { + force_error_print = true; + gsc_error_msg = error; + + game::Scr_ErrorInternal(); + } + + class extension final : public component_interface + { + public: + void post_unpack() override + { + utils::hook::set(SELECT_VALUE(0x14086F468, 0x1409E6CE8), scr_print); + utils::hook::set(SELECT_VALUE(0x14086F480, 0x1409E6D00), scr_print_ln); + + utils::hook::set(SELECT_VALUE(0x1403D353C, 0x14042E33C), 0x1000); // Scr_RegisterFunction + + utils::hook::set(SELECT_VALUE(0x1403D3542 + 4, 0x14042E342 + 4), RVA(&func_table)); // Scr_RegisterFunction + utils::hook::set(SELECT_VALUE(0x1403E0BDD + 3, 0x14043BBBE + 3), RVA(&func_table)); // VM_Execute_0 + utils::hook::inject(SELECT_VALUE(0x1403D38E4 + 3, 0x14042E734 + 3), &func_table); // Scr_BeginLoadScripts + + if (game::environment::is_sp()) + { + return; + } + + developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments"); + + utils::hook::nop(0x14043BBBE + 5, 2); + utils::hook::call(0x14043BBBE, vm_call_builtin_function); + + utils::hook::call(0x14043CEB1, vm_error_stub); + + utils::hook::call(0x14042E76F, scr_get_function_stub); + + utils::hook::set(0x1409E6E38, assert_ex_cmd); + utils::hook::set(0x1409E6E50, assert_msg_cmd); + utils::hook::set(0x1409E6E20, assert_cmd); + + add_function("replacefunc", [] + { + if (scr_get_type(0) != game::VAR_FUNCTION || scr_get_type(1) != game::VAR_FUNCTION) + { + throw gsc_error("Parameter must be a function"); + } + + notifies::set_gsc_hook(get_code_pos(0), get_code_pos(1)); + }); + + add_function("executecommand", [] + { + const auto* cmd = game::Scr_GetString(0); + command::execute(cmd); + }); + + add_function("isdedicated", [] + { + game::Scr_AddInt(game::environment::is_dedi()); + }); + } + }; +} + +REGISTER_COMPONENT(gsc::extension) diff --git a/src/client/component/gsc/script_extension.hpp b/src/client/component/gsc/script_extension.hpp new file mode 100644 index 0000000..0c07e9c --- /dev/null +++ b/src/client/component/gsc/script_extension.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace gsc +{ + extern void* func_table[0x1000]; + + extern const game::dvar_t* developer_script; + + void add_function(const std::string& name, game::BuiltinFunction function); + + void scr_error(const char* error); +} diff --git a/src/client/component/gsc/script_loading.cpp b/src/client/component/gsc/script_loading.cpp new file mode 100644 index 0000000..ea0c52e --- /dev/null +++ b/src/client/component/gsc/script_loading.cpp @@ -0,0 +1,369 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include +#include +#include +#include + +#include "component/filesystem.hpp" +#include "component/console.hpp" +#include "component/scripting.hpp" +#include "component/fastfiles.hpp" + +#include "script_loading.hpp" + +namespace gsc +{ + std::unique_ptr gsc_ctx; + + namespace + { + std::unordered_map main_handles; + std::unordered_map init_handles; + + std::unordered_map loaded_scripts; + utils::memory::allocator script_allocator; + + const game::dvar_t* developer_script; + + void clear() + { + main_handles.clear(); + init_handles.clear(); + loaded_scripts.clear(); + script_allocator.clear(); + } + + bool read_raw_script_file(const std::string& name, std::string* data) + { + if (filesystem::read_file(name, data)) + { + return true; + } + + // This will prevent 'fake' GSC raw files from being compiled. + // They are parsed by the game's own parser later as they are special files. + if (name.starts_with("maps/createfx") || name.starts_with("maps/createart") || + (name.starts_with("maps/mp") && name.ends_with("_fx.gsc"))) + { + return false; + } + + const auto* name_str = name.data(); + if (game::DB_XAssetExists(game::ASSET_TYPE_RAWFILE, name_str) && + !game::DB_IsXAssetDefault(game::ASSET_TYPE_RAWFILE, name_str)) + { + const auto asset = game::DB_FindXAssetHeader(game::ASSET_TYPE_RAWFILE, name.data(), false); + const auto len = game::DB_GetRawFileLen(asset.rawfile); + data->resize(len); + game::DB_GetRawBuffer(asset.rawfile, data->data(), len); + if (len > 0) + { + data->pop_back(); + } + + return true; + } + + return false; + } + + game::ScriptFile* load_custom_script(const char* file_name, const std::string& real_name) + { + if (const auto itr = loaded_scripts.find(real_name); itr != loaded_scripts.end()) + { + return itr->second; + } + + try + { + auto& compiler = gsc_ctx->compiler(); + auto& assembler = gsc_ctx->assembler(); + + std::string source_buffer{}; + if (!read_raw_script_file(real_name + ".gsc", &source_buffer)) + { + return nullptr; + } + + console::info("Compiling script '%s'\n", real_name.data()); + + std::vector data; + data.assign(source_buffer.begin(), source_buffer.end()); + + const auto assembly_ptr = compiler.compile(real_name, data); + // Pair of two buffers. First is the byte code and second is the stack + const auto output_script = assembler.assemble(*assembly_ptr); + + const auto script_file_ptr = static_cast(script_allocator.allocate(sizeof(game::ScriptFile))); + script_file_ptr->name = file_name; + + script_file_ptr->bytecodeLen = static_cast(std::get<0>(output_script).size); + script_file_ptr->len = static_cast(std::get<1>(output_script).size); + + const auto byte_code_size = static_cast(std::get<0>(output_script).size + 1); + const auto stack_size = static_cast(std::get<1>(output_script).size + 1); + + script_file_ptr->buffer = static_cast(script_allocator.allocate(stack_size)); + std::memcpy(const_cast(script_file_ptr->buffer), std::get<1>(output_script).data, std::get<1>(output_script).size); + + script_file_ptr->bytecode = static_cast(game::PMem_AllocFromSource_NoDebug(byte_code_size, 4, 1, game::PMEM_SOURCE_SCRIPT)); + std::memcpy(script_file_ptr->bytecode, std::get<0>(output_script).data, std::get<0>(output_script).size); + + script_file_ptr->compressedLen = 0; + + loaded_scripts[real_name] = script_file_ptr; + + return script_file_ptr; + } + catch (const std::exception& ex) + { + console::error("*********** script compile error *************\n"); + console::error("failed to compile '%s':\n%s", real_name.data(), ex.what()); + console::error("**********************************************\n"); + return nullptr; + } + } + + std::string get_script_file_name(const std::string& name) + { + const auto id = gsc_ctx->token_id(name); + if (!id) + { + return name; + } + + return std::to_string(id); + } + + std::pair> read_compiled_script_file(const std::string& name, const std::string& real_name) + { + const auto* script_file = game::DB_FindXAssetHeader(game::ASSET_TYPE_SCRIPTFILE, name.data(), false).scriptfile; + if (!script_file) + { + throw std::runtime_error(std::format("Could not load scriptfile '{}'", real_name)); + } + + console::info("Decompiling scriptfile '%s'\n", real_name.data()); + + const auto len = script_file->compressedLen; + const std::string stack{script_file->buffer, static_cast(len)}; + + const auto decompressed_stack = utils::compression::zlib::decompress(stack); + + std::vector stack_data; + stack_data.assign(decompressed_stack.begin(), decompressed_stack.end()); + + return {{script_file->bytecode, static_cast(script_file->bytecodeLen)}, stack_data}; + } + + void load_script(const std::string& name) + { + if (!game::Scr_LoadScript(name.data())) + { + return; + } + + const auto main_handle = game::Scr_GetFunctionHandle(name.data(), gsc_ctx->token_id("main")); + const auto init_handle = game::Scr_GetFunctionHandle(name.data(), gsc_ctx->token_id("init")); + + if (main_handle) + { + console::info("Loaded '%s::main'\n", name.data()); + main_handles[name] = main_handle; + } + + if (init_handle) + { + console::info("Loaded '%s::init'\n", name.data()); + init_handles[name] = init_handle; + } + } + + void load_scripts(const std::filesystem::path& root_dir) + { + const std::filesystem::path script_dir = root_dir / "scripts"; + if (!utils::io::directory_exists(script_dir.generic_string())) + { + return; + } + + const auto scripts = utils::io::list_files(script_dir.generic_string()); + for (const auto& script : scripts) + { + if (!script.ends_with(".gsc")) + { + continue; + } + + std::filesystem::path path(script); + const auto relative = path.lexically_relative(root_dir).generic_string(); + const auto base_name = relative.substr(0, relative.size() - 4); + + load_script(base_name); + } + } + + int db_is_x_asset_default(game::XAssetType type, const char* name) + { + if (loaded_scripts.contains(name)) + { + return 0; + } + + return game::DB_IsXAssetDefault(type, name); + } + + void gscr_load_game_type_script_stub() + { + utils::hook::invoke(0x1403CCB10); + + clear(); + + for (const auto& path : filesystem::get_search_paths()) + { + load_scripts(path); + } + } + + void db_get_raw_buffer_stub(const game::RawFile* rawfile, char* buf, const int size) + { + if (rawfile->len > 0 && rawfile->compressedLen == 0) + { + std::memset(buf, 0, size); + std::memcpy(buf, rawfile->buffer, std::min(rawfile->len, size)); + return; + } + + game::DB_GetRawBuffer(rawfile, buf, size); + } + + void g_load_structs_stub() + { + for (auto& function_handle : main_handles) + { + console::info("Executing '%s::main'\n", function_handle.first.data()); + const auto thread = game::Scr_ExecThread(static_cast(function_handle.second), 0); + game::RemoveRefToObject(thread); + } + + utils::hook::invoke(0x1403D2CA0); + } + + void scr_load_level_stub() + { + utils::hook::invoke(0x1403CDC60); + + for (auto& function_handle : init_handles) + { + console::info("Executing '%s::init'\n", function_handle.first.data()); + const auto thread = game::Scr_ExecThread(static_cast(function_handle.second), 0); + game::RemoveRefToObject(thread); + } + } + + void scr_begin_load_scripts_stub() + { + const auto comp_mode = developer_script->current.enabled ? + xsk::gsc::build::dev : + xsk::gsc::build::prod; + + gsc_ctx->init(comp_mode, []([[maybe_unused]] auto const* ctx, const auto& included_path) -> std::pair> + { + const auto script_name = std::filesystem::path(included_path).replace_extension().string(); + + std::string file_buffer; + if (!read_raw_script_file(included_path, &file_buffer) || file_buffer.empty()) + { + const auto name = get_script_file_name(script_name); + if (game::DB_XAssetExists(game::ASSET_TYPE_SCRIPTFILE, name.data())) + { + return read_compiled_script_file(name, script_name); + } + + throw std::runtime_error(std::format("Could not load gsc file '{}'", script_name)); + } + + std::vector script_data; + script_data.assign(file_buffer.begin(), file_buffer.end()); + + return {{}, script_data}; + }); + + utils::hook::invoke(SELECT_VALUE(0x1403D3860, 0x14042E6B0)); + } + + void scr_end_load_scripts_stub() + { + gsc_ctx->cleanup(); + + utils::hook::invoke(SELECT_VALUE(0x140603C00, 0x14042E7E0)); + } + } + + game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default) + { + std::string real_name = name; + const auto id = static_cast(std::strtol(name, nullptr, 10)); + if (id) + { + real_name = gsc_ctx->token_name(id); + } + + auto* script = load_custom_script(name, real_name); + if (script) + { + return script; + } + + return game::DB_FindXAssetHeader(type, name, allow_create_default).scriptfile; + } + + class loading final : public component_interface + { + public: + loading() + { + gsc_ctx = std::make_unique(); + } + + void post_unpack() override + { + // Load our scripts with an uncompressed stack + utils::hook::call(SELECT_VALUE(0x1403DC8F0, 0x140437940), db_get_raw_buffer_stub); + + utils::hook::call(SELECT_VALUE(0x14032D1E0, 0x1403CCED9), scr_begin_load_scripts_stub); // GScr_LoadScripts + utils::hook::call(SELECT_VALUE(0x14032D345, 0x1403CD08D), scr_end_load_scripts_stub); // GScr_LoadScripts + + developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments"); + + if (game::environment::is_sp()) + { + return; + } + + // ProcessScript + utils::hook::call(0x1404378D7, find_script); + utils::hook::call(0x1404378E7, db_is_x_asset_default); + + // GScr_LoadScripts + utils::hook::call(0x1403CD009, gscr_load_game_type_script_stub); + + // Exec script handles + utils::hook::call(0x14039F64E, g_load_structs_stub); + utils::hook::call(0x14039F653, scr_load_level_stub); + + scripting::on_shutdown([](int free_scripts) + { + if (free_scripts) + { + clear(); + } + }); + } + }; +} + +REGISTER_COMPONENT(gsc::loading) diff --git a/src/client/component/gsc/script_loading.hpp b/src/client/component/gsc/script_loading.hpp new file mode 100644 index 0000000..342ecaf --- /dev/null +++ b/src/client/component/gsc/script_loading.hpp @@ -0,0 +1,9 @@ +#pragma once +#include + +namespace gsc +{ + extern std::unique_ptr gsc_ctx; + + game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default); +} diff --git a/src/client/component/input.cpp b/src/client/component/input.cpp new file mode 100644 index 0000000..6c3ecb9 --- /dev/null +++ b/src/client/component/input.cpp @@ -0,0 +1,59 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "game_console.hpp" +#include "server_list.hpp" + +#include + +namespace input +{ + namespace + { + utils::hook::detour cl_char_event_hook; + utils::hook::detour cl_key_event_hook; + + void cl_char_event_stub(const int local_client_num, const int key) + { + if (!game_console::console_char_event(local_client_num, key)) + { + return; + } + + cl_char_event_hook.invoke(local_client_num, key); + } + + void cl_key_event_stub(const int local_client_num, const int key, const int down) + { + if (!game_console::console_key_event(local_client_num, key, down)) + { + return; + } + + if (game::environment::is_mp() && !server_list::sl_key_event(key, down)) + { + return; + } + + cl_key_event_hook.invoke(local_client_num, key, down); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + cl_char_event_hook.create(SELECT_VALUE(0x14023CE50, 0x1402C2AE0), cl_char_event_stub); + cl_key_event_hook.create(SELECT_VALUE(0x14023D070, 0x1402C2CE0), cl_key_event_stub); + } + }; +} + +REGISTER_COMPONENT(input::component) diff --git a/src/client/component/localized_strings.cpp b/src/client/component/localized_strings.cpp new file mode 100644 index 0000000..00e8910 --- /dev/null +++ b/src/client/component/localized_strings.cpp @@ -0,0 +1,66 @@ +#include +#include "loader/component_loader.hpp" +#include "localized_strings.hpp" +#include +#include +#include "game/game.hpp" + +namespace localized_strings +{ + namespace + { + utils::hook::detour seh_string_ed_get_string_hook; + + std::unordered_map& get_localized_overrides() + { + static std::unordered_map overrides; + return overrides; + } + + std::mutex& get_synchronization_mutex() + { + static std::mutex mutex; + return mutex; + } + + const char* seh_string_ed_get_string(const char* reference) + { + std::lock_guard _(get_synchronization_mutex()); + + auto& overrides = get_localized_overrides(); + const auto entry = overrides.find(reference); + if (entry != overrides.end()) + { + return utils::string::va("%s", entry->second.data()); + } + + return seh_string_ed_get_string_hook.invoke(reference); + } + + unsigned int g_localized_string_index_stub(const char* name, /*ConfigString*/ unsigned int start, + unsigned int max, int create, + const char* errormsg) + { + create = 1; + return game::G_FindConfigstringIndex(name, start, max, create, errormsg); + } + } + + void override(const std::string& key, const std::string& value) + { + std::lock_guard _(get_synchronization_mutex()); + get_localized_overrides()[key] = value; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Change some localized strings + seh_string_ed_get_string_hook.create(SELECT_VALUE(0x1403F42D0, 0x1404A5F60), &seh_string_ed_get_string); + } + }; +} + +REGISTER_COMPONENT(localized_strings::component) diff --git a/src/client/component/localized_strings.hpp b/src/client/component/localized_strings.hpp new file mode 100644 index 0000000..47c4389 --- /dev/null +++ b/src/client/component/localized_strings.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace localized_strings +{ + void override(const std::string& key, const std::string& value); +} diff --git a/src/client/component/logger.cpp b/src/client/component/logger.cpp new file mode 100644 index 0000000..1449658 --- /dev/null +++ b/src/client/component/logger.cpp @@ -0,0 +1,159 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "console.hpp" + +#include + +namespace logger +{ + namespace + { + utils::hook::detour com_error_hook; + + const game::dvar_t* logger_dev = nullptr; + + void print_com_error(int, const char* msg, ...) + { + char buffer[2048]{}; + va_list ap; + + va_start(ap, msg); + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + va_end(ap); + + console::error("%s", buffer); + } + + void com_error_stub(const int error, const char* msg, ...) + { + char buffer[2048]{}; + va_list ap; + + va_start(ap, msg); + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + va_end(ap); + + console::error("Error: %s\n", buffer); + + com_error_hook.invoke(error, "%s", buffer); + } + + void print_warning(const char* msg, ...) + { + char buffer[2048]{}; + va_list ap; + + va_start(ap, msg); + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + va_end(ap); + + console::warn("%s", buffer); + } + + void print(const char* msg, ...) + { + char buffer[2048]{}; + va_list ap; + + va_start(ap, msg); + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + va_end(ap); + + console::info("%s", buffer); + } + + void print_dev(const char* msg, ...) + { + if (!logger_dev->current.enabled) + { + return; + } + + char buffer[2048]{}; + va_list ap; + + va_start(ap, msg); + vsnprintf_s(buffer, _TRUNCATE, msg, ap); + va_end(ap); + + console::info("%s", buffer); + } + + // nullsub_56 -> nullsub_16 (iw6) + void nullsub_16() + { + utils::hook::call(0x1401CCBD2, print_warning); + utils::hook::call(0x1401CCBDE, print_warning); + utils::hook::call(0x1401CCBE6, print_warning); + utils::hook::call(0x1401CCBF2, print_warning); + + utils::hook::call(0x1401CCE48, print_warning); + utils::hook::call(0x1401CCE54, print_warning); + utils::hook::call(0x1401CCE5C, print_warning); + utils::hook::call(0x1401CCE68, print_warning); + + utils::hook::call(0x1401CD0AD, print_warning); + utils::hook::call(0x1401CD0B9, print_warning); + utils::hook::call(0x1401CD0C1, print_warning); + utils::hook::call(0x1401CD0CD, print_warning); + + utils::hook::call(0x1401CF46D, print_warning); + utils::hook::call(0x1401CF479, print_warning); + utils::hook::call(0x1401CF481, print_warning); + utils::hook::call(0x1401CF48D, print_warning); + + utils::hook::call(0x1401D02B8, print_warning); + utils::hook::call(0x1401D02D8, print_warning); + utils::hook::call(0x1401D02E4, print_warning); + + utils::hook::call(0x1401D0388, print_warning); + utils::hook::call(0x1401D03A8, print_warning); + utils::hook::call(0x1401D03B4, print_warning); + utils::hook::call(0x1401D03CD, print_warning); + + utils::hook::call(0x1401D1884, print_warning); + utils::hook::call(0x1401D1A36, print_warning); + } + + // sub_1400E7420 -> sub_1401DAA40 + void sub_1401DAA40() + { + utils::hook::call(0x1401C9CAE, print_warning); + utils::hook::call(0x1401CC7F5, print_warning); + utils::hook::call(0x1401CC97E, print_warning); + utils::hook::call(0x1401CE43C, print_dev); // lua start up + utils::hook::call(0x1401CF7E4, print_dev); + utils::hook::call(0x1401D15BA, print_dev); // lua memory used + utils::hook::call(0x1401D24BC, print_dev); // lui shutting down + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_mp()) + { + nullsub_16(); + sub_1401DAA40(); + } + + if (!game::environment::is_sp()) + { + utils::hook::call(0x140501AE3, print_com_error); + } + + com_error_hook.create(game::Com_Error, com_error_stub); + + // Make havok script's print function actually print + utils::hook::jump(SELECT_VALUE(0x1406283A4, 0x140732184), print); + + logger_dev = game::Dvar_RegisterBool("logger_dev", false, game::DVAR_FLAG_SAVED, "Print dev stuff"); + } + }; +} + +REGISTER_COMPONENT(logger::component) diff --git a/src/client/component/map_rotation.cpp b/src/client/component/map_rotation.cpp new file mode 100644 index 0000000..5fd4b4a --- /dev/null +++ b/src/client/component/map_rotation.cpp @@ -0,0 +1,292 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "scheduler.hpp" +#include "map_rotation.hpp" + +#include +#include + +namespace map_rotation +{ + namespace + { + rotation_data dedicated_rotation; + + const game::dvar_t* sv_map_rotation; + const game::dvar_t* sv_map_rotation_current; + const game::dvar_t* sv_random_map_rotation; + + void set_gametype(const std::string& gametype) + { + assert(!gametype.empty()); + + auto* g_gametype = game::Dvar_FindVar("g_gametype"); + game::Dvar_SetString(g_gametype, gametype.data()); + } + + void launch_map(const std::string& mapname) + { + assert(!mapname.empty()); + + command::execute(utils::string::va("map %s", mapname.data()), false); + } + + void launch_default_map() + { + auto* mapname = game::Dvar_FindVar("mapname"); + if (mapname && *mapname->current.string) + { + launch_map(mapname->current.string); + } + else + { + launch_map("mp_prisonbreak"); + } + } + + void apply_rotation(rotation_data& rotation) + { + assert(!rotation.empty()); + + std::size_t i = 0; + while (i < rotation.get_entries_size()) + { + const auto& entry = rotation.get_next_entry(); + if (entry.first == "map"s) + { + console::info("Loading new map: '%s'\n", entry.second.data()); + launch_map(entry.second); + + // Map was found so we exit the loop + break; + } + + if (entry.first == "gametype"s) + { + console::info("Applying new gametype: '%s'\n", entry.second.data()); + set_gametype(entry.second); + } + + ++i; + } + + if (i == rotation.get_entries_size()) + { + console::error("Map rotation does not contain any map. Restarting\n"); + launch_default_map(); + } + } + + void load_rotation(const std::string& data) + { + static auto loaded = false; + if (loaded) + { + return; + } + + loaded = true; + try + { + dedicated_rotation.parse(data); + } + catch (const std::exception& ex) + { + console::error("%s: %s contains invalid data!\n", ex.what(), sv_map_rotation->name); + } +#ifdef _DEBUG + console::info("dedicated_rotation size after parsing is '%llu'", dedicated_rotation.get_entries_size()); +#endif + } + + void load_map_rotation() + { + const std::string map_rotation = sv_map_rotation->current.string; + if (!map_rotation.empty()) + { +#ifdef _DEBUG + console::info("%s is not empty. Parsing...\n", sv_map_rotation->name); +#endif + load_rotation(map_rotation); + } + } + + void apply_map_rotation_current(const std::string& data) + { + assert(!data.empty()); + + rotation_data rotation_current; + + try + { + rotation_current.parse(data); + } + catch (const std::exception& ex) + { + console::error("%s: %s contains invalid data!\n", ex.what(), sv_map_rotation_current->name); + } + + game::Dvar_SetString(sv_map_rotation_current, ""); + + if (rotation_current.empty()) + { + console::warn("%s is empty or contains invalid data\n", sv_map_rotation_current->name); + launch_default_map(); + return; + } + + apply_rotation(rotation_current); + } + + void randomize_map_rotation() + { + if (sv_random_map_rotation->current.enabled) + { + console::info("Randomizing the map rotation\n"); + dedicated_rotation.randomize(); + } + } + + void perform_map_rotation() + { + if (game::Live_SyncOnlineDataFlags(0) != 0) + { + scheduler::on_game_initialized(perform_map_rotation, scheduler::pipeline::main, 1s); + return; + } + + console::info("Rotating map...\n"); + + // This takes priority because of backwards compatibility + const std::string map_rotation_current = sv_map_rotation_current->current.string; + if (!map_rotation_current.empty()) + { +#ifdef _DEBUG + console::info("Applying %s\n", sv_map_rotation_current->name); +#endif + apply_map_rotation_current(map_rotation_current); + return; + } + + load_map_rotation(); + if (dedicated_rotation.empty()) + { + console::warn("%s is empty or contains invalid data. Restarting map\n", sv_map_rotation->name); + launch_default_map(); + return; + } + + randomize_map_rotation(); + + apply_rotation(dedicated_rotation); + } + + void trigger_map_rotation() + { + scheduler::schedule([] + { + if (game::CL_IsCgameInitialized()) + { + return scheduler::cond_continue; + } + + command::execute("map_rotate", false); + return scheduler::cond_end; + }, scheduler::pipeline::main, 1s); + } + } + + rotation_data::rotation_data() + : index_(0) + { + } + + void rotation_data::randomize() + { + std::random_device rd; + std::mt19937 gen(rd()); + + std::ranges::shuffle(this->rotation_entries_, gen); + } + + void rotation_data::add_entry(const std::string& key, const std::string& value) + { + this->rotation_entries_.emplace_back(std::make_pair(key, value)); + } + + bool rotation_data::contains(const std::string& key, const std::string& value) const + { + return std::ranges::any_of(this->rotation_entries_, [&](const auto& entry) + { + return entry.first == key && entry.second == value; + }); + } + + bool rotation_data::empty() const noexcept + { + return this->rotation_entries_.empty(); + } + + std::size_t rotation_data::get_entries_size() const noexcept + { + return this->rotation_entries_.size(); + } + + rotation_data::rotation_entry& rotation_data::get_next_entry() + { + const auto index = this->index_; + ++this->index_ %= this->rotation_entries_.size(); + return this->rotation_entries_.at(index); + } + + void rotation_data::parse(const std::string& data) + { + const auto tokens = utils::string::split(data, ' '); + for (std::size_t i = 0; !tokens.empty() && i < (tokens.size() - 1); i += 2) + { + const auto& key = tokens[i]; + const auto& value = tokens[i + 1]; + + if (key == "map"s || key == "gametype"s) + { + this->add_entry(key, value); + } + else + { + throw map_rotation_parse_error(); + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_dedi()) + { + return; + } + + scheduler::once([] + { + sv_map_rotation = game::Dvar_RegisterString("sv_mapRotation", "", game::DvarFlags::DVAR_FLAG_NONE, ""); + sv_map_rotation_current = game::Dvar_RegisterString("sv_mapRotationCurrent", "", game::DvarFlags::DVAR_FLAG_NONE, ""); + }, scheduler::pipeline::main); + + sv_random_map_rotation = game::Dvar_RegisterBool("sv_randomMapRotation", false, game::DVAR_FLAG_NONE, "Randomize map rotation"); + + command::add("map_rotate", &perform_map_rotation); + + // Hook SV_MatchEnd in GScr_ExitLevel + utils::hook::jump(0x1403CBC30, &trigger_map_rotation); + //utils::hook::call(0x1403CBC6C, &trigger_map_rotation); + } + }; +} + +REGISTER_COMPONENT(map_rotation::component) diff --git a/src/client/component/map_rotation.hpp b/src/client/component/map_rotation.hpp new file mode 100644 index 0000000..e454dea --- /dev/null +++ b/src/client/component/map_rotation.hpp @@ -0,0 +1,34 @@ +#pragma once + +namespace map_rotation +{ + struct map_rotation_parse_error : public std::exception + { + [[nodiscard]] const char* what() const noexcept override { return "Map Rotation Parse Error"; } + }; + + class rotation_data + { + public: + using rotation_entry = std::pair; + + rotation_data(); + + void randomize(); + + // In case a new way to enrich the map rotation is added (other than sv_mapRotation) + // this method should be called to add a new entry (gamemode/map & value) + void add_entry(const std::string& key, const std::string& value); + + [[nodiscard]] bool contains(const std::string& key, const std::string& value) const; + [[nodiscard]] bool empty() const noexcept; + [[nodiscard]] std::size_t get_entries_size() const noexcept; + [[nodiscard]] rotation_entry& get_next_entry(); + + void parse(const std::string& data); + + private: + std::vector rotation_entries_; + std::size_t index_; + }; +} diff --git a/src/client/component/musical_talent.cpp b/src/client/component/musical_talent.cpp new file mode 100644 index 0000000..c608159 --- /dev/null +++ b/src/client/component/musical_talent.cpp @@ -0,0 +1,49 @@ +#include +#include "loader/component_loader.hpp" +#include "game_module.hpp" + +#include "game/game.hpp" + +#include + +namespace musical_talent +{ + namespace + { + bool is_main_menu_music(game::StreamedSound* sound) + { + return sound->filename.fileIndex == 1 && sound->filename.info.packed.offset == 0xBBAD000; + } + + void open_sound_handle_stub(HANDLE* handle, game::StreamedSound* sound) + { + if (is_main_menu_music(sound)) + { + const auto folder = game_module::get_host_module().get_folder(); + const auto file = folder + "/data/sound/patch-3-music.flac"; + *handle = CreateFileA(file.data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, nullptr); + } + else + { + return reinterpret_cast(0x1404F8B90)(handle, sound); + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_mp()) + { + return; + } + + utils::hook::call(0x1404903BD, open_sound_handle_stub); + } + }; +} + +REGISTER_COMPONENT(musical_talent::component) diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp new file mode 100644 index 0000000..e8d2436 --- /dev/null +++ b/src/client/component/network.cpp @@ -0,0 +1,291 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "command.hpp" +#include "network.hpp" +#include "console.hpp" + +#include +#include + +namespace network +{ + namespace + { + std::unordered_map& get_callbacks() + { + static std::unordered_map callbacks{}; + return callbacks; + } + + bool handle_command(game::netadr_s* address, const char* command, game::msg_t* message) + { + const auto cmd_string = utils::string::to_lower(command); + auto& callbacks = get_callbacks(); + const auto handler = callbacks.find(cmd_string); + const auto offset = cmd_string.size() + 5; + if (message->cursize < offset || handler == callbacks.end()) + { + return false; + } + + const std::string data(message->data + offset, message->cursize - offset); + + handler->second(*address, data); + return true; + } + + void handle_command_stub(utils::hook::assembler& a) + { + const auto return_unhandled = a.newLabel(); + + a.pushad64(); + + a.mov(r8, rsi); // message + a.mov(rdx, rdi); // command + a.mov(rcx, r14); // netaddr + + a.call_aligned(handle_command); + + a.test(al, al); + a.jz(return_unhandled); + + // Command handled + a.popad64(); + a.jmp(0x1402C6DE8); + + a.bind(return_unhandled); + a.popad64(); + a.jmp(0x1402C64EE); + } + + int net_compare_base_address(const game::netadr_s* a1, const game::netadr_s* a2) + { + if (a1->type == a2->type) + { + switch (a1->type) + { + case game::netadrtype_t::NA_BOT: + case game::netadrtype_t::NA_LOOPBACK: + return a1->port == a2->port; + + case game::netadrtype_t::NA_IP: + return !memcmp(a1->ip, a2->ip, 4); + case game::netadrtype_t::NA_BROADCAST: + return true; + default: + break; + } + } + + return false; + } + + int net_compare_address(const game::netadr_s* a1, const game::netadr_s* a2) + { + return net_compare_base_address(a1, a2) && a1->port == a2->port; + } + + void reconnect_migratated_client(game::mp::client_t*, game::netadr_s* from, const int, const int, const char*, + const char*, bool) + { + // This happens when a client tries to rejoin after being recently disconnected, OR by a duplicated guid + // We don't want this to do anything. It decides to crash seemingly randomly + // Rather than try and let the player in, just tell them they are a duplicate player and reject connection + game::NET_OutOfBandPrint(game::NS_SERVER, from, "error\nYou are already connected to the server."); + } + } + + void on(const std::string& command, const callback& callback) + { + get_callbacks()[utils::string::to_lower(command)] = callback; + } + + int dw_send_to_stub(const int size, const char* src, game::netadr_s* addr) + { + sockaddr s = {}; + game::NetadrToSockadr(addr, &s); + return sendto(*game::query_socket, src, size, 0, &s, 16) >= 0; + } + + void send(const game::netadr_s& address, const std::string& command, const std::string& data, const char separator) + { + std::string packet = "\xFF\xFF\xFF\xFF"; + packet.append(command); + packet.push_back(separator); + packet.append(data); + + send_data(address, packet); + } + + void send_data(const game::netadr_s& address, const std::string& data) + { + if (address.type == game::NA_LOOPBACK) + { + game::NET_SendLoopPacket(game::NS_CLIENT1, static_cast(data.size()), data.data(), &address); + } + else + { + game::Sys_SendPacket(static_cast(data.size()), data.data(), &address); + } + } + + bool are_addresses_equal(const game::netadr_s& a, const game::netadr_s& b) + { + return net_compare_address(&a, &b); + } + + const char* net_adr_to_string(const game::netadr_s& a) + { + if (a.type == game::netadrtype_t::NA_LOOPBACK) + { + return "loopback"; + } + + if (a.type == game::netadrtype_t::NA_BOT) + { + return "bot"; + } + + if (a.type == game::netadrtype_t::NA_IP || a.type == game::netadrtype_t::NA_BROADCAST) + { + if (a.port) + { + return utils::string::va("%u.%u.%u.%u:%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3], htons(a.port)); + } + + return utils::string::va("%u.%u.%u.%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3]); + } + + return "bad"; + } + + void set_xuid_config_string_stub(utils::hook::assembler& a) + { + const auto return_regular = a.newLabel(); + + a.mov(rax, ptr(rsp)); + a.mov(r9, 0x140477715); // This is the evil one :( + a.cmp(rax, r9); + a.jne(return_regular); + + // Do the original work + a.call_aligned(return_regular); + + // Jump to success branch + a.mov(rax, 0x14047771E); + a.mov(ptr(rsp), rax); + + a.ret(); + + a.bind(return_regular); + + a.sub(rsp, 0x38); + a.mov(eax, ptr(rcx)); + a.mov(r9d, ptr(rcx, 4)); + a.mov(r10, rdx); + + a.jmp(0x14041DFBD); + } + + game::dvar_t* register_netport_stub(const char* dvarName, int value, int min, int max, unsigned int flags, + const char* description) + { + auto dvar = game::Dvar_RegisterInt("net_port", 27016, 0, 0xFFFFu, game::DVAR_FLAG_LATCHED, "Network port"); + + // read net_port from command line + command::read_startup_variable("net_port"); + + return dvar; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + { + if (game::environment::is_sp()) + { + return; + } + + // redirect dw_sendto to raw socket + utils::hook::jump(0x140501A00, dw_send_to_stub); + + // intercept command handling + utils::hook::jump(0x1402C64CB, utils::hook::assemble(handle_command_stub), true); + + // handle xuid without secure connection + utils::hook::jump(0x14041DFB0, utils::hook::assemble(set_xuid_config_string_stub), true); + + utils::hook::jump(0x14041D010, net_compare_address); + utils::hook::jump(0x14041D060, net_compare_base_address); + + // don't establish secure conenction + utils::hook::set(0x1402ECF1D, 0xEB); + utils::hook::set(0x1402ED02A, 0xEB); + utils::hook::set(0x1402ED34D, 0xEB); + utils::hook::set(0x1402C4A1F, 0xEB); // + + // ignore unregistered connection + utils::hook::jump(0x140471AAC, reinterpret_cast(0x140471A50)); + utils::hook::set(0x140471AF0, 0xEB); + + // disable xuid verification + utils::hook::set(0x140154AA9, 0xEB); + utils::hook::set(0x140154AC3, 0xEB); + + // disable xuid verification + utils::hook::nop(0x140474584, 2); + utils::hook::set(0x1404745DB, 0xEB); + + // ignore configstring mismatch + utils::hook::set(0x1402CCCC7, 0xEB); + + // ignore dw handle in SV_PacketEvent + utils::hook::set(0x14047A17A, 0xEB); + utils::hook::call(0x14047A16E, &net_compare_address); + + // ignore dw handle in SV_FindClientByAddress + utils::hook::set(0x1404799AD, 0xEB); + utils::hook::call(0x1404799A1, &net_compare_address); + + // ignore dw handle in SV_DirectConnect + utils::hook::set(0x1404717BA, 0xEB); + utils::hook::set(0x1404719DF, 0xEB); + utils::hook::call(0x1404717AD, &net_compare_address); + utils::hook::call(0x1404719D2, &net_compare_address); + + // increase cl_maxpackets + utils::hook::set(0x1402C8083, 125); + utils::hook::set(0x1402C808C, 125); + + // ignore impure client + utils::hook::jump(0x140472671, reinterpret_cast(0x1404726F9)); + + // don't send checksum + utils::hook::set(0x140501A63, 0); + + // don't read checksum + utils::hook::jump(0x1405019CB, 0x1405019F3); + + // don't try to reconnect client + utils::hook::call(0x14047197E, reconnect_migratated_client); + + // allow server owner to modify net_port before the socket bind + utils::hook::call(0x140500FD0, register_netport_stub); + + // ignore built in "print" oob command and add in our own + utils::hook::set(0x1402C6AA4, 0xEB); + on("print", [](const game::netadr_s&, const std::string& data) + { + console::info("%s", data.data()); + }); + } + } + }; +} + +REGISTER_COMPONENT(network::component) diff --git a/src/client/component/network.hpp b/src/client/component/network.hpp new file mode 100644 index 0000000..4e6ae49 --- /dev/null +++ b/src/client/component/network.hpp @@ -0,0 +1,47 @@ +#pragma once + +namespace network +{ + using callback = std::function; + + void on(const std::string& command, const callback& callback); + void send(const game::netadr_s& address, const std::string& command, const std::string& data = {}, char separator = ' '); + void send_data(const game::netadr_s& address, const std::string& data); + + bool are_addresses_equal(const game::netadr_s& a, const game::netadr_s& b); + + const char* net_adr_to_string(const game::netadr_s& a); +} + +inline bool operator==(const game::netadr_s& a, const game::netadr_s& b) +{ + return network::are_addresses_equal(a, b); // +} + +inline bool operator!=(const game::netadr_s& a, const game::netadr_s& b) +{ + return !(a == b); // +} + +namespace std +{ + template <> + struct equal_to + { + using result_type = bool; + + bool operator()(const game::netadr_s& lhs, const game::netadr_s& rhs) const + { + return network::are_addresses_equal(lhs, rhs); + } + }; + + template <> + struct hash + { + size_t operator()(const game::netadr_s& x) const noexcept + { + return hash()(*reinterpret_cast(&x.ip[0])) ^ hash()(x.port); + } + }; +} diff --git a/src/client/component/notifies.cpp b/src/client/component/notifies.cpp new file mode 100644 index 0000000..72f35ff --- /dev/null +++ b/src/client/component/notifies.cpp @@ -0,0 +1,197 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "command.hpp" +#include "game_log.hpp" +#include "notifies.hpp" +#include "scheduler.hpp" +#include "scripting.hpp" + +#include + +namespace notifies +{ + bool hook_enabled = true; + + namespace + { + struct gsc_hook + { + const char* target_pos{}; + }; + + std::unordered_map vm_execute_hooks; + + const char* target_function = nullptr; + + void client_command_stub(const int client_num) + { + if (game::mp::g_entities[client_num].client == nullptr) + { + return; + } + + command::params_sv params; + + if (params[0] == "say"s || params[0] == "say_team"s) + { + std::string message(game::ConcatArgs(1)); + + auto msg_index = 0; + if (message[msg_index] == '\x1F') + { + msg_index = 1; + } + + auto hidden = false; + if (message[msg_index] == '/') + { + hidden = true; + + if (msg_index == 1) + { + // Overwrite / with \x1F only if present + message[msg_index] = message[msg_index - 1]; + } + // Skip over the first character + message.erase(message.begin()); + } + + scheduler::once([params, message, client_num] + { + const auto* guid = game::SV_GetGuid(client_num); + const auto* name = game::mp::svs_clients[client_num].name; + + game_log::g_log_printf("%s;%s;%i;%s;%s\n", + params.get(0), + guid, + client_num, + name, + message.data() + ); + + }, scheduler::pipeline::server); + + if (hidden) + { + return; + } + } + + // ClientCommand + utils::hook::invoke(0x1403929B0, client_num); + } + + bool execute_vm_hook(const char* pos) + { + if (!vm_execute_hooks.contains(pos)) + { + hook_enabled = true; + return false; + } + + if (!hook_enabled && pos > reinterpret_cast(vm_execute_hooks.size())) + { + hook_enabled = true; + return false; + } + + const auto hook = vm_execute_hooks[pos]; + target_function = hook.target_pos; + + return true; + } + + void vm_execute_stub(utils::hook::assembler& a) + { + const auto replace = a.newLabel(); + const auto end = a.newLabel(); + + a.pushad64(); + + a.mov(rcx, r14); + a.call_aligned(execute_vm_hook); + + a.cmp(al, 0); + a.jne(replace); + + a.popad64(); + a.jmp(end); + + a.bind(end); + + a.movzx(r15d, byte_ptr(r14)); + a.inc(r14); + a.lea(eax, dword_ptr(r15, -0x17)); + a.mov(dword_ptr(rbp, 0x60), r15d); + + a.jmp(0x14043A593); + + a.bind(replace); + + a.popad64(); + a.mov(rax, qword_ptr(reinterpret_cast(&target_function))); + a.mov(r14, rax); + a.jmp(end); + } + } + + void clear_callbacks() + { + vm_execute_hooks.clear(); + } + + void enable_vm_execute_hook() + { + hook_enabled = true; + } + + void disable_vm_execute_hook() + { + hook_enabled = false; + } + + void set_gsc_hook(const char* source, const char* target) + { + gsc_hook hook; + hook.target_pos = target; + vm_execute_hooks[source] = hook; + } + + void clear_hook(const char* pos) + { + vm_execute_hooks.erase(pos); + } + + std::size_t get_hook_count() + { + return vm_execute_hooks.size(); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + utils::hook::call(0x1404724DD, client_command_stub); + + utils::hook::jump(0x14043A584, utils::hook::assemble(vm_execute_stub), true); + + scripting::on_shutdown([](const bool free_scripts) + { + if (free_scripts) + { + vm_execute_hooks.clear(); + } + }); + } + }; +} + +REGISTER_COMPONENT(notifies::component) diff --git a/src/client/component/notifies.hpp b/src/client/component/notifies.hpp new file mode 100644 index 0000000..0016693 --- /dev/null +++ b/src/client/component/notifies.hpp @@ -0,0 +1,15 @@ +#pragma once + +namespace notifies +{ + extern bool hook_enabled; + + void set_gsc_hook(const char* source, const char* target); + void clear_hook(const char* pos); + std::size_t get_hook_count(); + + void clear_callbacks(); + + void enable_vm_execute_hook(); + void disable_vm_execute_hook(); +} diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp new file mode 100644 index 0000000..bc073e6 --- /dev/null +++ b/src/client/component/party.cpp @@ -0,0 +1,494 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "dvars.hpp" +#include "network.hpp" +#include "scheduler.hpp" +#include "server_list.hpp" +#include "party.hpp" + +#include "steam/steam.hpp" + +#include +#include +#include +#include + +#include + +namespace party +{ + namespace + { + struct + { + game::netadr_s host{}; + std::string challenge{}; + bool hostDefined{false}; + } connect_state; + + utils::hook::detour didyouknow_hook; + + std::string sv_motd; + + int sv_maxclients; + + void connect_to_party(const game::netadr_s& target, const std::string& mapname, const std::string& gametype) + { + if (game::environment::is_sp()) + { + return; + } + + if (game::Live_SyncOnlineDataFlags(0)) + { + scheduler::once([=]() + { + connect_to_party(target, mapname, gametype); + }, scheduler::pipeline::main, 1s); + return; + } + + switch_gamemode_if_necessary(gametype); + perform_game_initialization(); + + // CL_ConnectFromParty + char session_info[0x100] = {}; + reinterpret_cast(0x1402C5700)( + 0, session_info, &target, mapname.data(), gametype.data()); + } + + void disconnect_stub() + { + if (game::CL_IsCgameInitialized()) + { + // CL_ForwardCommandToServer + reinterpret_cast(0x1402C76C0)(0, "disconnect"); + // CL_WritePacket + reinterpret_cast(0x1402C1E70)(0); + } + // CL_Disconnect + reinterpret_cast(0x1402C6240)(0); + } + + const auto drop_reason_stub = utils::hook::assemble([](utils::hook::assembler& a) + { + a.mov(rdx, rdi); + a.mov(ecx, 2); + a.jmp(0x1402C617D); + }); + } + + void switch_gamemode_if_necessary(const std::string& gametype) + { + const auto target_mode = gametype == "aliens" ? game::CODPLAYMODE_ALIENS : game::CODPLAYMODE_CORE; + const auto current_mode = game::Com_GetCurrentCoDPlayMode(); + + if (current_mode != target_mode) + { + switch (target_mode) + { + case game::CODPLAYMODE_CORE: + game::SwitchToCoreMode(); + break; + case game::CODPLAYMODE_ALIENS: + game::SwitchToAliensMode(); + break; + } + } + } + + void perform_game_initialization() + { + // This fixes several crashes and impure client stuff + command::execute("onlinegame 1", true); + command::execute("exec default_xboxlive.cfg", true); + command::execute("xstartprivateparty", true); + command::execute("xblive_privatematch 0", true); + command::execute("startentitlements", true); + } + + int server_client_count() + { + return sv_maxclients; + } + + int get_client_count() + { + auto count = 0; + for (auto i = 0; i < *game::mp::svs_clientCount; ++i) + { + if (game::mp::svs_clients[i].header.state >= game::CS_CONNECTED) + { + ++count; + } + } + + return count; + } + + int get_bot_count() + { + auto count = 0; + for (auto i = 0; i < *game::mp::svs_clientCount; ++i) + { + if (game::mp::svs_clients[i].header.state >= game::CS_CONNECTED && + game::mp::svs_clients[i].testClient != game::TC_NONE) + { + ++count; + } + } + + return count; + } + + game::netadr_s& get_target() + { + return connect_state.host; + } + + void reset_connect_state() + { + connect_state = {}; + } + + int get_client_num_from_name(const std::string& name) + { + for (auto i = 0; !name.empty() && i < *game::mp::svs_clientCount; ++i) + { + if (game::mp::g_entities[i].client) + { + char client_name[16] = {0}; + strncpy_s(client_name, game::mp::g_entities[i].client->sess.cs.name, sizeof(client_name)); + game::I_CleanStr(client_name); + + if (client_name == name) + { + return i; + } + } + } + return -1; + } + + void connect(const game::netadr_s& target) + { + if (game::environment::is_sp()) + { + return; + } + + command::execute("lui_open popup_acceptinginvite", false); + + connect_state.host = target; + connect_state.challenge = utils::cryptography::random::get_challenge(); + connect_state.hostDefined = true; + + network::send(target, "getInfo", connect_state.challenge); + } + + void didyouknow_stub(game::dvar_t* dvar, const char* string) + { + if (dvar->name == "didyouknow"s && !party::sv_motd.empty()) + { + string = party::sv_motd.data(); + } + + return didyouknow_hook.invoke(dvar, string); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + // hook disconnect command function + utils::hook::jump(0x1402C6370, disconnect_stub); + + if (game::environment::is_mp()) + { + // show custom drop reason + utils::hook::nop(0x1402C6100, 13); + utils::hook::jump(0x1402C6100, drop_reason_stub, true); + } + + // enable custom kick reason in GScr_KickPlayer + utils::hook::set(0x1403CBFD0, 0xEB); + + didyouknow_hook.create(game::Dvar_SetString, didyouknow_stub); + + command::add("reconnect", []([[maybe_unused]] const command::params& params) + { + if (!connect_state.hostDefined) + { + console::info("Cannot connect to server.\n"); + return; + } + + if (game::CL_IsCgameInitialized()) + { + command::execute("disconnect"); + command::execute("reconnect"); + } + else + { + connect(connect_state.host); + } + }); + + command::add("connect", [](const command::params& params) + { + if (params.size() != 2) + { + return; + } + + game::netadr_s target{}; + if (game::NET_StringToAdr(params[1], &target)) + { + connect(target); + } + }); + + command::add("clientkick", [](const command::params& params) + { + if (params.size() < 2) + { + console::info("usage: clientkick , (optional)\n"); + return; + } + + if (!game::SV_Loaded()) + { + return; + } + + std::string reason; + if (params.size() > 2) + { + reason = params.join(2); + } + if (reason.empty()) + { + reason = "EXE_PLAYERKICKED"; + } + + const auto client_num = atoi(params.get(1)); + if (client_num < 0 || client_num >= *game::mp::svs_clientCount) + { + return; + } + + scheduler::once([client_num, reason] + { + game::SV_KickClientNum(client_num, reason.data()); + }, scheduler::pipeline::server); + }); + + command::add("kick", [](const command::params& params) + { + if (params.size() < 2) + { + console::info("usage: kick , (optional)\n"); + return; + } + + if (!game::SV_Loaded()) + { + return; + } + + std::string reason; + if (params.size() > 2) + { + reason = params.join(2); + } + if (reason.empty()) + { + reason = "EXE_PLAYERKICKED"; + } + + const std::string name = params.get(1); + if (name == "all"s) + { + for (auto i = 0; i < *game::mp::svs_clientCount; ++i) + { + scheduler::once([i, reason] + { + game::SV_KickClientNum(i, reason.data()); + }, scheduler::pipeline::server); + } + return; + } + + const auto client_num = get_client_num_from_name(name); + if (client_num < 0 || client_num >= *game::mp::svs_clientCount) + { + return; + } + + scheduler::once([client_num, reason] + { + game::SV_KickClientNum(client_num, reason.data()); + }, scheduler::pipeline::server); + }); + + scheduler::once([] + { + game::Dvar_RegisterString("sv_sayName", "console", game::DVAR_FLAG_NONE, + "The name to pose as for 'say' commands"); + game::Dvar_RegisterString("didyouknow", "", game::DVAR_FLAG_NONE, ""); + }, scheduler::pipeline::main); + + command::add("tell", [](const command::params& params) + { + if (params.size() < 3) + { + return; + } + + const auto client_num = atoi(params.get(1)); + const auto message = params.join(2); + const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string; + + game::SV_GameSendServerCommand(client_num, 0, utils::string::va("%c \"%s: %s\"", 84, name, message.data())); + console::info("%s -> %i: %s\n", name, client_num, message.data()); + }); + + command::add("tellraw", [](const command::params& params) + { + if (params.size() < 3) + { + return; + } + + const auto client_num = atoi(params.get(1)); + const auto message = params.join(2); + + game::SV_GameSendServerCommand(client_num, 0, utils::string::va("%c \"%s\"", 84, message.data())); + console::info("%i: %s\n", client_num, message.data()); + }); + + command::add("say", [](const command::params& params) + { + if (params.size() < 2) + { + return; + } + + const auto message = params.join(1); + const auto* const name = game::Dvar_FindVar("sv_sayName")->current.string; + + game::SV_GameSendServerCommand(-1, 0, utils::string::va("%c \"%s: %s\"", 84, name, message.data())); + console::info("%s: %s\n", name, message.data()); + }); + + command::add("sayraw", [](const command::params& params) + { + if (params.size() < 2) + { + return; + } + + const auto message = params.join(1); + + game::SV_GameSendServerCommand(-1, 0, utils::string::va("%c \"%s\"", 84, message.data())); + console::info("%s\n", message.data()); + }); + + network::on("getInfo", [](const game::netadr_s& target, const std::string& data) + { + utils::info_string info; + info.set("challenge", data); + info.set("gamename", "IW6"); + info.set("hostname", dvars::get_string("sv_hostname")); + info.set("gametype", dvars::get_string("g_gametype")); + info.set("sv_motd", dvars::get_string("sv_motd")); + info.set("xuid", utils::string::va("%llX", steam::SteamUser()->GetSteamID().bits)); + info.set("mapname", dvars::get_string("mapname")); + info.set("isPrivate", dvars::get_string("g_password").empty() ? "0" : "1"); + info.set("clients", std::to_string(get_client_count())); + info.set("bots", std::to_string(get_bot_count())); + info.set("sv_maxclients", std::to_string(*game::mp::svs_clientCount)); + info.set("protocol", std::to_string(PROTOCOL)); + info.set("shortversion", SHORTVERSION); + + network::send(target, "infoResponse", info.build(), '\n'); + }); + + if (game::environment::is_dedi()) + { + return; + } + + network::on("infoResponse", [](const game::netadr_s& target, const std::string& data) + { + const utils::info_string info(data); + server_list::handle_info_response(target, info); + + if (connect_state.host != target) + { + return; + } + + if (info.get("challenge") != connect_state.challenge) + { + console::info("Invalid challenge.\n"); + return; + } + + const auto mapname = info.get("mapname"); + if (mapname.empty()) + { + console::info("Invalid map.\n"); + return; + } + + const auto game_type = info.get("gametype"); + if (game_type.empty()) + { + console::info("Invalid gametype.\n"); + return; + } + + const auto game_name = info.get("gamename"); + if (game_name != "IW6"s) + { + console::info("Invalid gamename.\n"); + return; + } + + const auto is_private = info.get("isPrivate"); + if (is_private == "1"s && dvars::get_string("password").empty()) + { + console::info("Password is not set.\n"); + return; + } + + sv_motd = info.get("sv_motd"); + + try + { + sv_maxclients = std::stoi(info.get("sv_maxclients")); + } + catch ([[maybe_unused]] const std::exception& ex) + { + sv_maxclients = 1; + } + + connect_to_party(target, mapname, game_type); + }); + } + }; +} + +REGISTER_COMPONENT(party::component) diff --git a/src/client/component/party.hpp b/src/client/component/party.hpp new file mode 100644 index 0000000..fd32ce5 --- /dev/null +++ b/src/client/component/party.hpp @@ -0,0 +1,19 @@ +#pragma once + +namespace party +{ + void switch_gamemode_if_necessary(const std::string& gametype); + void perform_game_initialization(); + + void reset_connect_state(); + + void connect(const game::netadr_s& target); + void map_restart(); + + [[nodiscard]] int server_client_count(); + + [[nodiscard]] int get_client_count(); + [[nodiscard]] int get_bot_count(); + + [[nodiscard]] game::netadr_s& get_target(); +} diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp new file mode 100644 index 0000000..ccf635c --- /dev/null +++ b/src/client/component/patches.cpp @@ -0,0 +1,412 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "dvars.hpp" +#include "filesystem.hpp" +#include "scheduler.hpp" + +#include +#include + +namespace patches +{ + namespace + { + utils::hook::detour live_get_local_client_name_hook; + + const char* live_get_local_client_name() + { + return game::Dvar_FindVar("name")->current.string; + } + + utils::hook::detour sv_kick_client_num_hook; + + void sv_kick_client_num(const int clientNum, const char* reason) + { + // Don't kick bot to equalize team balance. + if (reason == "EXE_PLAYERKICKED_BOT_BALANCE"s) + { + return; + } + return sv_kick_client_num_hook.invoke(clientNum, reason); + } + + std::string get_login_username() + { + char username[UNLEN + 1]; + DWORD username_len = UNLEN + 1; + if (!GetUserNameA(username, &username_len)) + { + return "Unknown Soldier"; + } + + return std::string{ username, username_len - 1 }; + } + + utils::hook::detour com_register_dvars_hook; + + void com_register_dvars_stub() + { + if (game::environment::is_mp()) + { + // Make name save + game::Dvar_RegisterString("name", get_login_username().data(), game::DVAR_FLAG_SAVED, "Player name."); + } + + return com_register_dvars_hook.invoke(); + } + + utils::hook::detour dvar_register_int_hook; + + game::dvar_t* dvar_register_int(const char* name, int value, const int min, const int max, + const unsigned int flags, + const char* description) + { + // enable map selection in extinction + if (!strcmp(name, "extinction_map_selection_enabled")) + { + value = true; + } + + // enable extra loadouts + else if (!strcmp(name, "extendedLoadoutsEnable")) + { + value = true; + } + + // show all in-game store items + else if (strstr(name, "igs_")) + { + value = true; + } + + return dvar_register_int_hook.invoke(name, value, min, max, flags, description); + } + + game::dvar_t* register_fovscale_stub(const char* name, float /*value*/, float /*min*/, float /*max*/, + unsigned int /*flags*/, + const char* desc) + { + // changed max value from 2.0f -> 5.0f and min value from 0.5f -> 0.1f + return game::Dvar_RegisterFloat(name, 1.0f, 0.1f, 5.0f, game::DvarFlags::DVAR_FLAG_SAVED, desc); + } + + game::dvar_t* register_cg_gun_dvars(const char* name, float /*value*/, float /*min*/, float /*max*/, + unsigned int /*flags*/, const char* desc) + { + if (name == "cg_gun_x"s) + { + return game::Dvar_RegisterFloat(name, 0.0f, -1.0f, 2.0f, game::DvarFlags::DVAR_FLAG_SAVED, desc); + } + else + { + return game::Dvar_RegisterFloat(name, 0.0f, 0.0f, 0.0f, game::DvarFlags::DVAR_FLAG_NONE, desc); + } + } + + game::dvar_t* register_network_fps_stub(const char* name, int, int, int, unsigned int flags, + const char* desc) + { + return game::Dvar_RegisterInt(name, 1000, 20, 1000, flags, desc); + } + + bool cmd_exec_patch() + { + const command::params exec_params{}; + if (exec_params.size() == 2) + { + std::string file_name = exec_params.get(1); + if (file_name.find(".cfg") == std::string::npos) + file_name.append(".cfg"); + + const auto file = filesystem::file(file_name); + if (file.exists()) + { + game::Cbuf_ExecuteBufferInternal(0, 0, file.get_buffer().data(), game::Cmd_ExecuteSingleCommand); + return true; + } + } + + return false; + } + + auto cmd_exec_stub_mp = utils::hook::assemble([](utils::hook::assembler& a) + { + const auto success = a.newLabel(); + + a.pushad64(); + a.call_aligned(cmd_exec_patch); + a.test(al, al); + a.popad64(); + + a.jz(success); + a.mov(edx, 0x18000); + a.jmp(0x1403F7530); + + a.bind(success); + a.jmp(0x1403F7574); + }); + + auto cmd_exec_stub_sp = utils::hook::assemble([](utils::hook::assembler& a) + { + const auto success = a.newLabel(); + + a.pushad64(); + a.call_aligned(cmd_exec_patch); + a.test(al, al); + a.popad64(); + + a.jz(success); + a.mov(edx, 0x18000); + a.jmp(0x1403B39C0); + + a.bind(success); + a.jmp(0x1403B3A04); + }); + + int dvar_command_patch() // game makes this return an int and compares with eax instead of al -_- + { + const command::params args{}; + + if (args.size() <= 0) + return 0; + + auto* dvar = game::Dvar_FindVar(args.get(0)); + if (dvar) + { + if (args.size() == 1) + { + const auto current = game::Dvar_ValueToString(dvar, dvar->current); + const auto reset = game::Dvar_ValueToString(dvar, dvar->reset); + console::info("\"%s\" is: \"%s^7\" default: \"%s^7\"\n", dvar->name, current, reset); + console::info(" %s\n", dvars::dvar_get_domain(dvar->type, dvar->domain).data()); + } + else + { + char command[0x1000] = {0}; + game::Dvar_GetCombinedString(command, 1); + game::Dvar_SetCommand(args.get(0), command); + } + + return 1; + } + + return 0; + } + + game::Font_s* get_chat_font_handle() + { + return game::R_RegisterFont("fonts/bigFont"); + } + + void aim_assist_add_to_target_list(void* a1, void* a2) + { + if (!dvars::aimassist_enabled->current.enabled) + return; + + game::AimAssist_AddToTargetList(a1, a2); + } + + game::dvar_t* register_cg_fov_stub(const char* name, float value, float min, float /*max*/, + const unsigned int flags, + const char* description) + { + return game::Dvar_RegisterFloat(name, value, min, 160, flags | 1, description); + } + + void bsp_sys_error_stub(const char* error, const char* arg1) + { + if (game::environment::is_dedi()) + { + game::Sys_Error(error, arg1); + } + else + { + scheduler::once([]() + { + command::execute("reconnect"); + }, scheduler::pipeline::main, 1s); + game::Com_Error(game::ERR_DROP, error, arg1); + } + } + + utils::hook::detour cmd_lui_notify_server_hook; + void cmd_lui_notify_server_stub(game::mp::gentity_s* ent) + { + command::params_sv params{}; + const auto menu_id = atoi(params.get(1)); + const auto client = &game::mp::svs_clients[ent->s.clientNum]; + + // 9 => "end_game" + if (menu_id == 9 && client->header.netchan.remoteAddress.type != game::NA_LOOPBACK) + { + return; + } + + cmd_lui_notify_server_hook.invoke(ent); + } + + void update_last_seen_players_stub(utils::hook::assembler& a) + { + const auto safe_continue = a.newLabel(); + + // (game's code) + a.mov(rax, ptr(rbx)); // g_entities pointer + + // Avoid crash if pointer is nullptr + a.test(rax, rax); + a.jz(safe_continue); + + // Jump back in (game's code) + a.mov(dword_ptr(rax, 0x34F8), 0); + + // Continue to next iter in this loop + a.bind(safe_continue); + a.jmp(0x1403A1A10); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Increment ref-count on these + LoadLibraryA("PhysXDevice64.dll"); + LoadLibraryA("PhysXUpdateLoader64.dll"); + + // Unlock fps in main menu + utils::hook::set(SELECT_VALUE(0x140242DDB, 0x1402CF58B), 0xEB); + + // Unlock cg_fov + utils::hook::call(SELECT_VALUE(0x1401F3E96, 0x14027273C), register_cg_fov_stub); + if (game::environment::is_sp()) + { + utils::hook::call(0x1401F3EC7, register_cg_fov_stub); + } + + // set it to 3 to display both voice dlc announcers did only show 1 + game::Dvar_RegisterInt("igs_announcer", 3, 3, 3, game::DvarFlags::DVAR_FLAG_NONE, + "Show Announcer Packs. (Bitfield representing which announcer paks to show)"); + + // changed max value from 85 -> 1000 + if (!game::environment::is_dedi()) + { + game::Dvar_RegisterInt("com_maxfps", 85, 0, 1000, game::DvarFlags::DVAR_FLAG_SAVED, "Cap frames per second"); + } + + if (!game::environment::is_sp()) + { + //increased max limit for sv_network_fps, the lower limit is the default one. Original range is from 20 to 200 times a second. + utils::hook::call(0x140476F4F, register_network_fps_stub); + } + + // register cg_gun_ dvars with new values and flags + // maybe _x can stay usable within a reasonable range? it can make scoped weapons DRASTICALLY better on high FOVs + utils::hook::call(SELECT_VALUE(0x140228DDE, 0x1402AB04C), register_cg_gun_dvars); + utils::hook::call(SELECT_VALUE(0x140228E0E, 0x1402AB07C), register_cg_gun_dvars); + utils::hook::call(SELECT_VALUE(0x140228E3E, 0x1402AB0AC), register_cg_gun_dvars); + + // Register cg_fovscale with new params + utils::hook::call(SELECT_VALUE(0x140317079, 0x140272777), register_fovscale_stub); + + // Patch Dvar_Command to print out values how CoD4 does it + utils::hook::jump(SELECT_VALUE(0x1403BFCB0, 0x140416A60), dvar_command_patch); + + // Allow executing custom cfg files with the "exec" command + utils::hook::jump(SELECT_VALUE(0x1403B39BB, 0x1403F752B), SELECT_VALUE(0x1403B3A12, 0x1403F7582)); + //Use a relative jump to empty memory first + utils::hook::jump(SELECT_VALUE(0x1403B3A12, 0x1403F7582), SELECT_VALUE(cmd_exec_stub_sp, cmd_exec_stub_mp), + true); + // Use empty memory to go to our stub first (can't do close jump, so need space for 12 bytes) + + // Fix mouse lag + utils::hook::nop(SELECT_VALUE(0x14043E6CB, 0x140504A2B), 6); + scheduler::loop([]() + { + SetThreadExecutionState(ES_DISPLAY_REQUIRED); + }, scheduler::pipeline::main); + + // Allow kbam input when gamepad is enabled + utils::hook::nop(SELECT_VALUE(0x14023D490, 0x1402C3099), 2); + utils::hook::nop(SELECT_VALUE(0x14023B3AC, 0x1402C0CE0), 6); + + if (game::environment::is_sp()) + { + patch_sp(); + } + else + { + patch_mp(); + } + } + + static void patch_mp() + { + // Register dvars + com_register_dvars_hook.create(0x140413A90, &com_register_dvars_stub); + + // Use name dvar and add "saved" flags to it + utils::hook::set(0x1402C836D, 0x01); + live_get_local_client_name_hook.create(0x1404FDAA0, &live_get_local_client_name); + + // Patch SV_KickClientNum + sv_kick_client_num_hook.create(0x14046F730, &sv_kick_client_num); + + // Block changing name in-game + utils::hook::set(0x140470300, 0xC3); + + // Unlock all DLC items + utils::hook::set(0x1404EAC50, 0xC301B0); // Content_DoWeHaveDLCPackByName + utils::hook::set(0x140599890, 0xC301B0); // Entitlements_IsIDUnlocked + + // Enable DLC items, extra loadouts and map selection in extinction + dvar_register_int_hook.create(0x1404EE270, &dvar_register_int); + + // Patch game chat on resolutions higher than 1080p to use the right font + utils::hook::call(0x14025C825, get_chat_font_handle); + utils::hook::call(0x1402BC42F, get_chat_font_handle); + utils::hook::call(0x1402C3699, get_chat_font_handle); + + dvars::aimassist_enabled = game::Dvar_RegisterBool("aimassist_enabled", true, + game::DvarFlags::DVAR_FLAG_SAVED, + "Enables aim assist for controllers"); + // Client side aim assist dvar + utils::hook::call(0x14013B9AC, aim_assist_add_to_target_list); + + // Patch "Couldn't find the bsp for this map." error to not be fatal in mp + utils::hook::call(0x14031E8AB, bsp_sys_error_stub); + + // isProfanity + utils::hook::set(0x1402F61B0, 0xC3C033); + + // Don't register every replicated dvar as a network dvar + utils::hook::nop(0x1403E984E, 5); // Dvar_ForEach + + // Prevent clients from ending the game as non host by sending 'end_game' lui notification + cmd_lui_notify_server_hook.create(0x1403926A0, cmd_lui_notify_server_stub); + + // Remove cheat protection from r_umbraExclusive + dvars::override::register_bool("r_umbraExclusive", false, game::DVAR_FLAG_NONE); + + // Patch crash caused by the server trying to kick players for 'invalid password' + utils::hook::jump(0x1403A1A03, utils::hook::assemble(update_last_seen_players_stub), true); + utils::hook::nop(0x1403A1A0F, 1); + // ^^ + utils::hook::nop(0x1403A072F, 5); // LiveStorage_RecordMovementInMatchdata + } + + static void patch_sp() + { + // SP doesn't initialize WSA + WSADATA wsa_data; + WSAStartup(MAKEWORD(2, 2), &wsa_data); + } + }; +} + +REGISTER_COMPONENT(patches::component) diff --git a/src/client/component/ranked.cpp b/src/client/component/ranked.cpp new file mode 100644 index 0000000..4ca1017 --- /dev/null +++ b/src/client/component/ranked.cpp @@ -0,0 +1,109 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "dvars.hpp" + +#include +#include + +namespace ranked +{ + namespace + { + utils::hook::detour bg_bot_system_enabled_hook; + utils::hook::detour bg_ai_system_enabled_hook; + utils::hook::detour bg_bot_fast_file_enabled_hook; + utils::hook::detour bg_bots_using_team_difficulty_hook; + + int bg_bot_system_enabled_stub() + { + const auto* game_type = game::Dvar_FindVar("g_gametype")->current.string; + if (!std::strcmp(game_type, "aliens") || !std::strcmp(game_type, "horde")) + { + return bg_bot_system_enabled_hook.invoke(); + } + + return 1; + } + + int bg_ai_system_enabled_stub() + { + const auto* game_type = game::Dvar_FindVar("g_gametype")->current.string; + if (!std::strcmp(game_type, "aliens") || !std::strcmp(game_type, "horde")) + { + return bg_ai_system_enabled_hook.invoke(); + } + + return 1; + } + + int bg_bot_fast_file_enabled_stub() + { + const auto* game_type = game::Dvar_FindVar("g_gametype")->current.string; + if (!std::strcmp(game_type, "aliens") || !std::strcmp(game_type, "horde")) + { + return bg_bot_fast_file_enabled_hook.invoke(); + } + + return 1; + } + + int bg_bots_using_team_difficulty_stub() + { + const auto* game_type = game::Dvar_FindVar("g_gametype")->current.string; + if (!std::strcmp(game_type, "aliens") || !std::strcmp(game_type, "horde")) + { + return bg_bots_using_team_difficulty_hook.invoke(); + } + + return 1; + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + if (game::environment::is_mp()) + { + // This must be registered as 'true' to avoid crash when starting a private match + dvars::override::register_bool("xblive_privatematch", true, game::DVAR_FLAG_REPLICATED); + } + + if (game::environment::is_dedi() && !utils::flags::has_flag("unranked")) + { + dvars::override::register_bool("xblive_privatematch", false, game::DVAR_FLAG_WRITE); + + // Some dvar used in gsc + game::Dvar_RegisterBool("force_ranking", true, game::DVAR_FLAG_WRITE, "Force ranking"); + + // Fix sessionteam always returning none (SV_HasAssignedTeam_Internal) + utils::hook::set(0x140479CF0, 0xC300B0); + } + + // Always run bots, even if xblive_privatematch is 0 + bg_bot_system_enabled_hook.create(0x140217020, &bg_bot_system_enabled_stub); + bg_ai_system_enabled_hook.create(0x140216DC0, &bg_ai_system_enabled_stub); + bg_bot_fast_file_enabled_hook.create(0x140216F70, &bg_bot_fast_file_enabled_stub); + bg_bots_using_team_difficulty_hook.create(0x1402170E0, &bg_bots_using_team_difficulty_stub); + } + + void pre_destroy() override + { + bg_bot_system_enabled_hook.clear(); + bg_ai_system_enabled_hook.clear(); + bg_bot_fast_file_enabled_hook.clear(); + bg_bots_using_team_difficulty_hook.clear(); + } + }; +} + +REGISTER_COMPONENT(ranked::component) diff --git a/src/client/component/raw_mouse.cpp b/src/client/component/raw_mouse.cpp new file mode 100644 index 0000000..1108074 --- /dev/null +++ b/src/client/component/raw_mouse.cpp @@ -0,0 +1,198 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include + +#include + +namespace raw_mouse +{ + namespace + { + int mouse_raw_x = 0; + int mouse_raw_y = 0; + const game::dvar_t* cl_rawInput = nullptr; + + LRESULT wnd_proc_hook(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) + { + if (msg == WM_INPUT) + { + std::uint32_t size = sizeof(RAWINPUT); + static BYTE lpb[sizeof(RAWINPUT)]; + + GetRawInputData( + reinterpret_cast(lparam), + RID_INPUT, lpb, &size, + sizeof(RAWINPUTHEADER) + ); + + auto* raw = reinterpret_cast(lpb); + if (raw->header.dwType == RIM_TYPEMOUSE) + { + // Is there's really absolute mouse on earth? + if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) + { + mouse_raw_x = raw->data.mouse.lLastX; + mouse_raw_y = raw->data.mouse.lLastY; + } + else + { + mouse_raw_x += raw->data.mouse.lLastX; + mouse_raw_y += raw->data.mouse.lLastY; + } + } + + return TRUE; + } + + return game::MainWndProc(hwnd, msg, wparam, lparam); + } + + void in_clamp_mouse_move(tagPOINT ¤t_position) + { + tagRECT rc; + GetWindowRect(game::g_wv->hWnd, &rc); + + auto is_clamped = false; + if (current_position.x >= rc.left) + { + if (current_position.x >= rc.right) + { + current_position.x = rc.right - 1; + is_clamped = true; + } + } + else + { + current_position.x = rc.left; + is_clamped = true; + } + if (current_position.y >= rc.top) + { + if (current_position.y >= rc.bottom) + { + current_position.y = rc.bottom - 1; + is_clamped = true; + } + } + else + { + current_position.y = rc.top; + is_clamped = true; + } + + if (is_clamped) + { + SetCursorPos(current_position.x, current_position.y); + } + } + + void in_raw_mouse_move() + { + static const auto* r_displayMode = game::Dvar_FindVar("r_displayMode"); + + if (GetForegroundWindow() == game::g_wv->hWnd) + { + static tagPOINT current_position; + GetCursorPos(¤t_position); + + // is fullscreen + if (r_displayMode->current.integer == 0) + { + in_clamp_mouse_move(current_position); + } + + static auto old_x = 0, old_y = 0; + + const auto need_reset = game::s_wmv->oldPos.x == -100000; + + const auto delta_x = need_reset ? 0 : mouse_raw_x - old_x; + const auto delta_y = need_reset ? 0 : mouse_raw_y - old_y; + + old_x = mouse_raw_x; + old_y = mouse_raw_y; + + game::s_wmv->oldPos = current_position; + ScreenToClient(game::g_wv->hWnd, ¤t_position); + + current_position.x = current_position.x * game::vidConfigOut->displayWidth / game::vidConfigOut->monitorWidth; + current_position.y = current_position.y * game::vidConfigOut->displayHeight / game::vidConfigOut->monitorHeight; + + game::g_wv->recenterMouse = game::CL_MouseEvent(current_position.x, current_position.y, delta_x, delta_y); + + if (game::g_wv->recenterMouse && (delta_x || delta_y || need_reset)) + { + game::IN_RecenterMouse(); + } + } + } + + void in_mouse_move() + { + if (cl_rawInput->current.enabled) + { + in_raw_mouse_move(); + } + else + { + game::IN_MouseMove(); + } + } + + void in_raw_mouse_init(HWND hwnd) + { + RAWINPUTDEVICE rid[1]; + rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + rid[0].usUsage = HID_USAGE_GENERIC_MOUSE; + rid[0].dwFlags = RIDEV_INPUTSINK; + rid[0].hwndTarget = hwnd; + + RegisterRawInputDevices(rid, ARRAYSIZE(rid), sizeof(rid[0])); + } + + HWND CALLBACK create_window_ex_a_stub(DWORD dw_ex_style, LPCSTR lp_class_name, LPCSTR lp_window_name, + DWORD dw_style, int x, int y, int n_width, int n_height, HWND h_wnd_parent, HMENU h_menu, HINSTANCE h_instance, LPVOID lp_param) + { + const auto hwnd = CreateWindowExA(dw_ex_style, lp_class_name, lp_window_name, + dw_style, x, y, n_width, n_height, h_wnd_parent, h_menu, h_instance, lp_param); + + in_raw_mouse_init(hwnd); + + return hwnd; + } + + ATOM CALLBACK register_class_ex_a_stub(WNDCLASSEXA* wnd_class) + { + wnd_class->lpfnWndProc = wnd_proc_hook; + return RegisterClassExA(wnd_class); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + utils::hook::call(SELECT_VALUE(0x14043845F, 0x1404FC3FB), &in_mouse_move); + + utils::hook::call(SELECT_VALUE(0x140519F71, 0x1405E69A1), &create_window_ex_a_stub); + utils::hook::set(SELECT_VALUE(0x140519F76, 0x1405E69A6), 0x90); + + utils::hook::call(SELECT_VALUE(0x14043BF04, 0x140500824), ®ister_class_ex_a_stub); + utils::hook::set(SELECT_VALUE(0x14043BF09, 0x140500829), 0x90); + + cl_rawInput = game::Dvar_RegisterBool("cl_rawInput", true, + game::DVAR_FLAG_SAVED, "Use Raw Input for mouse input. This fixes mouse acceleration issue"); + } + }; +} + +REGISTER_COMPONENT(raw_mouse::component) diff --git a/src/client/component/rcon.cpp b/src/client/component/rcon.cpp new file mode 100644 index 0000000..d6a9d65 --- /dev/null +++ b/src/client/component/rcon.cpp @@ -0,0 +1,202 @@ +#include +#include "loader/component_loader.hpp" +#include +#include +#include "game/game.hpp" + +#include "command.hpp" +#include "console.hpp" +#include "network.hpp" +#include "scheduler.hpp" + +namespace rcon +{ + namespace + { + bool is_redirecting_ = false; + game::netadr_s redirect_target_ = {}; + std::recursive_mutex redirect_lock; + + void setup_redirect(const game::netadr_s& target) + { + std::lock_guard $(redirect_lock); + + is_redirecting_ = true; + redirect_target_ = target; + } + + void clear_redirect() + { + std::lock_guard $(redirect_lock); + + is_redirecting_ = false; + redirect_target_ = {}; + } + + std::string build_status_buffer() + { + const auto* sv_maxclients = game::Dvar_FindVar("sv_maxclients"); + const auto* mapname = game::Dvar_FindVar("mapname"); + + std::string buffer; + buffer.append(utils::string::va("map: %s\n", mapname->current.string)); + buffer.append("num score bot ping guid name address qport\n"); + buffer.append("--- ----- --- ---- -------------------------------- ---------------- --------------------- -----\n"); + + for (int i = 0; i < sv_maxclients->current.integer; i++) + { + const auto client = &game::mp::svs_clients[i]; + auto self = &game::mp::g_entities[i]; + + char clean_name[32] = {0}; + strncpy_s(clean_name, self->client->sess.cs.name, sizeof(clean_name)); + game::I_CleanStr(clean_name); + + if (client->header.state > game::CS_FREE && self && self->client) + { + buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n", + i, + self->client->sess.scores.score, + game::SV_BotIsBot(i) ? "Yes" : "No", + (client->header.state == game::CS_RECONNECTING) ? "CNCT" : (client->header.state == game::CS_ZOMBIE) ? "ZMBI" : utils::string::va("%4i", client->ping), + game::SV_GetGuid(i), + clean_name, + network::net_adr_to_string(client->header.netchan.remoteAddress), + client->header.netchan.remoteAddress.port) + ); + } + } + + return buffer; + } + + void send_rcon_command(const std::string& password, const std::string& data) + { + // If you are the server, don't bother with rcon and just execute the command + if (game::Dvar_FindVar("sv_running")->current.enabled) + { + game::Cbuf_AddText(0, data.data()); + return; + } + + if (password.empty()) + { + console::info("You must login first to use RCON\n"); + return; + } + + if (*reinterpret_cast(0x1419E1AE0) >= 5) //clientUIActive.connectionState >= CA_CONNECTED + { + const auto target = *reinterpret_cast(0x141CB535C); + const auto buffer = password + " " + data; + network::send(target, "rcon", buffer); + } + else + { + console::warn("You need to be connected to a server!\n"); + } + } + } + + bool message_redirect(const std::string& message) + { + std::lock_guard $(redirect_lock); + + if (is_redirecting_) + { + network::send(redirect_target_, "print\n", message); + return true; + } + return false; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) return; + + scheduler::once([]() + { + game::Dvar_RegisterString("rcon_password", "", game::DvarFlags::DVAR_FLAG_NONE, + "The password for remote console"); + }, scheduler::pipeline::main); + + command::add("status", []() + { + const auto sv_running = game::Dvar_FindVar("sv_running"); + if (!sv_running || !sv_running->current.enabled) + { + console::error("Server is not running\n"); + return; + } + + const auto status = build_status_buffer(); + console::info("%s", status.data()); + }); + + if (!game::environment::is_dedi()) + { + command::add("rcon", [](const command::params& params) + { + static std::string rcon_password{}; + + if (params.size() < 2) return; + + const auto operation = params.get(1); + if (operation == "login"s) + { + if (params.size() < 3) + return; + + rcon_password = params.get(2); + } + else if (operation == "logout"s) + { + rcon_password.clear(); + } + else + { + send_rcon_command(rcon_password, params.join(1)); + } + }); + } + else + { + network::on("rcon", [](const game::netadr_s& addr, const std::string& data) + { + const auto pos = data.find_first_of(" "); + if (pos == std::string::npos) + { + console::info("Invalid RCon request from %s\n", network::net_adr_to_string(addr)); + return; + } + + const auto password = data.substr(0, pos); + const auto command = data.substr(pos + 1); + const auto rcon_password = game::Dvar_FindVar("rcon_password"); + if (command.empty() || !rcon_password || !*rcon_password->current.string) + { + return; + } + + setup_redirect(addr); + + if (password != rcon_password->current.string) + { + console::error("Invalid rcon password\n"); + } + else + { + command::execute(command, true); + } + + clear_redirect(); + }); + } + } + }; +} + +REGISTER_COMPONENT(rcon::component) diff --git a/src/client/component/rcon.hpp b/src/client/component/rcon.hpp new file mode 100644 index 0000000..2a6c23c --- /dev/null +++ b/src/client/component/rcon.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace rcon +{ + bool message_redirect(const std::string& message); +} diff --git a/src/client/component/redirect.cpp b/src/client/component/redirect.cpp new file mode 100644 index 0000000..11b6e1b --- /dev/null +++ b/src/client/component/redirect.cpp @@ -0,0 +1,74 @@ +#include +#include "loader/component_loader.hpp" +#include "game_module.hpp" +#include +#include + +namespace redirect +{ + namespace + { + void launch_complementary_game(const bool singleplayer) + { + const auto self = game_module::get_host_module(); + + STARTUPINFOA startup_info; + PROCESS_INFORMATION process_info; + + ZeroMemory(&startup_info, sizeof(startup_info)); + ZeroMemory(&process_info, sizeof(process_info)); + startup_info.cb = sizeof(startup_info); + + auto* arguments = const_cast(utils::string::va("%s%s", self.get_path().data(), + (singleplayer ? " -singleplayer" : " -multiplayer"))); + CreateProcessA(self.get_path().data(), arguments, nullptr, nullptr, false, NULL, nullptr, nullptr, + &startup_info, &process_info); + + if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) + { + CloseHandle(process_info.hThread); + } + + if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) + { + CloseHandle(process_info.hProcess); + } + } + + HINSTANCE shell_execute_a(const HWND hwnd, const LPCSTR operation, const LPCSTR file, const LPCSTR parameters, + const LPCSTR directory, const INT show_cmd) + { + if (utils::string::starts_with(file, "steam://run/209160/")) + { + launch_complementary_game(true); + return HINSTANCE(33); + } + else if (utils::string::starts_with(file, "steam://run/209170/")) + { + launch_complementary_game(false); + return HINSTANCE(33); + } + + return ShellExecuteA(hwnd, operation, file, parameters, directory, show_cmd); + } + } + + class component final : public component_interface + { + public: + void* load_import(const std::string& library, const std::string& function) override + { + if (library == "SHELL32.dll") + { + if (function == "ShellExecuteA") + { + return shell_execute_a; + } + } + + return nullptr; + } + }; +} + +REGISTER_COMPONENT(redirect::component) diff --git a/src/client/component/renderer.cpp b/src/client/component/renderer.cpp new file mode 100644 index 0000000..0f20e45 --- /dev/null +++ b/src/client/component/renderer.cpp @@ -0,0 +1,59 @@ +#include +#include "loader/component_loader.hpp" +#include "utils/hook.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +namespace renderer +{ + namespace + { + utils::hook::detour r_init_draw_method_hook; + utils::hook::detour r_update_front_end_dvar_options_hook; + + void r_init_draw_method_stub() + { + game::gfxDrawMethod->drawScene = game::GFX_DRAW_SCENE_STANDARD; + game::gfxDrawMethod->baseTechType = dvars::r_fullbright->current.enabled ? game::TECHNIQUE_UNLIT : game::TECHNIQUE_LIT; + game::gfxDrawMethod->emissiveTechType = dvars::r_fullbright->current.enabled ? game::TECHNIQUE_UNLIT : game::TECHNIQUE_EMISSIVE; + game::gfxDrawMethod->forceTechType = dvars::r_fullbright->current.enabled ? game::TECHNIQUE_UNLIT : 0x19E; + } + + bool r_update_front_end_dvar_options_stub() + { + if (dvars::r_fullbright->modified) + { + dvars::r_fullbright->modified = false; + game::R_SyncRenderThread(); + + game::gfxDrawMethod->drawScene = game::GFX_DRAW_SCENE_STANDARD; + game::gfxDrawMethod->baseTechType = dvars::r_fullbright->current.enabled ? game::TECHNIQUE_UNLIT : game::TECHNIQUE_LIT; + game::gfxDrawMethod->emissiveTechType = dvars::r_fullbright->current.enabled ? game::TECHNIQUE_UNLIT : game::TECHNIQUE_EMISSIVE; + game::gfxDrawMethod->forceTechType = dvars::r_fullbright->current.enabled ? game::TECHNIQUE_UNLIT : 0x19E; + } + + return r_update_front_end_dvar_options_hook.invoke(); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + dvars::r_fullbright = game::Dvar_RegisterBool("r_fullbright", false, game::DvarFlags::DVAR_FLAG_SAVED, + "Toggles rendering without lighting"); + + r_init_draw_method_hook.create(SELECT_VALUE(0x1404FF600, 0x1405CB470), &r_init_draw_method_stub); + r_update_front_end_dvar_options_hook.create( + SELECT_VALUE(0x140535FF0, 0x140603240), &r_update_front_end_dvar_options_stub); + } + }; +} + +REGISTER_COMPONENT(renderer::component) diff --git a/src/client/component/resources.cpp b/src/client/component/resources.cpp new file mode 100644 index 0000000..c5c85b5 --- /dev/null +++ b/src/client/component/resources.cpp @@ -0,0 +1,70 @@ +#include +#include "loader/component_loader.hpp" +#include + +namespace resources +{ + namespace + { + HICON icon; + HANDLE splash, logo; + + HANDLE WINAPI load_image_a(const HINSTANCE handle, LPCSTR name, const UINT type, const int cx, const int cy, + const UINT load) + { + const utils::nt::library self; + if (!IS_INTRESOURCE(name) && name == "logo.bmp"s) return logo; + if (self.get_handle() == handle && name == LPCSTR(0x64)) return splash; + + return LoadImageA(handle, name, type, cx, cy, load); + } + + HICON WINAPI load_icon_a(const HINSTANCE handle, const LPCSTR name) + { + const utils::nt::library self; + if (self.get_handle() == handle && name == LPCSTR(2)) return icon; + + return LoadIconA(handle, name); + } + } + + class component final : public component_interface + { + public: + ~component() override + { + if (icon) DestroyIcon(icon); + if (logo) DeleteObject(logo); + if (splash) DeleteObject(splash); + } + + void post_start() override + { + const utils::nt::library self; + + icon = LoadIconA(self.get_handle(), MAKEINTRESOURCEA(ID_ICON)); + logo = LoadImageA(self.get_handle(), MAKEINTRESOURCEA(IMAGE_LOGO), 0, 0, 0, LR_COPYFROMRESOURCE); + splash = LoadImageA(self.get_handle(), MAKEINTRESOURCEA(IMAGE_SPLASH), 0, 0, 0, LR_COPYFROMRESOURCE); + } + + void* load_import(const std::string& library, const std::string& function) override + { + if (library == "USER32.dll") + { + if (function == "LoadIconA") + { + return load_icon_a; + } + + if (function == "LoadImageA") + { + return load_image_a; + } + } + + return nullptr; + } + }; +} + +REGISTER_COMPONENT(resources::component) diff --git a/src/client/component/scheduler.cpp b/src/client/component/scheduler.cpp new file mode 100644 index 0000000..bada509 --- /dev/null +++ b/src/client/component/scheduler.cpp @@ -0,0 +1,197 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "scheduler.hpp" + +#include +#include +#include + +namespace scheduler +{ + namespace + { + struct task + { + std::function handler{}; + std::chrono::milliseconds interval{}; + std::chrono::high_resolution_clock::time_point last_call{}; + }; + + using task_list = std::vector; + + class task_pipeline + { + public: + void add(task&& task) + { + new_callbacks_.access([&task](task_list& tasks) + { + tasks.emplace_back(std::move(task)); + }); + } + + void execute() + { + callbacks_.access([&](task_list& tasks) + { + this->merge_callbacks(); + + for (auto i = tasks.begin(); i != tasks.end();) + { + const auto now = std::chrono::high_resolution_clock::now(); + const auto diff = now - i->last_call; + + if (diff < i->interval) + { + ++i; + continue; + } + + i->last_call = now; + + const auto res = i->handler(); + if (res == cond_end) + { + i = tasks.erase(i); + } + else + { + ++i; + } + } + }); + } + + private: + utils::concurrency::container new_callbacks_; + utils::concurrency::container callbacks_; + + void merge_callbacks() + { + callbacks_.access([&](task_list& tasks) + { + new_callbacks_.access([&](task_list& new_tasks) + { + tasks.insert(tasks.end(), std::move_iterator(new_tasks.begin()), std::move_iterator(new_tasks.end())); + new_tasks = {}; + }); + }); + } + }; + + volatile bool kill = false; + std::thread thread; + task_pipeline pipelines[pipeline::count]; + utils::hook::detour r_end_frame_hook; + + void execute(const pipeline type) + { + assert(type >= 0 && type < pipeline::count); + pipelines[type].execute(); + } + + void r_end_frame_stub() + { + execute(pipeline::renderer); + r_end_frame_hook.invoke(); + } + + void server_frame_stub() + { + game::G_Glass_Update(); + execute(pipeline::server); + } + + void main_frame_stub() + { + execute(pipeline::main); + game::Com_Frame_Try_Block_Function(); + } + } + + void schedule(const std::function& callback, const pipeline type, + const std::chrono::milliseconds delay) + { + assert(type >= 0 && type < pipeline::count); + + task task; + task.handler = callback; + task.interval = delay; + task.last_call = std::chrono::high_resolution_clock::now(); + + pipelines[type].add(std::move(task)); + } + + void loop(const std::function& callback, const pipeline type, + const std::chrono::milliseconds delay) + { + schedule([callback]() + { + callback(); + return cond_continue; + }, type, delay); + } + + void once(const std::function& callback, const pipeline type, + const std::chrono::milliseconds delay) + { + schedule([callback]() + { + callback(); + return cond_end; + }, type, delay); + } + + void on_game_initialized(const std::function& callback, const pipeline type, + const std::chrono::milliseconds delay) + { + schedule([=]() + { + const auto dw_init = game::environment::is_sp() || game::Live_SyncOnlineDataFlags(0) == 0; + if (dw_init && game::Sys_IsDatabaseReady2()) + { + once(callback, type, delay); + return cond_end; + } + + return cond_continue; + }, pipeline::main); + } + + class component final : public component_interface + { + public: + void post_start() override + { + thread = utils::thread::create_named_thread("Async Scheduler", []() + { + while (!kill) + { + execute(pipeline::async); + std::this_thread::sleep_for(10ms); + } + }); + } + + void post_unpack() override + { + r_end_frame_hook.create(SELECT_VALUE(0x140534860, 0x140601AA0), scheduler::r_end_frame_stub); + + utils::hook::call(SELECT_VALUE(0x1403BC922, 0x140413142), scheduler::main_frame_stub); + utils::hook::call(SELECT_VALUE(0x1403185FD, 0x1403A0AF9), scheduler::server_frame_stub); + } + + void pre_destroy() override + { + kill = true; + if (thread.joinable()) + { + thread.join(); + } + } + }; +} + +REGISTER_COMPONENT(scheduler::component) diff --git a/src/client/component/scheduler.hpp b/src/client/component/scheduler.hpp new file mode 100644 index 0000000..1e0de7a --- /dev/null +++ b/src/client/component/scheduler.hpp @@ -0,0 +1,33 @@ +#pragma once + +namespace scheduler +{ + enum pipeline + { + // Asynchronuous pipeline, disconnected from the game + async = 0, + + // The game's rendering pipeline + renderer, + + // The game's server thread + server, + + // The game's main thread + main, + + count, + }; + + static const bool cond_continue = false; + static const bool cond_end = true; + + void schedule(const std::function& callback, pipeline type = pipeline::async, + std::chrono::milliseconds delay = 0ms); + void loop(const std::function& callback, pipeline type = pipeline::async, + std::chrono::milliseconds delay = 0ms); + void once(const std::function& callback, pipeline type = pipeline::async, + std::chrono::milliseconds delay = 0ms); + void on_game_initialized(const std::function& callback, pipeline type = pipeline::async, + std::chrono::milliseconds delay = 0ms); +} diff --git a/src/client/component/scripting.cpp b/src/client/component/scripting.cpp new file mode 100644 index 0000000..bf535a4 --- /dev/null +++ b/src/client/component/scripting.cpp @@ -0,0 +1,215 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "game/scripting/functions.hpp" + +#include "scripting.hpp" + +#include "gsc/script_loading.hpp" + +#include + +namespace scripting +{ + std::unordered_map> script_function_table; + std::unordered_map>> script_function_table_sort; + std::unordered_map> script_function_table_rev; + + std::string current_file; + + namespace + { + utils::hook::detour scr_load_level_hook; + utils::hook::detour g_shutdown_game_hook; + + utils::hook::detour scr_set_thread_position_hook; + utils::hook::detour process_script_hook; + utils::hook::detour sl_get_canonical_string_hook; + + utils::hook::detour g_find_config_string_index; + + std::string current_script_file; + std::uint32_t current_file_id = 0; + + std::unordered_map canonical_string_table; + + std::vector> shutdown_callbacks; + std::vector> init_callbacks; + + void scr_load_level_stub() + { + scr_load_level_hook.invoke(); + + for (const auto& callback : init_callbacks) + { + callback(); + } + } + + void g_shutdown_game_stub(const int free_scripts) + { + if (free_scripts) + { + script_function_table_sort.clear(); + script_function_table.clear(); + script_function_table_rev.clear(); + canonical_string_table.clear(); + } + + for (const auto& callback : shutdown_callbacks) + { + callback(free_scripts); + } + + return g_shutdown_game_hook.invoke(free_scripts); + } + + void process_script_stub(const char* filename) + { + current_script_file = filename; + + const auto file_id = std::atoi(filename); + if (file_id) + { + current_file_id = file_id; + } + else + { + current_file_id = 0; + current_file = filename; + } + + process_script_hook.invoke(filename); + } + + unsigned int sl_get_canonical_string_stub(const char* str) + { + const auto result = sl_get_canonical_string_hook.invoke(str); + canonical_string_table[result] = str; + return result; + } + + void add_function_sort(unsigned int id, const char* pos) + { + std::string filename = current_file; + if (current_file_id) + { + filename = get_token(current_file_id); + } + + if (!script_function_table_sort.contains(filename)) + { + auto* script = gsc::find_script(game::ASSET_TYPE_SCRIPTFILE, current_script_file.data(), false); + if (script) + { + const auto* end = &script->bytecode[script->bytecodeLen]; + script_function_table_sort[filename].emplace_back("__end__", reinterpret_cast(end)); + } + } + + const auto name = get_token(id); + auto& itr = script_function_table_sort[filename]; + itr.insert(itr.end() - 1, {name, pos}); + } + + void add_function(const std::string& file, unsigned int id, const char* pos) + { + const auto name = get_token(id); + script_function_table[file][name] = pos; + script_function_table_rev[pos] = { file, name }; + } + + void scr_set_thread_position_stub(unsigned int thread_name, const char* code_pos) + { + add_function_sort(thread_name, code_pos); + + if (current_file_id) + { + const auto name = get_token(current_file_id); + add_function(name, thread_name, code_pos); + } + else + { + add_function(current_file, thread_name, code_pos); + } + + scr_set_thread_position_hook.invoke(thread_name, code_pos); + } + + int has_config_string_index(const unsigned int csIndex) + { + const auto* s_constantConfigStringTypes = reinterpret_cast(0x141721F80); + return csIndex < 0xDC4 && s_constantConfigStringTypes[csIndex] < 0x18u; + } + + int is_pre_main_stub() + { + return game::SV_Loaded(); + } + + unsigned int g_find_config_string_index_stub(const char* name, const int start, const unsigned int max, const int create, const char* errormsg) + { + const auto* sv_running = game::Dvar_FindVar("sv_running"); + return g_find_config_string_index.invoke(name, start, max, sv_running->current.enabled, errormsg); + } + } + + std::string get_token(unsigned int id) + { + if (const auto itr = canonical_string_table.find(id); itr != canonical_string_table.end()) + { + return itr->second; + } + + return find_token(id); + } + + void on_shutdown(const std::function& callback) + { + shutdown_callbacks.push_back(callback); + } + + void on_init(const std::function& callback) + { + init_callbacks.push_back(callback); + } + + std::optional get_canonical_string(const unsigned int id) + { + if (const auto itr = canonical_string_table.find(id); itr != canonical_string_table.end()) + { + return {itr->second}; + } + + return {}; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // SP address is wrong, but should be ok + scr_load_level_hook.create(SELECT_VALUE(0x14013D5D0, 0x1403C4E60), &scr_load_level_stub); + g_shutdown_game_hook.create(SELECT_VALUE(0x140318C10, 0x1403A0DF0), &g_shutdown_game_stub); + + scr_set_thread_position_hook.create(SELECT_VALUE(0x1403D3560, 0x14042E360), &scr_set_thread_position_stub); + process_script_hook.create(SELECT_VALUE(0x1403DC870, 0x1404378C0), &process_script_stub); + sl_get_canonical_string_hook.create(game::SL_GetCanonicalString, &sl_get_canonical_string_stub); + + if (!game::environment::is_sp()) + { + // Make some room for pre_main hook + utils::hook::jump(0x1402084A0, has_config_string_index); + + // Allow precaching anytime + utils::hook::jump(0x1402084A5, is_pre_main_stub); + utils::hook::set(0x1402084D0, 0xD3EB); // jump to 0x1402084A5 + g_find_config_string_index.create(0x140161F90, &g_find_config_string_index_stub); + } + } + }; +} + +REGISTER_COMPONENT(scripting::component) diff --git a/src/client/component/scripting.hpp b/src/client/component/scripting.hpp new file mode 100644 index 0000000..c841903 --- /dev/null +++ b/src/client/component/scripting.hpp @@ -0,0 +1,16 @@ +#pragma once + +namespace scripting +{ + extern std::unordered_map> script_function_table; + extern std::unordered_map>> script_function_table_sort; + extern std::unordered_map> script_function_table_rev; + + extern std::string current_file; + + void on_shutdown(const std::function& callback); + void on_init(const std::function& callback); + + std::optional get_canonical_string(unsigned int id); + std::string get_token(unsigned int id); +} diff --git a/src/client/component/security.cpp b/src/client/component/security.cpp new file mode 100644 index 0000000..327af7e --- /dev/null +++ b/src/client/component/security.cpp @@ -0,0 +1,51 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "console.hpp" + +#include + +namespace security +{ + namespace + { + void set_cached_playerdata_stub(const int localclient, const int index1, const int index2) + { + if (index1 >= 0 && index1 < 18 && index2 >= 0 && index2 < 42) + { + reinterpret_cast(0x1405834B0)(localclient, index1, index2); + } + } + + void sv_execute_client_message_stub(game::mp::client_t* client, game::msg_t* msg) + { + if ((client->reliableSequence - client->reliableAcknowledge) < 0) + { + client->reliableAcknowledge = client->reliableSequence; + console::info("Negative reliableAcknowledge from %s - cl->reliableSequence is %i, reliableAcknowledge is %i\n", + client->name, client->reliableSequence, client->reliableAcknowledge); + return; + } + + utils::hook::invoke(0x140472500, client, msg); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) return; + + // Patch vulnerability in PlayerCards_SetCachedPlayerData + utils::hook::call(0x140287C5C, set_cached_playerdata_stub); + + // It is possible to make the server hang if left unchecked + utils::hook::call(0x14047A29A, sv_execute_client_message_stub); + } + }; +} + +REGISTER_COMPONENT(security::component) diff --git a/src/client/component/server_list.cpp b/src/client/component/server_list.cpp new file mode 100644 index 0000000..b8abc61 --- /dev/null +++ b/src/client/component/server_list.cpp @@ -0,0 +1,486 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" +#include "game/ui_scripting/execution.hpp" + +#include "server_list.hpp" +#include "console.hpp" +#include "command.hpp" +#include "dvars.hpp" +#include "localized_strings.hpp" +#include "network.hpp" +#include "scheduler.hpp" +#include "party.hpp" + +#include +#include +#include + +namespace server_list +{ + namespace + { + struct server_info + { + // gotta add more to this + int clients; + int max_clients; + int bots; + int ping; + bool is_private; + std::string host_name; + std::string map_name; + std::string game_type; + char in_game; + game::netadr_s address; + }; + + struct + { + game::netadr_s address{}; + volatile bool requesting = false; + std::unordered_map queued_servers{}; + } master_state; + + volatile bool update_server_list = false; + + std::mutex mutex; + std::vector servers; + + size_t server_list_index = 0; + + void lui_open_menu_stub(int /*controllerIndex*/, const char* /*menu*/, int /*a3*/, int /*a4*/, + unsigned int /*a5*/) + { + game::Cmd_ExecuteSingleCommand(0, 0, "lui_open menu_systemlink_join\n"); + } + + void refresh_server_list() + { + { + std::lock_guard _(mutex); + servers.clear(); + master_state.queued_servers.clear(); + server_list_index = 0; + } + + party::reset_connect_state(); + + if (get_master_server(master_state.address)) + { + master_state.requesting = true; + network::send(master_state.address, "getservers", utils::string::va("IW6 %i full empty", PROTOCOL)); + } + } + + void join_server(int, int, const int index) + { + std::lock_guard _(mutex); + + const auto i = static_cast(index) + server_list_index; + if (i < servers.size()) + { + static size_t last_index = 0xFFFFFFFF; + if (last_index != i) + { + last_index = i; + } + else + { + console::info("Connecting to (%d - %zu): %s\n", index, i, servers[i].host_name.data()); + party::connect(servers[i].address); + } + } + } + + void trigger_refresh() + { + update_server_list = true; + } + + bool server_list_refresher() + { + if (update_server_list) + { + update_server_list = false; + } + + return false; + } + + int ui_feeder_count() + { + std::lock_guard _(mutex); + return static_cast(servers.size() - server_list_index); + } + + const char* ui_feeder_item_text(int /*localClientNum*/, void* /*a2*/, void* /*a3*/, const int index, + const int column) + { + std::lock_guard _(mutex); + + const auto i = server_list_index + index; + + if (i >= servers.size()) + { + return ""; + } + + if (column == 0) + { + return utils::string::va("%s", servers[i].host_name.data()); + } + + if (column == 1) + { + return utils::string::va("%s", servers[i].map_name.data()); + } + + if (column == 2) + { + const auto client_count = servers[i].clients - servers[i].bots; + return utils::string::va("%d/%d [%d]", client_count, servers[i].max_clients, servers[i].bots); + } + + if (column == 3) + { + return utils::string::va("%s", servers[i].game_type.data()); + } + + if (column == 4) + { + return utils::string::va("%d", servers[i].ping); + } + + if (column == 5) + { + return utils::string::va("%d", servers[i].is_private); + } + + return ""; + } + + void sort_serverlist() + { + std::ranges::stable_sort(servers, [](const server_info& a, const server_info& b) + { + const auto a_players = a.clients - a.bots; + const auto b_players = b.clients - b.bots; + if (a_players == b_players) + { + return a.ping < b.ping; + } + + return a_players > b_players; + }); + } + + void insert_server(server_info&& server) + { + std::lock_guard _(mutex); + servers.emplace_back(std::move(server)); + sort_serverlist(); + trigger_refresh(); + } + + void do_frame_work() + { + auto& queue = master_state.queued_servers; + if (queue.empty()) + { + return; + } + + std::lock_guard _(mutex); + + size_t queried_servers = 0; + const size_t query_limit = 3; + + for (auto i = queue.begin(); i != queue.end();) + { + if (i->second) + { + const auto now = game::Sys_Milliseconds(); + if (now - i->second > 10'000) + { + i = queue.erase(i); + continue; + } + } + else if (queried_servers++ < query_limit) + { + i->second = game::Sys_Milliseconds(); + network::send(i->first, "getInfo", utils::cryptography::random::get_challenge()); + } + + ++i; + } + } + + bool is_server_list_open() + { + return game::Menu_IsMenuOpenAndVisible(0, "menu_systemlink_join"); + } + + bool scroll_down() + { + if (!is_server_list_open()) + { + return false; + } + + if (server_list_index + 16 < servers.size()) + { + ++server_list_index; + trigger_refresh(); + } + + return true; + } + + bool scroll_up() + { + if (!is_server_list_open()) + { + return false; + } + + if (server_list_index > 0) + { + --server_list_index; + trigger_refresh(); + } + + return true; + } + + int get_client_count() + { + std::lock_guard _(mutex); + auto count = 0; + + for (const auto& server : servers) + { + count += server.clients; + } + + return count; + } + + int get_bot_count() + { + std::lock_guard _(mutex); + auto count = 0; + + for (const auto& server : servers) + { + count += server.bots; + } + + return count; + } + + int get_max_clients_count() + { + std::lock_guard _(mutex); + auto count = 0; + + for (const auto& server : servers) + { + count += server.max_clients; + } + + return count; + } + + int get_total_active_players_count_stub(game::hks::lua_State* s, void* a2) + { + const auto clients = get_client_count(); + const auto bots = get_bot_count(); + const auto max = get_max_clients_count(); + + const auto str = utils::string::va("%d/%d [%d]", clients, max, bots); + ui_scripting::push_value(str); + + return 1; + } + } + + bool get_master_server(game::netadr_s& address) + { + return game::NET_StringToAdr("server.alterware.dev:20810", &address); + } + + void handle_info_response(const game::netadr_s& address, const utils::info_string& info) + { + int start_time{}; + const auto now = game::Sys_Milliseconds(); + + { + std::lock_guard _(mutex); + const auto entry = master_state.queued_servers.find(address); + + if (entry == master_state.queued_servers.end() || !entry->second) + { + return; + } + + start_time = entry->second; + master_state.queued_servers.erase(entry); + } + + if (dvars::get_string("ui_customModeName") == "mp"s) + { + if (info.get("gametype") == "aliens"s) + { + return; + } + } + else if (dvars::get_string("ui_customModeName") == "aliens"s) + { + if (info.get("gametype") != "aliens"s) + { + return; + } + } + + if (dvars::get_string("ui_mapvote_entrya_gametype") != "any"s && dvars::get_string("ui_mapvote_entrya_gametype") != info.get("gametype")) + { + return; + } + + if (dvars::get_string("ui_mapvote_entrya_mapname") != "any"s && dvars::get_string("ui_mapvote_entrya_mapname") != info.get("mapname")) + { + return; + } + + server_info server{}; + server.address = address; + server.host_name = info.get("hostname"); + server.map_name = game::UI_LocalizeMapname(info.get("mapname").data()); + server.game_type = game::UI_LocalizeGametype(info.get("gametype").data()); + server.clients = atoi(info.get("clients").data()); + server.max_clients = atoi(info.get("sv_maxclients").data()); + server.bots = atoi(info.get("bots").data()); + server.ping = now - start_time; + server.is_private = info.get("isPrivate") == "1"s; + server.in_game = 1; + + if (server.host_name.size() > 50) + { + server.host_name.resize(50); + } + + insert_server(std::move(server)); + } + + bool sl_key_event(const int key, const int down) + { + if (down) + { + if (key == game::keyNum_t::K_MWHEELUP) + { + return !scroll_up(); + } + + if (key == game::keyNum_t::K_MWHEELDOWN) + { + return !scroll_down(); + } + } + + return true; + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_mp()) return; + + localized_strings::override("PLATFORM_SYSTEM_LINK_TITLE", "SERVER LIST"); + localized_strings::override("LUA_MENU_STORE_CAPS", "SERVER LIST"); + localized_strings::override("LUA_MENU_STORE_DESC", "Browse available servers."); + localized_strings::override("MENU_NUMPLAYERS", "Players"); + + // hook LUI_OpenMenu to show server list instead of store popup + utils::hook::call(0x1404FE840, &lui_open_menu_stub); + + // refresh server list when needed + utils::hook::call(0x1402F7480, &server_list_refresher); + + // replace UI_RunMenuScript call in LUI_CoD_LuaCall_RefreshServerList to our refresh_servers + utils::hook::call(0x1401E7171, &refresh_server_list); + utils::hook::call(0x1401E7616, &join_server); + utils::hook::nop(0x1401E7635, 5); + + // do feeder stuff + utils::hook::call(0x1401E7225, &ui_feeder_count); + utils::hook::call(0x1401E7405, &ui_feeder_item_text); + + utils::hook::jump(0x1401EBE30, &get_total_active_players_count_stub, true); + scheduler::once(refresh_server_list, scheduler::pipeline::main); + + command::add("lui_open", [](const command::params& params) + { + if (params.size() <= 1) + { + console::info("usage: lui_open \n"); + return; + } + + game::LUI_OpenMenu(0, params[1], 1, 0, 0); + }); + + scheduler::loop(do_frame_work, scheduler::pipeline::main); + + network::on("getServersResponse", [](const game::netadr_s& target, const std::string& data) + { + { + std::lock_guard _(mutex); + if (!master_state.requesting || master_state.address != target) + { + return; + } + + master_state.requesting = false; + + std::optional start{}; + for (std::size_t i = 0; i + 6 < data.size(); ++i) + { + if (data[i + 6] == '\\') + { + start.emplace(i); + break; + } + } + + if (!start.has_value()) + { + return; + } + + for (auto i = start.value(); i + 6 < data.size(); i += 7) + { + if (data[i + 6] != '\\') + { + break; + } + + game::netadr_s address{}; + address.type = game::NA_IP; + address.localNetID = game::NS_CLIENT1; + std::memcpy(&address.ip[0], data.data() + i + 0, 4); + std::memcpy(&address.port, data.data() + i + 4, 2); + + master_state.queued_servers[address] = 0; + } + } + }); + } + }; +} + +REGISTER_COMPONENT(server_list::component) diff --git a/src/client/component/server_list.hpp b/src/client/component/server_list.hpp new file mode 100644 index 0000000..09f62b2 --- /dev/null +++ b/src/client/component/server_list.hpp @@ -0,0 +1,10 @@ +#pragma once +#include + +namespace server_list +{ + bool get_master_server(game::netadr_s& address); + void handle_info_response(const game::netadr_s& address, const utils::info_string& info); + + bool sl_key_event(int key, int down); +} diff --git a/src/client/component/slowmotion.cpp b/src/client/component/slowmotion.cpp new file mode 100644 index 0000000..d688083 --- /dev/null +++ b/src/client/component/slowmotion.cpp @@ -0,0 +1,74 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include +#include + +namespace slowmotion +{ + namespace + { + int delay = 0; + utils::hook::detour com_timescale_msec_hook; + + uint64_t com_timescale_msec(const int msec) + { + if (delay <= 0) + { + return com_timescale_msec_hook.invoke(msec); + } + else + { + delay -= msec; + return 0; + } + } + + void scr_cmd_set_slow_motion() + { + if (game::Scr_GetNumParam() < 1) + return; + + int duration = 1000; + float end = 1.0f; + const float start = game::Scr_GetFloat(0); + + if (game::Scr_GetNumParam() >= 2) + end = game::Scr_GetFloat(1); + + if (game::Scr_GetNumParam() >= 3) + duration = static_cast(game::Scr_GetFloat(2) * 1000.0f); + + const auto _delay = (start > end) ? 150 : 0; + + game::SV_SetConfigstring(game::CS_TIMESCALE, + utils::string::va("%i %i %g %g", *game::mp::gameTime, duration, start, end)); + game::Com_SetSlowMotion(start, end, duration - _delay); + + delay = _delay; + + for (auto i = 0; i < game::Dvar_FindVar("sv_maxclients")->current.integer; i++) + { + auto* client = &game::mp::svs_clients[i]; + client->nextSnapshotTime = *game::mp::serverTime - 1; + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_dedi()) return; + + utils::hook::jump(0x1403B4A10, scr_cmd_set_slow_motion); + + // Detour used here instead of call hook because Com_TimeScaleMsec is called from arxan encrypted function + com_timescale_msec_hook.create(0x140415D50, com_timescale_msec); + } + }; +} + +REGISTER_COMPONENT(slowmotion::component) diff --git a/src/client/component/splash.cpp b/src/client/component/splash.cpp new file mode 100644 index 0000000..de919df --- /dev/null +++ b/src/client/component/splash.cpp @@ -0,0 +1,141 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game_module.hpp" + +#include +#include + +namespace splash +{ + class component final : public component_interface + { + public: + void post_start() override + { + const utils::nt::library self; + image_ = LoadImageA(self, MAKEINTRESOURCE(IMAGE_SPLASH), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + } + + void post_load() override + { + if (game::environment::is_dedi()) + { + return; + } + + this->show(); + } + + void post_unpack() override + { + // Disable native splash screen + utils::hook::nop(SELECT_VALUE(0x14043C15B, 0x140500ADB), 5); + utils::hook::jump(SELECT_VALUE(0x14043D5A0, 0x140502000), destroy_stub); + utils::hook::jump(SELECT_VALUE(0x14043D5E0, 0x140502040), destroy_stub); + } + + void pre_destroy() override + { + this->destroy(); + + MSG msg; + while (this->window_ && IsWindow(this->window_)) + { + if (PeekMessageA(&msg, nullptr, NULL, NULL, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + { + std::this_thread::sleep_for(1ms); + } + } + + this->window_ = nullptr; + } + + private: + HWND window_{}; + HANDLE image_{}; + + static void destroy_stub() + { + component_loader::get()->destroy(); + } + + void destroy() const + { + if (this->window_ && IsWindow(this->window_)) + { + ShowWindow(this->window_, SW_HIDE); + DestroyWindow(this->window_); + UnregisterClassA("iw6-mod Splash Screen", utils::nt::library{}); + } + } + + void show() + { + WNDCLASSA wnd_class; + + const auto self = game_module::get_host_module(); + + wnd_class.style = CS_DROPSHADOW; + wnd_class.cbClsExtra = 0; + wnd_class.cbWndExtra = 0; + wnd_class.lpszMenuName = nullptr; + wnd_class.lpfnWndProc = DefWindowProcA; + wnd_class.hInstance = self; + wnd_class.hIcon = LoadIconA(self, reinterpret_cast(102)); + wnd_class.hCursor = LoadCursorA(nullptr, IDC_APPSTARTING); + wnd_class.hbrBackground = reinterpret_cast(6); + wnd_class.lpszClassName = "iw6-mod Splash Screen"; + + if (RegisterClassA(&wnd_class)) + { + const auto x_pixels = GetSystemMetrics(SM_CXFULLSCREEN); + const auto y_pixels = GetSystemMetrics(SM_CYFULLSCREEN); + + if (image_) + { + this->window_ = CreateWindowExA(WS_EX_APPWINDOW, "iw6-mod Splash Screen", "iw6-mod", + WS_POPUP | WS_SYSMENU, + (x_pixels - 320) / 2, (y_pixels - 100) / 2, 320, 100, nullptr, + nullptr, + self, nullptr); + + if (this->window_) + { + auto* const image_window = CreateWindowExA(0, "Static", nullptr, WS_CHILD | WS_VISIBLE | 0xEu, + 0, 0, + 320, 100, this->window_, nullptr, self, nullptr); + if (image_window) + { + RECT rect; + SendMessageA(image_window, 0x172u, 0, reinterpret_cast(image_)); + GetWindowRect(image_window, &rect); + + const int width = rect.right - rect.left; + rect.left = (x_pixels - width) / 2; + + const int height = rect.bottom - rect.top; + rect.top = (y_pixels - height) / 2; + + rect.right = rect.left + width; + rect.bottom = rect.top + height; + AdjustWindowRect(&rect, WS_CHILD | WS_VISIBLE | 0xEu, 0); + SetWindowPos(this->window_, nullptr, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, SWP_NOZORDER); + + ShowWindow(this->window_, SW_SHOW); + UpdateWindow(this->window_); + } + } + } + } + } + }; +} + +REGISTER_COMPONENT(splash::component) diff --git a/src/client/component/stats.cpp b/src/client/component/stats.cpp new file mode 100644 index 0000000..6c09998 --- /dev/null +++ b/src/client/component/stats.cpp @@ -0,0 +1,404 @@ +#include +#include +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" + +#include "command.hpp" +#include "console.hpp" + +namespace stats +{ + namespace + { + const int controller_index = 0; + + //Checks if it's a valid reserved lookup string otherwise it crashes the client. + bool is_reserved_lookup_string(const char* lookup_string) + { + const std::vector reserved_lookup_strings + { + //EXTINCTION MODE RESERVED LOOKUP STRINGS + "extinction_purchase_flags", + "extinction_tokens", + "extinction_crafted_flags", + "upgrades_enabled_flags", + "relics_enabled_flags", + "bonus_pool_size", + "bonus_pool_deadline", + //MULTIPLAYER + "prestigeLevel", + //COMMON + "mp_announcer_type" + }; + + return std::find(reserved_lookup_strings.begin(), reserved_lookup_strings.end(), lookup_string) + != reserved_lookup_strings.end(); + } + + game::StatsGroup get_statsgroup_for_reserved_lookup_string(const char* lookup_string) + { + enum game::StatsGroup statsgroup{ game::STATSGROUP_COOP }; + + if (!strcmp(lookup_string, "prestigeLevel")) + { + statsgroup = game::STATSGROUP_RANKED; + } + else if (!strcmp(lookup_string, "mp_announcer_type")) + { + statsgroup = game::STATSGROUP_COMMON; + } + + return statsgroup; + } + + game::StatsGroup get_statsgroup_for_lookup_string(const char* lookup_string) + { + const auto asset{ game::StructuredDataDef_GetAsset("mp/playerdata.def", 0x93FCu) }; + + bool found_param{ false }; + enum game::StatsGroup statsgroup{ game::STATSGROUP_RANKED }; + + for (int i = 0; i < asset->structs[23].propertyCount; ++i) + { + if (!strcmp(game::SL_ConvertToString(asset->structs[23].properties[i].name), lookup_string)) + { + statsgroup = game::STATSGROUP_COMMON; + found_param = true; + break; + } + } + + //no need to search it again if we already found it at the common strings + if (!found_param) + { + for (int i = 0; i < asset->structs[22].propertyCount; ++i) + { + if (!strcmp(game::SL_ConvertToString(asset->structs[22].properties[i].name), lookup_string)) + { + statsgroup = game::STATSGROUP_COOP; + break; + } + } + } + + return statsgroup; + } + + std::vector parse_params_to_lookup_strings(const command::params& params, bool setData) + { + std::vector lookup_strings_vector{}; + int amount_lookup_strings{ params.size() }; + + //last param is a value if we're setting data. + if (setData) + { + --amount_lookup_strings; + } + + for (int i = 1; i < amount_lookup_strings; ++i) + { + if (utils::string::is_numeric(params.get(i))) + { + lookup_strings_vector.push_back(game::SL_GetStringForInt(atoi(params.get(i)))); + } + else + { + lookup_strings_vector.push_back(game::SL_FindString(params.get(i))); + } + } + + return lookup_strings_vector; + } + + void set_player_data_for_lookup_string(const char* lookup_string, + const std::vector>& data, game::StatsGroup statsgroup) + { + unsigned int nav_strings[2]{}; + + nav_strings[0] = game::SL_FindString(lookup_string); + for (int i = 0; i < data.size(); ++i) + { + nav_strings[1] = game::SL_FindString(std::get<0>(data[i])); + game::LiveStorage_PlayerDataSetIntByNameArray( + controller_index, nav_strings, 2, std::get<1>(data[i]), statsgroup); + } + } + + void register_squadmembers_purchase() + { + unsigned int nav_strings[2]{}; + const game::StringTable* unlock_table{ nullptr }; + game::StringTable_GetAsset("mp/unlocktable.csv", &unlock_table); + + if (unlock_table) + { + //squad purchases challenge is defined at line 112 and ends at 152. + //it's defined 4 times each hence the jumps of 4 + for (int i = 112; i < 152; i += 4) + { + // Register squad purchases for calling cards + auto squadmember_purchase = game::StringTable_GetColumnValueForRow(unlock_table, i, 3); + + nav_strings[0] = game::SL_FindString("challengeState"); + nav_strings[1] = game::SL_FindString(squadmember_purchase); + game::LiveStorage_PlayerDataSetIntByNameArray( + controller_index, nav_strings, 2, 2, game::STATSGROUP_RANKED); + + nav_strings[0] = game::SL_FindString("challengeProgress"); + game::LiveStorage_PlayerDataSetIntByNameArray( + controller_index, nav_strings, 2, 1, game::STATSGROUP_RANKED); + } + } + } + + void unlock_all_squadmember(const int squadmember_index) + { + unsigned int nav_strings[5]{}; + const int amount_regular_loadouts{ 6 }; + const game::StringTable* squad_unlocktable{ nullptr }; + game::StringTable_GetAsset("mp/squadunlocktable.csv", &squad_unlocktable); + + //select specific squadmember + nav_strings[0] = game::SL_FindString("squadMembers"); + nav_strings[1] = game::SL_GetStringForInt(squadmember_index); + + //unlocks squadmember + nav_strings[2] = game::SL_FindString("inUse"); + game::LiveStorage_PlayerDataSetIntByNameArray( + controller_index, nav_strings, 3, 1, game::STATSGROUP_RANKED); + + //choose a default loadout otherwise unlocking loadouts won't work + nav_strings[2] = game::SL_FindString("defaultSet"); + game::LiveStorage_PlayerDataSetIntByNameArray( + controller_index, nav_strings, 3, 1, game::STATSGROUP_RANKED); + + //set max xp squad member + nav_strings[2] = game::SL_FindString("squadMemXP"); + game::LiveStorage_PlayerDataSetIntByNameArray( + controller_index, nav_strings, 3, 1230080, game::STATSGROUP_RANKED); + + //unlocks loadouts + nav_strings[2] = game::SL_FindString("loadouts"); + nav_strings[4] = game::SL_FindString("inUse"); + + for (int j = 0; j < amount_regular_loadouts; ++j) + { + nav_strings[3] = game::SL_GetStringForInt(j); + game::LiveStorage_PlayerDataSetIntByNameArray( + controller_index, nav_strings, 5, 2, game::STATSGROUP_RANKED); + } + + //unlocks all weapons, reticles and killstreaks + nav_strings[2] = game::SL_FindString("challengeState"); + if (squad_unlocktable) + { + for (int j = 0; j < squad_unlocktable->rowCount; ++j) + { + auto unlock_item = game::StringTable_GetColumnValueForRow(squad_unlocktable, j, 3); + + if (unlock_item[0] == '\0') + continue; + + nav_strings[3] = game::SL_FindString(unlock_item); + game::LiveStorage_PlayerDataSetIntByNameArray( + controller_index, nav_strings, 4, 2, game::STATSGROUP_RANKED); + } + } + } + + void unlock_all_extinction() + { + const auto persistent_data_buffer{ game::LiveStorage_GetPersistentDataBuffer(controller_index) }; + const std::vector> data{ + {"prestige", 25}, + {"experience", 1845000}, + //not sure if necessary + {"rank", 31}, + {"revives", 100}, + {"kills", 10000}, + {"escaped", 10}, + //unlocks background with the challenges "Beat any Extinction map with x Relic(s) Active" + {"headShots", 5} + }; + + set_player_data_for_lookup_string("alienPlayerStats", data, game::STATSGROUP_COOP); + + game::LiveStorage_PlayerDataSetReservedInt( + persistent_data_buffer, "extinction_purchase_flags", -1, 0, game::STATSGROUP_COOP); + game::LiveStorage_PlayerDataSetReservedInt( + persistent_data_buffer, "extinction_tokens", 5000, 0, game::STATSGROUP_COOP); + } + + void unlock_all_multiplayer() + { + const int amount_squad_members{ 10 }; + const auto persistent_data_buffer{ game::LiveStorage_GetPersistentDataBuffer(controller_index) }; + + for (int i = 0; i < amount_squad_members; ++i) + { + unlock_all_squadmember(i); + } + + register_squadmembers_purchase(); + + //not the correct way to set each squadmembers prestige + //but i couldn't figure it out how it's done. + for (int i = 0; i < amount_squad_members; ++i) + { + utils::hook::set(0x1445A2B20 + (i * 4), i); + } + + //set the players prestige to 10th prestige + game::LiveStorage_PlayerDataSetReservedInt( + persistent_data_buffer, "prestigeLevel", 10, 0, game::STATSGROUP_RANKED); + + //gives unlock points but not really necassary since everything is already unlocked + game::LiveStorage_PlayerDataSetIntByName(controller_index, game::SL_FindString("unlockPoints"), 5000, game::StatsGroup::STATSGROUP_RANKED); + } + + void unlock_all_challenges() + { + unsigned int nav_strings[2]{}; + const game::StringTable* challenges_table{ nullptr }; + game::StringTable_GetAsset("mp/allchallengestable.csv", &challenges_table); + + if (challenges_table) + { + for (int i = 0; i < challenges_table->rowCount; ++i) + { + // Find challenge + auto challenge{ game::StringTable_GetColumnValueForRow(challenges_table, i, 0) }; + + int max_state{ 0 }; + int max_progress{ 0 }; + + // Find correct tier and progress + for (int j = 0; j < 8; ++j) + { + int progress{ atoi(game::StringTable_GetColumnValueForRow(challenges_table, i, 9 + j * 2)) }; + if (!progress) break; + + max_state = j + 2; + max_progress = progress; + } + + nav_strings[0] = game::SL_FindString("challengeState"); + nav_strings[1] = game::SL_FindString(challenge); + game::LiveStorage_PlayerDataSetIntByNameArray( + controller_index, nav_strings, 2, max_state, game::STATSGROUP_RANKED); + + nav_strings[0] = game::SL_FindString("challengeProgress"); + game::LiveStorage_PlayerDataSetIntByNameArray( + controller_index, nav_strings, 2, max_progress, game::STATSGROUP_RANKED); + } + } + } + + void unlock_past_title_backgrounds() + { + const std::vector> data{ + {"playedmw3", 1}, + {"playedblackops2", 1}, + {"mw3prestige", 20}, + {"blackops2prestige", 11} + }; + + set_player_data_for_lookup_string("pastTitleData", data, game::STATSGROUP_COMMON); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_mp()) + { + return; + } + + command::add("setReservedPlayerDataInt", [](const command::params& params) + { + if (params.size() < 3 || !is_reserved_lookup_string(params.get(1))) + { + console::info("usage: setReservedPlayerDataInt , \n"); + return; + } + + const auto persistent_data_buffer{ game::LiveStorage_GetPersistentDataBuffer(controller_index) }; + const char* first_param{ params.get(1) }; + const auto value{ atoi(params.get(2)) }; + const auto statsgroup{ get_statsgroup_for_reserved_lookup_string(first_param) }; + + game::LiveStorage_PlayerDataSetReservedInt( + persistent_data_buffer, first_param, value, 0, statsgroup); + }); + + command::add("getReservedPlayerDataInt", [](const command::params& params) + { + if (params.size() < 2 || !is_reserved_lookup_string(params.get(1))) + { + console::info("usage: getReservedPlayerDataInt \n"); + return; + } + + const auto persistent_data_buffer{ game::LiveStorage_GetPersistentDataBuffer(controller_index) }; + const char* first_param{ params.get(1) }; + const auto statsgroup{ get_statsgroup_for_reserved_lookup_string(first_param) }; + + const auto result{ game::LiveStorage_PlayerDataGetReservedInt( + persistent_data_buffer, first_param, statsgroup) }; + console::info("%d\n", result); + }); + + command::add("setPlayerDataInt", [](const command::params& params) + { + if (params.size() < 3) + { + console::info("usage: setPlayerDataInt , ... , , \n"); + return; + } + + const std::vector lookup_strings_vector{parse_params_to_lookup_strings(params, true)}; + const auto value = atoi(params.get(params.size() - 1)); + const auto statsgroup{get_statsgroup_for_lookup_string(params.get(1))}; + + game::LiveStorage_PlayerDataSetIntByNameArray(controller_index, &lookup_strings_vector[0], params.size() - 2, value, statsgroup); + + //This is necessary for the stats to stick after closing the game + game::LiveStorage_StatsWriteNeeded(controller_index); + }); + + command::add("getPlayerDataInt", [](const command::params& params) + { + if (params.size() < 2) + { + console::info("usage: getPlayerDataInt , ... , \n"); + return; + } + + const std::vector lookup_strings_vector{parse_params_to_lookup_strings(params, false)}; + const auto statsgroup{ get_statsgroup_for_lookup_string(params.get(1)) }; + + const auto result{game::LiveStorage_PlayerDataGetIntByNameArray(controller_index, &lookup_strings_vector[0], params.size() - 1, statsgroup)}; + + console::info("%d\n", result); + }); + + command::add("unlockstats", []() + { + unlock_all_extinction(); + unlock_all_multiplayer(); + unlock_all_challenges(); + unlock_past_title_backgrounds(); + + //This is necessary for the stats to stick after closing the game + game::LiveStorage_StatsWriteNeeded(controller_index); + }); + } + }; +} + +REGISTER_COMPONENT(stats::component) diff --git a/src/client/component/steam_proxy.cpp b/src/client/component/steam_proxy.cpp new file mode 100644 index 0000000..935dbcb --- /dev/null +++ b/src/client/component/steam_proxy.cpp @@ -0,0 +1,210 @@ +#include +#include "loader/component_loader.hpp" +#include "scheduler.hpp" + +#include +#include +#include + +#include "game/game.hpp" + +#include "steam/interface.hpp" +#include "steam/steam.hpp" + +namespace steam_proxy +{ + namespace + { + enum class ownership_state + { + success, + unowned, + nosteam, + error, + }; + + ownership_state state_; + + utils::binary_resource runner_file(RUNNER, "runner.exe"); + } + + class component final : public component_interface + { + public: + void post_load() override + { + if (game::environment::is_dedi()) + { + return; + } + + this->load_client(); + this->clean_up_on_error(); + +#ifndef DEV_BUILD + try + { + const std::string game_type = game::environment::is_sp() ? "singleplayer" : "multiplayer"; + state_ = this->start_mod("\xF0\x9F\x92\x8E" " iw6-mod: " + (game_type), game::environment::is_sp() ? 209160 : 209170); + } + catch (const std::exception& ex) + { + state_ = ownership_state::error; + printf("Steam: %s\n", ex.what()); + } +#endif + (void)state_; + } + + void pre_destroy() override + { + if (this->steam_client_module_) + { + if (this->steam_pipe_) + { + if (this->global_user_) + { + this->steam_client_module_.invoke("Steam_ReleaseUser", this->steam_pipe_, this->global_user_); + } + + this->steam_client_module_.invoke("Steam_BReleaseSteamPipe", this->steam_pipe_); + } + } + } + + [[nodiscard]] const utils::nt::library& get_overlay_module() const + { + return steam_overlay_module_; + } + + private: + utils::nt::library steam_client_module_{}; + utils::nt::library steam_overlay_module_{}; + + steam::interface client_engine_{}; + steam::interface client_user_{}; + steam::interface client_utils_{}; + + void* steam_pipe_ = nullptr; + void* global_user_ = nullptr; + + [[nodiscard]] void* load_client_engine() const + { + if (!this->steam_client_module_) return nullptr; + + for (auto i = 1; i < 1000; ++i) + { + const auto* name = utils::string::va("CLIENTENGINE_INTERFACE_VERSION%03i", i); + auto* const client_engine = this->steam_client_module_.invoke("CreateInterface", name, nullptr); + if (client_engine) return client_engine; + } + + return nullptr; + } + + void load_client() + { + const std::filesystem::path steam_path = steam::SteamAPI_GetSteamInstallPath(); + if (steam_path.empty()) return; + + utils::nt::library::load(steam_path / "tier0_s64.dll"); + utils::nt::library::load(steam_path / "vstdlib_s64.dll"); + this->steam_overlay_module_ = utils::nt::library::load(steam_path / "gameoverlayrenderer64.dll"); + this->steam_client_module_ = utils::nt::library::load(steam_path / "steamclient64.dll"); + if (!this->steam_client_module_) return; + + this->client_engine_ = load_client_engine(); + if (!this->client_engine_) return; + + this->steam_pipe_ = this->steam_client_module_.invoke("Steam_CreateSteamPipe"); + this->global_user_ = this->steam_client_module_.invoke("Steam_ConnectToGlobalUser", this->steam_pipe_); + this->client_user_ = this->client_engine_.invoke(8, this->steam_pipe_, this->global_user_); + // GetIClientUser + this->client_utils_ = this->client_engine_.invoke(14, this->steam_pipe_); // GetIClientUtils + } + + ownership_state start_mod(const std::string& title, const size_t app_id) + { + __try + { + return this->start_mod_unsafe(title, app_id); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + this->do_cleanup(); + return ownership_state::error; + } + } + + ownership_state start_mod_unsafe(const std::string& title, size_t app_id) + { + if (!this->client_utils_ || !this->client_user_) + { + return ownership_state::nosteam; + } + + if (!this->client_user_.invoke("BIsSubscribedApp", app_id)) + { +#ifdef _DEBUG + app_id = 480; // Spacewar +#else + return ownership_state::unowned; +#endif + } + + this->client_utils_.invoke("SetAppIDForCurrentPipe", app_id, false); + + char our_directory[MAX_PATH]{}; + GetCurrentDirectoryA(sizeof(our_directory), our_directory); + + const auto path = runner_file.get_extracted_file(); + const auto* cmdline = utils::string::va("\"%s\" -proc %d", path.data(), GetCurrentProcessId()); + + steam::game_id game_id; + game_id.raw.type = 1; // k_EGameIDTypeGameMod + game_id.raw.app_id = app_id & 0xFFFFFF; + + const auto* mod_id = "iw6-mod"; + game_id.raw.mod_id = *reinterpret_cast(mod_id) | 0x80000000; + + this->client_user_.invoke("SpawnProcess", path.data(), cmdline, our_directory, + &game_id.bits, title.data(), 0, 0, 0); + + return ownership_state::success; + } + + void do_cleanup() + { + this->client_engine_ = nullptr; + this->client_user_ = nullptr; + this->client_utils_ = nullptr; + + this->steam_pipe_ = nullptr; + this->global_user_ = nullptr; + + this->steam_client_module_ = utils::nt::library{ nullptr }; + } + + void clean_up_on_error() + { + scheduler::schedule([this]() + { + if (this->steam_client_module_ + && this->steam_pipe_ + && this->global_user_ + && this->steam_client_module_.invoke("Steam_BConnected", this->global_user_, this->steam_pipe_) + && this->steam_client_module_.invoke("Steam_BLoggedOn", this->global_user_, this->steam_pipe_) + ) + { + return scheduler::cond_continue; + } + + this->do_cleanup(); + + return scheduler::cond_end; + }); + } + }; +} + +REGISTER_COMPONENT(steam_proxy::component) diff --git a/src/client/component/system_check.cpp b/src/client/component/system_check.cpp new file mode 100644 index 0000000..f7c0db1 --- /dev/null +++ b/src/client/component/system_check.cpp @@ -0,0 +1,99 @@ +#include +#include "loader/component_loader.hpp" +#include "system_check.hpp" + +#include "game/game.hpp" + +#include +#include + +namespace system_check +{ + namespace + { + std::string read_zone(const std::string& name) + { + std::string data{}; + if (utils::io::read_file(name, &data)) + { + return data; + } + + if (utils::io::read_file("zone/" + name, &data)) + { + return data; + } + + return {}; + } + + std::string hash_zone(const std::string& name) + { + const auto data = read_zone(name); + return utils::cryptography::sha256::compute(data, true); + } + + bool verify_hashes(const std::unordered_map& zone_hashes) + { + for (const auto& zone_hash : zone_hashes) + { + const auto hash = hash_zone(zone_hash.first); + if (hash != zone_hash.second) + { + return false; + } + } + + return true; + } + + bool is_system_valid() + { + static std::unordered_map mp_zone_hashes = + { + {"patch_common_mp.ff", "F1F08BFD03D0496199FAFD49CAA3E5786B70084A4C3C8841ACC4A7B7616D226C"}, + }; + + static std::unordered_map sp_zone_hashes = + { + {"patch_common.ff", "883DB33A1E386420EC6EF19F25C0D8081D01C1945BA2BCAD9FBD5460A201D6AA"}, + {"patch_common_alien_mp.ff", "78B00BFF961F69F9A45446D40638A5A7F5C3462F1AF05A833066772C62FB5DB2"}, + }; + + return verify_hashes(mp_zone_hashes) && (game::environment::is_dedi() || verify_hashes(sp_zone_hashes)); + } + + void verify_binary_version() + { + const auto value = *reinterpret_cast(0x140001337); + if (value != 0xDB0A33E7 && value != 0xA6D147E7) + { + throw std::runtime_error("Unsupported Call of Duty: Ghosts version"); + } + } + } + + bool is_valid() + { + static auto valid = is_system_valid(); + return valid; + } + + class component final : public component_interface + { + public: + void post_load() override + { + verify_binary_version(); + + if (!is_valid()) + { + game::show_error("Your game files are outdated or unsupported.\n" + "Please get the latest officially supported Call of Duty: Ghosts files, or you will get random crashes and issues.", + "Invalid game files!"); + } + } + }; +} + +REGISTER_COMPONENT(system_check::component) diff --git a/src/client/component/system_check.hpp b/src/client/component/system_check.hpp new file mode 100644 index 0000000..4813846 --- /dev/null +++ b/src/client/component/system_check.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace system_check +{ + bool is_valid(); +} diff --git a/src/client/component/thread_names.cpp b/src/client/component/thread_names.cpp new file mode 100644 index 0000000..2af1edf --- /dev/null +++ b/src/client/component/thread_names.cpp @@ -0,0 +1,59 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include "scheduler.hpp" + +#include + +namespace thread_names +{ + namespace + { + void set_thread_names() + { + static std::unordered_map thread_names = + { + {game::THREAD_CONTEXT_MAIN, "Main"}, + {game::THREAD_CONTEXT_BACKEND, "Backend"}, // Renderer + {game::THREAD_CONTEXT_WORKER0, "Worker0"}, + {game::THREAD_CONTEXT_WORKER1, "Worker1"}, + {game::THREAD_CONTEXT_WORKER2, "Worker2"}, + {game::THREAD_CONTEXT_WORKER3, "Worker3"}, + {game::THREAD_CONTEXT_WORKER4, "Worker4"}, + {game::THREAD_CONTEXT_WORKER5, "Worker5"}, + {game::THREAD_CONTEXT_WORKER6, "Worker6"}, + {game::THREAD_CONTEXT_WORKER7, "Worker7"}, + {game::THREAD_CONTEXT_SERVER, "Server"}, + {game::THREAD_CONTEXT_CINEMATIC, "Cinematic"}, + {game::THREAD_CONTEXT_DATABASE, "Database"}, + {game::THREAD_CONTEXT_STREAM, "Stream"}, + {game::THREAD_CONTEXT_SNDSTREAMPACKETCALLBACK, "Snd stream packet callback"}, + {game::THREAD_CONTEXT_STATS_WRITE, "Stats write"}, + }; + + for (const auto& thread_name : thread_names) + { + const auto id = game::threadIds[thread_name.first]; + if (id) + { + utils::thread::set_name(id, thread_name.second); + } + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + set_thread_names(); + scheduler::once(set_thread_names, scheduler::pipeline::main); + scheduler::once(set_thread_names, scheduler::pipeline::renderer); + scheduler::once(set_thread_names, scheduler::pipeline::server); + } + }; +} + +REGISTER_COMPONENT(thread_names::component) diff --git a/src/client/component/ui_scripting.cpp b/src/client/component/ui_scripting.cpp new file mode 100644 index 0000000..5a1f7cc --- /dev/null +++ b/src/client/component/ui_scripting.cpp @@ -0,0 +1,391 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "command.hpp" + +#include "localized_strings.hpp" +#include "console.hpp" +#include "game_module.hpp" + +#include "game/ui_scripting/execution.hpp" + +#include "ui_scripting.hpp" + +#include +#include + +namespace ui_scripting +{ + namespace + { + std::unordered_map> converted_functions; + + utils::hook::detour hks_start_hook; + utils::hook::detour hks_shutdown_hook; + utils::hook::detour hks_package_require_hook; + + struct script + { + std::string name; + std::string root; + }; + + struct globals + { + std::string in_require_script; + std::vector + + + \ No newline at end of file diff --git a/src/client/resources/splash.bmp b/src/client/resources/splash.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5c0d7b6c71300a47c9bf4b4d5785036d53f49151 GIT binary patch literal 1105976 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�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

9;FdMFCA9E#=yqkbK)pjzMsHZn%35LseAY< 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%0DO?367Ug@+IFsm{RGXm!w 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%0AFcan44^qWY=in-$Z}*osQFhMF+`0kM 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 bBYR= + +#pragma comment(linker, "/merge:.data=.cld") +#pragma comment(linker, "/merge:.rdata=.clr") +#pragma comment(linker, "/merge:.cl=.main") +#pragma comment(linker, "/merge:.text=.main") +#pragma comment(linker, "/stack:0x1000000") + +#ifdef INJECT_HOST_AS_LIB +#pragma comment(linker, "/base:0x150000000") +#else +#pragma comment(linker, "/base:0x140000000") +#endif + +#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language=''\"") + +#ifndef INJECT_HOST_AS_LIB +#pragma bss_seg(".payload") +char payload_data[BINARY_PAYLOAD_SIZE]; +#endif + +extern "C" +{ + __declspec(dllexport) DWORD NvOptimusEnablement = 1; + __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1; +}; + +extern "C" { +int s_read_arc4random(void*, size_t) +{ + return -1; +} + +int s_read_getrandom(void*, size_t) +{ + return -1; +} + +int s_read_urandom(void*, size_t) +{ + return -1; +} + +int s_read_ltm_rng(void*, size_t) +{ + return -1; +} +} diff --git a/src/client/std_include.hpp b/src/client/std_include.hpp new file mode 100644 index 0000000..3f7c182 --- /dev/null +++ b/src/client/std_include.hpp @@ -0,0 +1,97 @@ +#pragma once + +// MP: 0x0B459A00 +// SP: 0x079C6A00 +#define BINARY_PAYLOAD_SIZE 0x0B500000 + +// Decide whether to load the game as lib or to inject it +#define INJECT_HOST_AS_LIB + +#pragma warning(push) +#pragma warning(disable: 4100) +#pragma warning(disable: 4127) +#pragma warning(disable: 4244) +#pragma warning(disable: 4458) +#pragma warning(disable: 4702) +#pragma warning(disable: 4996) +#pragma warning(disable: 5054) + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// min and max is required by gdi, therefore NOMINMAX won't work +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#pragma warning(pop) +#pragma warning(disable: 4100) + +#pragma comment(lib, "Crypt32.lib") +#pragma comment(lib, "iphlpapi.lib") +#pragma comment(lib, "dbghelp.lib") +#pragma comment(lib, "ntdll.lib") +#pragma comment(lib, "urlmon.lib" ) +#pragma comment(lib, "ws2_32.lib") + +#include "resource.hpp" + +using namespace std::literals; diff --git a/src/client/steam/interface.cpp b/src/client/steam/interface.cpp new file mode 100644 index 0000000..708f55b --- /dev/null +++ b/src/client/steam/interface.cpp @@ -0,0 +1,98 @@ +#include +#include "interface.hpp" + +#include +#include + +namespace steam +{ + interface::interface() : interface(nullptr) + { + } + + interface::interface(void* interface_ptr) : interface_ptr_(static_cast(interface_ptr)) + { + } + + interface::operator bool() const + { + return this->interface_ptr_ != nullptr; + } + + void* interface::find_method(const std::string& name) + { + const auto method_entry = this->methods_.find(name); + if (method_entry != this->methods_.end()) + { + return method_entry->second; + } + + return this->search_method(name); + } + + void* interface::search_method(const std::string& name) + { + if (!utils::memory::is_bad_read_ptr(this->interface_ptr_)) + { + auto vftbl = *this->interface_ptr_; + + while (!utils::memory::is_bad_read_ptr(vftbl) && !utils::memory::is_bad_code_ptr(*vftbl)) + { + const auto ptr = *vftbl; + const auto result = this->analyze_method(ptr); + if (!result.empty()) + { + this->methods_[result] = ptr; + + if (result == name) + { + return ptr; + } + } + + ++vftbl; + } + } + + return {}; + } + + std::string interface::analyze_method(const void* method_ptr) + { + if (utils::memory::is_bad_code_ptr(method_ptr)) return {}; + + ud_t ud; + ud_init(&ud); + ud_set_mode(&ud, 64); + ud_set_pc(&ud, uint64_t(method_ptr)); + ud_set_input_buffer(&ud, static_cast(method_ptr), INT32_MAX); + + while (true) + { + ud_disassemble(&ud); + + if (ud_insn_mnemonic(&ud) == UD_Iret) + { + break; + } + + if (ud_insn_mnemonic(&ud) == UD_Ilea) + { + const auto* operand = ud_insn_opr(&ud, 1); + if (operand && operand->type == UD_OP_MEM && operand->base == UD_R_RIP) + { + auto* operand_ptr = reinterpret_cast(ud_insn_len(&ud) + ud_insn_off(&ud) + operand->lval.sdword); + if (!utils::memory::is_bad_read_ptr(operand_ptr) && utils::memory::is_rdata_ptr(operand_ptr)) + { + return operand_ptr; + } + + } + } + + if (*reinterpret_cast(ud.pc) == 0xCC) break; // int 3 + } + + return {}; + } +} diff --git a/src/client/steam/interface.hpp b/src/client/steam/interface.hpp new file mode 100644 index 0000000..fe2cf35 --- /dev/null +++ b/src/client/steam/interface.hpp @@ -0,0 +1,84 @@ +#pragma once + +#ifdef interface +#undef interface +#endif + +namespace steam +{ + struct raw_steam_id final + { + unsigned int account_id : 32; + unsigned int account_instance : 20; + unsigned int account_type : 4; + int universe : 8; + }; + + typedef union + { + raw_steam_id raw; + unsigned long long bits; + } steam_id; + +#pragma pack( push, 1 ) + struct raw_game_id final + { + unsigned int app_id : 24; + unsigned int type : 8; + unsigned int mod_id : 32; + }; + + typedef union + { + raw_game_id raw; + unsigned long long bits; + } game_id; +#pragma pack( pop ) + + class interface final + { + public: + + interface(); + interface(void* interface_ptr); + + operator bool() const; + + template + T invoke(const std::string& method_name, Args ... args) + { + if (!this->interface_ptr_) + { + throw std::runtime_error("Invalid interface pointer"); + } + + const auto method = this->find_method(method_name); + if (!method) + { + throw std::runtime_error("Unable to find method: " + method_name); + } + + return static_cast(method)(this->interface_ptr_, args...); + } + + template + T invoke(const size_t table_entry, Args ... args) + { + if (!this->interface_ptr_) + { + throw std::runtime_error("Invalid interface pointer"); + } + + return static_cast((*this->interface_ptr_)[table_entry])(this->interface_ptr_, args...); + } + + private: + void*** interface_ptr_; + std::unordered_map methods_; + + void* find_method(const std::string& name); + void* search_method(const std::string& name); + + std::string analyze_method(const void* method_ptr); + }; +} diff --git a/src/client/steam/interfaces/apps.cpp b/src/client/steam/interfaces/apps.cpp new file mode 100644 index 0000000..26f4a8f --- /dev/null +++ b/src/client/steam/interfaces/apps.cpp @@ -0,0 +1,104 @@ +#include +#include "steam/steam.hpp" + +namespace steam +{ + bool apps::BIsSubscribed() + { + return true; + } + + bool apps::BIsLowViolence() + { + return false; + } + + bool apps::BIsCybercafe() + { + return false; + } + + bool apps::BIsVACBanned() + { + return false; + } + + const char* apps::GetCurrentGameLanguage() + { + return "english"; + } + + const char* apps::GetAvailableGameLanguages() + { + return "english"; + } + + bool apps::BIsSubscribedApp(unsigned int appID) + { + return true; + } + + bool apps::BIsDlcInstalled(unsigned int appID) + { + return true; + } + + unsigned int apps::GetEarliestPurchaseUnixTime(unsigned int nAppID) + { + return 0; + } + + bool apps::BIsSubscribedFromFreeWeekend() + { + return false; + } + + int apps::GetDLCCount() + { + return 0; + } + + bool apps::BGetDLCDataByIndex(int iDLC, unsigned int* pAppID, bool* pbAvailable, char* pchName, + int cchNameBufferSize) + { + return false; + } + + void apps::InstallDLC(unsigned int nAppID) + { + } + + void apps::UninstallDLC(unsigned int nAppID) + { + } + + void apps::RequestAppProofOfPurchaseKey(unsigned int nAppID) + { + } + + bool apps::GetCurrentBetaName(char *pchName, int cchNameBufferSize) + { + strncpy_s(pchName, cchNameBufferSize, "public", cchNameBufferSize); + return true; + } + + bool apps::MarkContentCorrupt(bool bMissingFilesOnly) + { + return false; + } + + unsigned int apps::GetInstalledDepots(int *pvecDepots, unsigned int cMaxDepots) + { + return 0; + } + + unsigned int apps::GetAppInstallDir(unsigned int appID, char *pchFolder, unsigned int cchFolderBufferSize) + { + return 0; + } + + bool apps::BIsAppInstalled(unsigned int appID) + { + return false; + } +} diff --git a/src/client/steam/interfaces/apps.hpp b/src/client/steam/interfaces/apps.hpp new file mode 100644 index 0000000..afa7c65 --- /dev/null +++ b/src/client/steam/interfaces/apps.hpp @@ -0,0 +1,32 @@ +#pragma once + +namespace steam +{ + class apps + { + public: + ~apps() = default; + + virtual bool BIsSubscribed(); + virtual bool BIsLowViolence(); + virtual bool BIsCybercafe(); + virtual bool BIsVACBanned(); + virtual const char* GetCurrentGameLanguage(); + virtual const char* GetAvailableGameLanguages(); + virtual bool BIsSubscribedApp(unsigned int appID); + virtual bool BIsDlcInstalled(unsigned int appID); + virtual unsigned int GetEarliestPurchaseUnixTime(unsigned int nAppID); + virtual bool BIsSubscribedFromFreeWeekend(); + virtual int GetDLCCount(); + virtual bool BGetDLCDataByIndex(int iDLC, unsigned int* pAppID, bool* pbAvailable, char* pchName, + int cchNameBufferSize); + virtual void InstallDLC(unsigned int nAppID); + virtual void UninstallDLC(unsigned int nAppID); + virtual void RequestAppProofOfPurchaseKey(unsigned int nAppID); + virtual bool GetCurrentBetaName(char *pchName, int cchNameBufferSize); + virtual bool MarkContentCorrupt(bool bMissingFilesOnly); + virtual unsigned int GetInstalledDepots(int *pvecDepots, unsigned int cMaxDepots); + virtual unsigned int GetAppInstallDir(unsigned int appID, char *pchFolder, unsigned int cchFolderBufferSize); + virtual bool BIsAppInstalled(unsigned int appID); + }; +} diff --git a/src/client/steam/interfaces/friends.cpp b/src/client/steam/interfaces/friends.cpp new file mode 100644 index 0000000..d46c6a8 --- /dev/null +++ b/src/client/steam/interfaces/friends.cpp @@ -0,0 +1,312 @@ +#include +#include "steam/steam.hpp" + +namespace steam +{ + const char* friends::GetPersonaName() + { + return "GlaDos"; + } + + unsigned long long friends::SetPersonaName(const char* pchPersonaName) + { + return 0; + } + + int friends::GetPersonaState() + { + return 1; + } + + int friends::GetFriendCount(int eFriendFlags) + { + return 0; + } + + steam_id friends::GetFriendByIndex(int iFriend, int iFriendFlags) + { + return steam_id(); + } + + int friends::GetFriendRelationship(steam_id steamIDFriend) + { + return 0; + } + + int friends::GetFriendPersonaState(steam_id steamIDFriend) + { + return 0; + } + + const char* friends::GetFriendPersonaName(steam_id steamIDFriend) + { + return ""; + } + + bool friends::GetFriendGamePlayed(steam_id steamIDFriend, void* pFriendGameInfo) + { + return false; + } + + const char* friends::GetFriendPersonaNameHistory(steam_id steamIDFriend, int iPersonaName) + { + return ""; + } + + bool friends::HasFriend(steam_id steamIDFriend, int eFriendFlags) + { + return false; + } + + int friends::GetClanCount() + { + return 0; + } + + steam_id friends::GetClanByIndex(int iClan) + { + return steam_id(); + } + + const char* friends::GetClanName(steam_id steamIDClan) + { + return "3arc"; + } + + const char* friends::GetClanTag(steam_id steamIDClan) + { + return this->GetClanName(steamIDClan); + } + + bool friends::GetClanActivityCounts(steam_id steamID, int* pnOnline, int* pnInGame, int* pnChatting) + { + return false; + } + + unsigned long long friends::DownloadClanActivityCounts(steam_id groupIDs[], int nIds) + { + return 0; + } + + int friends::GetFriendCountFromSource(steam_id steamIDSource) + { + return 0; + } + + steam_id friends::GetFriendFromSourceByIndex(steam_id steamIDSource, int iFriend) + { + return steam_id(); + } + + bool friends::IsUserInSource(steam_id steamIDUser, steam_id steamIDSource) + { + return false; + } + + void friends::SetInGameVoiceSpeaking(steam_id steamIDUser, bool bSpeaking) + { + } + + void friends::ActivateGameOverlay(const char* pchDialog) + { + } + + void friends::ActivateGameOverlayToUser(const char* pchDialog, steam_id steamID) + { + } + + void friends::ActivateGameOverlayToWebPage(const char* pchURL) + { + } + + void friends::ActivateGameOverlayToStore(unsigned int nAppID, unsigned int eFlag) + { + OutputDebugStringA("Store requested!"); + } + + void friends::SetPlayedWith(steam_id steamIDUserPlayedWith) + { + } + + void friends::ActivateGameOverlayInviteDialog(steam_id steamIDLobby) + { + } + + int friends::GetSmallFriendAvatar(steam_id steamIDFriend) + { + return 0; + } + + int friends::GetMediumFriendAvatar(steam_id steamIDFriend) + { + return 0; + } + + int friends::GetLargeFriendAvatar(steam_id steamIDFriend) + { + return 0; + } + + bool friends::RequestUserInformation(steam_id steamIDUser, bool bRequireNameOnly) + { + return false; + } + + unsigned long long friends::RequestClanOfficerList(steam_id steamIDClan) + { + return 0; + } + + steam_id friends::GetClanOwner(steam_id steamIDClan) + { + return steam_id(); + } + + int friends::GetClanOfficerCount(steam_id steamIDClan) + { + return 0; + } + + steam_id friends::GetClanOfficerByIndex(steam_id steamIDClan, int iOfficer) + { + return steam_id(); + } + + int friends::GetUserRestrictions() + { + return 0; + } + + bool friends::SetRichPresence(const char* pchKey, const char* pchValue) + { + return true; + } + + void friends::ClearRichPresence() + { + } + + const char* friends::GetFriendRichPresence(steam_id steamIDFriend, const char* pchKey) + { + return ""; + } + + int friends::GetFriendRichPresenceKeyCount(steam_id steamIDFriend) + { + return 0; + } + + const char* friends::GetFriendRichPresenceKeyByIndex(steam_id steamIDFriend, int iKey) + { + return "a"; + } + + void friends::RequestFriendRichPresence(steam_id steamIDFriend) + { + } + + bool friends::InviteUserToGame(steam_id steamIDFriend, const char* pchConnectString) + { + return false; + } + + int friends::GetCoplayFriendCount() + { + return 0; + } + + steam_id friends::GetCoplayFriend(int iCoplayFriend) + { + return steam_id(); + } + + int friends::GetFriendCoplayTime(steam_id steamIDFriend) + { + return 0; + } + + unsigned int friends::GetFriendCoplayGame(steam_id steamIDFriend) + { + return 0; + } + + unsigned long long friends::JoinClanChatRoom(steam_id steamIDClan) + { + return 0; + } + + bool friends::LeaveClanChatRoom(steam_id steamIDClan) + { + return false; + } + + int friends::GetClanChatMemberCount(steam_id steamIDClan) + { + return 0; + } + + steam_id friends::GetChatMemberByIndex(steam_id steamIDClan, int iUser) + { + return steam_id(); + } + + bool friends::SendClanChatMessage(steam_id steamIDClanChat, const char *pchText) + { + return false; + } + + int friends::GetClanChatMessage(steam_id steamIDClanChat, int iMessage, void *prgchText, int cchTextMax, unsigned int *peChatEntryType, steam_id *pSteamIDChatter) + { + return 0; + } + + bool friends::IsClanChatAdmin(steam_id steamIDClanChat, steam_id steamIDUser) + { + return false; + } + + bool friends::IsClanChatWindowOpenInSteam(steam_id steamIDClanChat) + { + return false; + } + + bool friends::OpenClanChatWindowInSteam(steam_id steamIDClanChat) + { + return false; + } + + bool friends::CloseClanChatWindowInSteam(steam_id steamIDClanChat) + { + return false; + } + + bool friends::SetListenForFriendsMessages(bool bInterceptEnabled) + { + return false; + } + + bool friends::ReplyToFriendMessage(steam_id steamIDFriend, const char *pchMsgToSend) + { + return false; + } + + int friends::GetFriendMessage(steam_id steamIDFriend, int iMessageID, void *pvData, int cubData, unsigned int *peChatEntryType) + { + return 0; + } + + unsigned long long friends::GetFollowerCount(steam_id steamID) + { + return 0; + } + + unsigned long long friends::IsFollowing(steam_id steamID) + { + return 0; + } + + unsigned long long friends::EnumerateFollowingList(unsigned int unStartIndex) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/friends.hpp b/src/client/steam/interfaces/friends.hpp new file mode 100644 index 0000000..e4f5263 --- /dev/null +++ b/src/client/steam/interfaces/friends.hpp @@ -0,0 +1,74 @@ +#pragma once + +namespace steam +{ + class friends + { + public: + ~friends() = default; + + virtual const char* GetPersonaName(); + virtual unsigned long long SetPersonaName(const char* pchPersonaName); + virtual int GetPersonaState(); + virtual int GetFriendCount(int eFriendFlags); + virtual steam_id GetFriendByIndex(int iFriend, int iFriendFlags); + virtual int GetFriendRelationship(steam_id steamIDFriend); + virtual int GetFriendPersonaState(steam_id steamIDFriend); + virtual const char* GetFriendPersonaName(steam_id steamIDFriend); + virtual bool GetFriendGamePlayed(steam_id steamIDFriend, void* pFriendGameInfo); + virtual const char* GetFriendPersonaNameHistory(steam_id steamIDFriend, int iPersonaName); + virtual bool HasFriend(steam_id steamIDFriend, int eFriendFlags); + virtual int GetClanCount(); + virtual steam_id GetClanByIndex(int iClan); + virtual const char* GetClanName(steam_id steamIDClan); + virtual const char* GetClanTag(steam_id steamIDClan); + virtual bool GetClanActivityCounts(steam_id steamID, int *pnOnline, int *pnInGame, int *pnChatting); + virtual unsigned long long DownloadClanActivityCounts(steam_id groupIDs[], int nIds); + virtual int GetFriendCountFromSource(steam_id steamIDSource); + virtual steam_id GetFriendFromSourceByIndex(steam_id steamIDSource, int iFriend); + virtual bool IsUserInSource(steam_id steamIDUser, steam_id steamIDSource); + virtual void SetInGameVoiceSpeaking(steam_id steamIDUser, bool bSpeaking); + virtual void ActivateGameOverlay(const char* pchDialog); + virtual void ActivateGameOverlayToUser(const char* pchDialog, steam_id steamID); + virtual void ActivateGameOverlayToWebPage(const char* pchURL); + virtual void ActivateGameOverlayToStore(unsigned int nAppID, unsigned int eFlag); + virtual void SetPlayedWith(steam_id steamIDUserPlayedWith); + virtual void ActivateGameOverlayInviteDialog(steam_id steamIDLobby); + virtual int GetSmallFriendAvatar(steam_id steamIDFriend); + virtual int GetMediumFriendAvatar(steam_id steamIDFriend); + virtual int GetLargeFriendAvatar(steam_id steamIDFriend); + virtual bool RequestUserInformation(steam_id steamIDUser, bool bRequireNameOnly); + virtual unsigned long long RequestClanOfficerList(steam_id steamIDClan); + virtual steam_id GetClanOwner(steam_id steamIDClan); + virtual int GetClanOfficerCount(steam_id steamIDClan); + virtual steam_id GetClanOfficerByIndex(steam_id steamIDClan, int iOfficer); + virtual int GetUserRestrictions(); + virtual bool SetRichPresence(const char* pchKey, const char* pchValue); + virtual void ClearRichPresence(); + virtual const char* GetFriendRichPresence(steam_id steamIDFriend, const char* pchKey); + virtual int GetFriendRichPresenceKeyCount(steam_id steamIDFriend); + virtual const char* GetFriendRichPresenceKeyByIndex(steam_id steamIDFriend, int iKey); + virtual void RequestFriendRichPresence(steam_id steamIDFriend); + virtual bool InviteUserToGame(steam_id steamIDFriend, const char* pchConnectString); + virtual int GetCoplayFriendCount(); + virtual steam_id GetCoplayFriend(int iCoplayFriend); + virtual int GetFriendCoplayTime(steam_id steamIDFriend); + virtual unsigned int GetFriendCoplayGame(steam_id steamIDFriend); + virtual unsigned long long JoinClanChatRoom(steam_id steamIDClan); + virtual bool LeaveClanChatRoom(steam_id steamIDClan); + virtual int GetClanChatMemberCount(steam_id steamIDClan); + virtual steam_id GetChatMemberByIndex( steam_id steamIDClan, int iUser ); + virtual bool SendClanChatMessage(steam_id steamIDClanChat, const char *pchText); + virtual int GetClanChatMessage(steam_id steamIDClanChat, int iMessage, void *prgchText, int cchTextMax, unsigned int *peChatEntryType, steam_id *pSteamIDChatter); + virtual bool IsClanChatAdmin(steam_id steamIDClanChat, steam_id steamIDUser); + virtual bool IsClanChatWindowOpenInSteam(steam_id steamIDClanChat); + virtual bool OpenClanChatWindowInSteam(steam_id steamIDClanChat); + virtual bool CloseClanChatWindowInSteam(steam_id steamIDClanChat); + virtual bool SetListenForFriendsMessages(bool bInterceptEnabled); + virtual bool ReplyToFriendMessage(steam_id steamIDFriend, const char *pchMsgToSend); + virtual int GetFriendMessage(steam_id steamIDFriend, int iMessageID, void *pvData, int cubData, unsigned int *peChatEntryType); + virtual unsigned long long GetFollowerCount(steam_id steamID); + virtual unsigned long long IsFollowing(steam_id steamID); + virtual unsigned long long EnumerateFollowingList(unsigned int unStartIndex); + }; +} diff --git a/src/client/steam/interfaces/game_server.cpp b/src/client/steam/interfaces/game_server.cpp new file mode 100644 index 0000000..d340be4 --- /dev/null +++ b/src/client/steam/interfaces/game_server.cpp @@ -0,0 +1,204 @@ +#include +#include "steam/steam.hpp" + +namespace steam +{ + bool game_server::InitGameServer(unsigned int unGameIP, unsigned short unGamePort, unsigned short usQueryPort, + unsigned int unServerFlags, unsigned int nAppID, const char* pchVersion) + { + return true; + } + + void game_server::SetProduct(const char* pchProductName) + { + } + + void game_server::SetGameDescription(const char* pchGameDescription) + { + } + + void game_server::SetModDir(const char* pchModDir) + { + } + + void game_server::SetDedicatedServer(bool bDedicatedServer) + { + } + + void game_server::LogOn(const char* pszAccountName, const char* pszPassword) + { + } + + void game_server::LogOnAnonymous() + { + auto* const retvals = calloc(1, 1); + const auto result = callbacks::register_call(); + callbacks::return_call(retvals, 0, 101, result); + } + + void game_server::LogOff() + { + } + + bool game_server::BLoggedOn() + { + return true; + } + + bool game_server::BSecure() + { + return false; + } + + steam_id game_server::GetSteamID() + { + return SteamUser()->GetSteamID(); + } + + bool game_server::WasRestartRequested() + { + return false; + } + + void game_server::SetMaxPlayerCount(int cPlayersMax) + { + } + + void game_server::SetBotPlayerCount(int cBotPlayers) + { + } + + void game_server::SetServerName(const char* pszServerName) + { + } + + void game_server::SetMapName(const char* pszMapName) + { + } + + void game_server::SetPasswordProtected(bool bPasswordProtected) + { + } + + void game_server::SetSpectatorPort(unsigned short unSpectatorPort) + { + } + + void game_server::SetSpectatorServerName(const char* pszSpectatorServerName) + { + } + + void game_server::ClearAllKeyValues() + { + } + + void game_server::SetKeyValue(const char* pKey, const char* pValue) + { + } + + void game_server::SetGameTags(const char* pchGameTags) + { + } + + void game_server::SetGameData(const char* pchGameData) + { + } + + void game_server::SetRegion(const char* pchRegionName) + { + } + + int game_server::SendUserConnectAndAuthenticate(unsigned int unIPClient, const void* pvAuthBlob, + unsigned int cubAuthBlobSize, steam_id* pSteamIDUser) + { + return 0; + } + + steam_id game_server::CreateUnauthenticatedUserConnection() + { + return SteamUser()->GetSteamID(); + } + + void game_server::SendUserDisconnect(steam_id steamIDUser) + { + } + + bool game_server::BUpdateUserData(steam_id steamIDUser, const char* pchPlayerName, unsigned int uScore) + { + return false; + } + + int game_server::GetAuthSessionTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket) + { + return 0; + } + + int game_server::BeginAuthSession(const void* pAuthTicket, int cbAuthTicket, steam_id steamID) + { + return 0; + } + + void game_server::EndAuthSession(steam_id steamID) + { + } + + void game_server::CancelAuthTicket(int hAuthTicket) + { + } + + int game_server::UserHasLicenseForApp(steam_id steamID, unsigned int appID) + { + return 0; + } + + bool game_server::RequestUserGroupStatus(steam_id steamIDUser, steam_id steamIDGroup) + { + return false; + } + + void game_server::GetGameplayStats() + { + } + + unsigned long long game_server::GetServerReputation() + { + return 0; + } + + unsigned int game_server::GetPublicIP() + { + return 0; + } + + bool game_server::HandleIncomingPacket(const void* pData, int cbData, unsigned int srcIP, unsigned short srcPort) + { + return false; + } + + int game_server::GetNextOutgoingPacket(void* pOut, int cbMaxOut, unsigned int* pNetAdr, unsigned short* pPort) + { + return 0; + } + + void game_server::EnableHeartbeats(bool bActive) + { + } + + void game_server::SetHeartbeatInterval(int iHeartbeatInterval) + { + } + + void game_server::ForceHeartbeat() + { + } + + unsigned long long game_server::AssociateWithClan(steam_id clanID) + { + return 0; + } + + unsigned long long game_server::ComputeNewPlayerCompatibility(steam_id steamID) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/game_server.hpp b/src/client/steam/interfaces/game_server.hpp new file mode 100644 index 0000000..97a2d25 --- /dev/null +++ b/src/client/steam/interfaces/game_server.hpp @@ -0,0 +1,55 @@ +#pragma once + +namespace steam +{ + class game_server + { + public: + ~game_server() = default; + + virtual bool InitGameServer(unsigned int unGameIP, unsigned short unGamePort, unsigned short usQueryPort, unsigned int unServerFlags, unsigned int nAppID, const char *pchVersion); + virtual void SetProduct(const char *pchProductName); + virtual void SetGameDescription(const char *pchGameDescription); + virtual void SetModDir(const char *pchModDir); + virtual void SetDedicatedServer(bool bDedicatedServer); + virtual void LogOn(const char *pszAccountName, const char *pszPassword); + virtual void LogOnAnonymous(); + virtual void LogOff(); + virtual bool BLoggedOn(); + virtual bool BSecure(); + virtual steam_id GetSteamID(); + virtual bool WasRestartRequested(); + virtual void SetMaxPlayerCount(int cPlayersMax); + virtual void SetBotPlayerCount(int cBotPlayers); + virtual void SetServerName(const char *pszServerName); + virtual void SetMapName(const char *pszMapName); + virtual void SetPasswordProtected(bool bPasswordProtected); + virtual void SetSpectatorPort(unsigned short unSpectatorPort); + virtual void SetSpectatorServerName(const char *pszSpectatorServerName); + virtual void ClearAllKeyValues(); + virtual void SetKeyValue(const char *pKey, const char *pValue); + virtual void SetGameTags(const char *pchGameTags); + virtual void SetGameData(const char *pchGameData); + virtual void SetRegion(const char *pchRegionName); + virtual int SendUserConnectAndAuthenticate(unsigned int unIPClient, const void *pvAuthBlob, unsigned int cubAuthBlobSize, steam_id *pSteamIDUser); + virtual steam_id CreateUnauthenticatedUserConnection(); + virtual void SendUserDisconnect(steam_id steamIDUser); + virtual bool BUpdateUserData(steam_id steamIDUser, const char *pchPlayerName, unsigned int uScore); + virtual int GetAuthSessionTicket(void *pTicket, int cbMaxTicket, unsigned int *pcbTicket); + virtual int BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, steam_id steamID); + virtual void EndAuthSession(steam_id steamID); + virtual void CancelAuthTicket(int hAuthTicket); + virtual int UserHasLicenseForApp(steam_id steamID, unsigned int appID); + virtual bool RequestUserGroupStatus(steam_id steamIDUser, steam_id steamIDGroup); + virtual void GetGameplayStats(); + virtual unsigned long long GetServerReputation(); + virtual unsigned int GetPublicIP(); + virtual bool HandleIncomingPacket(const void *pData, int cbData, unsigned int srcIP, unsigned short srcPort); + virtual int GetNextOutgoingPacket(void *pOut, int cbMaxOut, unsigned int *pNetAdr, unsigned short *pPort); + virtual void EnableHeartbeats(bool bActive); + virtual void SetHeartbeatInterval(int iHeartbeatInterval); + virtual void ForceHeartbeat(); + virtual unsigned long long AssociateWithClan(steam_id clanID); + virtual unsigned long long ComputeNewPlayerCompatibility(steam_id steamID); + }; +} diff --git a/src/client/steam/interfaces/matchmaking.cpp b/src/client/steam/interfaces/matchmaking.cpp new file mode 100644 index 0000000..abea6b0 --- /dev/null +++ b/src/client/steam/interfaces/matchmaking.cpp @@ -0,0 +1,227 @@ +#include + +#include "steam/steam.hpp" + +#include + +namespace steam +{ + int matchmaking::GetFavoriteGameCount() + { + return 0; + } + + bool matchmaking::GetFavoriteGame(int iGame, unsigned int* pnAppID, unsigned int* pnIP, unsigned short* pnConnPort, + unsigned short* pnQueryPort, unsigned int* punFlags, + unsigned int* pRTime32LastPlayedOnServer) + { + return false; + } + + int matchmaking::AddFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, + unsigned short nQueryPort, unsigned int unFlags, + unsigned int rTime32LastPlayedOnServer) + { + return 0; + } + + bool matchmaking::RemoveFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, + unsigned short nQueryPort, unsigned int unFlags) + { + return false; + } + + unsigned long long matchmaking::RequestLobbyList() + { + return 0; + } + + void matchmaking::AddRequestLobbyListStringFilter(const char* pchKeyToMatch, const char* pchValueToMatch, + int eComparisonType) + { + } + + void matchmaking::AddRequestLobbyListNumericalFilter(const char* pchKeyToMatch, int nValueToMatch, + int eComparisonType) + { + } + + void matchmaking::AddRequestLobbyListNearValueFilter(const char* pchKeyToMatch, int nValueToBeCloseTo) + { + } + + void matchmaking::AddRequestLobbyListFilterSlotsAvailable(int nSlotsAvailable) + { + } + + void matchmaking::AddRequestLobbyListDistanceFilter(int eLobbyDistanceFilter) + { + } + + void matchmaking::AddRequestLobbyListResultCountFilter(int cMaxResults) + { + } + + void matchmaking::AddRequestLobbyListCompatibleMembersFilter(steam_id steamID) + { + } + + steam_id matchmaking::GetLobbyByIndex(int iLobby) + { + return steam_id(); + } + + unsigned long long matchmaking::CreateLobby(int eLobbyType, int cMaxMembers) + { + const auto result = callbacks::register_call(); + auto retvals = static_cast(calloc(1, sizeof(lobby_created))); + //::Utils::Memory::AllocateArray(); + steam_id id; + + id.raw.account_id = 1337132; + id.raw.universe = 1; + id.raw.account_type = 8; + id.raw.account_instance = 0x40000; + + retvals->m_e_result = 1; + retvals->m_ul_steam_id_lobby = id; + + callbacks::return_call(retvals, sizeof(lobby_created), lobby_created::callback_id, result); + + matchmaking::JoinLobby(id); + + return result; + } + + unsigned long long matchmaking::JoinLobby(steam_id steamIDLobby) + { + const auto result = callbacks::register_call(); + auto* retvals = static_cast(calloc(1, sizeof(lobby_enter))); + //::Utils::Memory::AllocateArray(); + retvals->m_b_locked = false; + retvals->m_e_chat_room_enter_response = 1; + retvals->m_rgf_chat_permissions = 0xFFFFFFFF; + retvals->m_ul_steam_id_lobby = steamIDLobby; + + callbacks::return_call(retvals, sizeof(lobby_enter), lobby_enter::callback_id, result); + + return result; + } + + void matchmaking::LeaveLobby(steam_id steamIDLobby) + { + + } + + bool matchmaking::InviteUserToLobby(steam_id steamIDLobby, steam_id steamIDInvitee) + { + return true; + } + + int matchmaking::GetNumLobbyMembers(steam_id steamIDLobby) + { + return 1; + } + + steam_id matchmaking::GetLobbyMemberByIndex(steam_id steamIDLobby, int iMember) + { + return SteamUser()->GetSteamID(); + } + + const char* matchmaking::GetLobbyData(steam_id steamIDLobby, const char* pchKey) + { + return ""; + } + + bool matchmaking::SetLobbyData(steam_id steamIDLobby, const char* pchKey, const char* pchValue) + { + return true; + } + + int matchmaking::GetLobbyDataCount(steam_id steamIDLobby) + { + return 0; + } + + bool matchmaking::GetLobbyDataByIndex(steam_id steamIDLobby, int iLobbyData, char* pchKey, int cchKeyBufferSize, + char* pchValue, int cchValueBufferSize) + { + return false; + } + + bool matchmaking::DeleteLobbyData(steam_id steamIDLobby, const char* pchKey) + { + return false; + } + + const char* matchmaking::GetLobbyMemberData(steam_id steamIDLobby, steam_id steamIDUser, const char* pchKey) + { + return ""; + } + + void matchmaking::SetLobbyMemberData(steam_id steamIDLobby, const char* pchKey, const char* pchValue) + { + } + + bool matchmaking::SendLobbyChatMsg(steam_id steamIDLobby, const void* pvMsgBody, int cubMsgBody) + { + return true; + } + + int matchmaking::GetLobbyChatEntry(steam_id steamIDLobby, int iChatID, steam_id* pSteamIDUser, void* pvData, + int cubData, int* peChatEntryType) + { + return 0; + } + + bool matchmaking::RequestLobbyData(steam_id steamIDLobby) + { + return false; + } + + void matchmaking::SetLobbyGameServer(steam_id steamIDLobby, unsigned int unGameServerIP, + unsigned short unGameServerPort, steam_id steamIDGameServer) + { + } + + bool matchmaking::GetLobbyGameServer(steam_id steamIDLobby, unsigned int* punGameServerIP, + unsigned short* punGameServerPort, steam_id* psteamIDGameServer) + { + return false; + } + + bool matchmaking::SetLobbyMemberLimit(steam_id steamIDLobby, int cMaxMembers) + { + return true; + } + + int matchmaking::GetLobbyMemberLimit(steam_id steamIDLobby) + { + return 0; + } + + bool matchmaking::SetLobbyType(steam_id steamIDLobby, int eLobbyType) + { + return true; + } + + bool matchmaking::SetLobbyJoinable(steam_id steamIDLobby, bool bLobbyJoinable) + { + return true; + } + + steam_id matchmaking::GetLobbyOwner(steam_id steamIDLobby) + { + return SteamUser()->GetSteamID(); + } + + bool matchmaking::SetLobbyOwner(steam_id steamIDLobby, steam_id steamIDNewOwner) + { + return true; + } + + bool matchmaking::SetLinkedLobby(steam_id steamIDLobby, steam_id steamIDLobby2) + { + return true; + } +} diff --git a/src/client/steam/interfaces/matchmaking.hpp b/src/client/steam/interfaces/matchmaking.hpp new file mode 100644 index 0000000..8892321 --- /dev/null +++ b/src/client/steam/interfaces/matchmaking.hpp @@ -0,0 +1,79 @@ +#pragma once + +namespace steam +{ + struct lobby_created final + { + enum { callback_id = 513 }; + + int m_e_result; + int m_pad; + steam_id m_ul_steam_id_lobby; + }; + + struct lobby_enter final + { + enum { callback_id = 504 }; + + steam_id m_ul_steam_id_lobby; + int m_rgf_chat_permissions; + bool m_b_locked; + int m_e_chat_room_enter_response; + }; + + class matchmaking + { + public: + ~matchmaking() = default; + + virtual int GetFavoriteGameCount(); + virtual bool GetFavoriteGame(int iGame, unsigned int* pnAppID, unsigned int* pnIP, unsigned short* pnConnPort, + unsigned short* pnQueryPort, unsigned int* punFlags, + unsigned int* pRTime32LastPlayedOnServer); + virtual int AddFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, + unsigned short nQueryPort, unsigned int unFlags, + unsigned int rTime32LastPlayedOnServer); + virtual bool RemoveFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, + unsigned short nQueryPort, unsigned int unFlags); + virtual unsigned long long RequestLobbyList(); + virtual void AddRequestLobbyListStringFilter(const char* pchKeyToMatch, const char* pchValueToMatch, + int eComparisonType); + virtual void AddRequestLobbyListNumericalFilter(const char* pchKeyToMatch, int nValueToMatch, + int eComparisonType); + virtual void AddRequestLobbyListNearValueFilter(const char* pchKeyToMatch, int nValueToBeCloseTo); + virtual void AddRequestLobbyListFilterSlotsAvailable(int nSlotsAvailable); + virtual void AddRequestLobbyListDistanceFilter(int eLobbyDistanceFilter); + virtual void AddRequestLobbyListResultCountFilter(int cMaxResults); + virtual void AddRequestLobbyListCompatibleMembersFilter(steam_id steamID); + virtual steam_id GetLobbyByIndex(int iLobby); + virtual unsigned long long CreateLobby(int eLobbyType, int cMaxMembers); + virtual unsigned long long JoinLobby(steam_id steamIDLobby); + virtual void LeaveLobby(steam_id steamIDLobby); + virtual bool InviteUserToLobby(steam_id steamIDLobby, steam_id steamIDInvitee); + virtual int GetNumLobbyMembers(steam_id steamIDLobby); + virtual steam_id GetLobbyMemberByIndex(steam_id steamIDLobby, int iMember); + virtual const char* GetLobbyData(steam_id steamIDLobby, const char* pchKey); + virtual bool SetLobbyData(steam_id steamIDLobby, const char* pchKey, const char* pchValue); + virtual int GetLobbyDataCount(steam_id steamIDLobby); + virtual bool GetLobbyDataByIndex(steam_id steamIDLobby, int iLobbyData, char* pchKey, int cchKeyBufferSize, + char* pchValue, int cchValueBufferSize); + virtual bool DeleteLobbyData(steam_id steamIDLobby, const char* pchKey); + virtual const char* GetLobbyMemberData(steam_id steamIDLobby, steam_id steamIDUser, const char* pchKey); + virtual void SetLobbyMemberData(steam_id steamIDLobby, const char* pchKey, const char* pchValue); + virtual bool SendLobbyChatMsg(steam_id steamIDLobby, const void* pvMsgBody, int cubMsgBody); + virtual int GetLobbyChatEntry(steam_id steamIDLobby, int iChatID, steam_id* pSteamIDUser, void* pvData, + int cubData, int* peChatEntryType); + virtual bool RequestLobbyData(steam_id steamIDLobby); + virtual void SetLobbyGameServer(steam_id steamIDLobby, unsigned int unGameServerIP, + unsigned short unGameServerPort, steam_id steamIDGameServer); + virtual bool GetLobbyGameServer(steam_id steamIDLobby, unsigned int* punGameServerIP, + unsigned short* punGameServerPort, steam_id* psteamIDGameServer); + virtual bool SetLobbyMemberLimit(steam_id steamIDLobby, int cMaxMembers); + virtual int GetLobbyMemberLimit(steam_id steamIDLobby); + virtual bool SetLobbyType(steam_id steamIDLobby, int eLobbyType); + virtual bool SetLobbyJoinable(steam_id steamIDLobby, bool bLobbyJoinable); + virtual steam_id GetLobbyOwner(steam_id steamIDLobby); + virtual bool SetLobbyOwner(steam_id steamIDLobby, steam_id steamIDNewOwner); + virtual bool SetLinkedLobby(steam_id steamIDLobby, steam_id steamIDLobby2); + }; +} diff --git a/src/client/steam/interfaces/networking.cpp b/src/client/steam/interfaces/networking.cpp new file mode 100644 index 0000000..bcd871a --- /dev/null +++ b/src/client/steam/interfaces/networking.cpp @@ -0,0 +1,121 @@ +#include +#include "steam/steam.hpp" + +namespace steam +{ + bool networking::SendP2PPacket(steam_id steamIDRemote, const void* pubData, unsigned int cubData, int eP2PSendType) + { + return false; + } + + bool networking::IsP2PPacketAvailable(unsigned int* pcubMsgSize, int idk) + { + return false; + } + + bool networking::ReadP2PPacket(void* pubDest, unsigned int cubDest, unsigned int* pcubMsgSize, + steam_id* psteamIDRemote) + { + return false; + } + + bool networking::AcceptP2PSessionWithUser(steam_id steamIDRemote) + { + return false; + } + + bool networking::CloseP2PSessionWithUser(steam_id steamIDRemote) + { + return false; + } + + bool networking::CloseP2PChannelWithUser(steam_id steamIDRemote, int iVirtualPort) + { + return false; + } + + bool networking::GetP2PSessionState(steam_id steamIDRemote, void* pConnectionState) + { + return false; + } + + bool networking::AllowP2PPacketRelay(bool bAllow) + { + return false; + } + + unsigned int networking::CreateListenSocket(int nVirtualP2PPort, unsigned int nIP, unsigned short nPort, + bool bAllowUseOfPacketRelay) + { + return NULL; + } + + unsigned int networking::CreateP2PConnectionSocket(steam_id steamIDTarget, int nVirtualPort, int nTimeoutSec, + bool bAllowUseOfPacketRelay) + { + return NULL; + } + + unsigned int networking::CreateConnectionSocket(unsigned int nIP, unsigned short nPort, int nTimeoutSec) + { + return NULL; + } + + bool networking::DestroySocket(unsigned int hSocket, bool bNotifyRemoteEnd) + { + return false; + } + + bool networking::DestroyListenSocket(unsigned int hSocket, bool bNotifyRemoteEnd) + { + return false; + } + + bool networking::SendDataOnSocket(unsigned int hSocket, void* pubData, unsigned int cubData, bool bReliable) + { + return false; + } + + bool networking::IsDataAvailableOnSocket(unsigned int hSocket, unsigned int* pcubMsgSize) + { + return false; + } + + bool networking::RetrieveDataFromSocket(unsigned int hSocket, void* pubDest, unsigned int cubDest, + unsigned int* pcubMsgSize) + { + return false; + } + + bool networking::IsDataAvailable(unsigned int hListenSocket, unsigned int* pcubMsgSize, unsigned int* phSocket) + { + return false; + } + + bool networking::RetrieveData(unsigned int hListenSocket, void* pubDest, unsigned int cubDest, + unsigned int* pcubMsgSize, unsigned int* phSocket) + { + return false; + } + + bool networking::GetSocketInfo(unsigned int hSocket, steam_id* pSteamIDRemote, int* peSocketStatus, + unsigned int* punIPRemote, unsigned short* punPortRemote) + { + return false; + } + + bool networking::GetListenSocketInfo(unsigned int hListenSocket, unsigned int* pnIP, unsigned short* pnPort) + { + return false; + } + + int networking::GetSocketConnectionType(unsigned int hSocket) + { + return 0; + } + + int networking::GetMaxPacketSize(unsigned int hSocket) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/networking.hpp b/src/client/steam/interfaces/networking.hpp new file mode 100644 index 0000000..bb1b29d --- /dev/null +++ b/src/client/steam/interfaces/networking.hpp @@ -0,0 +1,39 @@ +#pragma once + +namespace steam +{ + class networking + { + public: + ~networking() = default; + + virtual bool SendP2PPacket(steam_id steamIDRemote, const void* pubData, unsigned int cubData, int eP2PSendType); + virtual bool IsP2PPacketAvailable(unsigned int* pcubMsgSize, int idk); + virtual bool ReadP2PPacket(void* pubDest, unsigned int cubDest, unsigned int* pcubMsgSize, + steam_id* psteamIDRemote); + virtual bool AcceptP2PSessionWithUser(steam_id steamIDRemote); + virtual bool CloseP2PSessionWithUser(steam_id steamIDRemote); + virtual bool CloseP2PChannelWithUser(steam_id steamIDRemote, int iVirtualPort); + virtual bool GetP2PSessionState(steam_id steamIDRemote, void* pConnectionState); + virtual bool AllowP2PPacketRelay(bool bAllow); + virtual unsigned int CreateListenSocket(int nVirtualP2PPort, unsigned int nIP, unsigned short nPort, + bool bAllowUseOfPacketRelay); + virtual unsigned int CreateP2PConnectionSocket(steam_id steamIDTarget, int nVirtualPort, int nTimeoutSec, + bool bAllowUseOfPacketRelay); + virtual unsigned int CreateConnectionSocket(unsigned int nIP, unsigned short nPort, int nTimeoutSec); + virtual bool DestroySocket(unsigned int hSocket, bool bNotifyRemoteEnd); + virtual bool DestroyListenSocket(unsigned int hSocket, bool bNotifyRemoteEnd); + virtual bool SendDataOnSocket(unsigned int hSocket, void* pubData, unsigned int cubData, bool bReliable); + virtual bool IsDataAvailableOnSocket(unsigned int hSocket, unsigned int* pcubMsgSize); + virtual bool RetrieveDataFromSocket(unsigned int hSocket, void* pubDest, unsigned int cubDest, + unsigned int* pcubMsgSize); + virtual bool IsDataAvailable(unsigned int hListenSocket, unsigned int* pcubMsgSize, unsigned int* phSocket); + virtual bool RetrieveData(unsigned int hListenSocket, void* pubDest, unsigned int cubDest, + unsigned int* pcubMsgSize, unsigned int* phSocket); + virtual bool GetSocketInfo(unsigned int hSocket, steam_id* pSteamIDRemote, int* peSocketStatus, + unsigned int* punIPRemote, unsigned short* punPortRemote); + virtual bool GetListenSocketInfo(unsigned int hListenSocket, unsigned int* pnIP, unsigned short* pnPort); + virtual int GetSocketConnectionType(unsigned int hSocket); + virtual int GetMaxPacketSize(unsigned int hSocket); + }; +} diff --git a/src/client/steam/interfaces/remote_storage.cpp b/src/client/steam/interfaces/remote_storage.cpp new file mode 100644 index 0000000..14e7e43 --- /dev/null +++ b/src/client/steam/interfaces/remote_storage.cpp @@ -0,0 +1,283 @@ +#include +#include "steam/steam.hpp" + +namespace steam +{ + bool remote_storage::FileWrite(const char* pchFile, const void* pvData, int cubData) + { + return true; + } + + int remote_storage::FileRead(const char* pchFile, void* pvData, int cubDataToRead) + { + return 0; + } + + bool remote_storage::FileForget(const char* pchFile) + { + return false; + } + + bool remote_storage::FileDelete(const char* pchFile) + { + return false; + } + + unsigned long long remote_storage::FileShare(const char* pchFile) + { + return 0; + } + + bool remote_storage::SetSyncPlatforms(const char* pchFile, unsigned int eRemoteStoragePlatform) + { + return false; + } + + unsigned long long remote_storage::FileWriteStreamOpen(const char* pchFile) + { + return 0; + } + + int remote_storage::FileWriteStreamWriteChunk(unsigned long long hStream, const void* pvData, int cubData) + { + return 2; + } + + int remote_storage::FileWriteStreamClose(unsigned long long hStream) + { + return 2; + } + + int remote_storage::FileWriteStreamCancel(unsigned long long hStream) + { + return 2; + } + + bool remote_storage::FileExists(const char* pchFile) + { + return false; + } + + bool remote_storage::FilePersisted(const char* pchFile) + { + return false; + } + + int remote_storage::GetFileSize(const char* pchFile) + { + return 0; + } + + long long remote_storage::GetFileTimestamp(const char* pchFile) + { + return 0; + } + + unsigned remote_storage::GetSyncPlatforms(const char* pchFile) + { + return 0; + } + + int remote_storage::GetFileCount() + { + return 0; + } + + const char* remote_storage::GetFileNameAndSize(int iFile, int* pnFileSizeInBytes) + { + *pnFileSizeInBytes = 0; + return ""; + } + + bool remote_storage::GetQuota(int* pnTotalBytes, int* puAvailableBytes) + { + *pnTotalBytes = 0x10000000; + *puAvailableBytes = 0x10000000; + return false; + } + + bool remote_storage::IsCloudEnabledForAccount() + { + return false; + } + + bool remote_storage::IsCloudEnabledForApp() + { + return false; + } + + void remote_storage::SetCloudEnabledForApp(bool bEnabled) + { + } + + unsigned long long remote_storage::UGCDownload(unsigned long long hContent, unsigned int uUnk) + { + return 0; + } + + bool remote_storage::GetUGCDownloadProgress(unsigned long long hContent, unsigned int* puDownloadedBytes, + unsigned int* puTotalBytes) + { + return false; + } + + bool remote_storage::GetUGCDetails(unsigned long long hContent, unsigned int* pnAppID, char** ppchName, + int* pnFileSizeInBytes, steam_id* pSteamIDOwner) + { + return false; + } + + int remote_storage::UGCRead(unsigned long long hContent, void* pvData, int cubDataToRead, unsigned int uOffset) + { + return 0; + } + + int remote_storage::GetCachedUGCCount() + { + return 0; + } + + unsigned long long remote_storage::GetCachedUGCHandle(int iCachedContent) + { + return 0; + } + + unsigned long long remote_storage::PublishWorkshopFile(const char* pchFile, const char* pchPreviewFile, + unsigned int nConsumerAppId, const char* pchTitle, + const char* pchDescription, unsigned int eVisibility, + int* pTags, unsigned int eWorkshopFileType) + { + return 0; + } + + unsigned long long remote_storage::CreatePublishedFileUpdateRequest(unsigned long long unPublishedFileId) + { + return 0; + } + + bool remote_storage::UpdatePublishedFileFile(unsigned long long hUpdateRequest, const char* pchFile) + { + return false; + } + + bool remote_storage::UpdatePublishedFilePreviewFile(unsigned long long hUpdateRequest, const char* pchPreviewFile) + { + return false; + } + + bool remote_storage::UpdatePublishedFileTitle(unsigned long long hUpdateRequest, const char* pchTitle) + { + return false; + } + + bool remote_storage::UpdatePublishedFileDescription(unsigned long long hUpdateRequest, const char* pchDescription) + { + return false; + } + + bool remote_storage::UpdatePublishedFileVisibility(unsigned long long hUpdateRequest, unsigned int eVisibility) + { + return false; + } + + bool remote_storage::UpdatePublishedFileTags(unsigned long long hUpdateRequest, int* pTags) + { + return false; + } + + unsigned long long remote_storage::CommitPublishedFileUpdate(unsigned long long hUpdateRequest) + { + return 0; + } + + unsigned long long remote_storage::GetPublishedFileDetails(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::DeletePublishedFile(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::EnumerateUserPublishedFiles(unsigned int uStartIndex) + { + return 0; + } + + unsigned long long remote_storage::SubscribePublishedFile(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::EnumerateUserSubscribedFiles(unsigned int uStartIndex) + { + return 0; + } + + unsigned long long remote_storage::UnsubscribePublishedFile(unsigned long long unPublishedFileId) + { + return 0; + } + + bool remote_storage::UpdatePublishedFileSetChangeDescription(unsigned long long hUpdateRequest, + const char* cszDescription) + { + return false; + } + + unsigned long long remote_storage::GetPublishedItemVoteDetails(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::UpdateUserPublishedItemVote(unsigned long long unPublishedFileId, bool bVoteUp) + { + return 0; + } + + unsigned long long remote_storage::GetUserPublishedItemVoteDetails(unsigned long long unPublishedFileId) + { + return 0; + } + + unsigned long long remote_storage::EnumerateUserSharedWorkshopFiles(unsigned int nAppId, steam_id creatorSteamID, + unsigned int uStartIndex, int* pRequiredTags, + int* pExcludedTags) + { + return 0; + } + + unsigned long long remote_storage::PublishVideo(unsigned int eVideoProvider, const char* cszVideoAccountName, + const char* cszVideoIdentifier, const char* cszFileName, + unsigned int nConsumerAppId, const char* cszTitle, + const char* cszDescription, unsigned int eVisibility, int* pTags) + { + return 0; + } + + unsigned long long remote_storage::SetUserPublishedFileAction(unsigned long long unPublishedFileId, + unsigned int eAction) + { + return 0; + } + + unsigned long long remote_storage::EnumeratePublishedFilesByUserAction( + unsigned int eAction, unsigned int uStartIndex) + { + return 0; + } + + unsigned long long remote_storage::EnumeratePublishedWorkshopFiles(unsigned int eType, unsigned int uStartIndex, + unsigned int cDays, unsigned int cCount, + int* pTags, int* pUserTags) + { + return 0; + } + + unsigned long long remote_storage::UGCDownloadToLocation(unsigned long long hContent, const char* cszLocation, + unsigned int uUnk) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/remote_storage.hpp b/src/client/steam/interfaces/remote_storage.hpp new file mode 100644 index 0000000..0f68981 --- /dev/null +++ b/src/client/steam/interfaces/remote_storage.hpp @@ -0,0 +1,63 @@ +#pragma once + +namespace steam +{ + class remote_storage + { + public: + ~remote_storage() = default; + + virtual bool FileWrite(const char *pchFile, const void *pvData, int cubData); + virtual int FileRead(const char *pchFile, void *pvData, int cubDataToRead); + virtual bool FileForget(const char *pchFile); + virtual bool FileDelete(const char *pchFile); + virtual unsigned long long FileShare(const char *pchFile); + virtual bool SetSyncPlatforms(const char *pchFile, unsigned int eRemoteStoragePlatform); + virtual unsigned long long FileWriteStreamOpen(const char *pchFile); + virtual int FileWriteStreamWriteChunk(unsigned long long hStream, const void *pvData, int cubData); + virtual int FileWriteStreamClose(unsigned long long hStream); + virtual int FileWriteStreamCancel(unsigned long long hStream); + virtual bool FileExists(const char *pchFile); + virtual bool FilePersisted(const char *pchFile); + virtual int GetFileSize(const char *pchFile); + virtual long long GetFileTimestamp(const char *pchFile); + virtual unsigned int GetSyncPlatforms(const char *pchFile); + virtual int GetFileCount(); + virtual const char *GetFileNameAndSize(int iFile, int *pnFileSizeInBytes); + virtual bool GetQuota(int *pnTotalBytes, int *puAvailableBytes); + virtual bool IsCloudEnabledForAccount(); + virtual bool IsCloudEnabledForApp(); + virtual void SetCloudEnabledForApp(bool bEnabled); + virtual unsigned long long UGCDownload(unsigned long long hContent, unsigned int uUnk); + virtual bool GetUGCDownloadProgress(unsigned long long hContent, unsigned int *puDownloadedBytes, unsigned int *puTotalBytes); + virtual bool GetUGCDetails(unsigned long long hContent, unsigned int *pnAppID, char **ppchName, int *pnFileSizeInBytes, steam_id *pSteamIDOwner); + virtual int UGCRead(unsigned long long hContent, void *pvData, int cubDataToRead, unsigned int uOffset); + virtual int GetCachedUGCCount(); + virtual unsigned long long GetCachedUGCHandle(int iCachedContent); + virtual unsigned long long PublishWorkshopFile(const char *pchFile, const char *pchPreviewFile, unsigned int nConsumerAppId, const char *pchTitle, const char *pchDescription, unsigned int eVisibility, int *pTags, unsigned int eWorkshopFileType); + virtual unsigned long long CreatePublishedFileUpdateRequest(unsigned long long unPublishedFileId); + virtual bool UpdatePublishedFileFile(unsigned long long hUpdateRequest, const char *pchFile); + virtual bool UpdatePublishedFilePreviewFile(unsigned long long hUpdateRequest, const char *pchPreviewFile); + virtual bool UpdatePublishedFileTitle(unsigned long long hUpdateRequest, const char *pchTitle); + virtual bool UpdatePublishedFileDescription(unsigned long long hUpdateRequest, const char *pchDescription); + virtual bool UpdatePublishedFileVisibility(unsigned long long hUpdateRequest, unsigned int eVisibility); + virtual bool UpdatePublishedFileTags(unsigned long long hUpdateRequest, int *pTags); + virtual unsigned long long CommitPublishedFileUpdate(unsigned long long hUpdateRequest); + virtual unsigned long long GetPublishedFileDetails(unsigned long long unPublishedFileId); + virtual unsigned long long DeletePublishedFile(unsigned long long unPublishedFileId); + virtual unsigned long long EnumerateUserPublishedFiles(unsigned int uStartIndex); + virtual unsigned long long SubscribePublishedFile(unsigned long long unPublishedFileId); + virtual unsigned long long EnumerateUserSubscribedFiles(unsigned int uStartIndex); + virtual unsigned long long UnsubscribePublishedFile(unsigned long long unPublishedFileId); + virtual bool UpdatePublishedFileSetChangeDescription(unsigned long long hUpdateRequest, const char *cszDescription); + virtual unsigned long long GetPublishedItemVoteDetails(unsigned long long unPublishedFileId); + virtual unsigned long long UpdateUserPublishedItemVote(unsigned long long unPublishedFileId, bool bVoteUp); + virtual unsigned long long GetUserPublishedItemVoteDetails(unsigned long long unPublishedFileId); + virtual unsigned long long EnumerateUserSharedWorkshopFiles(unsigned int nAppId, steam_id creatorSteamID, unsigned int uStartIndex, int * pRequiredTags, int * pExcludedTags); + virtual unsigned long long PublishVideo(unsigned int eVideoProvider, const char *cszVideoAccountName, const char *cszVideoIdentifier, const char *cszFileName, unsigned int nConsumerAppId, const char *cszTitle, const char *cszDescription, unsigned int eVisibility, int *pTags); + virtual unsigned long long SetUserPublishedFileAction(unsigned long long unPublishedFileId, unsigned int eAction); + virtual unsigned long long EnumeratePublishedFilesByUserAction(unsigned int eAction, unsigned int uStartIndex); + virtual unsigned long long EnumeratePublishedWorkshopFiles(unsigned int eType, unsigned int uStartIndex, unsigned int cDays, unsigned int cCount, int *pTags, int *pUserTags); + virtual unsigned long long UGCDownloadToLocation(unsigned long long hContent, const char *cszLocation, unsigned int uUnk); + }; +} diff --git a/src/client/steam/interfaces/user.cpp b/src/client/steam/interfaces/user.cpp new file mode 100644 index 0000000..a20e6d4 --- /dev/null +++ b/src/client/steam/interfaces/user.cpp @@ -0,0 +1,163 @@ +#include +#include "steam/steam.hpp" + +#include + +#include "component/auth.hpp" + +namespace steam +{ + namespace + { + std::string auth_ticket; + + steam_id generate_steam_id() + { + steam_id id{}; + id.bits = auth::get_guid(); + return id; + } + } + + int user::GetHSteamUser() + { + return NULL; + } + + bool user::LoggedOn() + { + return true; + } + + steam_id user::GetSteamID() + { + static auto id = generate_steam_id(); + return id; + } + + int user::InitiateGameConnection(void* pAuthBlob, int cbMaxAuthBlob, steam_id steamIDGameServer, + unsigned int unIPServer, unsigned short usPortServer, bool bSecure) + { + return 0; + } + + void user::TerminateGameConnection(unsigned int unIPServer, unsigned short usPortServer) + { + } + + void user::TrackAppUsageEvent(steam_id gameID, int eAppUsageEvent, const char* pchExtraInfo) + { + } + + bool user::GetUserDataFolder(char* pchBuffer, int cubBuffer) + { + return false; + } + + void user::StartVoiceRecording() + { + } + + void user::StopVoiceRecording() + { + } + + int user::GetAvailableVoice(unsigned int* pcbCompressed, unsigned int* pcbUncompressed, + unsigned int nUncompressedVoiceDesiredSampleRate) + { + return 0; + } + + int user::GetVoice(bool bWantCompressed, void* pDestBuffer, unsigned int cbDestBufferSize, + unsigned int* nBytesWritten, bool bWantUncompressed, void* pUncompressedDestBuffer, + unsigned int cbUncompressedDestBufferSize, unsigned int* nUncompressBytesWritten, + unsigned int nUncompressedVoiceDesiredSampleRate) + { + return 0; + } + + int user::DecompressVoice(void* pCompressed, unsigned int cbCompressed, void* pDestBuffer, + unsigned int cbDestBufferSize, unsigned int* nBytesWritten) + { + return 0; + } + + unsigned int user::GetVoiceOptimalSampleRate() + { + return 0; + } + + unsigned int user::GetAuthSessionTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket) + { + static uint32_t ticket = 0; + *pcbTicket = 1; + + const auto result = callbacks::register_call(); + auto* response = static_cast(calloc(1, sizeof(get_auth_session_ticket_response))); + response->m_h_auth_ticket = ++ticket; + response->m_e_result = 1; // k_EResultOK; + + callbacks::return_call(response, sizeof(get_auth_session_ticket_response), get_auth_session_ticket_response::callback_id, result); + return response->m_h_auth_ticket; + } + + int user::BeginAuthSession(const void* pAuthTicket, int cbAuthTicket, steam_id steamID) + { + return 0; + } + + void user::EndAuthSession(steam_id steamID) + { + } + + void user::CancelAuthTicket(unsigned int hAuthTicket) + { + } + + unsigned int user::UserHasLicenseForApp(steam_id steamID, unsigned int appID) + { + return 0; + } + + bool user::BIsBehindNAT() + { + return false; + } + + void user::AdvertiseGame(steam_id steamIDGameServer, unsigned int unIPServer, unsigned short usPortServer) + { + } + + unsigned long long user::RequestEncryptedAppTicket(void* pUserData, int cbUserData) + { + // Generate the authentication ticket + const auto id = this->GetSteamID(); + + auth_ticket = "iw6-mod"; + auth_ticket.resize(32); + auth_ticket.append(static_cast(pUserData), cbUserData); + auth_ticket.append(reinterpret_cast(&id.bits), sizeof(id.bits)); + + // Create the call response + const auto result = callbacks::register_call(); + auto retvals = static_cast(calloc(1, sizeof(encrypted_app_ticket_response))); + retvals->m_e_result = 1; + + // Return the call response + callbacks::return_call(retvals, sizeof(encrypted_app_ticket_response), + encrypted_app_ticket_response::callback_id, result); + + return result; + } + + bool user::GetEncryptedAppTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket) + { + if (cbMaxTicket < 0 || auth_ticket.empty()) return false; + + const auto size = std::min(size_t(cbMaxTicket), auth_ticket.size()); + std::memcpy(pTicket, auth_ticket.data(), size); + *pcbTicket = static_cast(size); + + return true; + } +} diff --git a/src/client/steam/interfaces/user.hpp b/src/client/steam/interfaces/user.hpp new file mode 100644 index 0000000..c15a66a --- /dev/null +++ b/src/client/steam/interfaces/user.hpp @@ -0,0 +1,55 @@ +#pragma once + +namespace steam +{ + struct encrypted_app_ticket_response final + { + enum { callback_id = 154 }; + + int m_e_result; + }; + + struct get_auth_session_ticket_response + { + enum { callback_id = 163 }; + + unsigned int m_h_auth_ticket; + int m_e_result; + }; + + class user + { + public: + ~user() = default; + + virtual int GetHSteamUser(); + virtual bool LoggedOn(); + virtual steam_id GetSteamID(); + + virtual int InitiateGameConnection(void* pAuthBlob, int cbMaxAuthBlob, steam_id steamIDGameServer, + unsigned int unIPServer, unsigned short usPortServer, bool bSecure); + virtual void TerminateGameConnection(unsigned int unIPServer, unsigned short usPortServer); + virtual void TrackAppUsageEvent(steam_id gameID, int eAppUsageEvent, const char* pchExtraInfo = ""); + virtual bool GetUserDataFolder(char* pchBuffer, int cubBuffer); + virtual void StartVoiceRecording(); + virtual void StopVoiceRecording(); + virtual int GetAvailableVoice(unsigned int* pcbCompressed, unsigned int* pcbUncompressed, + unsigned int nUncompressedVoiceDesiredSampleRate); + virtual int GetVoice(bool bWantCompressed, void* pDestBuffer, unsigned int cbDestBufferSize, + unsigned int* nBytesWritten, bool bWantUncompressed, void* pUncompressedDestBuffer, + unsigned int cbUncompressedDestBufferSize, unsigned int* nUncompressBytesWritten, + unsigned int nUncompressedVoiceDesiredSampleRate); + virtual int DecompressVoice(void* pCompressed, unsigned int cbCompressed, void* pDestBuffer, + unsigned int cbDestBufferSize, unsigned int* nBytesWritten); + virtual unsigned int GetVoiceOptimalSampleRate(); + virtual unsigned int GetAuthSessionTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket); + virtual int BeginAuthSession(const void* pAuthTicket, int cbAuthTicket, steam_id steamID); + virtual void EndAuthSession(steam_id steamID); + virtual void CancelAuthTicket(unsigned int hAuthTicket); + virtual unsigned int UserHasLicenseForApp(steam_id steamID, unsigned int appID); + virtual bool BIsBehindNAT(); + virtual void AdvertiseGame(steam_id steamIDGameServer, unsigned int unIPServer, unsigned short usPortServer); + virtual unsigned long long RequestEncryptedAppTicket(void* pUserData, int cbUserData); + virtual bool GetEncryptedAppTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket); + }; +} diff --git a/src/client/steam/interfaces/user_stats.cpp b/src/client/steam/interfaces/user_stats.cpp new file mode 100644 index 0000000..6a1e16d --- /dev/null +++ b/src/client/steam/interfaces/user_stats.cpp @@ -0,0 +1,230 @@ +#include +#include "steam/steam.hpp" + +namespace steam +{ + bool user_stats::RequestCurrentStats() + { + return true; + } + + bool user_stats::GetStat(const char* pchName, int* pData) + { + return false; + } + + bool user_stats::GetStat(const char* pchName, float* pData) + { + return false; + } + + bool user_stats::SetStat(const char* pchName, int nData) + { + return false; + } + + bool user_stats::SetStat(const char* pchName, float fData) + { + return false; + } + + bool user_stats::UpdateAvgRateStat(const char* pchName, float flCountThisSession, double dSessionLength) + { + return false; + } + + bool user_stats::GetAchievement(const char* pchName, bool* pbAchieved) + { + return false; + } + + bool user_stats::SetAchievement(const char* pchName) + { + return false; + } + + bool user_stats::ClearAchievement(const char* pchName) + { + return false; + } + + bool user_stats::GetAchievementAndUnlockTime(const char* pchName, bool* pbAchieved, unsigned int* punUnlockTime) + { + return false; + } + + bool user_stats::StoreStats() + { + return false; + } + + int user_stats::GetAchievementIcon(const char* pchName) + { + return 0; + } + + const char* user_stats::GetAchievementDisplayAttribute(const char* pchName, const char* pchKey) + { + return ""; + } + + bool user_stats::IndicateAchievementProgress(const char* pchName, unsigned int nCurProgress, + unsigned int nMaxProgress) + { + return false; + } + + unsigned int user_stats::GetNumAchievements() + { + return 0; + } + + const char* user_stats::GetAchievementName(unsigned int iAchievement) + { + return ""; + } + + unsigned long long user_stats::RequestUserStats(steam_id steamIDUser) + { + return 0; + } + + bool user_stats::GetUserStat(steam_id steamIDUser, const char* pchName, int* pData) + { + return false; + } + + bool user_stats::GetUserStat(steam_id steamIDUser, const char* pchName, float* pData) + { + return false; + } + + bool user_stats::GetUserAchievement(steam_id steamIDUser, const char* pchName, bool* pbAchieved) + { + return false; + } + + bool user_stats::GetUserAchievementAndUnlockTime(steam_id steamIDUser, const char* pchName, bool* pbAchieved, + unsigned int* punUnlockTime) + { + return false; + } + + bool user_stats::ResetAllStats(bool bAchievementsToo) + { + return false; + } + + unsigned long long user_stats::FindOrCreateLeaderboard(const char* pchLeaderboardName, int eLeaderboardSortMethod, + int eLeaderboardDisplayType) + { + return 0; + } + + unsigned long long user_stats::FindLeaderboard(const char* pchLeaderboardName) + { + return 0; + } + + const char* user_stats::GetLeaderboardName(unsigned long long hSteamLeaderboard) + { + return ""; + } + + int user_stats::GetLeaderboardEntryCount(unsigned long long hSteamLeaderboard) + { + return 0; + } + + int user_stats::GetLeaderboardSortMethod(unsigned long long hSteamLeaderboard) + { + return 0; + } + + int user_stats::GetLeaderboardDisplayType(unsigned long long hSteamLeaderboard) + { + return 0; + } + + unsigned long long user_stats::DownloadLeaderboardEntries(unsigned long long hSteamLeaderboard, + int eLeaderboardDataRequest, int nRangeStart, int nRangeEnd) + { + return 0; + } + + unsigned long long user_stats::DownloadLeaderboardEntriesForUsers(unsigned long long hSteamLeaderboard, + steam_id* prgUsers, int cUsers) + { + return 0; + } + + bool user_stats::GetDownloadedLeaderboardEntry(unsigned long long hSteamLeaderboardEntries, int index, + int* pLeaderboardEntry, int* pDetails, int cDetailsMax) + { + return false; + } + + unsigned long long user_stats::UploadLeaderboardScore(unsigned long long hSteamLeaderboard, + int eLeaderboardUploadScoreMethod, int nScore, + const int* pScoreDetails, int cScoreDetailsCount) + { + return 0; + } + + unsigned long long user_stats::AttachLeaderboardUGC(unsigned long long hSteamLeaderboard, unsigned long long hUGC) + { + return 0; + } + + unsigned long long user_stats::GetNumberOfCurrentPlayers() + { + return 0; + } + + unsigned long long user_stats::RequestGlobalAchievementPercentages() + { + return 0; + } + + int user_stats::GetMostAchievedAchievementInfo(char* pchName, unsigned int unNameBufLen, float* pflPercent, + bool* pbAchieved) + { + return 0; + } + + int user_stats::GetNextMostAchievedAchievementInfo(int iIteratorPrevious, char* pchName, unsigned int unNameBufLen, + float* pflPercent, bool* pbAchieved) + { + return 0; + } + + bool user_stats::GetAchievementAchievedPercent(const char* pchName, float* pflPercent) + { + return false; + } + + unsigned long long user_stats::RequestGlobalStats(int nHistoryDays) + { + return 0; + } + + bool user_stats::GetGlobalStat(const char* pchStatName, long long* pData) + { + return false; + } + + bool user_stats::GetGlobalStat(const char* pchStatName, double* pData) + { + return false; + } + + int user_stats::GetGlobalStatHistory(const char* pchStatName, long long* pData, unsigned int cubData) + { + return 0; + } + + int user_stats::GetGlobalStatHistory(const char* pchStatName, double* pData, unsigned int cubData) + { + return 0; + } +} diff --git a/src/client/steam/interfaces/user_stats.hpp b/src/client/steam/interfaces/user_stats.hpp new file mode 100644 index 0000000..2960ea9 --- /dev/null +++ b/src/client/steam/interfaces/user_stats.hpp @@ -0,0 +1,65 @@ +#pragma once + +namespace steam +{ + class user_stats + { + public: + ~user_stats() = default; + + virtual bool RequestCurrentStats(); + virtual bool GetStat(const char* pchName, int* pData); + virtual bool GetStat(const char* pchName, float* pData); + virtual bool SetStat(const char* pchName, int nData); + virtual bool SetStat(const char* pchName, float fData); + virtual bool UpdateAvgRateStat(const char* pchName, float flCountThisSession, double dSessionLength); + virtual bool GetAchievement(const char* pchName, bool* pbAchieved); + virtual bool SetAchievement(const char* pchName); + virtual bool ClearAchievement(const char* pchName); + virtual bool GetAchievementAndUnlockTime(const char* pchName, bool* pbAchieved, unsigned int* punUnlockTime); + virtual bool StoreStats(); + virtual int GetAchievementIcon(const char* pchName); + virtual const char* GetAchievementDisplayAttribute(const char* pchName, const char* pchKey); + virtual bool IndicateAchievementProgress(const char* pchName, unsigned int nCurProgress, + unsigned int nMaxProgress); + virtual unsigned int GetNumAchievements(); + virtual const char *GetAchievementName(unsigned int iAchievement); + virtual unsigned long long RequestUserStats(steam_id steamIDUser); + virtual bool GetUserStat(steam_id steamIDUser, const char* pchName, int* pData); + virtual bool GetUserStat(steam_id steamIDUser, const char* pchName, float* pData); + virtual bool GetUserAchievement(steam_id steamIDUser, const char* pchName, bool* pbAchieved); + virtual bool GetUserAchievementAndUnlockTime(steam_id steamIDUser, const char* pchName, bool* pbAchieved, + unsigned int* punUnlockTime); + virtual bool ResetAllStats(bool bAchievementsToo); + virtual unsigned long long FindOrCreateLeaderboard(const char* pchLeaderboardName, int eLeaderboardSortMethod, + int eLeaderboardDisplayType); + virtual unsigned long long FindLeaderboard(const char* pchLeaderboardName); + virtual const char* GetLeaderboardName(unsigned long long hSteamLeaderboard); + virtual int GetLeaderboardEntryCount(unsigned long long hSteamLeaderboard); + virtual int GetLeaderboardSortMethod(unsigned long long hSteamLeaderboard); + virtual int GetLeaderboardDisplayType(unsigned long long hSteamLeaderboard); + virtual unsigned long long DownloadLeaderboardEntries(unsigned long long hSteamLeaderboard, + int eLeaderboardDataRequest, int nRangeStart, + int nRangeEnd); + virtual unsigned long long DownloadLeaderboardEntriesForUsers(unsigned long long hSteamLeaderboard, + steam_id* prgUsers, int cUsers); + virtual bool GetDownloadedLeaderboardEntry(unsigned long long hSteamLeaderboardEntries, int index, + int* pLeaderboardEntry, int* pDetails, int cDetailsMax); + virtual unsigned long long UploadLeaderboardScore(unsigned long long hSteamLeaderboard, + int eLeaderboardUploadScoreMethod, int nScore, + const int* pScoreDetails, int cScoreDetailsCount); + virtual unsigned long long AttachLeaderboardUGC(unsigned long long hSteamLeaderboard, unsigned long long hUGC); + virtual unsigned long long GetNumberOfCurrentPlayers(); + virtual unsigned long long RequestGlobalAchievementPercentages(); + virtual int GetMostAchievedAchievementInfo(char* pchName, unsigned int unNameBufLen, float* pflPercent, + bool* pbAchieved); + virtual int GetNextMostAchievedAchievementInfo(int iIteratorPrevious, char* pchName, unsigned int unNameBufLen, + float* pflPercent, bool* pbAchieved); + virtual bool GetAchievementAchievedPercent(const char* pchName, float* pflPercent); + virtual unsigned long long RequestGlobalStats(int nHistoryDays); + virtual bool GetGlobalStat(const char* pchStatName, long long* pData); + virtual bool GetGlobalStat(const char* pchStatName, double* pData); + virtual int GetGlobalStatHistory(const char* pchStatName, long long* pData, unsigned int cubData); + virtual int GetGlobalStatHistory(const char* pchStatName, double* pData, unsigned int cubData); + }; +} diff --git a/src/client/steam/interfaces/utils.cpp b/src/client/steam/interfaces/utils.cpp new file mode 100644 index 0000000..6099159 --- /dev/null +++ b/src/client/steam/interfaces/utils.cpp @@ -0,0 +1,118 @@ +#include +#include "steam/steam.hpp" + +namespace steam +{ + unsigned int utils::GetSecondsSinceAppActive() + { + return 0; + } + + unsigned int utils::GetSecondsSinceComputerActive() + { + return 0; + } + + int utils::GetConnectedUniverse() + { + return 1; + } + + unsigned int utils::GetServerRealTime() + { + return 0; + } + + const char* utils::GetIPCountry() + { + return "US"; + } + + bool utils::GetImageSize(int iImage, unsigned int* pnWidth, unsigned int* pnHeight) + { + return false; + } + + bool utils::GetImageRGBA(int iImage, unsigned char* pubDest, int nDestBufferSize) + { + return false; + } + + bool utils::GetCSERIPPort(unsigned int* unIP, unsigned short* usPort) + { + return false; + } + + unsigned char utils::GetCurrentBatteryPower() + { + return 255; + } + + unsigned int utils::GetAppID() + { + return 42690; + } + + void utils::SetOverlayNotificationPosition(int eNotificationPosition) + { + } + + bool utils::IsAPICallCompleted(unsigned long long hSteamAPICall, bool* pbFailed) + { + return false; + } + + int utils::GetAPICallFailureReason(unsigned long long hSteamAPICall) + { + return -1; + } + + bool utils::GetAPICallResult(unsigned long long hSteamAPICall, void* pCallback, int cubCallback, + int iCallbackExpected, bool* pbFailed) + { + return false; + } + + void utils::RunFrame() + { + } + + unsigned int utils::GetIPCCallCount() + { + return 0; + } + + void utils::SetWarningMessageHook(void (*pFunction)(int hpipe, const char* message)) + { + } + + bool utils::IsOverlayEnabled() + { + return false; + } + + bool utils::BOverlayNeedsPresent() + { + return false; + } + + unsigned long long utils::CheckFileSignature(const char* szFileName) + { + return 0; + } + + bool utils::ShowGamepadTextInput(int eInputMode, int eInputLineMode, const char *szText, unsigned int uMaxLength) + { + return false; + } + + unsigned int utils::GetEnteredGamepadTextLength() + { + return 0; + } + + bool utils::GetEnteredGamepadTextInput(char *pchValue, unsigned int cchValueMax) + { + return false; + } +} diff --git a/src/client/steam/interfaces/utils.hpp b/src/client/steam/interfaces/utils.hpp new file mode 100644 index 0000000..6413be4 --- /dev/null +++ b/src/client/steam/interfaces/utils.hpp @@ -0,0 +1,36 @@ +#pragma once + +namespace steam +{ + class utils + { + public: + ~utils() = default; + + virtual unsigned int GetSecondsSinceAppActive(); + virtual unsigned int GetSecondsSinceComputerActive(); + virtual int GetConnectedUniverse(); + virtual unsigned int GetServerRealTime(); + virtual const char* GetIPCountry(); + virtual bool GetImageSize(int iImage, unsigned int* pnWidth, unsigned int* pnHeight); + virtual bool GetImageRGBA(int iImage, unsigned char* pubDest, int nDestBufferSize); + virtual bool GetCSERIPPort(unsigned int* unIP, unsigned short* usPort); + virtual unsigned char GetCurrentBatteryPower(); + virtual unsigned int GetAppID(); + virtual void SetOverlayNotificationPosition(int eNotificationPosition); + virtual bool IsAPICallCompleted(unsigned long long hSteamAPICall, bool* pbFailed); + virtual int GetAPICallFailureReason(unsigned long long hSteamAPICall); + virtual bool GetAPICallResult(unsigned long long hSteamAPICall, void* pCallback, int cubCallback, + int iCallbackExpected, bool* pbFailed); + virtual void RunFrame(); + virtual unsigned int GetIPCCallCount(); + virtual void SetWarningMessageHook(void (*pFunction)(int hpipe, const char* message)); + virtual bool IsOverlayEnabled(); + virtual bool BOverlayNeedsPresent(); + virtual unsigned long long CheckFileSignature(const char* szFileName); + + virtual bool ShowGamepadTextInput(int eInputMode, int eInputLineMode, const char *szText, unsigned int uMaxLength); + virtual unsigned int GetEnteredGamepadTextLength(); + virtual bool GetEnteredGamepadTextInput(char *pchValue, unsigned int cchValueMax); + }; +} diff --git a/src/client/steam/steam.cpp b/src/client/steam/steam.cpp new file mode 100644 index 0000000..e03f569 --- /dev/null +++ b/src/client/steam/steam.cpp @@ -0,0 +1,237 @@ +#include +#include "steam/steam.hpp" + +namespace steam +{ + uint64_t callbacks::call_id_ = 0; + std::recursive_mutex callbacks::mutex_; + std::map callbacks::calls_; + std::map callbacks::result_handlers_; + std::vector callbacks::results_; + std::vector callbacks::callback_list_; + + uint64_t callbacks::register_call() + { + std::lock_guard _(mutex_); + calls_[++call_id_] = false; + return call_id_; + } + + void callbacks::register_callback(base* handler, const int callback) + { + std::lock_guard _(mutex_); + handler->set_i_callback(callback); + callback_list_.push_back(handler); + } + + void callbacks::unregister_callback(base* handler) + { + std::lock_guard _(mutex_); + for (auto i = callback_list_.begin(); i != callback_list_.end();) + { + if (*i == handler) + { + i = callback_list_.erase(i); + } + else + { + ++i; + } + } + } + + void callbacks::register_call_result(const uint64_t call, base* result) + { + std::lock_guard _(mutex_); + result_handlers_[call] = result; + } + + void callbacks::unregister_call_result(const uint64_t call, base* /*result*/) + { + std::lock_guard _(mutex_); + const auto i = result_handlers_.find(call); + if (i != result_handlers_.end()) + { + result_handlers_.erase(i); + } + } + + void callbacks::return_call(void* data, const int size, const int type, const uint64_t call) + { + std::lock_guard _(mutex_); + + result result{}; + result.call = call; + result.data = data; + result.size = size; + result.type = type; + + calls_[call] = true; + + results_.emplace_back(result); + } + + void callbacks::run_callbacks() + { + std::lock_guard _(mutex_); + + for (const auto& result : results_) + { + if (result_handlers_.find(result.call) != result_handlers_.end()) + { + result_handlers_[result.call]->run(result.data, false, result.call); + } + + for (const auto& callback : callback_list_) + { + if (callback && callback->get_i_callback() == result.type) + { + callback->run(result.data, false, 0); + } + } + + if (result.data) + { + free(result.data); + } + } + + results_.clear(); + } + + extern "C" + { + bool SteamAPI_RestartAppIfNecessary() + { + return false; + } + + bool SteamAPI_Init() + { + return true; + } + + void SteamAPI_RegisterCallResult(callbacks::base* result, const uint64_t call) + { + callbacks::register_call_result(call, result); + } + + void SteamAPI_RegisterCallback(callbacks::base* handler, const int callback) + { + callbacks::register_callback(handler, callback); + } + + void SteamAPI_RunCallbacks() + { + callbacks::run_callbacks(); + } + + void SteamAPI_Shutdown() + { + } + + void SteamAPI_UnregisterCallResult(callbacks::base* result, const uint64_t call) + { + callbacks::unregister_call_result(call, result); + } + + void SteamAPI_UnregisterCallback(callbacks::base* handler) + { + callbacks::unregister_callback(handler); + } + + const char* SteamAPI_GetSteamInstallPath() + { + static std::string install_path{}; + if (!install_path.empty()) + { + return install_path.data(); + } + + HKEY reg_key; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\WOW6432Node\\Valve\\Steam", 0, KEY_QUERY_VALUE, + ®_key) == + ERROR_SUCCESS) + { + char path[MAX_PATH] = { 0 }; + DWORD length = sizeof(path); + RegQueryValueExA(reg_key, "InstallPath", nullptr, nullptr, reinterpret_cast(path), + &length); + RegCloseKey(reg_key); + + install_path = path; + } + + return install_path.data(); + } + + + bool SteamGameServer_Init() + { + return true; + } + + void SteamGameServer_RunCallbacks() + { + } + + void SteamGameServer_Shutdown() + { + } + + + friends* SteamFriends() + { + static friends friends; + return &friends; + } + + matchmaking* SteamMatchmaking() + { + static matchmaking matchmaking; + return &matchmaking; + } + + game_server* SteamGameServer() + { + static game_server game_server; + return &game_server; + } + + networking* SteamNetworking() + { + static networking networking; + return &networking; + } + + remote_storage* SteamRemoteStorage() + { + static remote_storage remote_storage; + return &remote_storage; + } + + user* SteamUser() + { + static user user; + return &user; + } + + utils* SteamUtils() + { + static utils utils; + return &utils; + } + + apps* SteamApps() + { + static apps apps; + return &apps; + } + + user_stats* SteamUserStats() + { + static user_stats user_stats; + return &user_stats; + } + } +} diff --git a/src/client/steam/steam.hpp b/src/client/steam/steam.hpp new file mode 100644 index 0000000..7f4ad5a --- /dev/null +++ b/src/client/steam/steam.hpp @@ -0,0 +1,123 @@ +#pragma once + +#define STEAM_EXPORT extern "C" __declspec(dllexport) + +#include + +struct raw_steam_id final +{ + unsigned int account_id : 32; + unsigned int account_instance : 20; + unsigned int account_type : 4; + int universe : 8; +}; + +typedef union +{ + raw_steam_id raw; + unsigned long long bits; +} steam_id; + +#pragma pack( push, 1 ) +struct raw_game_id final +{ + unsigned int app_id : 24; + unsigned int type : 8; + unsigned int mod_id : 32; +}; + +typedef union +{ + raw_game_id raw; + unsigned long long bits; +} game_id; +#pragma pack( pop ) + +#include "interfaces/apps.hpp" +#include "interfaces/user.hpp" +#include "interfaces/utils.hpp" +#include "interfaces/friends.hpp" +#include "interfaces/user_stats.hpp" +#include "interfaces/game_server.hpp" +#include "interfaces/networking.hpp" +#include "interfaces/matchmaking.hpp" +#include "interfaces/remote_storage.hpp" + +namespace steam +{ + class callbacks + { + public: + class base + { + public: + base() : flags_(0), callback_(0) + { + } + + virtual void run(void* pv_param) = 0; + virtual void run(void* pv_param, bool failure, uint64_t handle) = 0; + virtual int get_callback_size_bytes() = 0; + + int get_i_callback() const { return callback_; } + void set_i_callback(const int i_callback) { callback_ = i_callback; } + + protected: + ~base() = default; + + unsigned char flags_; + int callback_; + }; + + struct result final + { + void* data{}; + int size{}; + int type{}; + uint64_t call{}; + }; + + static uint64_t register_call(); + + static void register_callback(base* handler, int callback); + static void unregister_callback(base* handler); + + static void register_call_result(uint64_t call, base* result); + static void unregister_call_result(uint64_t call, base* result); + + static void return_call(void* data, int size, int type, uint64_t call); + static void run_callbacks(); + + private: + static uint64_t call_id_; + static std::recursive_mutex mutex_; + static std::map calls_; + static std::map result_handlers_; + static std::vector results_; + static std::vector callback_list_; + }; + + STEAM_EXPORT bool SteamAPI_RestartAppIfNecessary(); + STEAM_EXPORT bool SteamAPI_Init(); + STEAM_EXPORT void SteamAPI_RegisterCallResult(callbacks::base* result, uint64_t call); + STEAM_EXPORT void SteamAPI_RegisterCallback(callbacks::base* handler, int callback); + STEAM_EXPORT void SteamAPI_RunCallbacks(); + STEAM_EXPORT void SteamAPI_Shutdown(); + STEAM_EXPORT void SteamAPI_UnregisterCallResult(callbacks::base* result, const uint64_t call); + STEAM_EXPORT void SteamAPI_UnregisterCallback(callbacks::base* handler); + STEAM_EXPORT const char* SteamAPI_GetSteamInstallPath(); + + STEAM_EXPORT bool SteamGameServer_Init(); + STEAM_EXPORT void SteamGameServer_RunCallbacks(); + STEAM_EXPORT void SteamGameServer_Shutdown(); + + STEAM_EXPORT friends* SteamFriends(); + STEAM_EXPORT matchmaking* SteamMatchmaking(); + STEAM_EXPORT game_server* SteamGameServer(); + STEAM_EXPORT networking* SteamNetworking(); + STEAM_EXPORT remote_storage* SteamRemoteStorage(); + STEAM_EXPORT user* SteamUser(); + STEAM_EXPORT utils* SteamUtils(); + STEAM_EXPORT apps* SteamApps(); + STEAM_EXPORT user_stats* SteamUserStats(); +} diff --git a/src/common/utils/binary_resource.cpp b/src/common/utils/binary_resource.cpp new file mode 100644 index 0000000..859e1be --- /dev/null +++ b/src/common/utils/binary_resource.cpp @@ -0,0 +1,67 @@ +#include "binary_resource.hpp" +#include "nt.hpp" +#include "io.hpp" + +namespace utils +{ + namespace + { + std::string get_temp_folder() + { + char path[MAX_PATH]{}; + if (!GetTempPathA(sizeof(path), path)) + { + throw std::runtime_error("Unable to get temp path"); + } + + return path; + } + + std::string write_existing_temp_file(const std::string& file, const std::string& data, const bool fatal_if_overwrite_fails) + { + const auto temp = get_temp_folder(); + const auto file_path = temp + file; + + std::string current_data; + if (!io::read_file(file_path, ¤t_data)) + { + if (!io::write_file(file_path, data)) + { + throw std::runtime_error("Failed to write file: " + file_path); + } + + return file_path; + } + + if (current_data == data || io::write_file(file_path, data) || !fatal_if_overwrite_fails) + { + return file_path; + } + + throw std::runtime_error( + "Temporary file was already written, but differs. It can't be overwritten as it's still in use: " + + file_path); + } + } + + binary_resource::binary_resource(const int id, std::string file) + : filename_(std::move(file)) + { + this->resource_ = nt::load_resource(id); + + if (this->resource_.empty()) + { + throw std::runtime_error("Unable to load resource: " + std::to_string(id)); + } + } + + std::string binary_resource::get_extracted_file(const bool fatal_if_overwrite_fails) + { + if (this->path_.empty()) + { + this->path_ = write_existing_temp_file(this->filename_, this->resource_, fatal_if_overwrite_fails); + } + + return this->path_; + } +} diff --git a/src/common/utils/binary_resource.hpp b/src/common/utils/binary_resource.hpp new file mode 100644 index 0000000..06eb1fa --- /dev/null +++ b/src/common/utils/binary_resource.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace utils +{ + class binary_resource + { + public: + binary_resource(int id, std::string file); + + std::string get_extracted_file(bool fatal_if_overwrite_fails = false); + + private: + std::string resource_; + std::string filename_; + std::string path_; + }; +} diff --git a/src/common/utils/com.cpp b/src/common/utils/com.cpp new file mode 100644 index 0000000..6e63d00 --- /dev/null +++ b/src/common/utils/com.cpp @@ -0,0 +1,126 @@ +#include "com.hpp" +#include "nt.hpp" +#include "string.hpp" + +#include + +#include +#include + + +namespace utils::com +{ + namespace + { + [[maybe_unused]] class _ + { + public: + _() + { + if(FAILED(CoInitialize(nullptr))) + { + throw std::runtime_error("Failed to initialize the component object model"); + } + } + + ~_() + { + CoUninitialize(); + } + } __; + } + + bool select_folder(std::string& out_folder, const std::string& title, const std::string& selected_folder) + { + IFileOpenDialog* file_dialog = nullptr; + if(FAILED(CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&file_dialog)))) + { + throw std::runtime_error("Failed to create co instance"); + } + + const auto $1 = gsl::finally([file_dialog]() + { + file_dialog->Release(); + }); + + DWORD dw_options; + if(FAILED(file_dialog->GetOptions(&dw_options))) + { + throw std::runtime_error("Failed to get options"); + } + + if(FAILED(file_dialog->SetOptions(dw_options | FOS_PICKFOLDERS))) + { + throw std::runtime_error("Failed to set options"); + } + + std::wstring wide_title(title.begin(), title.end()); + if(FAILED(file_dialog->SetTitle(wide_title.data()))) + { + throw std::runtime_error("Failed to set title"); + } + + if (!selected_folder.empty()) + { + file_dialog->ClearClientData(); + + std::wstring wide_selected_folder(selected_folder.begin(), selected_folder.end()); + for (auto& chr : wide_selected_folder) + { + if (chr == L'/') + { + chr = L'\\'; + } + } + + IShellItem* shell_item = nullptr; + if(FAILED(SHCreateItemFromParsingName(wide_selected_folder.data(), NULL, IID_PPV_ARGS(&shell_item)))) + { + throw std::runtime_error("Failed to create item from parsing name"); + } + + if (FAILED(file_dialog->SetDefaultFolder(shell_item))) + { + throw std::runtime_error("Failed to set default folder"); + } + } + + const auto result = file_dialog->Show(nullptr); + if(result == HRESULT_FROM_WIN32(ERROR_CANCELLED)) + { + return false; + } + + if (FAILED(result)) + { + throw std::runtime_error("Failed to show dialog"); + } + + IShellItem* result_item = nullptr; + if(FAILED(file_dialog->GetResult(&result_item))) + { + throw std::runtime_error("Failed to get result"); + } + + const auto $2 = gsl::finally([result_item]() + { + result_item->Release(); + }); + + PWSTR raw_path = nullptr; + if(FAILED(result_item->GetDisplayName(SIGDN_FILESYSPATH, &raw_path))) + { + throw std::runtime_error("Failed to get path display name"); + } + + const auto $3 = gsl::finally([raw_path]() + { + CoTaskMemFree(raw_path); + }); + + const std::wstring result_path = raw_path; + out_folder = string::convert(result_path); + + return true; + } +} diff --git a/src/common/utils/com.hpp b/src/common/utils/com.hpp new file mode 100644 index 0000000..b8c26ff --- /dev/null +++ b/src/common/utils/com.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace utils::com +{ + bool select_folder(std::string& out_folder, const std::string& title = "Select a Folder", const std::string& selected_folder = {}); +} diff --git a/src/common/utils/compression.cpp b/src/common/utils/compression.cpp new file mode 100644 index 0000000..1688cee --- /dev/null +++ b/src/common/utils/compression.cpp @@ -0,0 +1,169 @@ +#include "memory.hpp" +#include "compression.hpp" + +#include +#include + +#include + +#include "io.hpp" + +namespace utils::compression +{ + namespace zlib + { + namespace + { + class zlib_stream + { + public: + zlib_stream() + { + memset(&stream_, 0, sizeof(stream_)); + valid_ = inflateInit(&stream_) == Z_OK; + } + + zlib_stream(zlib_stream&&) = delete; + zlib_stream(const zlib_stream&) = delete; + zlib_stream& operator=(zlib_stream&&) = delete; + zlib_stream& operator=(const zlib_stream&) = delete; + + ~zlib_stream() + { + if (valid_) + { + inflateEnd(&stream_); + } + } + + z_stream& get() + { + return stream_; // + } + + bool is_valid() const + { + return valid_; + } + + private: + bool valid_{false}; + z_stream stream_{}; + }; + } + + std::string decompress(const std::string& data) + { + std::string buffer{}; + zlib_stream stream_container{}; + if (!stream_container.is_valid()) + { + return {}; + } + + int ret{}; + size_t offset = 0; + static thread_local uint8_t dest[CHUNK] = {0}; + auto& stream = stream_container.get(); + + do + { + const auto input_size = std::min(sizeof(dest), data.size() - offset); + stream.avail_in = static_cast(input_size); + stream.next_in = reinterpret_cast(data.data()) + offset; + offset += stream.avail_in; + + do + { + stream.avail_out = sizeof(dest); + stream.next_out = dest; + + ret = inflate(&stream, Z_NO_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) + { + return {}; + } + + buffer.insert(buffer.end(), dest, dest + sizeof(dest) - stream.avail_out); + } + while (stream.avail_out == 0); + } + while (ret != Z_STREAM_END); + + return buffer; + } + + std::string compress(const std::string& data) + { + std::string result{}; + auto length = compressBound(static_cast(data.size())); + result.resize(length); + + if (compress2(reinterpret_cast(result.data()), &length, + reinterpret_cast(data.data()), static_cast(data.size()), + Z_BEST_COMPRESSION) != Z_OK) + { + return {}; + } + + result.resize(length); + return result; + } + } + + namespace zip + { + namespace + { + bool add_file(zipFile& zip_file, const std::string& filename, const std::string& data) + { + const auto zip_64 = data.size() > 0xffffffff ? 1 : 0; + if (ZIP_OK != zipOpenNewFileInZip64(zip_file, filename.data(), nullptr, nullptr, 0, nullptr, 0, nullptr, + Z_DEFLATED, Z_BEST_COMPRESSION, zip_64)) + { + return false; + } + + const auto _ = gsl::finally([&zip_file]() + { + zipCloseFileInZip(zip_file); + }); + + return ZIP_OK == zipWriteInFileInZip(zip_file, data.data(), static_cast(data.size())); + } + } + + void archive::add(std::string filename, std::string data) + { + this->files_[std::move(filename)] = std::move(data); + } + + bool archive::write(const std::string& filename, const std::string& comment) + { + // Hack to create the directory :3 + io::write_file(filename, {}); + io::remove_file(filename); + + auto* zip_file = zipOpen64(filename.data(), 0); + if (!zip_file) + { + return false; + } + + const auto _ = gsl::finally([&zip_file, &comment]() + { + zipClose(zip_file, comment.empty() ? nullptr : comment.data()); + }); + + for (const auto& file : this->files_) + { + if (!add_file(zip_file, file.first, file.second)) + { + return false; + } + } + + return true; + } + } +} diff --git a/src/common/utils/compression.hpp b/src/common/utils/compression.hpp new file mode 100644 index 0000000..dfe36ad --- /dev/null +++ b/src/common/utils/compression.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#define CHUNK 16384u + +namespace utils::compression +{ + namespace zlib + { + std::string compress(const std::string& data); + std::string decompress(const std::string& data); + } + + namespace zip + { + class archive + { + public: + void add(std::string filename, std::string data); + bool write(const std::string& filename, const std::string& comment = {}); + + private: + std::unordered_map files_; + }; + } +}; diff --git a/src/common/utils/concurrency.hpp b/src/common/utils/concurrency.hpp new file mode 100644 index 0000000..f77a2a4 --- /dev/null +++ b/src/common/utils/concurrency.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +namespace utils::concurrency +{ + template + class container + { + public: + template + R access(F&& accessor) const + { + std::lock_guard _{ mutex_ }; + return accessor(object_); + } + + template + R access(F&& accessor) + { + std::lock_guard _{ mutex_ }; + return accessor(object_); + } + + template + R access_with_lock(F&& accessor) const + { + std::unique_lock lock{ mutex_ }; + return accessor(object_, lock); + } + + template + R access_with_lock(F&& accessor) + { + std::unique_lock lock{ mutex_ }; + return accessor(object_, lock); + } + + T& get_raw() { return object_; } + const T& get_raw() const { return object_; } + + private: + mutable MutexType mutex_{}; + T object_{}; + }; +} diff --git a/src/common/utils/cryptography.cpp b/src/common/utils/cryptography.cpp new file mode 100644 index 0000000..2e2065a --- /dev/null +++ b/src/common/utils/cryptography.cpp @@ -0,0 +1,640 @@ +#include "string.hpp" +#include "cryptography.hpp" +#include "nt.hpp" +#include + +#undef max +using namespace std::string_literals; + +/// http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/Source/libtomcrypt/doc/libTomCryptDoc.pdf + +namespace utils::cryptography +{ + namespace + { + struct __ + { + __() + { + ltc_mp = ltm_desc; + + register_cipher(&aes_desc); + register_cipher(&des3_desc); + + register_prng(&sprng_desc); + register_prng(&fortuna_desc); + register_prng(&yarrow_desc); + + register_hash(&sha1_desc); + register_hash(&sha256_desc); + register_hash(&sha512_desc); + } + } ___; + + [[maybe_unused]] const char* cs(const uint8_t* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] char* cs(uint8_t* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] const uint8_t* cs(const char* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] uint8_t* cs(char* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] unsigned long ul(const size_t value) + { + return static_cast(value); + } + + class prng + { + public: + prng(const ltc_prng_descriptor& descriptor, const bool autoseed = true) + : state_(std::make_unique()) + , descriptor_(descriptor) + { + this->id_ = register_prng(&descriptor); + if (this->id_ == -1) + { + throw std::runtime_error("PRNG "s + this->descriptor_.name + " could not be registered!"); + } + + if (autoseed) + { + this->auto_seed(); + } + else + { + this->descriptor_.start(this->state_.get()); + } + } + + ~prng() + { + this->descriptor_.done(this->state_.get()); + } + + prng_state* get_state() const + { + this->descriptor_.ready(this->state_.get()); + return this->state_.get(); + } + + int get_id() const + { + return this->id_; + } + + void add_entropy(const void* data, const size_t length) const + { + this->descriptor_.add_entropy(static_cast(data), ul(length), this->state_.get()); + } + + void read(void* data, const size_t length) const + { + this->descriptor_.read(static_cast(data), ul(length), this->get_state()); + } + + private: + int id_; + std::unique_ptr state_; + const ltc_prng_descriptor& descriptor_; + + void auto_seed() const + { + rng_make_prng(128, this->id_, this->state_.get(), nullptr); + + int i[4]; // uninitialized data + auto* i_ptr = &i; + this->add_entropy(reinterpret_cast(&i), sizeof(i)); + this->add_entropy(reinterpret_cast(&i_ptr), sizeof(i_ptr)); + + auto t = time(nullptr); + this->add_entropy(reinterpret_cast(&t), sizeof(t)); + } + }; + + const prng prng_(fortuna_desc); + } + + ecc::key::key() + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + + ecc::key::~key() + { + this->free(); + } + + ecc::key::key(key&& obj) noexcept + : key() + { + this->operator=(std::move(obj)); + } + + ecc::key::key(const key& obj) + : key() + { + this->operator=(obj); + } + + ecc::key& ecc::key::operator=(key&& obj) noexcept + { + if (this != &obj) + { + std::memmove(&this->key_storage_, &obj.key_storage_, sizeof(this->key_storage_)); + ZeroMemory(&obj.key_storage_, sizeof(obj.key_storage_)); + } + + return *this; + } + + ecc::key& ecc::key::operator=(const key& obj) + { + if (this != &obj && obj.is_valid()) + { + this->deserialize(obj.serialize(obj.key_storage_.type)); + } + + return *this; + } + + bool ecc::key::is_valid() const + { + return (!memory::is_set(&this->key_storage_, 0, sizeof(this->key_storage_))); + } + + ecc_key& ecc::key::get() + { + return this->key_storage_; + } + + const ecc_key& ecc::key::get() const + { + return this->key_storage_; + } + + std::string ecc::key::get_public_key() const + { + uint8_t buffer[512] = {0}; + unsigned long length = sizeof(buffer); + + if (ecc_ansi_x963_export(&this->key_storage_, buffer, &length) == CRYPT_OK) + { + return std::string(cs(buffer), length); + } + + return {}; + } + + void ecc::key::set(const std::string& pub_key_buffer) + { + this->free(); + + if (ecc_ansi_x963_import(cs(pub_key_buffer.data()), + ul(pub_key_buffer.size()), + &this->key_storage_) != CRYPT_OK) + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + } + + void ecc::key::deserialize(const std::string& key) + { + this->free(); + + if (ecc_import(cs(key.data()), ul(key.size()), + &this->key_storage_) != CRYPT_OK + ) + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + } + + std::string ecc::key::serialize(const int type) const + { + uint8_t buffer[4096] = {0}; + unsigned long length = sizeof(buffer); + + if (ecc_export(buffer, &length, type, &this->key_storage_) == CRYPT_OK) + { + return std::string(cs(buffer), length); + } + + return ""; + } + + void ecc::key::free() + { + if (this->is_valid()) + { + ecc_free(&this->key_storage_); + } + + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + + bool ecc::key::operator==(key& key) const + { + return (this->is_valid() && key.is_valid() && this->serialize(PK_PUBLIC) == key.serialize(PK_PUBLIC)); + } + + uint64_t ecc::key::get_hash() const + { + const auto hash = sha1::compute(this->get_public_key()); + if (hash.size() >= 8) + { + return *reinterpret_cast(hash.data()); + } + + return 0; + } + + ecc::key ecc::generate_key(const int bits) + { + key key; + ecc_make_key(prng_.get_state(), prng_.get_id(), bits / 8, &key.get()); + + return key; + } + + ecc::key ecc::generate_key(const int bits, const std::string& entropy) + { + key key{}; + const prng yarrow(yarrow_desc, false); + yarrow.add_entropy(entropy.data(), entropy.size()); + + ecc_make_key(yarrow.get_state(), yarrow.get_id(), bits / 8, &key.get()); + + return key; + } + + std::string ecc::sign_message(const key& key, const std::string& message) + { + if (!key.is_valid()) return ""; + + uint8_t buffer[512]; + unsigned long length = sizeof(buffer); + + ecc_sign_hash(cs(message.data()), ul(message.size()), buffer, &length, prng_.get_state(), prng_.get_id(), + &key.get()); + + return std::string(cs(buffer), length); + } + + bool ecc::verify_message(const key& key, const std::string& message, const std::string& signature) + { + if (!key.is_valid()) return false; + + auto result = 0; + return (ecc_verify_hash(cs(signature.data()), + ul(signature.size()), + cs(message.data()), + ul(message.size()), &result, + &key.get()) == CRYPT_OK && result != 0); + } + + bool ecc::encrypt(const key& key, std::string& data) + { + std::string out_data{}; + out_data.resize(std::max(ul(data.size() * 3), ul(0x100))); + + auto out_len = ul(out_data.size()); + auto crypt = [&]() + { + return ecc_encrypt_key(cs(data.data()), ul(data.size()), cs(out_data.data()), &out_len, + prng_.get_state(), prng_.get_id(), find_hash("sha512"), &key.get()); + }; + + auto res = crypt(); + + if (res == CRYPT_BUFFER_OVERFLOW) + { + out_data.resize(out_len); + res = crypt(); + } + + if (res != CRYPT_OK) + { + return false; + } + + out_data.resize(out_len); + data = std::move(out_data); + return true; + } + + bool ecc::decrypt(const key& key, std::string& data) + { + std::string out_data{}; + out_data.resize(std::max(ul(data.size() * 3), ul(0x100))); + + auto out_len = ul(out_data.size()); + auto crypt = [&]() + { + return ecc_decrypt_key(cs(data.data()), ul(data.size()), cs(out_data.data()), &out_len, &key.get()); + }; + + auto res = crypt(); + + if (res == CRYPT_BUFFER_OVERFLOW) + { + out_data.resize(out_len); + res = crypt(); + } + + if (res != CRYPT_OK) + { + return false; + } + + out_data.resize(out_len); + data = std::move(out_data); + return true; + } + + std::string rsa::encrypt(const std::string& data, const std::string& hash, const std::string& key) + { + rsa_key new_key; + rsa_import(cs(key.data()), ul(key.size()), &new_key); + const auto _ = gsl::finally([&]() + { + rsa_free(&new_key); + }); + + + std::string out_data{}; + out_data.resize(std::max(ul(data.size() * 3), ul(0x100))); + + auto out_len = ul(out_data.size()); + auto crypt = [&]() + { + return rsa_encrypt_key(cs(data.data()), ul(data.size()), cs(out_data.data()), &out_len, cs(hash.data()), + ul(hash.size()), prng_.get_state(), prng_.get_id(), find_hash("sha512"), &new_key); + }; + + auto res = crypt(); + + if (res == CRYPT_BUFFER_OVERFLOW) + { + out_data.resize(out_len); + res = crypt(); + } + + if (res == CRYPT_OK) + { + out_data.resize(out_len); + return out_data; + } + + return {}; + } + + std::string des3::encrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string enc_data; + enc_data.resize(data.size()); + + symmetric_CBC cbc; + const auto des3 = find_cipher("3des"); + + cbc_start(des3, cs(iv.data()), cs(key.data()), static_cast(key.size()), 0, &cbc); + cbc_encrypt(cs(data.data()), cs(enc_data.data()), ul(data.size()), &cbc); + cbc_done(&cbc); + + return enc_data; + } + + std::string des3::decrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string dec_data; + dec_data.resize(data.size()); + + symmetric_CBC cbc; + const auto des3 = find_cipher("3des"); + + cbc_start(des3, cs(iv.data()), cs(key.data()), static_cast(key.size()), 0, &cbc); + cbc_decrypt(cs(data.data()), cs(dec_data.data()), ul(data.size()), &cbc); + cbc_done(&cbc); + + return dec_data; + } + + std::string tiger::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string tiger::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[24] = {0}; + + hash_state state; + tiger_init(&state); + tiger_process(&state, data, ul(length)); + tiger_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string aes::encrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string enc_data; + enc_data.resize(data.size()); + + symmetric_CBC cbc; + const auto aes = find_cipher("aes"); + + cbc_start(aes, cs(iv.data()), cs(key.data()), + static_cast(key.size()), 0, &cbc); + cbc_encrypt(cs(data.data()), + cs(enc_data.data()), + ul(data.size()), &cbc); + cbc_done(&cbc); + + return enc_data; + } + + std::string aes::decrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string dec_data; + dec_data.resize(data.size()); + + symmetric_CBC cbc; + const auto aes = find_cipher("aes"); + + cbc_start(aes, cs(iv.data()), cs(key.data()), + static_cast(key.size()), 0, &cbc); + cbc_decrypt(cs(data.data()), + cs(dec_data.data()), + ul(data.size()), &cbc); + cbc_done(&cbc); + + return dec_data; + } + + std::string hmac_sha1::compute(const std::string& data, const std::string& key) + { + std::string buffer; + buffer.resize(20); + + hmac_state state; + hmac_init(&state, find_hash("sha1"), cs(key.data()), ul(key.size())); + hmac_process(&state, cs(data.data()), static_cast(data.size())); + + auto out_len = ul(buffer.size()); + hmac_done(&state, cs(buffer.data()), &out_len); + + buffer.resize(out_len); + return buffer; + } + + std::string sha1::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string sha1::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[20] = {0}; + + hash_state state; + sha1_init(&state); + sha1_process(&state, data, ul(length)); + sha1_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string sha256::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string sha256::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[32] = {0}; + + hash_state state; + sha256_init(&state); + sha256_process(&state, data, ul(length)); + sha256_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string sha512::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string sha512::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[64] = {0}; + + hash_state state; + sha512_init(&state); + sha512_process(&state, data, ul(length)); + sha512_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string base64::encode(const uint8_t* data, const size_t len) + { + std::string result; + result.resize((len + 2) * 2); + + auto out_len = ul(result.size()); + if (base64_encode(data, ul(len), result.data(), &out_len) != CRYPT_OK) + { + return {}; + } + + result.resize(out_len); + return result; + } + + std::string base64::encode(const std::string& data) + { + return base64::encode(cs(data.data()), static_cast(data.size())); + } + + std::string base64::decode(const std::string& data) + { + std::string result; + result.resize((data.size() + 2) * 2); + + auto out_len = ul(result.size()); + if (base64_decode(data.data(), ul(data.size()), cs(result.data()), &out_len) != CRYPT_OK) + { + return {}; + } + + result.resize(out_len); + return result; + } + + unsigned int jenkins_one_at_a_time::compute(const std::string& data) + { + return compute(data.data(), data.size()); + } + + unsigned int jenkins_one_at_a_time::compute(const char* key, const size_t len) + { + unsigned int hash, i; + for (hash = i = 0; i < len; ++i) + { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; + } + + uint32_t random::get_integer() + { + uint32_t result; + random::get_data(&result, sizeof(result)); + return result; + } + + std::string random::get_challenge() + { + std::string result; + result.resize(sizeof(uint32_t)); + random::get_data(result.data(), result.size()); + return string::dump_hex(result, ""); + } + + void random::get_data(void* data, const size_t size) + { + prng_.read(data, size); + } +} diff --git a/src/common/utils/cryptography.hpp b/src/common/utils/cryptography.hpp new file mode 100644 index 0000000..9538c5e --- /dev/null +++ b/src/common/utils/cryptography.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include +#include + +namespace utils::cryptography +{ + namespace ecc + { + class key final + { + public: + key(); + ~key(); + + key(key&& obj) noexcept; + key(const key& obj); + key& operator=(key&& obj) noexcept; + key& operator=(const key& obj); + + bool is_valid() const; + + ecc_key& get(); + const ecc_key& get() const; + + std::string get_public_key() const; + + void set(const std::string& pub_key_buffer); + + void deserialize(const std::string& key); + + std::string serialize(int type = PK_PRIVATE) const; + + void free(); + + bool operator==(key& key) const; + + uint64_t get_hash() const; + + private: + ecc_key key_storage_{}; + }; + + key generate_key(int bits); + key generate_key(int bits, const std::string& entropy); + std::string sign_message(const key& key, const std::string& message); + bool verify_message(const key& key, const std::string& message, const std::string& signature); + + bool encrypt(const key& key, std::string& data); + bool decrypt(const key& key, std::string& data); + } + + namespace rsa + { + std::string encrypt(const std::string& data, const std::string& hash, const std::string& key); + } + + namespace des3 + { + std::string encrypt(const std::string& data, const std::string& iv, const std::string& key); + std::string decrypt(const std::string& data, const std::string& iv, const std::string& key); + } + + namespace tiger + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace aes + { + std::string encrypt(const std::string& data, const std::string& iv, const std::string& key); + std::string decrypt(const std::string& data, const std::string& iv, const std::string& key); + } + + namespace hmac_sha1 + { + std::string compute(const std::string& data, const std::string& key); + } + + namespace sha1 + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace sha256 + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace sha512 + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace base64 + { + std::string encode(const uint8_t* data, size_t len); + std::string encode(const std::string& data); + std::string decode(const std::string& data); + } + + namespace jenkins_one_at_a_time + { + unsigned int compute(const std::string& data); + unsigned int compute(const char* key, size_t len); + }; + + namespace random + { + uint32_t get_integer(); + std::string get_challenge(); + void get_data(void* data, size_t size); + } +} diff --git a/src/common/utils/flags.cpp b/src/common/utils/flags.cpp new file mode 100644 index 0000000..ecb7318 --- /dev/null +++ b/src/common/utils/flags.cpp @@ -0,0 +1,46 @@ +#include "flags.hpp" +#include "string.hpp" +#include "nt.hpp" + +#include + +namespace utils::flags +{ + void parse_flags(std::vector& flags) + { + int num_args; + auto* const argv = CommandLineToArgvW(GetCommandLineW(), &num_args); + + flags.clear(); + + if (argv) + { + for (auto i = 0; i < num_args; ++i) + { + std::wstring wide_flag(argv[i]); + if (wide_flag[0] == L'-') + { + wide_flag.erase(wide_flag.begin()); + flags.emplace_back(string::convert(wide_flag)); + } + } + + LocalFree(argv); + } + } + + bool has_flag(const std::string& flag) + { + static auto parsed = false; + static std::vector enabled_flags; + + if (!parsed) + { + parse_flags(enabled_flags); + parsed = true; + } + + return std::ranges::any_of(enabled_flags.cbegin(), enabled_flags.cend(), + [flag](const auto& elem) { return string::to_lower(elem) == string::to_lower(flag); }); + } +} diff --git a/src/common/utils/flags.hpp b/src/common/utils/flags.hpp new file mode 100644 index 0000000..cf304b2 --- /dev/null +++ b/src/common/utils/flags.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace utils::flags +{ + bool has_flag(const std::string& flag); +} diff --git a/src/common/utils/hook.cpp b/src/common/utils/hook.cpp new file mode 100644 index 0000000..be05cb9 --- /dev/null +++ b/src/common/utils/hook.cpp @@ -0,0 +1,310 @@ +#include "hook.hpp" +#include "string.hpp" + +#include + +namespace utils::hook +{ + namespace + { + [[maybe_unused]] class _ + { + public: + _() + { + if (MH_Initialize() != MH_OK) + { + throw std::runtime_error("Failed to initialize MinHook"); + } + } + + ~_() + { + MH_Uninitialize(); + } + } __; + } + + void assembler::pushad64() + { + this->push(rax); + this->push(rcx); + this->push(rdx); + this->push(rbx); + this->push(rsp); + this->push(rbp); + this->push(rsi); + this->push(rdi); + + this->sub(rsp, 0x40); + } + + void assembler::popad64() + { + this->add(rsp, 0x40); + + this->pop(rdi); + this->pop(rsi); + this->pop(rbp); + this->pop(rsp); + this->pop(rbx); + this->pop(rdx); + this->pop(rcx); + this->pop(rax); + } + + void assembler::prepare_stack_for_call() + { + const auto reserve_callee_space = this->newLabel(); + const auto stack_unaligned = this->newLabel(); + + this->test(rsp, 0xF); + this->jnz(stack_unaligned); + + this->sub(rsp, 0x8); + this->push(rsp); + + this->push(rax); + this->mov(rax, ptr(rsp, 8, 8)); + this->add(rax, 0x8); + this->mov(ptr(rsp, 8, 8), rax); + this->pop(rax); + + this->jmp(reserve_callee_space); + + this->bind(stack_unaligned); + this->push(rsp); + + this->bind(reserve_callee_space); + this->sub(rsp, 0x40); + } + + void assembler::restore_stack_after_call() + { + this->lea(rsp, ptr(rsp, 0x40)); + this->pop(rsp); + } + + asmjit::Error assembler::call(void* target) + { + return Assembler::call(size_t(target)); + } + + asmjit::Error assembler::jmp(void* target) + { + return Assembler::jmp(size_t(target)); + } + + detour::detour(const size_t place, void* target) : detour(reinterpret_cast(place), target) + { + } + + detour::detour(void* place, void* target) + { + this->create(place, target); + } + + detour::~detour() + { + this->clear(); + } + + void detour::enable() const + { + MH_EnableHook(this->place_); + } + + void detour::disable() const + { + MH_DisableHook(this->place_); + } + + void detour::create(void* place, void* target) + { + this->clear(); + this->place_ = place; + + if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK) + { + throw std::runtime_error(string::va("Unable to create hook at location: %p", this->place_)); + } + + this->enable(); + } + + void detour::create(const size_t place, void* target) + { + this->create(reinterpret_cast(place), target); + } + + void detour::clear() + { + if (this->place_) + { + MH_RemoveHook(this->place_); + } + + this->place_ = nullptr; + this->original_ = nullptr; + } + + void* detour::get_original() const + { + return this->original_; + } + + bool iat(const nt::library& library, const std::string& target_library, const std::string& process, void* stub) + { + if (!library.is_valid()) return false; + + auto* const ptr = library.get_iat_entry(target_library, process); + if (!ptr) return false; + + DWORD protect; + VirtualProtect(ptr, sizeof(*ptr), PAGE_EXECUTE_READWRITE, &protect); + + *ptr = stub; + + VirtualProtect(ptr, sizeof(*ptr), protect, &protect); + return true; + } + + void nop(void* place, const size_t length) + { + DWORD old_protect{}; + VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); + + std::memset(place, 0x90, length); + + VirtualProtect(place, length, old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, length); + } + + void nop(const size_t place, const size_t length) + { + nop(reinterpret_cast(place), length); + } + + void copy(void* place, const void* data, const size_t length) + { + DWORD old_protect{}; + VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); + + std::memmove(place, data, length); + + VirtualProtect(place, length, old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, length); + } + + void copy(const size_t place, const void* data, const size_t length) + { + copy(reinterpret_cast(place), data, length); + } + + bool is_relatively_far(const void* pointer, const void* data, const int offset) + { + const int64_t diff = size_t(data) - (size_t(pointer) + offset); + const auto small_diff = int32_t(diff); + return diff != int64_t(small_diff); + } + + void call(void* pointer, void* data) + { + if (is_relatively_far(pointer, data)) + { + throw std::runtime_error("Too far away to create 32bit relative branch"); + } + + auto* patch_pointer = PBYTE(pointer); + set(patch_pointer, 0xE8); + set(patch_pointer + 1, int32_t(size_t(data) - (size_t(pointer) + 5))); + } + + void call(const size_t pointer, void* data) + { + return call(reinterpret_cast(pointer), data); + } + + void call(const size_t pointer, const size_t data) + { + return call(pointer, reinterpret_cast(data)); + } + + void jump(void* pointer, void* data, const bool use_far) + { + static const unsigned char jump_data[] = { + 0x48, 0xb8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xff, 0xe0 + }; + + if (!use_far && is_relatively_far(pointer, data)) + { + throw std::runtime_error("Too far away to create 32bit relative branch"); + } + + auto* patch_pointer = PBYTE(pointer); + + if (use_far) + { + copy(patch_pointer, jump_data, sizeof(jump_data)); + copy(patch_pointer + 2, &data, sizeof(data)); + } + else + { + set(patch_pointer, 0xE9); + set(patch_pointer + 1, int32_t(size_t(data) - (size_t(pointer) + 5))); + } + } + + void jump(const size_t pointer, void* data, const bool use_far) + { + return jump(reinterpret_cast(pointer), data, use_far); + } + + void jump(const size_t pointer, const size_t data, const bool use_far) + { + return jump(pointer, reinterpret_cast(data), use_far); + } + + void* assemble(const std::function& asm_function) + { + static asmjit::JitRuntime runtime; + + asmjit::CodeHolder code; + code.init(runtime.environment()); + + assembler a(&code); + + asm_function(a); + + void* result = nullptr; + runtime.add(&result, &code); + + return result; + } + + void inject(void* pointer, const void* data) + { + if (is_relatively_far(pointer, data, 4)) + { + throw std::runtime_error("Too far away to create 32bit relative branch"); + } + + set(pointer, int32_t(size_t(data) - (size_t(pointer) + 4))); + } + + void inject(const size_t pointer, const void* data) + { + return inject(reinterpret_cast(pointer), data); + } + + void* follow_branch(void* address) + { + auto* const data = static_cast(address); + if (*data != 0xE8 && *data != 0xE9) + { + throw std::runtime_error("No branch instruction found"); + } + + return extract(data + 1); + } +} diff --git a/src/common/utils/hook.hpp b/src/common/utils/hook.hpp new file mode 100644 index 0000000..251131e --- /dev/null +++ b/src/common/utils/hook.hpp @@ -0,0 +1,156 @@ +#pragma once +#include "signature.hpp" + +#include +#include + +using namespace asmjit::x86; + +namespace utils::hook +{ + class assembler : public Assembler + { + public: + using Assembler::Assembler; + using Assembler::call; + using Assembler::jmp; + + void pushad64(); + void popad64(); + + void prepare_stack_for_call(); + void restore_stack_after_call(); + + template + void call_aligned(T&& target) + { + this->prepare_stack_for_call(); + this->call(std::forward(target)); + this->restore_stack_after_call(); + } + + asmjit::Error call(void* target); + asmjit::Error jmp(void* target); + }; + + class detour + { + public: + detour() = default; + detour(void* place, void* target); + detour(size_t place, void* target); + ~detour(); + + detour(detour&& other) noexcept + { + this->operator=(std::move(other)); + } + + detour& operator=(detour&& other) noexcept + { + if (this != &other) + { + this->~detour(); + + this->place_ = other.place_; + this->original_ = other.original_; + + other.place_ = nullptr; + other.original_ = nullptr; + } + + return *this; + } + + detour(const detour&) = delete; + detour& operator=(const detour&) = delete; + + void enable() const; + void disable() const; + + void create(void* place, void* target); + void create(size_t place, void* target); + void clear(); + + template + T* get() const + { + return static_cast(this->get_original()); + } + + template + T invoke(Args ... args) + { + return static_cast(this->get_original())(args...); + } + + [[nodiscard]] void* get_original() const; + + private: + void* place_{}; + void* original_{}; + }; + + bool iat(const nt::library& library, const std::string& target_library, const std::string& process, void* stub); + + void nop(void* place, size_t length); + void nop(size_t place, size_t length); + + void copy(void* place, const void* data, size_t length); + void copy(size_t place, const void* data, size_t length); + + bool is_relatively_far(const void* pointer, const void* data, int offset = 5); + + void call(void* pointer, void* data); + void call(size_t pointer, void* data); + void call(size_t pointer, size_t data); + + void jump(void* pointer, void* data, bool use_far = false); + void jump(size_t pointer, void* data, bool use_far = false); + void jump(size_t pointer, size_t data, bool use_far = false); + + void* assemble(const std::function& asm_function); + + void inject(void* pointer, const void* data); + void inject(size_t pointer, const void* data); + + template + T extract(void* address) + { + auto* const data = static_cast(address); + const auto offset = *reinterpret_cast(data); + return reinterpret_cast(data + offset + 4); + } + + void* follow_branch(void* address); + + template + static void set(void* place, T value) + { + DWORD old_protect; + VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect); + + *static_cast(place) = value; + + VirtualProtect(place, sizeof(T), old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, sizeof(T)); + } + + template + static void set(const size_t place, T value) + { + return set(reinterpret_cast(place), value); + } + + template + static T invoke(size_t func, Args ... args) + { + return reinterpret_cast(func)(args...); + } + + template + static T invoke(void* func, Args ... args) + { + return static_cast(func)(args...); + } +} diff --git a/src/common/utils/http.cpp b/src/common/utils/http.cpp new file mode 100644 index 0000000..0274c79 --- /dev/null +++ b/src/common/utils/http.cpp @@ -0,0 +1,48 @@ +#include "http.hpp" +#include "nt.hpp" +#include + +namespace utils::http +{ + std::optional get_data(const std::string& url) + { + CComPtr stream; + + if (FAILED(URLOpenBlockingStreamA(nullptr, url.data(), &stream, 0, nullptr))) + { + return {}; + } + + char buffer[0x1000]; + std::string result; + + HRESULT status{}; + + do + { + DWORD bytes_read = 0; + status = stream->Read(buffer, sizeof(buffer), &bytes_read); + + if (bytes_read > 0) + { + result.append(buffer, bytes_read); + } + } + while (SUCCEEDED(status) && status != S_FALSE); + + if (FAILED(status)) + { + return {}; + } + + return {result}; + } + + std::future> get_data_async(const std::string& url) + { + return std::async(std::launch::async, [url]() + { + return get_data(url); + }); + } +} \ No newline at end of file diff --git a/src/common/utils/http.hpp b/src/common/utils/http.hpp new file mode 100644 index 0000000..16c733e --- /dev/null +++ b/src/common/utils/http.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include +#include +#include + +namespace utils::http +{ + std::optional get_data(const std::string& url); + std::future> get_data_async(const std::string& url); +} \ No newline at end of file diff --git a/src/common/utils/info_string.cpp b/src/common/utils/info_string.cpp new file mode 100644 index 0000000..229d0ef --- /dev/null +++ b/src/common/utils/info_string.cpp @@ -0,0 +1,65 @@ +#include "info_string.hpp" +#include "string.hpp" + +namespace utils +{ + info_string::info_string(const std::string& buffer) + { + this->parse(buffer); + } + + info_string::info_string(const std::string_view& buffer) + : info_string(std::string{buffer}) + { + } + + void info_string::set(const std::string& key, const std::string& value) + { + this->key_value_pairs_[key] = value; + } + + std::string info_string::get(const std::string& key) const + { + const auto value = this->key_value_pairs_.find(key); + if (value != this->key_value_pairs_.end()) + { + return value->second; + } + + return {}; + } + + void info_string::parse(std::string buffer) + { + if (buffer[0] == '\\') + { + buffer = buffer.substr(1); + } + + const auto key_values = string::split(buffer, '\\'); + for (size_t i = 0; !key_values.empty() && i < (key_values.size() - 1); i += 2) + { + const auto& key = key_values[i]; + const auto& value = key_values[i + 1]; + + if (!this->key_value_pairs_.contains(key)) + { + this->key_value_pairs_[key] = value; + } + } + } + + std::string info_string::build() const + { + std::string info_string; + for (const auto& [key, val] : this->key_value_pairs_) + { + info_string.append("\\"); + info_string.append(key); + info_string.append("\\"); + info_string.append(val); + } + + return info_string; + } +} diff --git a/src/common/utils/info_string.hpp b/src/common/utils/info_string.hpp new file mode 100644 index 0000000..7391041 --- /dev/null +++ b/src/common/utils/info_string.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +namespace utils +{ + class info_string + { + public: + info_string() = default; + info_string(const std::string& buffer); + info_string(const std::string_view& buffer); + + void set(const std::string& key, const std::string& value); + std::string get(const std::string& key) const; + std::string build() const; + + private: + std::unordered_map key_value_pairs_{}; + + void parse(std::string buffer); + }; +} diff --git a/src/common/utils/io.cpp b/src/common/utils/io.cpp new file mode 100644 index 0000000..8be0e08 --- /dev/null +++ b/src/common/utils/io.cpp @@ -0,0 +1,123 @@ +#include "io.hpp" +#include "nt.hpp" +#include + +namespace utils::io +{ + bool remove_file(const std::string& file) + { + return DeleteFileA(file.data()) == TRUE; + } + + bool move_file(const std::string& src, const std::string& target) + { + return MoveFileA(src.data(), target.data()) == TRUE; + } + + bool file_exists(const std::string& file) + { + return std::ifstream(file).good(); + } + + bool write_file(const std::string& file, const std::string& data, const bool append) + { + const auto pos = file.find_last_of("/\\"); + if (pos != std::string::npos) + { + create_directory(file.substr(0, pos)); + } + + std::ofstream stream( + file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : 0)); + + if (stream.is_open()) + { + stream.write(data.data(), static_cast(data.size())); + stream.close(); + return true; + } + + return false; + } + + std::string read_file(const std::string& file) + { + std::string data; + read_file(file, &data); + return data; + } + + bool read_file(const std::string& file, std::string* data) + { + if (!data) return false; + data->clear(); + + if (file_exists(file)) + { + std::ifstream stream(file, std::ios::binary); + if (!stream.is_open()) return false; + + stream.seekg(0, std::ios::end); + const std::streamsize size = stream.tellg(); + stream.seekg(0, std::ios::beg); + + if (size > -1) + { + data->resize(static_cast(size)); + stream.read(data->data(), size); + stream.close(); + return true; + } + } + + return false; + } + + size_t file_size(const std::string& file) + { + if (file_exists(file)) + { + std::ifstream stream(file, std::ios::binary); + + if (stream.good()) + { + stream.seekg(0, std::ios::end); + return static_cast(stream.tellg()); + } + } + + return 0; + } + + bool create_directory(const std::string& directory) + { + return std::filesystem::create_directories(directory); + } + + bool directory_exists(const std::string& directory) + { + return std::filesystem::is_directory(directory); + } + + bool directory_is_empty(const std::string& directory) + { + return std::filesystem::is_empty(directory); + } + + std::vector list_files(const std::string& directory) + { + std::vector files; + + for (auto& file : std::filesystem::directory_iterator(directory)) + { + files.push_back(file.path().generic_string()); + } + + return files; + } + + void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target) + { + std::filesystem::copy(src, target, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::recursive); + } +} diff --git a/src/common/utils/io.hpp b/src/common/utils/io.hpp new file mode 100644 index 0000000..ab4ebaa --- /dev/null +++ b/src/common/utils/io.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include + +namespace utils::io +{ + bool remove_file(const std::string& file); + bool move_file(const std::string& src, const std::string& target); + bool file_exists(const std::string& file); + bool write_file(const std::string& file, const std::string& data, bool append = false); + bool read_file(const std::string& file, std::string* data); + std::string read_file(const std::string& file); + size_t file_size(const std::string& file); + bool create_directory(const std::string& directory); + bool directory_exists(const std::string& directory); + bool directory_is_empty(const std::string& directory); + std::vector list_files(const std::string& directory); + void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target); +} diff --git a/src/common/utils/memory.cpp b/src/common/utils/memory.cpp new file mode 100644 index 0000000..b351737 --- /dev/null +++ b/src/common/utils/memory.cpp @@ -0,0 +1,164 @@ +#include "memory.hpp" +#include "nt.hpp" + +namespace utils +{ + memory::allocator memory::mem_allocator_; + + memory::allocator::~allocator() + { + this->clear(); + } + + void memory::allocator::clear() + { + std::lock_guard _(this->mutex_); + + for (const auto& data : this->pool_) + { + memory::free(data); + } + + this->pool_.clear(); + } + + void memory::allocator::free(void* data) + { + std::lock_guard _(this->mutex_); + + const auto j = std::find(this->pool_.begin(), this->pool_.end(), data); + if (j != this->pool_.end()) + { + memory::free(data); + this->pool_.erase(j); + } + } + + void memory::allocator::free(const void* data) + { + this->free(const_cast(data)); + } + + void* memory::allocator::allocate(const size_t length) + { + std::lock_guard _(this->mutex_); + + auto* data = memory::allocate(length); + this->pool_.push_back(data); + return data; + } + + bool memory::allocator::empty() const + { + return this->pool_.empty(); + } + + char* memory::allocator::duplicate_string(const std::string& string) + { + std::lock_guard _(this->mutex_); + + auto* data = memory::duplicate_string(string); + this->pool_.push_back(data); + return data; + } + + void* memory::allocate(const size_t length) + { + return std::calloc(length, 1); + } + + char* memory::duplicate_string(const std::string& string) + { + auto* new_string = allocate_array(string.size() + 1); + std::memcpy(new_string, string.data(), string.size()); + return new_string; + } + + void memory::free(void* data) + { + std::free(data); + } + + void memory::free(const void* data) + { + free(const_cast(data)); + } + + bool memory::is_set(const void* mem, const char chr, const size_t length) + { + const auto* mem_arr = static_cast(mem); + + for (size_t i = 0; i < length; ++i) + { + if (mem_arr[i] != chr) + { + return false; + } + } + + return true; + } + + bool memory::is_bad_read_ptr(const void* ptr) + { + MEMORY_BASIC_INFORMATION mbi = {}; + if (VirtualQuery(ptr, &mbi, sizeof(mbi))) + { + const DWORD mask = (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | + PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); + auto b = !(mbi.Protect & mask); + // check the page is not a guard page + if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; + + return b; + } + + return true; + } + + bool memory::is_bad_code_ptr(const void* ptr) + { + MEMORY_BASIC_INFORMATION mbi = {}; + if (VirtualQuery(ptr, &mbi, sizeof(mbi))) + { + const DWORD mask = (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); + auto b = !(mbi.Protect & mask); + // check the page is not a guard page + if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; + + return b; + } + + return true; + } + + bool memory::is_rdata_ptr(void* ptr) + { + const std::string rdata = ".rdata"; + const auto pointer_lib = utils::nt::library::get_by_address(ptr); + + for (const auto& section : pointer_lib.get_section_headers()) + { + const auto size = sizeof(section->Name); + char name[size + 1]; + name[size] = 0; + std::memcpy(name, section->Name, size); + + if (name == rdata) + { + const auto target = size_t(ptr); + const size_t source_start = size_t(pointer_lib.get_ptr()) + section->PointerToRawData; + const size_t source_end = source_start + section->SizeOfRawData; + + return target >= source_start && target <= source_end; + } + } + + return false; + } + + memory::allocator* memory::get_allocator() + { + return &memory::mem_allocator_; + } +} diff --git a/src/common/utils/memory.hpp b/src/common/utils/memory.hpp new file mode 100644 index 0000000..0448894 --- /dev/null +++ b/src/common/utils/memory.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include +#include + +namespace utils +{ + class memory final + { + public: + class allocator final + { + public: + ~allocator(); + + void clear(); + + void free(void* data); + + void free(const void* data); + + void* allocate(size_t length); + + template + T* allocate() + { + return this->allocate_array(1); + } + + template + T* allocate_array(const size_t count = 1) + { + return static_cast(this->allocate(count * sizeof(T))); + } + + bool empty() const; + + char* duplicate_string(const std::string& string); + + private: + std::mutex mutex_; + std::vector pool_; + }; + + static void* allocate(size_t length); + + template + static T* allocate() + { + return allocate_array(1); + } + + template + static T* allocate_array(const size_t count = 1) + { + return static_cast(allocate(count * sizeof(T))); + } + + static char* duplicate_string(const std::string& string); + + static void free(void* data); + static void free(const void* data); + + static bool is_set(const void* mem, char chr, size_t length); + + static bool is_bad_read_ptr(const void* ptr); + static bool is_bad_code_ptr(const void* ptr); + static bool is_rdata_ptr(void* ptr); + + static allocator* get_allocator(); + + private: + static allocator mem_allocator_; + }; +} diff --git a/src/common/utils/nt.cpp b/src/common/utils/nt.cpp new file mode 100644 index 0000000..db7c9df --- /dev/null +++ b/src/common/utils/nt.cpp @@ -0,0 +1,275 @@ +#include "nt.hpp" + +namespace utils::nt +{ + library library::load(const std::string& name) + { + return library(LoadLibraryA(name.data())); + } + + library library::load(const std::filesystem::path& path) + { + return load(path.generic_string()); + } + + library library::get_by_address(void* address) + { + HMODULE handle = nullptr; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast(address), &handle); + return library(handle); + } + + library::library() + { + this->module_ = GetModuleHandleA(nullptr); + } + + library::library(const std::string& name) + { + this->module_ = GetModuleHandleA(name.data()); + } + + library::library(const HMODULE handle) + { + this->module_ = handle; + } + + bool library::operator==(const library& obj) const + { + return this->module_ == obj.module_; + } + + library::operator bool() const + { + return this->is_valid(); + } + + library::operator HMODULE() const + { + return this->get_handle(); + } + + PIMAGE_NT_HEADERS library::get_nt_headers() const + { + if (!this->is_valid()) return nullptr; + return reinterpret_cast(this->get_ptr() + this->get_dos_header()->e_lfanew); + } + + PIMAGE_DOS_HEADER library::get_dos_header() const + { + return reinterpret_cast(this->get_ptr()); + } + + PIMAGE_OPTIONAL_HEADER library::get_optional_header() const + { + if (!this->is_valid()) return nullptr; + return &this->get_nt_headers()->OptionalHeader; + } + + std::vector library::get_section_headers() const + { + std::vector headers; + + auto nt_headers = this->get_nt_headers(); + auto section = IMAGE_FIRST_SECTION(nt_headers); + + for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section) + { + if (section) headers.push_back(section); + } + + return headers; + } + + std::uint8_t* library::get_ptr() const + { + return reinterpret_cast(this->module_); + } + + void library::unprotect() const + { + if (!this->is_valid()) return; + + DWORD protection; + VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE, + &protection); + } + + size_t library::get_relative_entry_point() const + { + if (!this->is_valid()) return 0; + return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint; + } + + void* library::get_entry_point() const + { + if (!this->is_valid()) return nullptr; + return this->get_ptr() + this->get_relative_entry_point(); + } + + bool library::is_valid() const + { + return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE; + } + + std::string library::get_name() const + { + if (!this->is_valid()) return {}; + + auto path = this->get_path(); + const auto pos = path.find_last_of("/\\"); + if (pos == std::string::npos) return path; + + return path.substr(pos + 1); + } + + std::string library::get_path() const + { + if (!this->is_valid()) return {}; + + char name[MAX_PATH]{}; + GetModuleFileNameA(this->module_, name, sizeof name); + + return name; + } + + std::string library::get_folder() const + { + if (!this->is_valid()) return {}; + + const auto path = std::filesystem::path(this->get_path()); + return path.parent_path().generic_string(); + } + + void library::free() + { + if (this->is_valid()) + { + FreeLibrary(this->module_); + this->module_ = nullptr; + } + } + + HMODULE library::get_handle() const + { + return this->module_; + } + + void** library::get_iat_entry(const std::string& module_name, const std::string& proc_name) const + { + return this->get_iat_entry(module_name, proc_name.data()); + } + + void** library::get_iat_entry(const std::string& module_name, const char* proc_name) const + { + if (!this->is_valid()) return nullptr; + + const library other_module(module_name); + if (!other_module.is_valid()) return nullptr; + + auto* const target_function = other_module.get_proc(proc_name); + if (!target_function) return nullptr; + + auto* header = this->get_optional_header(); + if (!header) return nullptr; + + auto* import_descriptor = reinterpret_cast(this->get_ptr() + header->DataDirectory + [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + + while (import_descriptor->Name) + { + if (!_stricmp(reinterpret_cast(this->get_ptr() + import_descriptor->Name), module_name.data())) + { + auto* original_thunk_data = reinterpret_cast(import_descriptor-> + OriginalFirstThunk + this->get_ptr()); + auto* thunk_data = reinterpret_cast(import_descriptor->FirstThunk + this-> + get_ptr()); + + while (original_thunk_data->u1.AddressOfData) + { + if (thunk_data->u1.Function == reinterpret_cast(target_function)) + { + return reinterpret_cast(&thunk_data->u1.Function); + } + + const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF; + + if (ordinal_number <= 0xFFFF) + { + auto* proc = GetProcAddress(other_module.module_, reinterpret_cast(ordinal_number)); + if (reinterpret_cast(proc) == target_function) + { + return reinterpret_cast(&thunk_data->u1.Function); + } + } + + ++original_thunk_data; + ++thunk_data; + } + + //break; + } + + ++import_descriptor; + } + + return nullptr; + } + + bool is_wine() + { + static const auto has_wine_export = []() -> bool + { + const library ntdll("ntdll.dll"); + return ntdll.get_proc("wine_get_version"); + }(); + + return has_wine_export; + } + + void raise_hard_exception() + { + int data = false; + const library ntdll("ntdll.dll"); + ntdll.invoke_pascal("RtlAdjustPrivilege", 19, true, false, &data); + ntdll.invoke_pascal("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data); + } + + std::string load_resource(const int id) + { + auto* const res = FindResource(library(), MAKEINTRESOURCE(id), RT_RCDATA); + if (!res) return {}; + + auto* const handle = LoadResource(nullptr, res); + if (!handle) return {}; + + return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res)); + } + + void relaunch_self() + { + const library self; + + STARTUPINFOA startup_info; + PROCESS_INFORMATION process_info; + + ZeroMemory(&startup_info, sizeof(startup_info)); + ZeroMemory(&process_info, sizeof(process_info)); + startup_info.cb = sizeof(startup_info); + + char current_dir[MAX_PATH]; + GetCurrentDirectoryA(sizeof(current_dir), current_dir); + auto* const command_line = GetCommandLineA(); + + CreateProcessA(self.get_path().data(), command_line, nullptr, nullptr, false, NULL, nullptr, current_dir, + &startup_info, &process_info); + + if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) CloseHandle(process_info.hThread); + if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) CloseHandle(process_info.hProcess); + } + + void terminate(const uint32_t code) + { + TerminateProcess(GetCurrentProcess(), code); + } +} diff --git a/src/common/utils/nt.hpp b/src/common/utils/nt.hpp new file mode 100644 index 0000000..c0e903d --- /dev/null +++ b/src/common/utils/nt.hpp @@ -0,0 +1,120 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN +#include + +// min and max is required by gdi, therefore NOMINMAX won't work +#ifdef max +#undef max +#endif + +#ifdef min +#undef min +#endif + +#include +#include +#include + +namespace utils::nt +{ + class library final + { + public: + static library load(const std::string& name); + static library load(const std::filesystem::path& path); + static library get_by_address(void* address); + + library(); + explicit library(const std::string& name); + explicit library(HMODULE handle); + + library(const library& a) : module_(a.module_) + { + } + + bool operator!=(const library& obj) const { return !(*this == obj); }; + bool operator==(const library& obj) const; + + operator bool() const; + operator HMODULE() const; + + void unprotect() const; + void* get_entry_point() const; + size_t get_relative_entry_point() const; + + bool is_valid() const; + std::string get_name() const; + std::string get_path() const; + std::string get_folder() const; + std::uint8_t* get_ptr() const; + void free(); + + HMODULE get_handle() const; + + template + T get_proc(const std::string& process) const + { + if (!this->is_valid()) T{}; + return reinterpret_cast(GetProcAddress(this->module_, process.data())); + } + + template + T get_proc(const char* name) const + { + if (!this->is_valid()) T{}; + return reinterpret_cast(GetProcAddress(this->module_, name)); + } + + template + std::function get(const std::string& process) const + { + if (!this->is_valid()) return std::function(); + return static_cast(this->get_proc(process)); + } + + template + T invoke(const std::string& process, Args ... args) const + { + auto method = this->get(process); + if (method) return method(args...); + return T(); + } + + template + T invoke_pascal(const std::string& process, Args ... args) const + { + auto method = this->get(process); + if (method) return method(args...); + return T(); + } + + template + T invoke_this(const std::string& process, void* this_ptr, Args ... args) const + { + auto method = this->get(this_ptr, process); + if (method) return method(args...); + return T(); + } + + std::vector get_section_headers() const; + + PIMAGE_NT_HEADERS get_nt_headers() const; + PIMAGE_DOS_HEADER get_dos_header() const; + PIMAGE_OPTIONAL_HEADER get_optional_header() const; + + void** get_iat_entry(const std::string& module_name, const std::string& proc_name) const; + void** get_iat_entry(const std::string& module_name, const char* name) const; + + private: + HMODULE module_; + }; + + bool is_wine(); + + __declspec(noreturn) void raise_hard_exception(); + std::string load_resource(int id); + + void relaunch_self(); + __declspec(noreturn) void terminate(uint32_t code = 0); +} diff --git a/src/common/utils/signature.cpp b/src/common/utils/signature.cpp new file mode 100644 index 0000000..5a32dab --- /dev/null +++ b/src/common/utils/signature.cpp @@ -0,0 +1,210 @@ +#include "signature.hpp" +#include +#include + +#include + +namespace utils::hook +{ + void signature::load_pattern(const std::string& pattern) + { + this->mask_.clear(); + this->pattern_.clear(); + + uint8_t nibble = 0; + auto has_nibble = false; + + for(auto val : pattern) + { + if (val == ' ') continue; + if(val == '?') + { + this->mask_.push_back(val); + this->pattern_.push_back(0); + } + else + { + if((val < '0' || val > '9') && (val < 'A' || val > 'F') && (val < 'a' || val> 'f')) + { + throw std::runtime_error("Invalid pattern"); + } + + char str[] = { val, 0 }; + const auto current_nibble = static_cast(strtol(str, nullptr, 16)); + + if(!has_nibble) + { + has_nibble = true; + nibble = current_nibble; + } + else + { + has_nibble = false; + const uint8_t byte = current_nibble | (nibble << 4); + + this->mask_.push_back('x'); + this->pattern_.push_back(byte); + } + } + } + + while (!this->mask_.empty() && this->mask_.back() == '?') + { + this->mask_.pop_back(); + this->pattern_.pop_back(); + } + + if(this->has_sse_support()) + { + while (this->pattern_.size() < 16) + { + this->pattern_.push_back(0); + } + } + + if(has_nibble) + { + throw std::runtime_error("Invalid pattern"); + } + } + + std::vector signature::process_range(uint8_t* start, const size_t length) const + { + if (this->has_sse_support()) return this->process_range_vectorized(start, length); + return this->process_range_linear(start, length); + } + + std::vector signature::process_range_linear(uint8_t* start, const size_t length) const + { + std::vector result; + + for (size_t i = 0; i < length; ++i) + { + const auto address = start + i; + + size_t j = 0; + for (; j < this->mask_.size(); ++j) + { + if (this->mask_[j] != '?' && this->pattern_[j] != address[j]) + { + break; + } + } + + if (j == this->mask_.size()) + { + result.push_back(size_t(address)); + } + } + + return result; + } + + std::vector signature::process_range_vectorized(uint8_t* start, const size_t length) const + { + std::vector result; + __declspec(align(16)) char desired_mask[16] = { 0 }; + + for (size_t i = 0; i < this->mask_.size(); i++) + { + desired_mask[i / 8] |= (this->mask_[i] == '?' ? 0 : 1) << i % 8; + } + + const auto mask = _mm_load_si128(reinterpret_cast(desired_mask)); + const auto comparand = _mm_loadu_si128(reinterpret_cast(this->pattern_.data())); + + for (size_t i = 0; i < length; ++i) + { + const auto address = start + i; + const auto value = _mm_loadu_si128(reinterpret_cast(address)); + const auto comparison = _mm_cmpestrm(value, 16, comparand, static_cast(this->mask_.size()), _SIDD_CMP_EQUAL_EACH); + + const auto matches = _mm_and_si128(mask, comparison); + const auto equivalence = _mm_xor_si128(mask, matches); + + if (_mm_test_all_zeros(equivalence, equivalence)) + { + result.push_back(size_t(address)); + } + } + + return result; + } + + signature::signature_result signature::process() const + { + const auto range = this->length_ - this->mask_.size(); + const auto cores = std::max(1u, std::thread::hardware_concurrency()); + + if (range <= cores * 10ull) return this->process_serial(); + return this->process_parallel(); + } + + signature::signature_result signature::process_serial() const + { + const auto sub = this->has_sse_support() ? 16 : this->mask_.size(); + return { this->process_range(this->start_, this->length_ - sub) }; + } + + signature::signature_result signature::process_parallel() const + { + const auto sub = this->has_sse_support() ? 16 : this->mask_.size(); + const auto range = this->length_ - sub; + const auto cores = std::max(1u, std::thread::hardware_concurrency() / 2); // Only use half of the available cores + const auto grid = range / cores; + + std::mutex mutex; + std::vector result; + std::vector threads; + + for(auto i = 0u; i < cores; ++i) + { + const auto start = this->start_ + (grid * i); + const auto length = (i + 1 == cores) ? (this->start_ + this->length_ - sub) - start : grid; + threads.emplace_back([&, start, length]() + { + auto local_result = this->process_range(start, length); + if (local_result.empty()) return; + + std::lock_guard _(mutex); + for(const auto& address : local_result) + { + result.push_back(address); + } + }); + } + + for(auto& t : threads) + { + if(t.joinable()) + { + t.join(); + } + } + + std::sort(result.begin(), result.end()); + return { std::move(result) }; + } + + bool signature::has_sse_support() const + { + if (this->mask_.size() <= 16) + { + int cpu_id[4]; + __cpuid(cpu_id, 0); + + if (cpu_id[0] >= 1) + { + __cpuidex(cpu_id, 1, 0); + return (cpu_id[2] & (1 << 20)) != 0; + } + } + + return false; + } +} + +utils::hook::signature::signature_result operator"" _sig(const char* str, const size_t len) +{ + return utils::hook::signature(std::string(str, len)).process(); +} diff --git a/src/common/utils/signature.hpp b/src/common/utils/signature.hpp new file mode 100644 index 0000000..4b88ebb --- /dev/null +++ b/src/common/utils/signature.hpp @@ -0,0 +1,74 @@ +#pragma once +#include "nt.hpp" +#include + +namespace utils::hook +{ + class signature final + { + public: + class signature_result + { + public: + signature_result(std::vector&& matches) : matches_(std::move(matches)) + { + + } + + [[nodiscard]] uint8_t* get(const size_t index) const + { + if(index >= this->count()) + { + throw std::runtime_error("Invalid index"); + } + + return reinterpret_cast(this->matches_[index]); + } + + [[nodiscard]] size_t count() const + { + return this->matches_.size(); + } + + private: + std::vector matches_; + }; + + explicit signature(const std::string& pattern, const nt::library library = {}) + : signature(pattern, library.get_ptr(), library.get_optional_header()->SizeOfImage) + { + } + + signature(const std::string& pattern, void* start, void* end) + : signature(pattern, start, size_t(end) - size_t(start)) + { + } + + signature(const std::string& pattern, void* start, const size_t length) + : start_(static_cast(start)), length_(length) + { + this->load_pattern(pattern); + } + + signature_result process() const; + + private: + std::string mask_; + std::basic_string pattern_; + + uint8_t* start_; + size_t length_; + + void load_pattern(const std::string& pattern); + + signature_result process_parallel() const; + signature_result process_serial() const; + std::vector process_range(uint8_t* start, size_t length) const; + std::vector process_range_linear(uint8_t* start, size_t length) const; + std::vector process_range_vectorized(uint8_t* start, size_t length) const; + + bool has_sse_support() const; + }; +} + +utils::hook::signature::signature_result operator"" _sig(const char* str, size_t len); diff --git a/src/common/utils/smbios.cpp b/src/common/utils/smbios.cpp new file mode 100644 index 0000000..07f65c0 --- /dev/null +++ b/src/common/utils/smbios.cpp @@ -0,0 +1,94 @@ +#include "smbios.hpp" +#include "memory.hpp" + +#define WIN32_LEAN_AND_MEAN +#include +#include + +namespace utils::smbios +{ + namespace + { +#pragma warning(push) +#pragma warning(disable: 4200) + struct RawSMBIOSData + { + BYTE Used20CallingMethod; + BYTE SMBIOSMajorVersion; + BYTE SMBIOSMinorVersion; + BYTE DmiRevision; + DWORD Length; + BYTE SMBIOSTableData[]; + }; + + typedef struct + { + BYTE type; + BYTE length; + WORD handle; + } dmi_header; +#pragma warning(pop) + + std::vector get_smbios_data() + { + DWORD size = 0; + std::vector data{}; + + size = GetSystemFirmwareTable('RSMB', 0, nullptr, size); + data.resize(size); + GetSystemFirmwareTable('RSMB', 0, data.data(), size); + + return data; + } + + std::string parse_uuid(const uint8_t* data) + { + if (utils::memory::is_set(data, 0, 16) || utils::memory::is_set(data, -1, 16)) + { + return {}; + } + + char uuid[16] = { 0 }; + *reinterpret_cast(uuid + 0) = + _byteswap_ulong(*reinterpret_cast(data + 0)); + *reinterpret_cast(uuid + 4) = + _byteswap_ushort(*reinterpret_cast(data + 4)); + *reinterpret_cast(uuid + 6) = + _byteswap_ushort(*reinterpret_cast(data + 6)); + memcpy(uuid + 8, data + 8, 8); + + return std::string(uuid, sizeof(uuid)); + } + } + + std::string get_uuid() + { + auto smbios_data = get_smbios_data(); + auto* raw_data = reinterpret_cast(smbios_data.data()); + + auto* data = raw_data->SMBIOSTableData; + for (DWORD i = 0; i + sizeof(dmi_header) < raw_data->Length;) + { + auto* header = reinterpret_cast(data + i); + if (header->length < 4) + { + return {}; + } + + if (header->type == 0x01 && header->length >= 0x19) + { + return parse_uuid(data + i + 0x8); + } + + i += header->length; + while ((i + 1) < raw_data->Length && *reinterpret_cast(data + i) != 0) + { + ++i; + } + + i += 2; + } + + return {}; + } +} diff --git a/src/common/utils/smbios.hpp b/src/common/utils/smbios.hpp new file mode 100644 index 0000000..bbd1939 --- /dev/null +++ b/src/common/utils/smbios.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace utils::smbios +{ + std::string get_uuid(); +} diff --git a/src/common/utils/string.cpp b/src/common/utils/string.cpp new file mode 100644 index 0000000..6236584 --- /dev/null +++ b/src/common/utils/string.cpp @@ -0,0 +1,185 @@ +#include "string.hpp" +#include +#include +#include + +#include "nt.hpp" + +namespace utils::string +{ + const char* va(const char* fmt, ...) + { + static thread_local va_provider<8, 256> provider; + + va_list ap; + va_start(ap, fmt); + + const char* result = provider.get(fmt, ap); + + va_end(ap); + return result; + } + + std::vector split(const std::string& s, const char delim) + { + std::stringstream ss(s); + std::string item; + std::vector elems; + + while (std::getline(ss, item, delim)) + { + elems.push_back(item); // elems.push_back(std::move(item)); // if C++11 (based on comment from @mchiasson) + } + + return elems; + } + + std::string to_lower(const std::string& text) + { + std::string result; + std::ranges::transform(text, std::back_inserter(result), [](const unsigned char input) + { + return static_cast(std::tolower(input)); + }); + + return result; + } + + std::string to_upper(const std::string& text) + { + std::string result; + std::ranges::transform(text, std::back_inserter(result), [](const unsigned char input) + { + return static_cast(std::toupper(input)); + }); + + return result; + } + + bool starts_with(const std::string& text, const std::string& substring) + { + return text.find(substring) == 0; + } + + bool ends_with(const std::string& text, const std::string& substring) + { + if (substring.size() > text.size()) return false; + return std::equal(substring.rbegin(), substring.rend(), text.rbegin()); + } + + bool is_numeric(const std::string& text) + { + return std::to_string(atoi(text.data())) == text; + } + + std::string dump_hex(const std::string& data, const std::string& separator) + { + std::string result; + + for (unsigned int i = 0; i < data.size(); ++i) + { + if (i > 0) + { + result.append(separator); + } + + result.append(va("%02X", data[i] & 0xFF)); + } + + return result; + } + + std::string get_clipboard_data() + { + if (OpenClipboard(nullptr)) + { + std::string data; + + auto* const clipboard_data = GetClipboardData(1u); + if (clipboard_data) + { + auto* const cliptext = static_cast(GlobalLock(clipboard_data)); + if (cliptext) + { + data.append(cliptext); + GlobalUnlock(clipboard_data); + } + } + + CloseClipboard(); + + return data; + } + return {}; + } + + void strip(const char* in, char* out, size_t max) + { + if (!in || !out) return; + + max--; + auto current = 0u; + while (*in != 0 && current < max) + { + const auto color_index = (*(in + 1) - 48) >= 0xC ? 7 : (*(in + 1) - 48); + + if (*in == '^' && (color_index != 7 || *(in + 1) == '7')) + { + ++in; + } + else + { + *out = *in; + ++out; + ++current; + } + + ++in; + } + + *out = '\0'; + } + + std::string convert(const std::wstring& wstr) + { + std::string result; + result.reserve(wstr.size()); + + for (const auto& chr : wstr) + { + result.push_back(static_cast(chr)); + } + + return result; + } + + std::wstring convert(const std::string& str) + { + std::wstring result; + result.reserve(str.size()); + + for (const auto& chr : str) + { + result.push_back(static_cast(chr)); + } + + return result; + } + + std::string replace(std::string str, const std::string& from, const std::string& to) + { + if (from.empty()) + { + return str; + } + + size_t start_pos = 0; + while ((start_pos = str.find(from, start_pos)) != std::string::npos) + { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); + } + + return str; + } +} diff --git a/src/common/utils/string.hpp b/src/common/utils/string.hpp new file mode 100644 index 0000000..6a50c3e --- /dev/null +++ b/src/common/utils/string.hpp @@ -0,0 +1,99 @@ +#pragma once +#include "memory.hpp" +#include + +template +constexpr auto ARRAY_COUNT(Type(&)[n]) { return n; } + +namespace utils::string +{ + template + class va_provider final + { + public: + static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0"); + + va_provider() : current_buffer_(0) + { + } + + char* get(const char* format, const va_list ap) + { + ++this->current_buffer_ %= ARRAY_COUNT(this->string_pool_); + auto entry = &this->string_pool_[this->current_buffer_]; + + if (!entry->size || !entry->buffer) + { + throw std::runtime_error("String pool not initialized"); + } + + while (true) + { + const int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap); + if (res > 0) break; // Success + if (res == 0) return nullptr; // Error + + entry->double_size(); + } + + return entry->buffer; + } + + private: + class entry final + { + public: + explicit entry(const size_t _size = MinBufferSize) : size(_size), buffer(nullptr) + { + if (this->size < MinBufferSize) this->size = MinBufferSize; + this->allocate(); + } + + ~entry() + { + if (this->buffer) memory::get_allocator()->free(this->buffer); + this->size = 0; + this->buffer = nullptr; + } + + void allocate() + { + if (this->buffer) memory::get_allocator()->free(this->buffer); + this->buffer = memory::get_allocator()->allocate_array(this->size + 1); + } + + void double_size() + { + this->size *= 2; + this->allocate(); + } + + size_t size; + char* buffer; + }; + + size_t current_buffer_; + entry string_pool_[Buffers]; + }; + + const char* va(const char* fmt, ...); + + std::vector split(const std::string& s, char delim); + + std::string to_lower(const std::string& text); + std::string to_upper(const std::string& text); + bool starts_with(const std::string& text, const std::string& substring); + bool ends_with(const std::string& text, const std::string& substring); + bool is_numeric(const std::string& text); + + std::string dump_hex(const std::string& data, const std::string& separator = " "); + + std::string get_clipboard_data(); + + void strip(const char* in, char* out, size_t max); + + std::string convert(const std::wstring& wstr); + std::wstring convert(const std::string& str); + + std::string replace(std::string str, const std::string& from, const std::string& to); +} diff --git a/src/common/utils/thread.cpp b/src/common/utils/thread.cpp new file mode 100644 index 0000000..7239b53 --- /dev/null +++ b/src/common/utils/thread.cpp @@ -0,0 +1,128 @@ +#include "thread.hpp" +#include "string.hpp" + +#include + +#include + +namespace utils::thread +{ + bool set_name(const HANDLE t, const std::string& name) + { + const nt::library kernel32("kernel32.dll"); + if (!kernel32) + { + return false; + } + + const auto set_description = kernel32.get_proc("SetThreadDescription"); + if (!set_description) + { + return false; + } + + return SUCCEEDED(set_description(t, string::convert(name).data())); + } + + bool set_name(const DWORD id, const std::string& name) + { + auto* const t = OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, id); + if (!t) return false; + + const auto _ = gsl::finally([t]() + { + CloseHandle(t); + }); + + return set_name(t, name); + } + + bool set_name(std::thread& t, const std::string& name) + { + return set_name(t.native_handle(), name); + } + + bool set_name(const std::string& name) + { + return set_name(GetCurrentThread(), name); + } + + std::vector get_thread_ids() + { + auto* const h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetCurrentProcessId()); + if (h == INVALID_HANDLE_VALUE) + { + return {}; + } + + const auto _ = gsl::finally([h]() + { + CloseHandle(h); + }); + + THREADENTRY32 entry{}; + entry.dwSize = sizeof(entry); + if (!Thread32First(h, &entry)) + { + return {}; + } + + std::vector ids{}; + + do + { + const auto check_size = entry.dwSize < FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + + sizeof(entry.th32OwnerProcessID); + entry.dwSize = sizeof(entry); + + if (check_size && entry.th32OwnerProcessID == GetCurrentProcessId()) + { + ids.emplace_back(entry.th32ThreadID); + } + } + while (Thread32Next(h, &entry)); + + return ids; + } + + void for_each_thread(const std::function& callback) + { + const auto ids = get_thread_ids(); + + for (const auto& id : ids) + { + auto* const thread = OpenThread(THREAD_ALL_ACCESS, FALSE, id); + if (thread != nullptr) + { + const auto _ = gsl::finally([thread]() + { + CloseHandle(thread); + }); + + callback(thread); + } + } + } + + void suspend_other_threads() + { + for_each_thread([](const HANDLE thread) + { + if (GetThreadId(thread) != GetCurrentThreadId()) + { + SuspendThread(thread); + } + }); + } + + void resume_other_threads() + { + for_each_thread([](const HANDLE thread) + { + if (GetThreadId(thread) != GetCurrentThreadId()) + { + ResumeThread(thread); + } + }); + } +} diff --git a/src/common/utils/thread.hpp b/src/common/utils/thread.hpp new file mode 100644 index 0000000..4ea3598 --- /dev/null +++ b/src/common/utils/thread.hpp @@ -0,0 +1,25 @@ +#pragma once +#include +#include "nt.hpp" + +namespace utils::thread +{ + bool set_name(HANDLE t, const std::string& name); + bool set_name(DWORD id, const std::string& name); + bool set_name(std::thread& t, const std::string& name); + bool set_name(const std::string& name); + + template + std::thread create_named_thread(const std::string& name, Args&&... args) + { + auto t = std::thread(std::forward(args)...); + set_name(t, name); + return t; + } + + std::vector get_thread_ids(); + void for_each_thread(const std::function& callback); + + void suspend_other_threads(); + void resume_other_threads(); +} diff --git a/src/common/utils/toast.cpp b/src/common/utils/toast.cpp new file mode 100644 index 0000000..693b4af --- /dev/null +++ b/src/common/utils/toast.cpp @@ -0,0 +1,109 @@ +#include "toast.hpp" +#include "string.hpp" + +#pragma warning(push) +#pragma warning(disable: 6387) +#include +#pragma warning(pop) + +namespace utils +{ + namespace + { + bool initialize() + { + static bool initialized = false; + static bool success = false; + if (initialized) + { + return success; + } + + initialized = true; + auto* instance = WinToastLib::WinToast::instance(); + if (!instance) + { + success = false; + return success; + } + + instance->setAppName(L"iw6-mod"); + instance->setAppUserModelId( + WinToastLib::WinToast::configureAUMI(L"AlterWare", L"iw6-mod", L"", L"20201212")); + + WinToastLib::WinToast::WinToastError error; + success = instance->initialize(&error); + + return success; + } + + class toast_handler : public WinToastLib::IWinToastHandler + { + public: + void toastActivated() const override + { + } + + void toastActivated(const int /*actionIndex*/) const override + { + } + + void toastFailed() const override + { + } + + void toastDismissed(WinToastDismissalReason /*state*/) const override + { + } + }; + } + + toast::toast(const int64_t id) + : id_(id) + { + } + + toast::operator bool() const + { + return this->id_ >= 0; + } + + void toast::hide() const + { + if (this->operator bool()) + { + WinToastLib::WinToast::instance()->hideToast(this->id_); + } + } + + toast toast::show(const std::string& title, const std::string& text) + { + if (!initialize()) + { + return toast{-1}; + } + + WinToastLib::WinToastTemplate toast_template(WinToastLib::WinToastTemplate::Text02); + toast_template.setTextField(string::convert(title), WinToastLib::WinToastTemplate::FirstLine); + toast_template.setTextField(string::convert(text), WinToastLib::WinToastTemplate::SecondLine); + toast_template.setDuration(WinToastLib::WinToastTemplate::Long); + + return toast{WinToastLib::WinToast::instance()->showToast(toast_template, new toast_handler())}; + } + + toast toast::show(const std::string& title, const std::string& text, const std::string& image) + { + if (!initialize()) + { + return {-1}; + } + + WinToastLib::WinToastTemplate toast_template(WinToastLib::WinToastTemplate::ImageAndText02); + toast_template.setTextField(string::convert(title), WinToastLib::WinToastTemplate::FirstLine); + toast_template.setTextField(string::convert(text), WinToastLib::WinToastTemplate::SecondLine); + toast_template.setDuration(WinToastLib::WinToastTemplate::Long); + toast_template.setImagePath(string::convert(image)); + + return {WinToastLib::WinToast::instance()->showToast(toast_template, new toast_handler())}; + } +} diff --git a/src/common/utils/toast.hpp b/src/common/utils/toast.hpp new file mode 100644 index 0000000..739c5c8 --- /dev/null +++ b/src/common/utils/toast.hpp @@ -0,0 +1,19 @@ +#pragma once +#include + +namespace utils +{ + class toast + { + public: + static toast show(const std::string& title, const std::string& text); + static toast show(const std::string& title, const std::string& text, const std::string& image); + + operator bool() const; + void hide() const; + + private: + toast(int64_t id); + int64_t id_; + }; +} diff --git a/src/runner/debugger.cpp b/src/runner/debugger.cpp new file mode 100644 index 0000000..d58149b --- /dev/null +++ b/src/runner/debugger.cpp @@ -0,0 +1,95 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include "debugger.hpp" + +namespace +{ + bool acquire_debug_privilege() + { + TOKEN_PRIVILEGES token_privileges; + ZeroMemory(&token_privileges, sizeof(token_privileges)); + token_privileges.PrivilegeCount = 1; + + HANDLE token; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) + { + return false; + } + + if (!LookupPrivilegeValue(nullptr, SE_DEBUG_NAME, &token_privileges.Privileges[0].Luid)) + { + CloseHandle(token); + return false; + } + + token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + DWORD size; + if (!AdjustTokenPrivileges(token, FALSE, &token_privileges, 0, nullptr, &size)) + { + CloseHandle(token); + return false; + } + + return CloseHandle(token) != FALSE; + } +} + +debugger::debugger(const unsigned long process_id, const bool start) +{ + if (!start) + { + return; + } + + this->runner_ = std::thread([this, process_id]() + { + this->terminate_ = false; + this->run(process_id); + }); +} + +debugger::~debugger() +{ + this->terminate_ = true; + if (this->runner_.joinable()) + { + this->runner_.join(); + } +} + +void debugger::run(const unsigned long process_id) const +{ + acquire_debug_privilege(); + if (!DebugActiveProcess(process_id)) + { + return; + } + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); + + DEBUG_EVENT event; + while (!this->terminate_ && WaitForDebugEvent(&event,INFINITE)) + { + if (event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) + { + ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); + continue; + } + + if (event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) + { + ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE); + break; + } + +#ifdef DEV_BUILD + if (event.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) + { + OutputDebugStringA("Debugger attached!\n"); + } +#endif + + ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE); + } +} diff --git a/src/runner/debugger.hpp b/src/runner/debugger.hpp new file mode 100644 index 0000000..99d1073 --- /dev/null +++ b/src/runner/debugger.hpp @@ -0,0 +1,15 @@ +#pragma once +#include + +class debugger +{ +public: + debugger(unsigned long process_id, bool start); + ~debugger(); + +private: + volatile bool terminate_ = false; + std::thread runner_; + + void run(unsigned long process_id) const; +}; diff --git a/src/runner/resource.rc b/src/runner/resource.rc new file mode 100644 index 0000000..e9db75c --- /dev/null +++ b/src/runner/resource.rc @@ -0,0 +1,100 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + +2 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE VFT_DLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "AlterWare" + VALUE "FileDescription", "Steam mod runner" + VALUE "FileVersion", "1.0.0.0" + VALUE "InternalName", "Runner" + VALUE "LegalCopyright", "All rights reserved." + VALUE "OriginalFilename", "runner.exe" + VALUE "ProductName", "runner" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// Binary Data +// + +102 ICON "../client/resources/icon.ico" + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/runner/runner.cpp b/src/runner/runner.cpp new file mode 100644 index 0000000..01c32d2 --- /dev/null +++ b/src/runner/runner.cpp @@ -0,0 +1,26 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include "debugger.hpp" + +int __stdcall WinMain(HINSTANCE, HINSTANCE, PSTR, int) +{ + const auto* const command = "-proc "; + const char* parent_proc = strstr(GetCommandLineA(), command); + + if (parent_proc) + { + const auto pid = DWORD(atoi(parent_proc + strlen(command))); + auto* const process_handle = OpenProcess(SYNCHRONIZE, FALSE, pid); + if (process_handle) + { + //debugger _(pid, strstr(GetCommandLineA(), "-debug ") != nullptr); + WaitForSingleObject(process_handle, INFINITE); + CloseHandle(process_handle); + return 0; + } + } + + return 1; +} diff --git a/src/tlsdll/dllmain.cpp b/src/tlsdll/dllmain.cpp new file mode 100644 index 0000000..56d31a6 --- /dev/null +++ b/src/tlsdll/dllmain.cpp @@ -0,0 +1,7 @@ +#define TLS_PAYLOAD_SIZE 0x2000 +thread_local char tls_data[TLS_PAYLOAD_SIZE]; + +__declspec(dllexport) void* get_tls_data() +{ + return &tls_data[0]; +} diff --git a/src/tlsdll/resource.rc b/src/tlsdll/resource.rc new file mode 100644 index 0000000..dbd2de6 --- /dev/null +++ b/src/tlsdll/resource.rc @@ -0,0 +1,100 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + +2 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE VFT_DLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "AlterWare" + VALUE "FileDescription", "TLS index allocation dll" + VALUE "FileVersion", "1.0.0.0" + VALUE "InternalName", "TLS DLL" + VALUE "LegalCopyright", "All rights reserved." + VALUE "OriginalFilename", "tlsdll.dll" + VALUE "ProductName", "tlsdll" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// Binary Data +// + +// Nothing here + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/tools/protoc.exe b/tools/protoc.exe new file mode 100644 index 0000000..7993ba7 --- /dev/null +++ b/tools/protoc.exe @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7be0d7163d4bc97fde49df00aa789bf386a8d56eab7a394d684c6cf5dfd50030 +size 3909120